diff --git a/.gitignore b/.gitignore index 73e0407c4b..8f8ff1f454 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ cmake_targets/log/ cmake_targets/*/build/ cmake_targets/ran_build/ +cmake_targets/nas_sim_tools/build/ log/ lte_build_oai/ targets/bin/ + +# vscode +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..7f095acc16 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,96 @@ +# RELEASE NOTES: # + +## [v1.2.1](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.2.1) -> February 2020. ## + +* Bug fix for mutex lock for wake-up signal + +## [v1.2.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.2.0) -> January 2020. ## + +This version adds the following implemented features: + +* LTE-M : eNB support for Mode A repetitions + - PUSCH CE - 8 Repetitions +* Improved CDRX implementation for monolithic eNB +* Experimental eMBMS support (now also on eNB side) +* Experimental MCE - Multicast Coordination Entity +* Bug fixes + +This version also has an improved code quality: + +* Better Test Coverage in Continuous Integration: + - Initial framework to do long-run testing at R2LAB + +## [v1.1.1](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.1.1) -> November 2019. ## + +- Bug fix in the TDD Fair Round-Robin scheduler + +## [v1.1.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.1.0) -> July 2019. ## + +This version adds the following implemented features: + +* Experimental support of LTE-M + - Single LTE-M UE attachment, legacy-LTE UE attachment is disabled +* X2 interface and handover (also X2-U interface) + - In FDD and TDD +* CU/DU split (F1 interface) + - Tested only in FDD +* CDRX + - Tested only in FDD +* Experimental eMBMS support (only on UE side) +* Experimental multi-RRU support + - Tested only in TDD + +This version has an improved code quality: + +* Simplification of the Build System + - A single build includes all full-stack simulators, S1/noS1 modes and one HW platform (such as USRP, BladeRF, ...) +* TUN interface is now used as default for the data plane + - for UE, eNB-noS1 and UE-noS1 +* Code Cleanup +* Better Static Code Analysis: + - Limited number of errors in cppcheck + - Important Decrease on high Impact errors in CoverityScan +* Better Test Coverage in Continuous Integration: + - TM2, CDRX, IF4.5, F1 + - OAI UE is tested in S1 and noS1 modes with USRP board + - Multi-RRU TDD mode + - X2 Handover in FDD mode + +## [v1.0.3](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.0.3) -> June 2019. ## + +- Bug fix for LimeSuite v19.04.0 API + +## [v1.0.2](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.0.2) -> February 2019. ## + +- Full OAI support for 3.13.1 UHD + +## [v1.0.1](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.0.1) -> February 2019. ## + +- Bug fix for the UE L1 simulator. + +## [v1.0.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v1.0.0) -> January 2019. ## + +This version first implements the architectural split described in the following picture. + +![Block Diagram](./doc/images/oai_lte_enb_func_split_arch.png) + +* Only FAPI, nFAPI and IF4.5 interfaces are implemented. +* Repository tree structure prepares future integrations of features such as LTE-M, nbIOT or 5G-NR. +* Preliminary X2 support has been implemented. +* S1-flex has been introduced. +* New tools: config library, telnet server, ... +* A lot of bugfixes and a proper automated Continuous Integration process validates contributions. + +Old Releases: + +* v0.6.1 -> Mostly bugfixes. This is the last version without NFAPI. +* v0.6 -> RRH functionality, UE greatly improved, better TDD support, a lot of bugs fixed. + - WARNING: oaisim in PHY abstraction mode does not work, you need to use v0.5.2 for that. +* v0.5.2 -> Last version with old code for oaisim (abstraction mode works) +* v0.5.1 -> Merge of bugfix-137-uplink-fixes. It includes stablity fixes for eNB +* v0.5 -> Merge of enhancement-10-harmony-lts. It includes fixes for Ubuntu 16.04 support +* v0.4 -> Merge of feature-131-new-license. It closes issue#131 and changes the license to OAI Public License V1.0 +* v0.3 -> Last stable commit on develop branch before the merge of feature-131-new-license. This is the last commit with GPL License +* v0.2 -> Merge of enhancement-10-harmony to include NGFI RRH + New Interface for RF/BBU +* v0.1 -> Last stable commit on develop branch before enhancement-10-harmony + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..61e44bdd55 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# Contributing to OpenAirInterface # + +We want to make contributing to this project as easy and transparent as possible. + +Please refer to the steps described on our website: [How to contribute to OAI](https://www.openairinterface.org/?page_id=112) + +1. Sign and return a Contributor License Agreement to OAI team. +2. Create an account on [Eurecom GitLab Server](https://gitlab.eurecom.fr). +3. Provide the identifiant of this account to the OAI team (mailto:contact@openairinterface.org) so you have developer rights on this repository. +4. The policies are described in these wiki pages: [OAI Policies](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/oai-policies-home) + - PLEASE DO NOT FORK the OAI repository on your own Eurecom GitLab account. It just eats up space on our servers. + - You can fork onto another hosting system. But we will NOT accept a merge request from a forked repository. + * This decision was made for the license reasons. + * The Continuous Integration will reject your merge request. + - All merge requests SHALL have `develop` branch as target branch. + +## Coding Styles ## + +There are described [here](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/guidelines/guidelines-home) + +## License ## + +By contributing to OpenAirInterface, you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree. diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000000..65c6105660 --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,23 @@ +The source code of openairinterface5g is distributed under **OAI Public License V1.1**. + +For more details of the license, refer to [LICENSE](LICENSE) file in the same directory. + +However, the source code also contains third party software that is acknowledged here for reference. + +## Credits for LFDS user space source code located in folder openair2/UTILS/LFDS/liblfds6.1.1/ ## + +See on [liblfds website](https://liblfds.org/) the license section. + +
+"There is no license. You are free to use this software in any way, for any purpose. Go forth and create wealth!
+If however for legal reasons a licence is required, the license of your choice will be granted."
+
+ +## Credits for source code common/utils/collection/queue.h: ## + +The Regents of the University of California: BSD 3-Clause Licence. + +## Credits for source code common/utils/collection/tree.h: ## + +Niels Provos : BSD 2-Clause Licence. + diff --git a/NOTICE.txt b/NOTICE.txt deleted file mode 100644 index 38d493284a..0000000000 --- a/NOTICE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The source code of openairinterface5g is distributed under OAI Public License V1.0. -For more details of the license, refer to LICENSE file in the same directory. - -However, the source code also contains third party software that is acknowledged here for reference. - -Credits for LFDS user space source code located in folder openair2/UTILS/LFDS/liblfds6.1.1/ -http://liblfds.org/. -Extract from http://liblfds.org/pages/downloads_and_license.html: -"There is no license. You are free to use this software in any way, for any purpose. Go forth and create wealth! -If however for legal reasons a licence is required, the license of your choice will be granted." - - -Credits for source code common/utils/collection/queue.h: -The Regents of the University of California: BSD 3-Clause Licence. - - -Credits for source code common/utils/collection/tree.h: -Niels Provos : BSD 2-Clause Licence. - - - diff --git a/README.md b/README.md new file mode 100644 index 0000000000..7651aea5c9 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# OpenAirInterface License # + +OpenAirInterface is under OpenAirInterface Software Alliance license. + + * [OAI License Model](http://www.openairinterface.org/?page_id=101) + * [OAI License v1.1 on our website](http://www.openairinterface.org/?page_id=698) + +It is distributed under **OAI Public License V1.1**. + +The license information is distributed under [LICENSE](LICENSE) file in the same directory. + +Please see [NOTICE](NOTICE.md) file for third party software that is included in the sources. + +# Where to Start # + + * [The implemented features](./doc/FEATURE_SET.md) + * [How to build](./doc/BUILD.md) + * [How to run the modems](./doc/RUNMODEM.md) + +# RAN repository structure # + +The OpenAirInterface (OAI) software is composed of the following parts: + +
+openairinterface5g
+├── ci-scripts        : Meta-scripts used by the OSA CI process. Contains also configuration files used day-to-day by CI.
+├── cmake_targets     : Build utilities to compile (simulation, emulation and real-time platforms), and generated build files.
+├── common            : Some common OAI utilities, other tools can be found at openair2/UTILS.
+├── doc               : Contains an up-to-date feature set list and starting tutorials.
+├── executables       : Top-level executable source files.
+├── LICENSE           : License file.
+├── maketags          : Script to generate emacs tags.
+├── nfapi             : Contains the NFAPI code. A local Readme file provides more details.
+├── openair1          : 3GPP LTE Rel-10/12 PHY layer / 3GPP NR Rel-15 layer. A local Readme file provides more details.
+│   ├── PHY
+│   ├── SCHED
+│   ├── SCHED_NBIOT
+│   ├── SCHED_NR
+│   ├── SCHED_NR_UE
+│   ├── SCHED_UE
+│   └── SIMULATION    : PHY RF simulation.
+├── openair2          : 3GPP LTE Rel-10 RLC/MAC/PDCP/RRC/X2AP + LTE Rel-14 M2AP implementation. Also 3GPP NR Rel-15 RLC/MAC/PDCP/RRC/X2AP.
+│   ├── COMMON
+│   ├── DOCS
+│   ├── ENB_APP
+│   ├── F1AP
+│   ├── GNB_APP
+│   ├── LAYER2/RLC/   : with the following subdirectories: UM_v9.3.0, TM_v9.3.0, and AM_v9.3.0.
+│   ├── LAYER2/PDCP/PDCP_v10.1.0
+│   ├── M2AP
+│   ├── MCE_APP
+│   ├── NETWORK_DRIVER
+│   ├── NR_PHY_INTERFACE
+│   ├── NR_UE_PHY_INTERFACE
+│   ├── PHY_INTERFACE
+│   ├── RRC
+│   ├── UTIL
+│   └── X2AP
+├── openair3          : 3GPP LTE Rel10 for S1AP, NAS GTPV1-U for both ENB and UE.
+│   ├── COMMON
+│   ├── DOCS
+│   ├── GTPV1-U
+│   ├── M3AP
+│   ├── MME_APP
+│   ├── NAS
+│   ├── S1AP
+│   ├── SCTP
+│   ├── SECU
+│   ├── TEST
+│   ├── UDP
+│   └── UTILS
+└── targets           : Top-level wrappers for unitary simulation for PHY channels, system-level emulation (eNB-UE with and without S1), and realtime eNB and UE and RRH GW.
+
diff --git a/README.txt b/README.txt deleted file mode 100644 index 8fb670de98..0000000000 --- a/README.txt +++ /dev/null @@ -1,95 +0,0 @@ -OpenAirInterface is under OpenAirInterface Software Alliance license. -├── http://www.openairinterface.org/?page_id=101 -├── http://www.openairinterface.org/?page_id=698 - -It is distributed under OAI Public License V1.1. -The license information is distributed under LICENSE file in the same directory. -Please see NOTICE.txt for third party software that is included in the sources. - -The OpenAirInterface (OAI) software is composed of the following parts: - -openairinterface5g -├── ci-scripts: Meta-scripts used by the OSA CI process. Contains also configuration files used day-to-day by CI. -├── cmake_targets: Build utilities to compile (simulation, emulation and real-time platforms), and generated build files -├── common : Some common OAI utilities, other tools can be found at openair2/UTILS -├── doc : Contains an up-to-date feature set list -├── LICENSE -├── maketags : Script to generate emacs tags -├── nfapi : Contains the NFAPI code. A local Readme file provides more details. -├── openair1 : 3GPP LTE Rel-10/12 PHY layer + PHY RF simulation. A local Readme file provides more details. -├── openair2 : 3GPP LTE Rel-10 RLC/MAC/PDCP/RRC/X2AP implementation. - ├── COMMON - ├── DOCS - ├── ENB_APP - ├── LAYER2/RLC/ with the following subdirectories: UM_v9.3.0, TM_v9.3.0, and AM_v9.3.0. - ├── LAYER2/PDCP/PDCP_v10.1.0. - ├── NETWORK_DRIVER - ├── PHY_INTERFACE - ├── RRC/LITE - ├── UTIL - ├── X2AP -├── openair3: 3GPP LTE Rel10 for S1AP, NAS GTPV1-U for both ENB and UE. - ├── COMMON - ├── DOCS - ├── GTPV1-U - ├── NAS - ├── S1AP - ├── SCTP - ├── SECU - ├── UDP - ├── UTILS -└── targets: Top-level wrappers for unitary simulation for PHY channels, system-level emulation (eNB-UE with and without S1), and realtime eNB and UE and RRH GW. - - -RELEASE NOTES: - -v1.1.1 -> November 2019. Bug fix in the TDD Fair Round-Robin scheduler -v1.1.0 -> July 2019. This version adds the following implemented features: - * Experimental support of LTE-M - - Single LTE-M UE attachment, legacy-LTE UE attachment is disabled - * X2 interface and handover (also X2-U interface) - - In FDD and TDD - * CU/DU split (F1 interface) - - Tested only in FDD - * CDRX - - Tested only in FDD - * Experimental eMBMS support (only on UE side) - * Experimental multi-RRU support - - Tested only in TDD - This version has an improved code quality: - * Simplification of the Build System - - A single build includes all full-stack simulators, S1/noS1 modes and one HW platform (such as USRP, BladeRF, ...) - * TUN interface is now used as default for the data plane - - for UE, eNB-noS1 and UE-noS1 - * Code Cleanup - * Better Static Code Analysis: - - Limited number of errors in cppcheck - - Important Decrease on high Impact errors in CoverityScan - * Better Test Coverage in Continuous Integration: - - TM2, CDRX, IF4.5, F1 - - OAI UE is tested in S1 and noS1 modes with USRP board - - Multi-RRU TDD mode - - X2 Handover in FDD mode - -v1.0.3 -> June 2019: Bug fix for LimeSuite v19.04.0 API -v1.0.2 -> February 2019: Full OAI support for 3.13.1 UHD -v1.0.1 -> February 2019: Bug fix for the UE L1 simulator. -v1.0.0 -> January 2019. This version first implements the architectural split described in doc/oai_lte_enb_func_split_arch.png picture. - Only FAPI, nFAPI and IF4.5 interfaces are implemented. - Repository tree structure prepares future integrations of features such as LTE-M, nbIOT or 5G-NR. - Preliminary X2 support has been implemented. - S1-flex has been introduced. - New tools: config library, telnet server, ... - A lot of bugfixes and a proper automated Continuous Integration process validates contributions. - -v0.6.1 -> Mostly bugfixes. This is the last version without NFAPI. -v0.6 -> RRH functionality, UE greatly improved, better TDD support, - a lot of bugs fixed. WARNING: oaisim in PHY abstraction mode does not - work, you need to use v0.5.2 for that. -v0.5.2 -> Last version with old code for oaisim (abstraction mode works) -v0.5.1 -> Merge of bugfix-137-uplink-fixes. It includes stablity fixes for eNB -v0.5 -> Merge of enhancement-10-harmony-lts. It includes fixes for Ubuntu 16.04 support -v0.4 -> Merge of feature-131-new-license. It closes issue#131 and changes the license to OAI Public License V1.0 -v0.3 -> Last stable commit on develop branch before the merge of feature-131-new-license. This is the last commit with GPL License -v0.2 -> Merge of enhancement-10-harmony to include NGFI RRH + New Interface for RF/BBU -v0.1 -> Last stable commit on develop branch before enhancement-10-harmony diff --git a/ci-scripts/Jenkinsfile-gitlab b/ci-scripts/Jenkinsfile-gitlab index 2792e3556a..8dfa5c4ec4 100644 --- a/ci-scripts/Jenkinsfile-gitlab +++ b/ci-scripts/Jenkinsfile-gitlab @@ -55,6 +55,8 @@ pipeline { "Analysis with cppcheck", "Test phy-sim", "Test basic-sim", + "Test L1-sim", + "Test RF-sim", "Test L2-sim", "Test-Mono-FDD-Band7", "Test-Mono-TDD-Band40", @@ -340,7 +342,11 @@ pipeline { always { script { dir ('archives') { - sh "zip -r -qq vm_build_logs.zip basic_sim enb_usrp phy_sim cppcheck enb_eth ue_eth gnb_usrp nrue_usrp red_hat" + if (fileExists('red_hat')) { + sh "zip -r -qq vm_build_logs.zip basic_sim enb_usrp phy_sim cppcheck enb_eth ue_eth gnb_usrp nr_ue_usrp red_hat" + } else { + sh "zip -r -qq vm_build_logs.zip basic_sim enb_usrp phy_sim cppcheck enb_eth ue_eth gnb_usrp nr_ue_usrp" + } } if(fileExists('archives/vm_build_logs.zip')) { archiveArtifacts artifacts: 'archives/vm_build_logs.zip' diff --git a/ci-scripts/Jenkinsfile-inria-r2lab b/ci-scripts/Jenkinsfile-inria-r2lab index 6ae7522999..3c4dddae8b 100644 --- a/ci-scripts/Jenkinsfile-inria-r2lab +++ b/ci-scripts/Jenkinsfile-inria-r2lab @@ -59,6 +59,9 @@ def r2labEPC0IpAddr = r2labBaseIpAddr + r2labEPC0Idx def r2labUE0Idx = '6' def r2labUE0 = 'fit0' + r2labUE0Idx def r2labUE0IpAddr = r2labBaseIpAddr + r2labUE0Idx +def r2labENB1Idx = '16' +def r2labENB1 = 'fit' + r2labENB1Idx +def r2labENB1IpAddr = r2labBaseIpAddr + r2labENB1Idx pipeline { agent { @@ -131,7 +134,7 @@ pipeline { [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.R2LAB_Credentials}", usernameVariable: 'r2labuser', passwordVariable: 'r2labpassword'] ]) { sh "python3 /home/eurecom/inria-scripts/booking-lease.py --book-lease --from ${BOOK_TIMESTAMP}T${r2labStartTime} --duration ${r2labDuration} --slice inria_oaici ${r2labuser} ${r2labpassword}" - sh "python3 /home/eurecom/inria-scripts/booking-lease.py --get-leases ${r2labuser} ${r2labpassword}" + sh "python3 /home/eurecom/inria-scripts/booking-lease.py --get-leases ${r2labuser} ${r2labpassword} | grep -v nightly" } } } @@ -143,21 +146,25 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labPythonExeIdx} > /dev/null 2>&1'" sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labPythonExeIdx}'" - echo '\u2705 \u001B[32mLoad Image for one eNB\u001B[0m' - sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx} > /dev/null 2>&1'" - sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labENB0Idx}'" - sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx}'" + echo '\u2705 \u001B[32mLoad Image for two (2) eNBs\u001B[0m' + sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx},${r2labENB1Idx} > /dev/null 2>&1'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labENB0Idx},${r2labENB1Idx}'" + sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx},${r2labENB1Idx}'" + sh "sleep 5" + sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx},${r2labENB1Idx}'" echo '\u2705 \u001B[32mLoad Image for one OAI UE\u001B[0m' sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labUE0Idx} > /dev/null 2>&1'" sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labUE0Idx}'" sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labUE0Idx}'" + sh "sleep 5" + sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labUE0Idx}'" echo '\u2705 \u001B[32mLoad Image for one EPC\u001B[0m' sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-epc ${r2labEPC0Idx} > /dev/null 2>&1'" sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labEPC0Idx}'" - sh "ssh -t inria_oaici@faraday.inria.fr 'nodes ${r2labUE0Idx},${r2labPythonExeIdx},${r2labEPC0Idx},${r2labENB0Idx} && st'" + sh "ssh -t inria_oaici@faraday.inria.fr 'nodes ${r2labUE0Idx},${r2labPythonExeIdx},${r2labEPC0Idx},${r2labENB0Idx},${r2labENB1Idx} && st'" } } } @@ -183,7 +190,6 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:m11 172.16.1.102 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:m10 192.168.10.110 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:sxu 172.55.55.102 up\"'" - sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:s1u 192.168.248.159 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:sxc 172.55.55.101 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:s5c 172.58.58.102 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:p5c 172.58.58.101 up\"'" @@ -195,9 +201,6 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ip rule add from 12.0.0.0/8 table lte\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ip rule add from 12.1.1.0/8 table lte\"'" - // Adding a route on the eNB for the S1U interface - sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labENB0} \"echo ${fitpasswd} | sudo -S ip route add 192.168.248.0/24 via ${r2labEPC0IpAddr} dev control\"'" - // For the moment, simple way to route traffic from python executor to any UEs sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labPythonExe} \"echo ${fitpasswd} | sudo -S ip route add 12.1.1.0/24 via ${r2labEPC0IpAddr} dev control\"'" } @@ -214,7 +217,7 @@ pipeline { String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") for (xmlFile in myXmlTestSuite) { try { - sh "ssh -t -t inria_oaici@faraday.inria.fr 'ssh -t -t -b 192.168.3.100 ${fituser}@${r2labPythonExe} \"cd openairinterface5g/ci-scripts && python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=${ranRepoBranch} --ranCommitID=${GIT_COMMIT_TO_RUN} --ranAllowMerge=false --eNBIPAddress=${r2labENB0IpAddr} --eNBUserName=${fituser} --eNBPassword=${fitpasswd} --eNBSourceCodePath=/home/${fituser}/openairinterface5g --UEIPAddress=${r2labUE0IpAddr} --UEUserName=${fituser} --UEPassword=${fitpasswd} --UESourceCodePath=/home/${fituser}/openairinterface5g --EPCIPAddress=${r2labEPC0IpAddr} --EPCType=OAI-Rel14-CUPS --EPCUserName=${fituser} --EPCPassword=${fitpasswd} --EPCSourceCodePath=/home/${fituser}/openair-cn --ADBIPAddress=${r2labEPC0IpAddr} --ADBUserName=${fituser} --ADBPassword=${fitpasswd} --ADBType=distributed --XMLTestFile=${xmlFile}\"'" + sh "ssh -t -t inria_oaici@faraday.inria.fr 'ssh -t -t -b 192.168.3.100 ${fituser}@${r2labPythonExe} \"cd openairinterface5g/ci-scripts && python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=${ranRepoBranch} --ranCommitID=${GIT_COMMIT_TO_RUN} --ranAllowMerge=false --eNBIPAddress=${r2labENB0IpAddr} --eNBUserName=${fituser} --eNBPassword=${fitpasswd} --eNBSourceCodePath=/home/${fituser}/openairinterface5g --eNB1IPAddress=${r2labENB1IpAddr} --eNB1UserName=${fituser} --eNB1Password=${fitpasswd} --eNB1SourceCodePath=/home/${fituser}/openairinterface5g --UEIPAddress=${r2labUE0IpAddr} --UEUserName=${fituser} --UEPassword=${fitpasswd} --UESourceCodePath=/home/${fituser}/openairinterface5g --EPCIPAddress=${r2labEPC0IpAddr} --EPCType=OAI-Rel14-CUPS --EPCUserName=${fituser} --EPCPassword=${fitpasswd} --EPCSourceCodePath=/home/${fituser}/openair-cn --ADBIPAddress=${r2labEPC0IpAddr} --ADBUserName=${fituser} --ADBPassword=${fitpasswd} --ADBType=distributed --XMLTestFile=${xmlFile}\"'" } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false diff --git a/ci-scripts/Jenkinsfile-tmp-full-ran b/ci-scripts/Jenkinsfile-tmp-full-ran index 7211a54bcf..15ad0379af 100644 --- a/ci-scripts/Jenkinsfile-tmp-full-ran +++ b/ci-scripts/Jenkinsfile-tmp-full-ran @@ -208,12 +208,12 @@ pipeline { [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'], [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.ADB_Credentials}", usernameVariable: 'ADB_Username', passwordVariable: 'ADB_Password'] ]) { - sh "python3 main.py --mode=InitiateHtml --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}" + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}" String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") for (xmlFile in myXmlTestSuite) { if (fileExists(xmlFile)) { try { - sh "python3 main.py --mode=TesteNB --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBTargetBranch=${eNB_TargetBranch} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --UEIPAddress=${params.UE_IPAddress} --UEUserName=${UE_Username} --UEPassword=${UE_Password} --UESourceCodePath=${params.UE_SourceCodePath} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile}" + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --UEIPAddress=${params.UE_IPAddress} --UEUserName=${UE_Username} --UEPassword=${UE_Password} --UESourceCodePath=${params.UE_SourceCodePath} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile}" } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false diff --git a/ci-scripts/Jenkinsfile-tmp-ran b/ci-scripts/Jenkinsfile-tmp-ran index 5ffaefa89f..ab1573de7f 100644 --- a/ci-scripts/Jenkinsfile-tmp-ran +++ b/ci-scripts/Jenkinsfile-tmp-ran @@ -36,6 +36,9 @@ def testStageName = params.pipelineTestStageName // Name of the phone resource def ciSmartPhoneResource = params.smartphonesResource +// Name of the phone resource +def ciEpcResource = params.epcResource + // Terminate Status def termUE = 0 def termENB = 1 @@ -64,7 +67,7 @@ pipeline { options { disableConcurrentBuilds() ansiColor('xterm') - lock (ciSmartPhoneResource) + lock(extra: [[resource: ciEpcResource]], resource: ciSmartPhoneResource) } // the following parameter options are commented out so it shows the ones // that you SHALL have to run the job. @@ -217,12 +220,12 @@ pipeline { [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'], [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.ADB_Credentials}", usernameVariable: 'ADB_Username', passwordVariable: 'ADB_Password'] ]) { - sh "python3 main.py --mode=InitiateHtml --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}" + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}" String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") for (xmlFile in myXmlTestSuite) { if (fileExists(xmlFile)) { try { - sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile}" + sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile}" } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false diff --git a/ci-scripts/Jenkinsfile-tmp-ue b/ci-scripts/Jenkinsfile-tmp-ue index c2db977bcb..e5e456cf7f 100644 --- a/ci-scripts/Jenkinsfile-tmp-ue +++ b/ci-scripts/Jenkinsfile-tmp-ue @@ -187,12 +187,12 @@ pipeline { [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.UE_Credentials}", usernameVariable: 'UE_Username', passwordVariable: 'UE_Password'], [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.ADB_Credentials}", usernameVariable: 'ADB_Username', passwordVariable: 'ADB_Password'] ]) { - sh "python3 main.py --mode=InitiateHtml --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}" + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}" String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") for (xmlFile in myXmlTestSuite) { if (fileExists(xmlFile)) { try { - sh "python3 main.py --mode=TestUE --UEIPAddress=${params.UE_IPAddress} --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBTargetBranch=${eNB_TargetBranch} --UEUserName=${UE_Username} --UEPassword=${UE_Password} --UESourceCodePath=${params.UE_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile}" + sh "python3 main.py --mode=TestUE --UEIPAddress=${params.UE_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --UEUserName=${UE_Username} --UEPassword=${UE_Password} --UESourceCodePath=${params.UE_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile}" } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false diff --git a/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf new file mode 100644 index 0000000000..db1c5eae2a --- /dev/null +++ b/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf @@ -0,0 +1,273 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + // In seconds + rrc_inactivity_threshold = 30; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_eNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 17; + downlink_frequency = 736000000L; + uplink_frequency_offset = -30000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -25; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -104; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + + //Parameters for SIB18 + rxPool_sc_CP_Len = "normal"; + rxPool_sc_Period = "sf40"; + rxPool_data_CP_Len = "normal"; + rxPool_ResourceConfig_prb_Num = 20; + rxPool_ResourceConfig_prb_Start = 5; + rxPool_ResourceConfig_prb_End = 44; + rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + rxPool_ResourceConfig_offsetIndicator_choice = 0; + rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; +/* rxPool_dataHoppingConfig_hoppingParameter = 0; + rxPool_dataHoppingConfig_numSubbands = "ns1"; + rxPool_dataHoppingConfig_rbOffset = 0; + rxPool_commTxResourceUC-ReqAllowed = "TRUE"; +*/ + // Parameters for SIB19 + discRxPool_cp_Len = "normal" + discRxPool_discPeriod = "rf32" + discRxPool_numRetx = 1; + discRxPool_numRepetition = 2; + discRxPool_ResourceConfig_prb_Num = 5; + discRxPool_ResourceConfig_prb_Start = 3; + discRxPool_ResourceConfig_prb_End = 21; + discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + discRxPool_ResourceConfig_offsetIndicator_choice = 0; + discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; + + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + phy_test_mode = 0; + puSch10xSnr = 160; + puCch10xSnr = 160; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 125; + eNB_instances = [0]; + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "eth0"; + FLEXRAN_IPV4_ADDRESS = "CI_MME_IP_ADDR"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf new file mode 100644 index 0000000000..fbb8c5d6f8 --- /dev/null +++ b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf @@ -0,0 +1,417 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + // In seconds + rrc_inactivity_threshold = 30; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_eNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 17; + downlink_frequency = 736000000L; + uplink_frequency_offset = -30000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -25; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -104; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + + //Parameters for SIB18 + rxPool_sc_CP_Len = "normal"; + rxPool_sc_Period = "sf40"; + rxPool_data_CP_Len = "normal"; + rxPool_ResourceConfig_prb_Num = 20; + rxPool_ResourceConfig_prb_Start = 5; + rxPool_ResourceConfig_prb_End = 44; + rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + rxPool_ResourceConfig_offsetIndicator_choice = 0; + rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; +/* rxPool_dataHoppingConfig_hoppingParameter = 0; + rxPool_dataHoppingConfig_numSubbands = "ns1"; + rxPool_dataHoppingConfig_rbOffset = 0; + rxPool_commTxResourceUC-ReqAllowed = "TRUE"; +*/ + // Parameters for SIB19 + discRxPool_cp_Len = "normal" + discRxPool_discPeriod = "rf32" + discRxPool_numRetx = 1; + discRxPool_numRepetition = 2; + discRxPool_ResourceConfig_prb_Num = 5; + discRxPool_ResourceConfig_prb_Start = 3; + discRxPool_ResourceConfig_prb_End = 21; + discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + discRxPool_ResourceConfig_offsetIndicator_choice = 0; + discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; + + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + + ///M2 + target_mce_m2_ip_address = ( { ipv4 = "127.0.0.7"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_enb_m2 = "yes"; + + mbms_configuration_data_list = ( + { + mbsfn_sync_area = 0x0001; + mbms_service_area_list=( + { + mbms_service_area=0x0001; + } + ); + } + + ); + + + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + ENB_IPV4_ADDRESS_FOR_M2C = "127.0.0.2/24"; + ENB_PORT_FOR_M2C = 36443; # Spec 36443 + }; + } +); + +MCEs = ( + { + MCE_ID = 0xe00; + + MCE_name = "MCE-Vicomtech-LTEBox"; + + //M2 + enable_mce_m2 = "yes"; + + //M3 + enable_mce_m3 = "yes"; + + target_mme_m3_ip_address = ( { ipv4 = "127.0.0.18"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + + NETWORK_INTERFACES : + { + MCE_INTERFACE_NAME_FOR_M2_ENB = "lo"; + MCE_IPV4_ADDRESS_FOR_M2C = "127.0.0.7/24"; + MCE_PORT_FOR_M2C = 36443; # Spec 36443 + + MCE_INTERFACE_NAME_FOR_M3_MME = "lo"; + MCE_IPV4_ADDRESS_FOR_M3C = "127.0.0.3/24"; + MCE_PORT_FOR_M3C = 36444; # Spec 36444 + }; + + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + }; + + mbms_sched_info : + { + mcch_update_time = 10; + mbms_area_config_list = ( + { + common_sf_allocation_period = 2; #rf4(0) rf8(1) rf16(2) rf32(3) rf64(4) rf128(5) rf256(6) + mbms_area_id = 0; + pmch_config_list = ( + { + allocated_sf_end=64; + data_mcs=10; + mch_scheduling_period = 0; #rf8(0) + mbms_session_list = ( + { + #plnm + service_id ->tmgi + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + } + service_id=0; + lcid=8; #this must be properly defined lcid:8+service:0 -> rab_id:8 + } + ); + } + ); + + mbms_sf_config_list = ( + { + radioframe_allocation_period=1; #n1(0) n2(1) n4(2) n8(3) n16(4) n32(5) + radioframe_alloocation_offset=0; + num_frame="oneFrame"; + subframe_allocation=57; #xx100000 + //num_frame="fourFrame"; + //subframe_allocation=14548987; # + } + + ); + + } + ); + }; + mcch_config_per_mbsfn_area = ( + { + mbsfn_area = 0; + pdcch_length = 1; #s1(0), s2(1) + repetition_period = 0; #rf32(0), rf64(1), rf128(2), rf256(3) + offset = 0; + modification_period = 0; #rf512(0; rf1024(1) + subframe_allocation_info = 32; #BITSTRING (6bits -> one frame) xx100101 + mcs = 0; #n2(0), n7(1), n13(2), n19(3) + } + ); + #); #end mbms_scheduling_info + + } +); + + +MMEs = ( + { + MME_ID = 0xe00; + + MME_name = "MME-MBMS-Vicomtech-LTEBox"; + + //M3 + enable_mme_m3 = "yes"; + NETWORK_INTERFACES : + { + MME_INTERFACE_NAME_FOR_M3_MCE = "lo"; + MME_IPV4_ADDRESS_FOR_M3C = "127.0.0.18/24"; + MME_PORT_FOR_M3C = 36444; # Spec 36444 + + }; + } +); + + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + phy_test_mode = 0; + puSch10xSnr = 160; + puCch10xSnr = 160; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 125; + eNB_instances = [0]; + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "eth0"; + FLEXRAN_IPV4_ADDRESS = "CI_MME_IP_ADDR"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf new file mode 100644 index 0000000000..46ab966017 --- /dev/null +++ b/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf @@ -0,0 +1,279 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe10; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + // In seconds + rrc_inactivity_threshold = 30; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_eNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 10; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -25; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -104; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + + //Parameters for SIB18 + rxPool_sc_CP_Len = "normal"; + rxPool_sc_Period = "sf40"; + rxPool_data_CP_Len = "normal"; + rxPool_ResourceConfig_prb_Num = 20; + rxPool_ResourceConfig_prb_Start = 5; + rxPool_ResourceConfig_prb_End = 44; + rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + rxPool_ResourceConfig_offsetIndicator_choice = 0; + rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; +/* rxPool_dataHoppingConfig_hoppingParameter = 0; + rxPool_dataHoppingConfig_numSubbands = "ns1"; + rxPool_dataHoppingConfig_rbOffset = 0; + rxPool_commTxResourceUC-ReqAllowed = "TRUE"; +*/ + // Parameters for SIB19 + discRxPool_cp_Len = "normal" + discRxPool_discPeriod = "rf32" + discRxPool_numRetx = 1; + discRxPool_numRepetition = 2; + discRxPool_ResourceConfig_prb_Num = 5; + discRxPool_ResourceConfig_prb_Start = 3; + discRxPool_ResourceConfig_prb_End = 21; + discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + discRxPool_ResourceConfig_offsetIndicator_choice = 0; + discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; + + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + target_enb_x2_ip_address = ( + { ipv4 = "CI_RCC_IP_ADDR"; + ipv6 = "192:168:30::17"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + phy_test_mode = 0; + puSch10xSnr = 160; + puCch10xSnr = 160; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 125; + eNB_instances = [0]; + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "eth0"; + FLEXRAN_IPV4_ADDRESS = "CI_MME_IP_ADDR"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf index e71bb00ffb..d92804ae44 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf @@ -21,183 +21,166 @@ gNBs = ////////// Physical parameters: - component_carriers = ( - { - node_function = "3GPP_gNODEB"; - node_timing = "synch_to_ext_device"; - node_synch_ref = 0; - frame_type = "TDD"; - DL_prefix_type = "NORMAL"; - UL_prefix_type = "NORMAL"; - eutra_band = 78; - downlink_frequency = 3510000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 106; - nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 125; - MIB_subCarrierSpacingCommon = 30; - MIB_ssb_SubcarrierOffset = 0; - MIB_dmrs_TypeA_Position = 2; - pdcch_ConfigSIB1 = 0; - SIB1_frequencyOffsetSSB = "khz5"; - SIB1_ssb_PeriodicityServingCell = 5; - SIB1_ss_PBCH_BlockPower = -60; - absoluteFrequencySSB = 0; - DL_FreqBandIndicatorNR = 15; - DL_absoluteFrequencyPointA = 15; - DL_offsetToCarrier = 15; - DL_SCS_SubcarrierSpacing = "kHz30"; - DL_SCS_SpecificCarrier_k0 = 0; - DL_carrierBandwidth = 15; - DL_locationAndBandwidth = 15; - DL_BWP_SubcarrierSpacing = "kHz30"; - DL_BWP_prefix_type = "NORMAL"; - UL_FreqBandIndicatorNR = 15; - UL_absoluteFrequencyPointA = 13; - UL_additionalSpectrumEmission = 3; - UL_p_Max = -1; - UL_frequencyShift7p5khz = "TRUE"; - UL_offsetToCarrier = 10; - UL_SCS_SubcarrierSpacing = "kHz30"; - UL_SCS_SpecificCarrier_k0 = 0; - UL_carrierBandwidth = 15; - UL_locationAndBandwidth = 15; - UL_BWP_SubcarrierSpacing = "kHz30"; - UL_BWP_prefix_type = "NORMAL"; - UL_timeAlignmentTimerCommon = "infinity"; - ServingCellConfigCommon_n_TimingAdvanceOffset = "n0" - ServingCellConfigCommon_ssb_PositionsInBurst_PR = 0x01; - ServingCellConfigCommon_ssb_periodicityServingCell = 10; - ServingCellConfigCommon_dmrs_TypeA_Position = 2; - NIA_SubcarrierSpacing = "kHz15"; - ServingCellConfigCommon_ss_PBCH_BlockPower = -60; - referenceSubcarrierSpacing = "kHz15"; - dl_UL_TransmissionPeriodicity = "ms0p5"; - nrofDownlinkSlots = 10; - nrofDownlinkSymbols = 10; - nrofUplinkSlots = 10; - nrofUplinkSymbols = 10; - rach_totalNumberOfRA_Preambles = 63; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_choice = "oneEighth"; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneEighth = 4; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneFourth = 8; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneHalf = 16; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_one = 24; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_two = 32; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_four = 8; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_eight = 4; - rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_sixteen = 2; - rach_groupBconfigured = "ENABLE"; - rach_ra_Msg3SizeGroupA = 56; - rach_messagePowerOffsetGroupB = "dB0"; - rach_numberOfRA_PreamblesGroupA = 32; - rach_ra_ContentionResolutionTimer = 8; - rsrp_ThresholdSSB = 64; - rsrp_ThresholdSSB_SUL = 64; - prach_RootSequenceIndex_choice = "l839"; - prach_RootSequenceIndex_l839 = 0; - prach_RootSequenceIndex_l139 = 0; - prach_msg1_SubcarrierSpacing = "kHz30"; - restrictedSetConfig = "unrestrictedSet"; - msg3_transformPrecoding = "ENABLE"; - prach_ConfigurationIndex = 10; - prach_msg1_FDM = "one"; - prach_msg1_FrequencyStart = 10; - zeroCorrelationZoneConfig = 10; - preambleReceivedTargetPower = -150; - preambleTransMax = 6; - powerRampingStep = "dB0"; - ra_ResponseWindow = 8; - groupHoppingEnabledTransformPrecoding = "ENABLE"; - msg3_DeltaPreamble = 0; - p0_NominalWithGrant = 0; - PUSCH_TimeDomainResourceAllocation_k2 = 0; - PUSCH_TimeDomainResourceAllocation_mappingType = "typeA"; - PUSCH_TimeDomainResourceAllocation_startSymbolAndLength = 0; - pucch_ResourceCommon = 0; - pucch_GroupHopping = "neither"; - hoppingId = 0; - p0_nominal = -30; - PDSCH_TimeDomainResourceAllocation_k0 = 2; - PDSCH_TimeDomainResourceAllocation_mappingType = "typeA"; - PDSCH_TimeDomainResourceAllocation_startSymbolAndLength = 0; - rateMatchPatternId = 0; - RateMatchPattern_patternType = "bitmaps"; - symbolsInResourceBlock = "oneSlot"; - periodicityAndPattern = 2; - RateMatchPattern_controlResourceSet = 5; - RateMatchPattern_subcarrierSpacing = "kHz30"; - RateMatchPattern_mode = "dynamic"; - controlResourceSetZero = 0; - searchSpaceZero = 0; - searchSpaceSIB1 = 10; - searchSpaceOtherSystemInformation = 10; - pagingSearchSpace = 10; - ra_SearchSpace = 10; - PDCCH_common_controlResourceSetId = 5; - PDCCH_common_ControlResourceSet_duration = 2; - PDCCH_cce_REG_MappingType = "nonInterleaved"; - PDCCH_reg_BundleSize = 3; - PDCCH_interleaverSize = 3; - PDCCH_shiftIndex = 10; - PDCCH_precoderGranularity = "sameAsREG-bundle"; - PDCCH_TCI_StateId = 32; - tci_PresentInDCI = "ENABLE"; - PDCCH_DMRS_ScramblingID = 0; - SearchSpaceId = 10; - commonSearchSpaces_controlResourceSetId = 5; - SearchSpace_monitoringSlotPeriodicityAndOffset_choice = "sl1"; - SearchSpace_monitoringSlotPeriodicityAndOffset_value = 0; - SearchSpace_duration = 2; - SearchSpace_nrofCandidates_aggregationLevel1 = 0; - SearchSpace_nrofCandidates_aggregationLevel2 = 0; - SearchSpace_nrofCandidates_aggregationLevel4 = 0; - SearchSpace_nrofCandidates_aggregationLevel8 = 0; - SearchSpace_nrofCandidates_aggregationLevel16 = 0; - SearchSpace_searchSpaceType = "common"; - Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel1 = 1; - Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel2 = 1; - Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel4 = 1; - Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel8 = 1; - Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel16 = 1; - Common_dci_Format2_3_monitoringPeriodicity = 1; - Common_dci_Format2_3_nrofPDCCH_Candidates = 1; - ue_Specific__dci_Formats = "formats0-0-And-1-0"; - RateMatchPatternLTE_CRS_carrierFreqDL = 6; - RateMatchPatternLTE_CRS_carrierBandwidthDL = 6; - RateMatchPatternLTE_CRS_nrofCRS_Ports = 1; - RateMatchPatternLTE_CRS_v_Shift = 0; - RateMatchPatternLTE_CRS_radioframeAllocationPeriod = 1; - RateMatchPatternLTE_CRS_radioframeAllocationOffset = 0; - RateMatchPatternLTE_CRS_subframeAllocation_choice = "oneFrame"; - } - ); - - - srb1_parameters : + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + + servingCellConfigCommon = ( { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] - timer_poll_retransmit = 80; + #spCellConfigCommon - # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] - timer_reordering = 35; + physCellId = 0; - # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] - timer_status_prohibit = 0; +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641032; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640000; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=50 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 13475; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=2,L=3 + initialDLBWPstartSymbolAndLength_0 = 40; - # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] - poll_pdu = 4; + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=2,L=12 + initialDLBWPstartSymbolAndLength_1 = 53; - # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] - poll_byte = 99999; + initialDLBWPk0_2 = 0; + initialDLBWPmappingType_2 = 0; + #this is SS=1,L=12 + initialDLBWPstartSymbolAndLength_2 = 54; + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 13475; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -118; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#0 = 839, 1 = 139 + prach_RootSequenceIndex_PR = 1; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, + +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 2; + initialULBWPmappingType_0 = 1 + # this is SS=0 L=11 + initialULBWPstartSymbolAndLength_0 = 55; + + initialULBWPk2_1 = 2; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=12 + initialULBWPstartSymbolAndLength_1 = 69; + + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 10; + } + + ); - # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] - max_retx_threshold = 4; - } # ------- SCTP definitions SCTP : @@ -254,8 +237,8 @@ RUs = ( max_pdschReferenceSignalPower = -27; max_rxgain = 114; eNB_instances = [0]; - sdr_addrs = "addr=192.168.20.2,second_addr=192.168.10.2,mgmt_addr=192.168.20.2,clock_source=external,time_source=external"; - + sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2"; + clock_src = "external"; } ); @@ -268,16 +251,6 @@ THREAD_STRUCT = ( } ); -NETWORK_CONTROLLER : -{ - FLEXRAN_ENABLED = "no"; - FLEXRAN_INTERFACE_NAME = "lo"; - FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; - FLEXRAN_PORT = 2210; - FLEXRAN_CACHE = "/mnt/oai_agent_cache"; - FLEXRAN_AWAIT_RECONF = "no"; -}; - log_config : { global_log_level ="info"; diff --git a/ci-scripts/conf_files/lte-fdd-mbms-basic-sim.conf b/ci-scripts/conf_files/lte-fdd-mbms-basic-sim.conf new file mode 100644 index 0000000000..53261ec32d --- /dev/null +++ b/ci-scripts/conf_files/lte-fdd-mbms-basic-sim.conf @@ -0,0 +1,418 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_eNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -27; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -104; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + + //Parameters for SIB18 + rxPool_sc_CP_Len = "normal"; + rxPool_sc_Period = "sf40"; + rxPool_data_CP_Len = "normal"; + rxPool_ResourceConfig_prb_Num = 20; + rxPool_ResourceConfig_prb_Start = 5; + rxPool_ResourceConfig_prb_End = 44; + rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + rxPool_ResourceConfig_offsetIndicator_choice = 0; + rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; +/* rxPool_dataHoppingConfig_hoppingParameter = 0; + rxPool_dataHoppingConfig_numSubbands = "ns1"; + rxPool_dataHoppingConfig_rbOffset = 0; + rxPool_commTxResourceUC-ReqAllowed = "TRUE"; +*/ + // Parameters for SIB19 + discRxPool_cp_Len = "normal" + discRxPool_discPeriod = "rf32" + discRxPool_numRetx = 1; + discRxPool_numRepetition = 2; + discRxPool_ResourceConfig_prb_Num = 5; + discRxPool_ResourceConfig_prb_Start = 3; + discRxPool_ResourceConfig_prb_End = 21; + discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + discRxPool_ResourceConfig_offsetIndicator_choice = 0; + discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; + + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + + ////////// MCE parameters: + target_mce_m2_ip_address = ( { ipv4 = "127.0.0.7"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + ///M2 + enable_enb_m2 = "yes"; + + + mbms_configuration_data_list = ( + { + mbsfn_sync_area = 0x0001; + mbms_service_area_list=( + { + mbms_service_area=0x0001; + } + ); + } + + ); + + + + NETWORK_INTERFACES : + { + + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + + ENB_IPV4_ADDRESS_FOR_M2C = "127.0.0.2/24"; + ENB_PORT_FOR_M2C = 36443; # Spec 36443 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + phy_test_mode = 0; + puSch10xSnr = 200; + puCch10xSnr = 200; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +MCEs = ( + { + MCE_ID = 0xe00; + + MCE_name = "MCE-Vicomtech-LTEBox"; + + //M2 + enable_mce_m2 = "yes"; + + //M3 + enable_mce_m3 = "yes"; + + target_mme_m3_ip_address = ( { ipv4 = "127.0.0.18"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + + NETWORK_INTERFACES : + { + MCE_INTERFACE_NAME_FOR_M2_ENB = "lo"; + MCE_IPV4_ADDRESS_FOR_M2C = "127.0.0.7/24"; + MCE_PORT_FOR_M2C = 36443; # Spec 36443 + + MCE_INTERFACE_NAME_FOR_M3_MME = "lo"; + MCE_IPV4_ADDRESS_FOR_M3C = "127.0.0.3/24"; + MCE_PORT_FOR_M3C = 36444; # Spec 36444 + }; + + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + }; + + mbms_sched_info : + { + mcch_update_time = 10; + mbms_area_config_list = ( + { + common_sf_allocation_period = 1; #rf4(0) rf8(1) rf16(2) rf32(3) rf64(4) rf128(5) rf256(6) + mbms_area_id = 0; + pmch_config_list = ( + { + allocated_sf_end=32; + data_mcs=14; + mch_scheduling_period = 0; #rf8(0) + mbms_session_list = ( + { + #plnm + service_id ->tmgi + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + } + service_id=0; #keep this allways as 0 (workaround for TUN if) + lcid=5; #this must be properly defined lcid:6+service:0 -> rab_id:5 //with new RLC set lcid either 4 or 5 + } + ); + } + ); + + mbms_sf_config_list = ( + { + radioframe_allocation_period=0; #n1(0) n2(1) n4(2) n8(3) n16(4) n32(5) + radioframe_alloocation_offset=0; + num_frame="oneFrame"; + subframe_allocation=57; #xx111001 + //num_frame="fourFrame"; + //subframe_allocation=14548987; # + } + ); + + } + ); + }; + + + mcch_config_per_mbsfn_area = ( + { + mbsfn_area = 0; + pdcch_length = 1; #s1(0), s2(1) + repetition_period = 0; #rf32(0), rf64(1), rf128(2), rf256(3) + offset = 0; + modification_period = 0; #rf512(0; rf1024(1) + subframe_allocation_info = 32; #BITSTRING (6bits -> one frame) xx100000 + mcs = 1; #n2(0), n7(1), n13(2), n19(3) + } + ); + + #); #end mbms_scheduling_info + + } +); + +MMEs = ( + { + MME_ID = 0xe00; + + MME_name = "MME-MBMS-Vicomtech-LTEBox"; + + //M3 + enable_mme_m3 = "yes"; + NETWORK_INTERFACES : + { + MME_INTERFACE_NAME_FOR_M3_MCE = "lo"; + MME_IPV4_ADDRESS_FOR_M3C = "127.0.0.18/24"; + MME_PORT_FOR_M3C = 36444; # Spec 36444 + + }; + } +); + + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 125; + eNB_instances = [0]; + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "ens3"; + FLEXRAN_IPV4_ADDRESS = "CI_FLEXRAN_CTL_IP_ADDR"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; diff --git a/ci-scripts/conf_files/rcc.band7.tm1.mbms-s1ap.if4p5.50PRB.lo.conf b/ci-scripts/conf_files/rcc.band7.tm1.mbms-s1ap.if4p5.50PRB.lo.conf new file mode 100644 index 0000000000..b61e5e05b1 --- /dev/null +++ b/ci-scripts/conf_files/rcc.band7.tm1.mbms-s1ap.if4p5.50PRB.lo.conf @@ -0,0 +1,378 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + # real_time choice in {hard, rt-preempt, no} + real_time = "no"; + + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 600; + + plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "NGFI_RCC_IF4p5"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2685000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 50; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 2; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -27; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -104; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + mbms_dedicated_serving_cell = "DISABLE" + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.15.130"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + + + ////////// MCE parameters: + target_mce_m2_ip_address = ( { ipv4 = "127.0.0.7"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + ///M2 + enable_enb_m2 = "yes"; + + + mbms_configuration_data_list = ( + { + mbsfn_sync_area = 0x0001; + mbms_service_area_list=( + { + mbms_service_area=0x0001; + } + ); + } + + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "enp2s0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.10.15/24"; + ENB_INTERFACE_NAME_FOR_S1U = "enp2s0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.10.15/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + + ENB_IPV4_ADDRESS_FOR_X2C = "127.0.0.2/24"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + + ENB_IPV4_ADDRESS_FOR_M2C = "127.0.0.2/24"; + ENB_PORT_FOR_M2C = 36443; # Spec 36443 + }; + } +); + +MCEs = ( + { + MCE_ID = 0xe00; + + MCE_name = "MCE-Vicomtech-LTEBox"; + + //M2 + enable_mce_m2 = "yes"; + + //M3 + enable_mce_m3 = "yes"; + + target_mme_m3_ip_address = ( { ipv4 = "127.0.0.18"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + + NETWORK_INTERFACES : + { + MCE_INTERFACE_NAME_FOR_M2_ENB = "lo"; + MCE_IPV4_ADDRESS_FOR_M2C = "127.0.0.7/24"; + MCE_PORT_FOR_M2C = 36443; # Spec 36443 + + MCE_INTERFACE_NAME_FOR_M3_MME = "lo"; + MCE_IPV4_ADDRESS_FOR_M3C = "127.0.0.3/24"; + MCE_PORT_FOR_M3C = 36444; # Spec 36444 + }; + + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + }; + + mbms_sched_info : + { + mcch_update_time = 10; + mbms_area_config_list = ( + { + common_sf_allocation_period = 2; #rf4(0) rf8(1) rf16(2) rf32(3) rf64(4) rf128(5) rf256(6) + mbms_area_id = 0; + pmch_config_list = ( + { + allocated_sf_end=32; + data_mcs=14; + mch_scheduling_period = 0; #rf8(0) + mbms_session_list = ( + { + #plnm + service_id ->tmgi + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + } + service_id=0; #keep this allways as 0 (workaround for TUN if) + lcid=6; #this must be properly defined lcid:6+service:0 -> rab_id:6 + } + ); + } + ); + + mbms_sf_config_list = ( + { + radioframe_allocation_period=1; #n1(0) n2(1) n4(2) n8(3) n16(4) n32(5) + radioframe_alloocation_offset=0; + num_frame="oneFrame"; + subframe_allocation=57; #xx111001 + //num_frame="fourFrame"; + //subframe_allocation=14548987; # + } + ); + + } + ); + }; + + + mcch_config_per_mbsfn_area = ( + { + mbsfn_area = 0; + pdcch_length = 1; #s1(0), s2(1) + repetition_period = 0; #rf32(0), rf64(1), rf128(2), rf256(3) + offset = 0; + modification_period = 0; #rf512(0; rf1024(1) + subframe_allocation_info = 32; #BITSTRING (6bits -> one frame) xx100000 + mcs = 1; #n2(0), n7(1), n13(2), n19(3) + } + ); + + #); #end mbms_scheduling_info + + } +); +MMEs = ( + { + MME_ID = 0xe00; + + MME_name = "MME-MBMS-Vicomtech-LTEBox"; + + //M3 + enable_mme_m3 = "yes"; + NETWORK_INTERFACES : + { + MME_INTERFACE_NAME_FOR_M3_MCE = "lo"; + MME_IPV4_ADDRESS_FOR_M3C = "127.0.0.18/24"; + MME_PORT_FOR_M3C = 36444; # Spec 36444 + + }; + } +); + + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_if_name = "lo"; + remote_address = "127.0.0.2"; + local_address = "127.0.0.1"; + local_portc = 50000; + remote_portc = 50000; + local_portd = 50001; + remote_portd = 50001; + local_rf = "no" + tr_preference = "udp_if4p5" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + eNB_instances = [0]; + is_slave = "no"; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +log_config = { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; +}; diff --git a/ci-scripts/conf_files/rcc.band7.tm1.mbms.if4p5.50PRB.lo.conf b/ci-scripts/conf_files/rcc.band7.tm1.mbms.if4p5.50PRB.lo.conf new file mode 100644 index 0000000000..5daaa8d13a --- /dev/null +++ b/ci-scripts/conf_files/rcc.band7.tm1.mbms.if4p5.50PRB.lo.conf @@ -0,0 +1,378 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + # real_time choice in {hard, rt-preempt, no} + real_time = "no"; + + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "NGFI_RCC_IF4p5"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2685000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 50; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 2; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -27; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -104; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + mbms_dedicated_serving_cell = "DISABLE" + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "127.0.0.3"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + + + ////////// MCE parameters: + target_mce_m2_ip_address = ( { ipv4 = "127.0.0.7"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + ///M2 + enable_enb_m2 = "yes"; + + + mbms_configuration_data_list = ( + { + mbsfn_sync_area = 0x0001; + mbms_service_area_list=( + { + mbms_service_area=0x0001; + } + ); + } + + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "lo"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.0.2/24"; + ENB_INTERFACE_NAME_FOR_S1U = "lo"; + ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.5/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + + ENB_IPV4_ADDRESS_FOR_X2C = "127.0.0.2/24"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + + ENB_IPV4_ADDRESS_FOR_M2C = "127.0.0.2/24"; + ENB_PORT_FOR_M2C = 36443; # Spec 36443 + }; + } +); + +MCEs = ( + { + MCE_ID = 0xe00; + + MCE_name = "MCE-Vicomtech-LTEBox"; + + //M2 + enable_mce_m2 = "yes"; + + //M3 + enable_mce_m3 = "yes"; + + target_mme_m3_ip_address = ( { ipv4 = "127.0.0.18"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + + NETWORK_INTERFACES : + { + MCE_INTERFACE_NAME_FOR_M2_ENB = "lo"; + MCE_IPV4_ADDRESS_FOR_M2C = "127.0.0.7/24"; + MCE_PORT_FOR_M2C = 36443; # Spec 36443 + + MCE_INTERFACE_NAME_FOR_M3_MME = "lo"; + MCE_IPV4_ADDRESS_FOR_M3C = "127.0.0.3/24"; + MCE_PORT_FOR_M3C = 36444; # Spec 36444 + }; + + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + }; + + mbms_sched_info : + { + mcch_update_time = 10; + mbms_area_config_list = ( + { + common_sf_allocation_period = 2; #rf4(0) rf8(1) rf16(2) rf32(3) rf64(4) rf128(5) rf256(6) + mbms_area_id = 0; + pmch_config_list = ( + { + allocated_sf_end=32; + data_mcs=14; + mch_scheduling_period = 0; #rf8(0) + mbms_session_list = ( + { + #plnm + service_id ->tmgi + plnm: + { + mcc = 208; + mnc = 93; + mnc_length = 2; + } + service_id=0; #keep this allways as 0 (workaround for TUN if) + lcid=6; #this must be properly defined lcid:6+service:0 -> rab_id:6 + } + ); + } + ); + + mbms_sf_config_list = ( + { + radioframe_allocation_period=1; #n1(0) n2(1) n4(2) n8(3) n16(4) n32(5) + radioframe_alloocation_offset=0; + num_frame="oneFrame"; + subframe_allocation=57; #xx111001 + //num_frame="fourFrame"; + //subframe_allocation=14548987; # + } + ); + + } + ); + }; + + + mcch_config_per_mbsfn_area = ( + { + mbsfn_area = 0; + pdcch_length = 1; #s1(0), s2(1) + repetition_period = 0; #rf32(0), rf64(1), rf128(2), rf256(3) + offset = 0; + modification_period = 0; #rf512(0; rf1024(1) + subframe_allocation_info = 32; #BITSTRING (6bits -> one frame) xx100000 + mcs = 1; #n2(0), n7(1), n13(2), n19(3) + } + ); + + #); #end mbms_scheduling_info + + } +); +MMEs = ( + { + MME_ID = 0xe00; + + MME_name = "MME-MBMS-Vicomtech-LTEBox"; + + //M3 + enable_mme_m3 = "yes"; + NETWORK_INTERFACES : + { + MME_INTERFACE_NAME_FOR_M3_MCE = "lo"; + MME_IPV4_ADDRESS_FOR_M3C = "127.0.0.18/24"; + MME_PORT_FOR_M3C = 36444; # Spec 36444 + + }; + } +); + + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_if_name = "lo"; + remote_address = "127.0.0.2"; + local_address = "127.0.0.1"; + local_portc = 50000; + remote_portc = 50000; + local_portd = 50001; + remote_portd = 50001; + local_rf = "no" + tr_preference = "udp_if4p5" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + eNB_instances = [0]; + is_slave = "no"; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +log_config = { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; +}; diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 049c7c5b41..21d51105f8 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -136,11 +136,14 @@ class SSHConnection(): self.eNB_serverId = '' self.eNBLogFiles = ['', '', ''] self.eNBOptions = ['', '', ''] + self.eNBmbmsEnables = [False, False, False] + self.eNBstatuses = [-1, -1, -1] self.ping_args = '' self.ping_packetloss_threshold = '' self.iperf_args = '' self.iperf_packetloss_threshold = '' self.iperf_profile = '' + self.iperf_options = '' self.nbMaxUEtoAttach = -1 self.UEDevices = [] self.UEDevicesStatus = [] @@ -245,6 +248,7 @@ class SSHConnection(): elif self.sshresponse == 1: logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') logging.debug('Expected Line : ' + expectedline) + logging.debug(str(self.ssh.before)) sys.exit(self.sshresponse) elif self.sshresponse == 2: logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') @@ -550,9 +554,14 @@ class SSHConnection(): else: self.air_interface = 'lte' ue_prefix = '' + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) + if result is not None: + full_ran_repo_name = self.ranRepository + else: + full_ran_repo_name = self.ranRepository + '.git' self.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) + self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) # here add a check if git clone or git fetch went smoothly self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) self.command('git config user.name "OAI Jenkins"', '\$', 5) @@ -665,7 +674,8 @@ class SSHConnection(): self.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) self.command('cd /opt/hss_sim0609', '\$', 5) self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + # based on Robert's feedback, new method to run simulated HSS + self.command('sudo su -c "cd /opt/hss_sim0609 && screen -dm -S simulated_hss ./starthss_real"', '\$', 5) else: logging.error('This option should not occur!') self.close() @@ -829,13 +839,13 @@ class SSHConnection(): # do not reset board twice in IF4.5 case result = re.search('^rru|^enb|^du.band', str(config_file)) if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 30) + self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) result = re.search('type: b200', str(self.ssh.before)) if result is not None: logging.debug('Found a B2xx device --> resetting it') self.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) # Reloading FGPA bin firmware - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 30) + self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) # Make a copy and adapt to EPC / eNB IP addresses self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); @@ -847,6 +857,17 @@ class SSHConnection(): self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); else: self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); + self.eNBmbmsEnables[int(self.eNB_instance)] = False + self.command('grep enable_enb_m2 ' + ci_full_config_file, '\$', 2); + result = re.search('yes', str(self.ssh.before)) + if result is not None: + self.eNBmbmsEnables[int(self.eNB_instance)] = True + logging.debug('\u001B[1m MBMS is enabled on this eNB\u001B[0m') + result = re.search('noS1', str(self.Initialize_eNB_args)) + eNBinNoS1 = False + if result is not None: + eNBinNoS1 = True + logging.debug('\u001B[1m eNB is in noS1 configuration \u001B[0m') # Launch eNB with the modified config file self.command('source oaienv', '\$', 5) self.command('cd cmake_targets', '\$', 5) @@ -865,6 +886,7 @@ class SSHConnection(): time.sleep(6) doLoop = True loopCounter = 20 + enbDidSync = False while (doLoop): loopCounter = loopCounter - 1 if (loopCounter == 0): @@ -903,31 +925,56 @@ class SSHConnection(): time.sleep(6) else: doLoop = False - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) - logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') + enbDidSync = True time.sleep(10) + if enbDidSync and eNBinNoS1: + self.command('ifconfig oaitun_enb1', '\$', 4) + self.command('ifconfig oaitun_enb1', '\$', 4) + result = re.search('inet addr:1|inet 1', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1m oaitun_enb1 interface is mounted and configured\u001B[0m') + else: + logging.error('\u001B[1m oaitun_enb1 interface is either NOT mounted or NOT configured\u001B[0m') + if self.eNBmbmsEnables[int(self.eNB_instance)]: + self.command('ifconfig oaitun_enm1', '\$', 4) + result = re.search('inet addr', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1m oaitun_enm1 interface is mounted and configured\u001B[0m') + else: + logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m') + if enbDidSync: + self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) + self.close() + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') def InitializeUE_common(self, device_id, idx): try: self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if not self.ADBCentralized: # Reboot UE - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) # Wait - time.sleep(60) + #time.sleep(60) # Put in LTE-Mode only - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) # enable data service - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) # we need to do radio on/off cycle to make sure of above changes # airplane mode off // radio on - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(10) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + #time.sleep(10) + # airplane mode on // radio off + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + + # normal procedure without reboot + # enable data service + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) # airplane mode on // radio off self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) self.close() @@ -985,18 +1032,24 @@ class SSHConnection(): UE_prefix = 'NR ' self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) # b2xx_fx3_utils reset procedure - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 30) + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 60) result = re.search('type: b200', str(self.ssh.before)) if result is not None: logging.debug('Found a B2xx device --> resetting it') self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) # Reloading FGPA bin firmware - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 30) + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 60) result = re.search('type: n3xx', str(self.ssh.before)) if result is not None: logging.debug('Found a N3xx device --> resetting it') self.command('cd ' + self.UESourceCodePath, '\$', 5) # Initialize_OAI_UE_args usually start with -C and followed by the location in repository + # in case of NR-UE, we may have rrc_config_path (Temporary?) + modifiedUeOptions = str(self.Initialize_OAI_UE_args) + if self.air_interface == 'nr': + result = re.search('--rrc_config_path ', modifiedUeOptions) + if result is not None: + modifiedUeOptions = modifiedUeOptions.replace('rrc_config_path ', 'rrc_config_path ' + self.UESourceCodePath + '/') self.command('source oaienv', '\$', 5) self.command('cd cmake_targets/ran_build/build', '\$', 5) if self.air_interface == 'lte': @@ -1011,7 +1064,7 @@ class SSHConnection(): self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - self.command('echo "ulimit -c unlimited && ./'+ self.air_interface +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.command('echo "ulimit -c unlimited && ./'+ self.air_interface +'-uesoftmodem ' + modifiedUeOptions + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) self.UELogFile = 'ue_' + self.testCase_id + '.log' @@ -1058,6 +1111,9 @@ class SSHConnection(): if result is not None: self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT -r *-uesoftmodem', '\$', 4) time.sleep(3) + outterLoopCounter = outterLoopCounter - 1 + if (outterLoopCounter == 0): + doOutterLoop = False continue if self.air_interface == 'nr': fullSyncStatus = True @@ -1095,6 +1151,7 @@ class SSHConnection(): if fullSyncStatus and gotSyncStatus and self.air_interface == 'lte': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) if result is None: + self.command('ifconfig oaitun_ue1', '\$', 4) self.command('ifconfig oaitun_ue1', '\$', 4) # ifconfig output is different between ubuntu 16 and ubuntu 18 result = re.search('inet addr:1|inet 1', str(self.ssh.before)) @@ -1102,13 +1159,17 @@ class SSHConnection(): logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') tunnelInterfaceStatus = True else: - self.command('ifconfig oaitun_ue1', '\$', 4) - result = re.search('inet addr:1|inet 1', str(self.ssh.before)) + logging.debug(str(self.ssh.before)) + logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') + tunnelInterfaceStatus = False + if self.eNBmbmsEnables[0]: + self.command('ifconfig oaitun_uem1', '\$', 4) + result = re.search('inet addr', str(self.ssh.before)) if result is not None: - logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') - tunnelInterfaceStatus = True + logging.debug('\u001B[1m oaitun_uem1 interface is mounted and configured\u001B[0m') + tunnelInterfaceStatus = tunnelInterfaceStatus and True else: - logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') + logging.error('\u001B[1m oaitun_uem1 interface is either NOT mounted or NOT configured\u001B[0m') tunnelInterfaceStatus = False else: tunnelInterfaceStatus = True @@ -1126,7 +1187,10 @@ class SSHConnection(): self.UEDevicesStatus.append(UE_STATUS_DETACHED) else: if self.air_interface == 'lte': - self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' + if self.eNBmbmsEnables[0]: + self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' + else: + self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') else: self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' @@ -1160,6 +1224,11 @@ class SSHConnection(): # Calling twice AT to clear all buffers self.command('AT', 'OK|ERROR', 5) self.command('AT', 'OK', 5) + # Doing a power cycle + self.command('AT^RESET', 'SIMSTORE,READY', 15) + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + self.command('ATE1', 'OK', 5) # Disabling the Radio self.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') @@ -1913,11 +1982,27 @@ class SSHConnection(): def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) + # Launch ping on the EPC side (true for ltebox and old open-air-cn) + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False ping_time = re.findall("-c (\d+)",str(self.ping_args)) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + else: + cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + ping_status = ret.returncode + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' @@ -2226,7 +2311,7 @@ class SSHConnection(): req_bandwidth = '%.1f Gbits/sec' % req_bw req_bw = req_bw * 1000000000 - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) (\((?P[0-9\.]+)%\))', str(self.ssh.before)) + result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) if result is not None: bitrate = result.group('bitrate') packetloss = result.group('packetloss') @@ -2274,6 +2359,8 @@ class SSHConnection(): statusQueue.put(msg) lock.release() return 0 + else: + return -2 def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): @@ -2443,11 +2530,17 @@ class SSHConnection(): self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) self.close() else: - if udpIperf: - cmd = 'nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' else: - cmd = 'nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - logging.debug(cmd + '\n') + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + if udpIperf: + cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + else: + cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + logging.debug(cmd) subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') time.sleep(0.5) @@ -2472,7 +2565,12 @@ class SSHConnection(): if (device_id == 'OAI-UE'): iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: - iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + if self.ADBCentralized: + iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT Case if iperf_status < 0: self.close() @@ -2491,12 +2589,12 @@ class SSHConnection(): self.close() else: cmd = 'killall --signal SIGKILL iperf' - logging.debug(cmd + '\n') + logging.debug(cmd) subprocess.run(cmd, shell=True) time.sleep(1) self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') # in case of failure, retrieve server log - if (clientStatus == -1): + if (clientStatus == -1) or (clientStatus == -2): if launchFromEpc: time.sleep(1) if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): @@ -2515,6 +2613,8 @@ class SSHConnection(): return useIperf3 = False udpIperf = True + + self.ueIperfVersion = '2.0.5' if (device_id != 'OAI-UE'): self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it @@ -2534,9 +2634,30 @@ class SSHConnection(): self.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return + else: + if self.ADBCentralized: + self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' else: useIperf3 = True self.close() + else: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('iperf --version', '\$', 5) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' + self.close() # in case of iperf, UL has its own function if (not useIperf3): result = re.search('-R', str(self.iperf_args)) @@ -2571,7 +2692,7 @@ class SSHConnection(): self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) else: self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &\' > /dev/null 2>&1', self.ADBUserName, 60) + self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) time.sleep(0.5) self.close() @@ -2607,7 +2728,13 @@ class SSHConnection(): if launchFromEpc: iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: - cmd = 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' message = cmd + '\n' logging.debug(cmd) ret = subprocess.run(cmd, shell=True) @@ -2652,6 +2779,9 @@ class SSHConnection(): self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') else: self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + # fromdos has to be called on the python executor not on ADB server + cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log' + subprocess.run(cmd, shell=True) self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI UE: @@ -2691,17 +2821,18 @@ class SSHConnection(): iClientIPAddr = self.eNBIPAddress iClientUser = self.eNBUserName iClientPasswd = self.eNBPassword - # Starting the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - # args SHALL be "-c client -u any" - # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 - # -B 10.0.1.1 -u -s -i 1 -fm - server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) - server_options = server_options.replace('-c','-B') - self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) - self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) - time.sleep(0.5) - self.close() + if self.iperf_options != 'sink': + # Starting the iperf server + self.open(iServerIPAddr, iServerUser, iServerPasswd) + # args SHALL be "-c client -u any" + # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 + # -B 10.0.1.1 -u -s -i 1 -fm + server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) + server_options = server_options.replace('-c','-B') + self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) + self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) + time.sleep(0.5) + self.close() # Starting the iperf client modified_options = self.Iperf_ComputeModifiedBW(0, 1) @@ -2717,14 +2848,22 @@ class SSHConnection(): logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') clientStatus = -2 else: - clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + if self.iperf_options == 'sink': + clientStatus = 0 + status_queue.put(0) + status_queue.put('OAI-UE') + status_queue.put('10.0.1.2') + status_queue.put('Sink Test : no check') + else: + clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) self.close() # Stopping the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - self.command('killall --signal SIGKILL iperf', '\$', 5) - time.sleep(0.5) - self.close() + if self.iperf_options != 'sink': + self.open(iServerIPAddr, iServerUser, iServerPasswd) + self.command('killall --signal SIGKILL iperf', '\$', 5) + time.sleep(0.5) + self.close() if (clientStatus == -1): if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '.log') @@ -2732,9 +2871,10 @@ class SSHConnection(): self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) # copying on the EPC server for logCollection - copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + if (clientStatus == -1): + copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') copyin_res = self.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') @@ -2786,6 +2926,18 @@ class SSHConnection(): self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return + + self.dummyIperfVersion = '2.0.10' + #cmd = 'iperf --version' + #logging.debug(cmd + '\n') + #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) + #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.5' + #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.10' + multi_jobs = [] i = 0 ue_num = len(self.UEIPAddresses) @@ -2926,7 +3078,24 @@ class SSHConnection(): def CheckeNBProcess(self, status_queue): try: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + # At least the instance 0 SHALL be on! + if self.eNBstatuses[0] == 0: + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + elif self.eNBstatuses[0] == 1: + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + elif self.eNBstatuses[0] == 2: + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + else: + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + self.open(lIpAddr, lUserName, lPassWord) self.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-softmodem | grep -v grep', '\$', 5) result = re.search(self.air_interface + '-softmodem', str(self.ssh.before)) if result is None: @@ -3025,8 +3194,10 @@ class SSHConnection(): uciStatMsgCount = 0 pdcpFailure = 0 ulschFailure = 0 + ulschOK = 0 cdrxActivationMessageCount = 0 dropNotEnoughRBs = 0 + mbmsRequestMsg = 0 self.htmleNBFailureMsg = '' isRRU = False isSlave = False @@ -3136,6 +3307,10 @@ class SSHConnection(): result = re.search('ULSCH in error in round', str(line)) if result is not None: ulschFailure += 1 + if self.air_interface == 'nr': + result = re.search('ULSCH received ok', str(line)) + if result is not None: + ulschOK += 1 result = re.search('BAD all_segments_received', str(line)) if result is not None: rlcDiscardBuffer += 1 @@ -3145,6 +3320,10 @@ class SSHConnection(): result = re.search('dropping, not enough RBs', str(line)) if result is not None: dropNotEnoughRBs += 1 + if self.eNBmbmsEnables[int(self.eNB_instance)]: + result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line)) + if result is not None: + mbmsRequestMsg += 1 enb_log_file.close() logging.debug(' File analysis completed') self.htmleNBFailureMsg = '' @@ -3164,6 +3343,11 @@ class SSHConnection(): statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') self.htmleNBFailureMsg += statMsg + '\n' + if self.air_interface == 'nr': + if ulschOK > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(ulschOK) + ' "ULSCH received ok" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' if dropNotEnoughRBs > 0: statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') @@ -3196,6 +3380,11 @@ class SSHConnection(): rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') self.htmleNBFailureMsg += rrcMsg + '\n' + if self.eNBmbmsEnables[int(self.eNB_instance)]: + if mbmsRequestMsg > 0: + rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' if X2HO_inNbProcedures > 0: rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') @@ -3262,6 +3451,9 @@ class SSHConnection(): uciStatMsgCount = 0 pdcpDataReqFailedCount = 0 badDciCount = 0 + f1aRetransmissionCount = 0 + fatalErrorCount = 0 + macBsrTimerExpiredCount = 0 rrcConnectionRecfgComplete = 0 no_cell_sync_found = False mib_found = False @@ -3271,6 +3463,7 @@ class SSHConnection(): nrDecodeMib = 0 nrFoundDCI = 0 nrCRCOK = 0 + mbms_messages = 0 self.htmlUEFailureMsg = '' for line in ue_log_file.readlines(): result = re.search('nr_synchro_time', str(line)) @@ -3313,9 +3506,18 @@ class SSHConnection(): result = re.search('PDCP data request failed', str(line)) if result is not None and not exitSignalReceived: pdcpDataReqFailedCount += 1 - result = re.search('bad DCI 1A', str(line)) + result = re.search('bad DCI 1', str(line)) if result is not None and not exitSignalReceived: badDciCount += 1 + result = re.search('Format1A Retransmission but TBS are different', str(line)) + if result is not None and not exitSignalReceived: + f1aRetransmissionCount += 1 + result = re.search('FATAL ERROR', str(line)) + if result is not None and not exitSignalReceived: + fatalErrorCount += 1 + result = re.search('MAC BSR Triggered ReTxBSR Timer expiry', str(line)) + if result is not None and not exitSignalReceived: + macBsrTimerExpiredCount += 1 result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) if result is not None: rrcConnectionRecfgComplete += 1 @@ -3323,6 +3525,10 @@ class SSHConnection(): result = re.search('No cell synchronization found, abandoning', str(line)) if result is not None: no_cell_sync_found = True + if self.eNBmbmsEnables[0]: + result = re.search('TRIED TO PUSH MBMS DATA', str(line)) + if result is not None: + mbms_messages += 1 result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) if result is not None and (not mib_found): try: @@ -3430,9 +3636,29 @@ class SSHConnection(): logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') self.htmlUEFailureMsg += statMsg + '\n' if badDciCount > 0: - statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1A" message(s)' + statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1(A)" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') self.htmlUEFailureMsg += statMsg + '\n' + if f1aRetransmissionCount > 0: + statMsg = 'UE showed ' + str(f1aRetransmissionCount) + ' "Format1A Retransmission but TBS are different" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if fatalErrorCount > 0: + statMsg = 'UE showed ' + str(fatalErrorCount) + ' "FATAL ERROR:" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if macBsrTimerExpiredCount > 0: + statMsg = 'UE showed ' + str(fatalErrorCount) + ' "MAC BSR Triggered ReTxBSR Timer expiry" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if self.eNBmbmsEnables[0]: + if mbms_messages > 0: + statMsg = 'UE showed ' + str(mbms_messages) + ' "TRIED TO PUSH MBMS DATA" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + else: + statMsg = 'UE did NOT SHOW "TRIED TO PUSH MBMS DATA" message(s)' + logging.debug('\u001B[1;30;41m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' if foundSegFault: logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') if not nrUEFlag: @@ -3542,6 +3768,7 @@ class SSHConnection(): logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + self.eNBmbmsEnables[int(self.eNB_instance)] = False return if self.eNB_serverId != '0': self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') @@ -3550,11 +3777,14 @@ class SSHConnection(): if (logStatus < 0): self.CreateHtmlTestRow('N/A', 'KO', logStatus) self.preamtureExit = True + self.eNBmbmsEnables[int(self.eNB_instance)] = False return else: self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) else: self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBmbmsEnables[int(self.eNB_instance)] = False + self.eNBstatuses[int(self.eNB_instance)] = -1 def TerminateHSS(self): self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) @@ -4040,7 +4270,7 @@ class SSHConnection(): if result is not None: self.UhdVersion = result.group('uhd_version') logging.debug('UHD Version is: ' + self.UhdVersion) - self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 30) + self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 60) usrp_boards = re.findall('product: ([0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) count = 0 for board in usrp_boards: @@ -4558,6 +4788,13 @@ def GetParametersFromXML(action): if SSH.iperf_profile != 'balanced' and SSH.iperf_profile != 'unbalanced' and SSH.iperf_profile != 'single-ue': logging.debug('ERROR: test-case has wrong profile ' + SSH.iperf_profile) SSH.iperf_profile = 'balanced' + SSH.iperf_options = test.findtext('iperf_options') + if (SSH.iperf_options is None): + SSH.iperf_options = 'check' + else: + if SSH.iperf_options != 'check' and SSH.iperf_options != 'sink': + logging.debug('ERROR: test-case has wrong option ' + SSH.iperf_options) + SSH.iperf_options = 'check' if action == 'IdleSleep': string_field = test.findtext('idle_sleep_time_in_sec') diff --git a/ci-scripts/rcc-files/rbconfig.raw b/ci-scripts/rcc-files/rbconfig.raw deleted file mode 100644 index 9c561b7a9f..0000000000 --- a/ci-scripts/rcc-files/rbconfig.raw +++ /dev/null @@ -1 +0,0 @@ - (ׂÀ \ No newline at end of file diff --git a/ci-scripts/rcc-files/reconfig.raw b/ci-scripts/rcc-files/reconfig.raw deleted file mode 100644 index 5c5e01afe2..0000000000 Binary files a/ci-scripts/rcc-files/reconfig.raw and /dev/null differ diff --git a/ci-scripts/reportBuildLocally.sh b/ci-scripts/reportBuildLocally.sh index b6c2ca104a..54372ac6ba 100755 --- a/ci-scripts/reportBuildLocally.sh +++ b/ci-scripts/reportBuildLocally.sh @@ -509,7 +509,7 @@ function report_build { sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Expression depends on order of evaluation of side effects" unknownEvaluationOrder sca_summary_table_footer ./archives/cppcheck/cppcheck.xml - summary_table_header "OAI Build eNB -- USRP option" ./archives/enb_usrp + summary_table_header "OAI Build: 4G LTE eNB -- USRP option" ./archives/enb_usrp summary_table_row "LTE SoftModem - Release 15" ./archives/enb_usrp/lte-softmodem.Rel15.txt "Built target lte-softmodem" ./enb_usrp_row1.html summary_table_row "Coding - Release 15" ./archives/enb_usrp/coding.Rel15.txt "Built target coding" ./enb_usrp_row2.html summary_table_row "OAI USRP device if - Release 15" ./archives/enb_usrp/oai_usrpdevif.Rel15.txt "Built target oai_usrpdevif" ./enb_usrp_row3.html @@ -521,7 +521,7 @@ function report_build { summary_table_row "TCP Bridge - Release 15" ./archives/enb_usrp/tcp_bridge_oai.Rel15.txt "Built target tcp_bridge_oai" ./enb_usrp_row9.html summary_table_footer - summary_table_header "OAI Build basic simulator option" ./archives/basic_sim + summary_table_header "OAI Build: 4G LTE basic simulator option" ./archives/basic_sim summary_table_row "LTE SoftModem - Release 15" ./archives/basic_sim/lte-softmodem.Rel15.txt "Built target lte-softmodem" ./basic_sim_row1.html summary_table_row "LTE UE SoftModem - Release 15" ./archives/basic_sim/lte-uesoftmodem.Rel15.txt "Built target lte-uesoftmodem" ./basic_sim_row2.htm summary_table_row "Coding - Release 15" ./archives/basic_sim/coding.Rel15.txt "Built target coding" ./basic_sim_row3.html @@ -537,7 +537,7 @@ function report_build { summary_table_row "NVRAM - Release 15" ./archives/basic_sim/nvram.Rel15.txt "Built target nvram" ./basic_sim_row13.html summary_table_footer - summary_table_header "OAI Build Physical simulators option" ./archives/phy_sim + summary_table_header "OAI Build: 4G LTE / 5G NR Physical simulators option" ./archives/phy_sim summary_table_row "LTE DL Simulator - Release 15" ./archives/phy_sim/dlsim.Rel15.txt "Built target dlsim" ./phy_sim_row1.html summary_table_row "LTE UL Simulator - Release 15" ./archives/phy_sim/ulsim.Rel15.txt "Built target ulsim" ./phy_sim_row2.html summary_table_row "Coding - Release 15" ./archives/phy_sim/coding.Rel15.txt "Built target coding" ./phy_sim_row3.html @@ -581,7 +581,7 @@ function report_build { if [ -f archives/gnb_usrp/nr-softmodem.Rel15.txt ] then - summary_table_header "OAI Build gNB -- USRP option" ./archives/gnb_usrp + summary_table_header "OAI Build: 5G NR gNB -- USRP option" ./archives/gnb_usrp summary_table_row "5G NR SoftModem - Release 15" ./archives/gnb_usrp/nr-softmodem.Rel15.txt "Built target nr-softmodem" ./gnb_usrp_row1.html summary_table_row "Coding - Release 15" ./archives/gnb_usrp/coding.Rel15.txt "Built target coding" ./gnb_usrp_row2.html summary_table_row "OAI USRP device if - Release 15" ./archives/gnb_usrp/oai_usrpdevif.Rel15.txt "Built target oai_usrpdevif" ./gnb_usrp_row3.html @@ -592,20 +592,20 @@ function report_build { summary_table_footer fi - if [ -f archives/nrue_usrp/nr-uesoftmodem.Rel15.txt ] + if [ -f archives/nr_ue_usrp/nr-uesoftmodem.Rel15.txt ] then - summary_table_header "OAI Build 5G NR UE -- USRP option" ./archives/nrue_usrp - summary_table_row "5G NR UE SoftModem - Release 15" ./archives/nrue_usrp/nr-uesoftmodem.Rel15.txt "Built target nr-uesoftmodem" ./nrue_usrp_row1.html - summary_table_row "Coding - Release 15" ./archives/nrue_usrp/coding.Rel15.txt "Built target coding" ./nrue_usrp_row2.html - summary_table_row "OAI USRP device if - Release 15" ./archives/nrue_usrp/oai_usrpdevif.Rel15.txt "Built target oai_usrpdevif" ./nrue_usrp_row3.html - summary_table_row "OAI ETHERNET transport - Release 15" ./archives/nrue_usrp/oai_eth_transpro.Rel15.txt "Built target oai_eth_transpro" ./nrue_usrp_row4.html - summary_table_row "NASMESH - Release 15" ./archives/nrue_usrp/nasmesh.Rel15.txt "Built target nasmesh" ./nrue_usrp_row5.html - summary_table_row "Parameters Lib Config - Release 15" ./archives/nrue_usrp/params_libconfig.Rel15.txt "Built target params_libconfig" ./nrue_usrp_row6.html - summary_table_row "RB Tool - Release 15" ./archives/nrue_usrp/rb_tool.Rel15.txt "Built target rb_tool" ./nrue_usrp_row7.html + summary_table_header "OAI Build: 5G NR UE -- USRP option" ./archives/nr_ue_usrp + summary_table_row "5G NR UE SoftModem - Release 15" ./archives/nr_ue_usrp/nr-uesoftmodem.Rel15.txt "Built target nr-uesoftmodem" ./nr_ue_usrp_row1.html + summary_table_row "Coding - Release 15" ./archives/nr_ue_usrp/coding.Rel15.txt "Built target coding" ./nr_ue_usrp_row2.html + summary_table_row "OAI USRP device if - Release 15" ./archives/nr_ue_usrp/oai_usrpdevif.Rel15.txt "Built target oai_usrpdevif" ./nr_ue_usrp_row3.html + summary_table_row "OAI ETHERNET transport - Release 15" ./archives/nr_ue_usrp/oai_eth_transpro.Rel15.txt "Built target oai_eth_transpro" ./nr_ue_usrp_row4.html + summary_table_row "NASMESH - Release 15" ./archives/nr_ue_usrp/nasmesh.Rel15.txt "Built target nasmesh" ./nr_ue_usrp_row5.html + summary_table_row "Parameters Lib Config - Release 15" ./archives/nr_ue_usrp/params_libconfig.Rel15.txt "Built target params_libconfig" ./nr_ue_usrp_row6.html + summary_table_row "RB Tool - Release 15" ./archives/nr_ue_usrp/rb_tool.Rel15.txt "Built target rb_tool" ./nr_ue_usrp_row7.html summary_table_footer fi - summary_table_header "OAI Build eNB -- ETHERNET transport option" ./archives/enb_eth + summary_table_header "OAI Build: 4G LTE eNB -- ETHERNET transport option" ./archives/enb_eth summary_table_row "LTE SoftModem - Release 15" ./archives/enb_eth/lte-softmodem.Rel15.txt "Built target lte-softmodem" ./enb_eth_row1.html summary_table_row "Coding - Release 15" ./archives/enb_eth/coding.Rel15.txt "Built target coding" ./enb_eth_row2.html summary_table_row "OAI ETHERNET transport - Release 15" ./archives/enb_eth/oai_eth_transpro.Rel15.txt "Built target oai_eth_transpro" ./enb_eth_row3.html @@ -614,7 +614,7 @@ function report_build { summary_table_row "TCP OAI Bridge - Release 15" ./archives/enb_eth/tcp_bridge_oai.Rel15.txt "Built target tcp_bridge_oai" ./enb_eth_row6.html summary_table_footer - summary_table_header "OAI Build UE -- ETHERNET transport option" ./archives/ue_eth + summary_table_header "OAI Build: 4G LTE UE -- ETHERNET transport option" ./archives/ue_eth summary_table_row "LTE UE SoftModem - Release 15" ./archives/ue_eth/lte-uesoftmodem.Rel15.txt "Built target lte-uesoftmodem" ./ue_eth_row1.html summary_table_row "Coding - Release 15" ./archives/ue_eth/coding.Rel15.txt "Built target coding" ./ue_eth_row2.html summary_table_row "OAI ETHERNET transport - Release 15" ./archives/ue_eth/oai_eth_transpro.Rel15.txt "Built target oai_eth_transpro" ./ue_eth_row3.html @@ -631,7 +631,7 @@ function report_build { then echo "

Red Hat Enterprise Linux Server release 7.6) -- Summary

" >> ./build_results.html - summary_table_header "Red Hat -- OAI Build eNB -- USRP option" ./archives/red_hat + summary_table_header "OAI Build: 4G LTE eNB -- USRP option (RHEL)" ./archives/red_hat summary_table_row "LTE SoftModem - Release 15" ./archives/red_hat/lte-softmodem.Rel15.txt "Built target lte-softmodem" ./enb_usrp_rh_row1.html summary_table_row "Coding - Release 15" ./archives/red_hat/coding.Rel15.txt "Built target coding" ./enb_usrp_rh_row2.html summary_table_row "OAI USRP device if - Release 15" ./archives/red_hat/oai_usrpdevif.Rel15.txt "Built target oai_usrpdevif" ./enb_usrp_rh_row3.html @@ -671,9 +671,9 @@ function report_build { cat $DETAILS_TABLE >> ./build_results.html done fi - if [ -f ./nrue_usrp_row1.html ] || [ -f ./nrue_usrp_row2.html ] || [ -f ./nrue_usrp_row3.html ] || [ -f ./nrue_usrp_row4.html ] + if [ -f ./nr_ue_usrp_row1.html ] || [ -f ./nr_ue_usrp_row2.html ] || [ -f ./nr_ue_usrp_row3.html ] || [ -f ./nr_ue_usrp_row4.html ] then - for DETAILS_TABLE in `ls ./nrue_usrp_row*.html` + for DETAILS_TABLE in `ls ./nr_ue_usrp_row*.html` do cat $DETAILS_TABLE >> ./build_results.html done diff --git a/ci-scripts/reportTestLocally.sh b/ci-scripts/reportTestLocally.sh index e087cc04e6..b74fe93a1f 100755 --- a/ci-scripts/reportTestLocally.sh +++ b/ci-scripts/reportTestLocally.sh @@ -112,7 +112,7 @@ function analyzeIperfFiles { echo " OK" >> ./test_simulator_results.html fi else - EFFECTIVE_BITRATE=`tail -n3 $IPERF_CASE | egrep "Mbits/sec" | sed -e "s#^.*MBytes *##" -e "s#sec.*#sec#"` + EFFECTIVE_BITRATE=`tail -n3 $IPERF_CASE | egrep "bits/sec" | sed -e "s#^.*Bytes *##" -e "s#sec.*#sec#"` if [[ $EFFECTIVE_BITRATE =~ .*Kbits/sec.* ]] then EFFECTIVE_BITRATE=`echo $EFFECTIVE_BITRATE | sed -e "s# *Kbits/sec.*##"` @@ -136,9 +136,9 @@ function analyzeIperfFiles { else echo " OK" >> ./test_simulator_results.html fi - EFFECTIVE_BITRATE=`tail -n3 $IPERF_CASE | egrep "Mbits/sec" | sed -e "s#^.*MBytes *##" -e "s#sec.*#sec#"` - JITTER=`tail -n3 $IPERF_CASE | egrep "Mbits/sec" | sed -e "s#^.*Mbits/sec *##" -e "s#ms.*#ms#"` - PACKETLOSS=`tail -n3 $IPERF_CASE | egrep "Mbits/sec" | sed -e "s#^.*(##" -e "s#).*##"` + EFFECTIVE_BITRATE=`tail -n3 $IPERF_CASE | egrep "bits/sec" | sed -e "s#^.*Bytes *##" -e "s#sec.*#sec#"` + JITTER=`tail -n3 $IPERF_CASE | egrep "bits/sec" | sed -e "s#^.*bits/sec *##" -e "s#ms.*#ms#"` + PACKETLOSS=`tail -n3 $IPERF_CASE | egrep "bits/sec" | sed -e "s#^.*(##" -e "s#).*##"` fi echo " " >> ./test_simulator_results.html echo "
" >> ./test_simulator_results.html
@@ -253,7 +253,7 @@ function report_test {
     ARCHIVES_LOC=archives/basic_sim/test
     if [ -d $ARCHIVES_LOC ]
     then
-        echo "   

Basic Simulator Check

" >> ./test_simulator_results.html + echo "

4G LTE Basic Simulator Check

" >> ./test_simulator_results.html if [ -f $ARCHIVES_LOC/test_final_status.log ] then @@ -373,7 +373,7 @@ function report_test { if [ -e $JENKINS_WKSP/flexran/flexran_build_complete.txt ] then - echo "

Basic Simulator + FlexRan Controller Check

" >> ./test_simulator_results.html + echo "

4G LTE Basic Simulator + FlexRan Controller Check

" >> ./test_simulator_results.html echo "
" >> ./test_simulator_results.html echo " TEST was SUCCESSFUL " >> ./test_simulator_results.html echo "
" >> ./test_simulator_results.html @@ -403,11 +403,11 @@ function report_test { ARCHIVES_LOC=archives/rf_sim/test if [ -d $ARCHIVES_LOC ] then - echo "

5G NR RF Simulator Check

" >> ./test_simulator_results.html + echo "

4G LTE RF Simulator Check

" >> ./test_simulator_results.html if [ -f $ARCHIVES_LOC/test_final_status.log ] then - if [ `grep -c TEST_OK $ARCHIVES_LOC/test_final_status.log` -eq 1 ] + if [ `egrep -c "LTE: TEST_OK" $ARCHIVES_LOC/test_final_status.log` -eq 1 ] then echo "
" >> ./test_simulator_results.html echo " TEST was SUCCESSFUL " >> ./test_simulator_results.html @@ -423,8 +423,228 @@ function report_test { echo "
" >> ./test_simulator_results.html fi - echo " " >> ./test_simulator_results.html - echo "
" >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo "
" >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + + EPC_CONFIGS=("wS1 noS1") + TRANS_MODES=("fdd") + BW_CASES=(05 10) + for CN_CONFIG in ${EPC_CONFIGS[@]} + do + for TMODE in ${TRANS_MODES[@]} + do + for BW in ${BW_CASES[@]} + do + echo " " >> ./test_simulator_results.html + if [[ $CN_CONFIG =~ .*wS1.* ]] + then + echo " " >> ./test_simulator_results.html + else + echo " " >> ./test_simulator_results.html + fi + echo " " >> ./test_simulator_results.html + ENB_LOG=$ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_enb.log + UE_LOG=`echo $ENB_LOG | sed -e "s#enb#ue#"` + if [ -f $ENB_LOG ] && [ -f $UE_LOG ] + then + NAME_ENB=`echo $ENB_LOG | sed -e "s#$ARCHIVES_LOC/##"` + NAME_UE=`echo $UE_LOG | sed -e "s#$ARCHIVES_LOC/##"` + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + NB_ENB_GOT_SYNC=`egrep -c "got sync" $ENB_LOG` + if [[ $CN_CONFIG =~ .*noS1.* ]] + then + NB_ENB_TUNNEL_UP=`egrep -c "Interface oaitun_enb1 successfully configured" $ENB_LOG` + fi + NB_UE_GOT_SYNC=`egrep -c "rfsimulator: Success" $UE_LOG` + NB_ENB_SYNCED_WITH_UE=`egrep -c "Generating RRCConnectionReconfigurationComplete" $UE_LOG` + if [[ $CN_CONFIG =~ .*noS1.* ]] + then + NB_UE_TUNNEL_UP=`egrep -c "Interface oaitun_ue1 successfully configured" $UE_LOG` + else + NB_UE_TUNNEL_UP=`egrep -c "executing ifconfig oaitun_ue1" $UE_LOG` + fi + if [ $NB_ENB_GOT_SYNC -gt 0 ] && [ $NB_UE_GOT_SYNC -gt 0 ] && [ $NB_ENB_SYNCED_WITH_UE -gt 0 ] + then + echo " " >> ./test_simulator_results.html + else + echo " " >> ./test_simulator_results.html + fi + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + fi + PING_LOGS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_ping*.log 2> /dev/null` + analyzePingFiles + + IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_dl*client*txt | grep -v mbms 2> /dev/null` + analyzeIperfFiles + + IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_ul*client*txt | grep -v mbms 2> /dev/null` + analyzeIperfFiles + done + done + done + + # MBMS Case + CN_CONFIG="noS1" + TMODE="fdd" + BW_CASES=(05) + for BW in ${BW_CASES[@]} + do + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + ENB_LOG=$ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_enb_mbms.log + UE_LOG=`echo $ENB_LOG | sed -e "s#enb#ue#"` + if [ -f $ENB_LOG ] && [ -f $UE_LOG ] + then + NAME_ENB=`echo $ENB_LOG | sed -e "s#$ARCHIVES_LOC/##"` + NAME_UE=`echo $UE_LOG | sed -e "s#$ARCHIVES_LOC/##"` + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + NB_ENB_GOT_SYNC=`egrep -c "got sync" $ENB_LOG` + NB_ENB_TUNNEL_UP=`egrep -c "Interface oaitun_enb1 successfully configured" $ENB_LOG` + NB_ENB_MTUNNEL_UP=`egrep -c "Interface oaitun_enm1 successfully configured" $ENB_LOG` + NB_UE_GOT_SYNC=`egrep -c "rfsimulator: Success" $UE_LOG` + NB_ENB_SYNCED_WITH_UE=`egrep -c "Generating RRCConnectionReconfigurationComplete" $UE_LOG` + NB_UE_TUNNEL_UP=`egrep -c "Interface oaitun_ue1 successfully configured" $UE_LOG` + NB_UE_MTUNNEL_UP=`egrep -c "Interface oaitun_uem1 successfully configured" $UE_LOG` + NB_UE_MBMS_PUSH_MSG=`egrep -c "TRIED TO PUSH MBMS DATA TO" $UE_LOG` + if [ $NB_ENB_GOT_SYNC -gt 0 ] && [ $NB_UE_GOT_SYNC -gt 0 ] && [ $NB_ENB_SYNCED_WITH_UE -gt 0 ] && [ $NB_UE_MBMS_PUSH_MSG -gt 0 ] + then + echo " " >> ./test_simulator_results.html + else + echo " " >> ./test_simulator_results.html + fi + echo " " >> ./test_simulator_results.html + echo " " >> ./test_simulator_results.html + fi + #PING_LOGS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_ping*.log 2> /dev/null` + #analyzePingFiles + + #IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_dl*client*txt | grep -v mbms 2> /dev/null` + #analyzeIperfFiles + + #IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_ul*client*txt | grep -v mbms 2> /dev/null` + #analyzeIperfFiles + done + echo "
Log File NameCommandStatusStatistics
Test with EPC (aka withS1): ${TMODE} -- ${BW}MHz Test without EPC (aka noS1): ${TMODE} -- ${BW}MHz
$NAME_ENB --- $NAME_UEN/AOKKO
" >> ./test_simulator_results.html
+                    if [ $NB_ENB_GOT_SYNC -gt 0 ]
+                    then
+                        echo "- eNB --> got sync" >> ./test_simulator_results.html
+                    else
+                        echo "- eNB NEVER got sync" >> ./test_simulator_results.html
+                    fi
+                    if [[ $CN_CONFIG =~ .*noS1.* ]]
+                    then
+                        if [ $NB_ENB_TUNNEL_UP -gt 0 ]
+                        then
+                            echo "- eNB mounted oaitun_enb1 interface" >> ./test_simulator_results.html
+                        else
+                            echo "- eNB NEVER mounted oaitun_enb1 interface" >> ./test_simulator_results.html
+                        fi
+                    fi
+                    if [ $NB_UE_GOT_SYNC -gt 0 ]
+                    then
+                        echo "- LTE UE --> got sync" >> ./test_simulator_results.html
+                    else
+                        echo "- LTE UE NEVER got sync" >> ./test_simulator_results.html
+                    fi
+                    if [ $NB_ENB_SYNCED_WITH_UE -gt 0 ]
+                    then
+                        echo "- LTE UE attached to eNB" >> ./test_simulator_results.html
+                    else
+                        echo "- LTE UE NEVER attached to eNB" >> ./test_simulator_results.html
+                    fi
+                    if [ $NB_UE_TUNNEL_UP -gt 0 ]
+                    then
+                        echo "- LTE UE mounted oaitun_ue1 interface" >> ./test_simulator_results.html
+                    else
+                        echo "- LTE UE NEVER mounted oaitun_ue1 interface" >> ./test_simulator_results.html
+                    fi
+                    echo "        
Test MBMS without EPC (aka noS1): ${TMODE} -- ${BW}MHz
$NAME_ENB --- $NAME_UEN/AOKKO
" >> ./test_simulator_results.html
+                if [ $NB_ENB_GOT_SYNC -gt 0 ]
+                then
+                    echo "- eNB --> got sync" >> ./test_simulator_results.html
+                else
+                    echo "- eNB NEVER got sync" >> ./test_simulator_results.html
+                fi
+                if [ $NB_ENB_TUNNEL_UP -gt 0 ]
+                then
+                    echo "- eNB mounted oaitun_enb1 interface" >> ./test_simulator_results.html
+                else
+                    echo "- eNB NEVER mounted oaitun_enb1 interface" >> ./test_simulator_results.html
+                fi
+                if [ $NB_ENB_MTUNNEL_UP -gt 0 ]
+                then
+                    echo "- eNB mounted oaitun_enm1 interface" >> ./test_simulator_results.html
+                else
+                    echo "- eNB NEVER mounted oaitun_enm1 interface" >> ./test_simulator_results.html
+                fi
+                if [ $NB_UE_GOT_SYNC -gt 0 ]
+                then
+                    echo "- LTE UE --> got sync" >> ./test_simulator_results.html
+                else
+                    echo "- LTE UE NEVER got sync" >> ./test_simulator_results.html
+                fi
+                if [ $NB_ENB_SYNCED_WITH_UE -gt 0 ]
+                then
+                    echo "- LTE UE attached to eNB" >> ./test_simulator_results.html
+                else
+                    echo "- LTE UE NEVER attached to eNB" >> ./test_simulator_results.html
+                fi
+                if [ $NB_UE_TUNNEL_UP -gt 0 ]
+                then
+                    echo "- LTE UE mounted oaitun_ue1 interface" >> ./test_simulator_results.html
+                else
+                    echo "- LTE UE NEVER mounted oaitun_ue1 interface" >> ./test_simulator_results.html
+                fi
+                if [ $NB_UE_MTUNNEL_UP -gt 0 ]
+                then
+                    echo "- LTE UE mounted oaitun_uem1 interface" >> ./test_simulator_results.html
+                else
+                    echo "- LTE UE NEVER mounted oaitun_uem1 interface" >> ./test_simulator_results.html
+                fi
+                if [ $NB_UE_MBMS_PUSH_MSG -gt 0 ]
+                then
+                    echo "- LTE UE tried to push ${NB_UE_MBMS_PUSH_MSG} MBMS DATA" >> ./test_simulator_results.html
+                else
+                    echo "- LTE UE NEVER pushed MBMS DATA" >> ./test_simulator_results.html
+                fi
+                echo "        
" >> ./test_simulator_results.html + echo "
" >> ./test_simulator_results.html + + echo "

5G NR RF Simulator Check

" >> ./test_simulator_results.html + + if [ -f $ARCHIVES_LOC/test_final_status.log ] + then + if [ `egrep -c "5G-NR: TEST_OK" $ARCHIVES_LOC/test_final_status.log` -eq 1 ] + then + echo "
" >> ./test_simulator_results.html + echo " TEST was SUCCESSFUL " >> ./test_simulator_results.html + echo "
" >> ./test_simulator_results.html + else + echo "
" >> ./test_simulator_results.html + echo " TEST was a FAILURE! " >> ./test_simulator_results.html + echo "
" >> ./test_simulator_results.html + fi + else + echo "
" >> ./test_simulator_results.html + echo " COULD NOT DETERMINE TEST FINAL STATUS! " >> ./test_simulator_results.html + echo "
" >> ./test_simulator_results.html + fi + + echo " " >> ./test_simulator_results.html + echo "
" >> ./test_simulator_results.html echo " " >> ./test_simulator_results.html echo " " >> ./test_simulator_results.html echo " " >> ./test_simulator_results.html @@ -460,10 +680,10 @@ function report_test { echo " " >> ./test_simulator_results.html echo " " >> ./test_simulator_results.html NB_ENB_GOT_SYNC=`egrep -c "got sync" $ENB_LOG` - NB_ENB_TUNNEL_UP=`egrep -c "Interface oaitun_enb1 successfuly configured" $ENB_LOG` + NB_ENB_TUNNEL_UP=`egrep -c "Interface oaitun_enb1 successfully configured" $ENB_LOG` NB_UE_GOT_SYNC=`egrep -c "rfsimulator: Success" $UE_LOG` NB_ENB_SYNCED_WITH_UE=`egrep -c "Initial sync: starting PBCH detection" $UE_LOG` - NB_UE_TUNNEL_UP=`egrep -c "Interface oaitun_ue1 successfuly configured" $UE_LOG` + NB_UE_TUNNEL_UP=`egrep -c "Interface oaitun_ue1 successfully configured" $UE_LOG` if [ $NB_ENB_GOT_SYNC -gt 0 ] && [ $NB_UE_GOT_SYNC -gt 0 ] && [ $NB_ENB_SYNCED_WITH_UE -gt 0 ] then echo " " >> ./test_simulator_results.html @@ -510,8 +730,8 @@ function report_test { IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}prb_${CN_CONFIG}_iperf_dl*client*txt 2> /dev/null` analyzeIperfFiles - #IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_iperf_ul*client*txt 2> /dev/null` - #analyzeIperfFiles + IPERF_TESTS=`ls $ARCHIVES_LOC/${TMODE}_${BW}prb_${CN_CONFIG}_iperf_ul*client*txt 2> /dev/null` + analyzeIperfFiles done done done @@ -523,7 +743,7 @@ function report_test { ARCHIVES_LOC=archives/l2_sim/test if [ -d $ARCHIVES_LOC ] then - echo "

L2-NFAPI Simulator Check

" >> ./test_simulator_results.html + echo "

4G LTE L2-NFAPI Simulator Check

" >> ./test_simulator_results.html if [ -f $ARCHIVES_LOC/test_final_status.log ] then diff --git a/ci-scripts/rrc-files/rbconfig.raw b/ci-scripts/rrc-files/rbconfig.raw new file mode 100644 index 0000000000..b03f18d121 Binary files /dev/null and b/ci-scripts/rrc-files/rbconfig.raw differ diff --git a/ci-scripts/rrc-files/reconfig.raw b/ci-scripts/rrc-files/reconfig.raw new file mode 100644 index 0000000000..97b41d9b6b Binary files /dev/null and b/ci-scripts/rrc-files/reconfig.raw differ diff --git a/ci-scripts/runTestOnVM.sh b/ci-scripts/runTestOnVM.sh index 118c4b4d9e..502c1a5d47 100755 --- a/ci-scripts/runTestOnVM.sh +++ b/ci-scripts/runTestOnVM.sh @@ -169,6 +169,14 @@ function get_ue_ip_addr { rm $1 } +function get_ue_mbms_ip_addr { + local LOC_IF_ID=$3 + echo "ifconfig oaitun_uem${LOC_IF_ID} | egrep \"inet addr\" | sed -e 's#^.*inet addr:##' -e 's# P-t-P:.*\$##'" > $1 + UE_IP_ADDR=`ssh -T -o StrictHostKeyChecking=no ubuntu@$2 < $1` + echo "Test UE${LOC_IF_ID} MBMS IP Address is : $UE_IP_ADDR" + rm $1 +} + function get_enb_noS1_ip_addr { echo "ifconfig oaitun_enb1 | egrep \"inet addr\" | sed -e 's#^.*inet addr:##' -e 's# P-t-P:.*\$##'" > $1 ENB_IP_ADDR=`ssh -T -o StrictHostKeyChecking=no ubuntu@$2 < $1` @@ -176,6 +184,13 @@ function get_enb_noS1_ip_addr { rm $1 } +function get_enb_mbms_noS1_ip_addr { + echo "ifconfig oaitun_enm1 | egrep \"inet addr\" | sed -e 's#^.*inet addr:##' -e 's# P-t-P:.*\$##'" > $1 + ENB_IP_ADDR=`ssh -T -o StrictHostKeyChecking=no ubuntu@$2 < $1` + echo "Test eNB MBMS IP Address is : $ENB_IP_ADDR" + rm $1 +} + function ping_ue_ip_addr { local LOC_FG_OR_BG=$5 echo "echo \"COMMAND IS: ping -c 20 $3\" > $4" > $1 @@ -327,6 +342,7 @@ function check_iperf { local FILE_COMPLETE=`egrep -c "Server Report" ${LOC_BASE_LOG}_client.txt` if [ $FILE_COMPLETE -eq 0 ] then + # This part will become obsolete once we have UL if [[ $LOC_IS_RF_SIM -eq 1 ]] && [[ $LOC_IS_NR -eq 1 ]] then echo "no UL integration right now --> normal to have no server report" @@ -335,11 +351,11 @@ function check_iperf { local EFFECTIVE_BANDWIDTH=`tail -n1 ${LOC_BASE_LOG}_server.txt | sed -e "s#^.*MBytes *##" -e "s#^.*KBytes *##" -e "s#sec.*#sec#"` if [[ $2 =~ .*K.* ]] then - local BW_SUFFIX="K" + local BW_PREFIX="K" else - local BW_SUFFIX="M" + local BW_PREFIX="M" fi - if [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW}.*${BW_SUFFIX}bits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_ONE}.*${BW_SUFFIX}bits.* ]] + if [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW}.*${BW_PREFIX}bits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_ONE}.*${BW_PREFIX}bits.* ]] then echo "got requested DL bandwidth: $EFFECTIVE_BANDWIDTH" else @@ -355,10 +371,19 @@ function check_iperf { echo "File Report not found" fi else - local EFFECTIVE_BANDWIDTH=`tail -n3 ${LOC_BASE_LOG}_client.txt | egrep "Mbits/sec" | sed -e "s#^.*MBytes *##" -e "s#sec.*#sec#"` + if [ `egrep -c "Mbits/sec" ${LOC_BASE_LOG}_client.txt` -ne 0 ] + then + local EFFECTIVE_BANDWIDTH=`tail -n3 ${LOC_BASE_LOG}_client.txt | egrep "Mbits/sec" | sed -e "s#^.*MBytes *##" -e "s#sec.*#sec#"` + local BW_PREFIX="M" + fi + if [ `egrep -c "Kbits/sec" ${LOC_BASE_LOG}_client.txt` -ne 0 ] + then + local EFFECTIVE_BANDWIDTH=`tail -n3 ${LOC_BASE_LOG}_client.txt | egrep "Kbits/sec" | sed -e "s#^.*KBytes *##" -e "s#sec.*#sec#"` + local BW_PREFIX="K" + fi if [ $LOC_IS_DL -eq 1 ] && [ $LOC_IS_BASIC_SIM -eq 1 ] then - if [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW}.*Mbits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_ONE}.*Mbits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_TWO}.*Mbits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_THREE}.*Mbits.* ]] + if [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW}.*${BW_PREFIX}bits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_ONE}.*${BW_PREFIX}bits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_TWO}.*${BW_PREFIX}bits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_THREE}.*${BW_PREFIX}bits.* ]] then echo "got requested DL bandwidth: $EFFECTIVE_BANDWIDTH" else @@ -366,7 +391,7 @@ function check_iperf { IPERF_STATUS=-1 fi else - if [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW}.*Mbits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_ONE}.*Mbits.* ]] + if [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW}.*${BW_PREFIX}bits.* ]] || [[ $EFFECTIVE_BANDWIDTH =~ .*${LOC_REQ_BW_MINUS_ONE}.*${BW_PREFIX}bits.* ]] then if [ $LOC_IS_DL -eq 1 ] then @@ -375,7 +400,7 @@ function check_iperf { echo "got requested UL bandwidth: $EFFECTIVE_BANDWIDTH" fi else - echo "not basic-sim got LESS than requested DL bandwidth: $EFFECTIVE_BANDWIDTH" + echo "got LESS than requested DL bandwidth: $EFFECTIVE_BANDWIDTH" IPERF_STATUS=-1 fi fi @@ -522,7 +547,7 @@ function install_epc_on_vm { echo "############################################################" echo "Install EPC on EPC VM ($LOC_EPC_VM_NAME)" echo "############################################################" - echo "sudo [ -f 01proxy ] && cp 01proxy /etc/apt/apt.conf.d/" > $LOC_EPC_VM_CMDS + echo "[ -f 01proxy ] && sudo cp 01proxy /etc/apt/apt.conf.d/" > $LOC_EPC_VM_CMDS echo "touch /home/ubuntu/.hushlogin" >> $LOC_EPC_VM_CMDS echo "echo \"sudo apt-get --yes --quiet install zip openjdk-8-jre libconfuse-dev libreadline-dev liblog4c-dev libgcrypt-dev libsctp-dev python2.7 python2.7-dev daemon iperf\"" >> $LOC_EPC_VM_CMDS echo "sudo apt-get update > zip-install.txt 2>&1" >> $LOC_EPC_VM_CMDS @@ -588,8 +613,11 @@ function start_epc { echo "############################################################" echo "echo \"cd /opt/hss_sim0609\"" > $LOC_EPC_VM_CMDS echo "cd /opt/hss_sim0609" >> $LOC_EPC_VM_CMDS - echo "echo \"sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real\"" >> $LOC_EPC_VM_CMDS - echo "sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real" >> $LOC_EPC_VM_CMDS + echo "sudo rm -f hss.log" >> $LOC_EPC_VM_CMDS + #echo "echo \"sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real\"" >> $LOC_EPC_VM_CMDS + #echo "sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real" >> $LOC_EPC_VM_CMDS + echo "echo \"screen -dm -S simulated_hss ./starthss_real\"" >> $LOC_EPC_VM_CMDS + echo "sudo su -c \"screen -dm -S simulated_hss ./starthss_real\"" >> $LOC_EPC_VM_CMDS echo "echo \"cd /opt/ltebox/tools/\"" >> $LOC_EPC_VM_CMDS echo "cd /opt/ltebox/tools/" >> $LOC_EPC_VM_CMDS @@ -845,9 +873,9 @@ function start_l2_sim_ue { echo "cd /home/ubuntu/tmp/cmake_targets/ran_build/build/" >> $1 if [ $LOC_S1_CONFIGURATION -eq 0 ] then - echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --L2-emul 3 --num-ues $LOC_NB_UES --nums_ue_thread $LOC_NB_UES --nokrnmod 1 --log_config.global_log_options level,nocolor --noS1\" > ./my-lte-softmodem-run.sh " >> $1 + echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --L2-emul 3 --num-ues $LOC_NB_UES --nums_ue_thread 1 --nokrnmod 1 --log_config.global_log_options level,nocolor --noS1\" > ./my-lte-softmodem-run.sh " >> $1 else - echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --L2-emul 3 --num-ues $LOC_NB_UES --nums_ue_thread $LOC_NB_UES --nokrnmod 1 --log_config.global_log_options level,nocolor\" > ./my-lte-softmodem-run.sh " >> $1 + echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --L2-emul 3 --num-ues $LOC_NB_UES --nums_ue_thread 1 --nokrnmod 1 --log_config.global_log_options level,nocolor\" > ./my-lte-softmodem-run.sh " >> $1 fi echo "chmod 775 ./my-lte-softmodem-run.sh" >> $1 echo "cat ./my-lte-softmodem-run.sh" >> $1 @@ -880,8 +908,9 @@ function start_l2_sim_ue { else echo "L2-SIM UE is sync'ed w/ eNB" fi - local max_interfaces_to_check=1 - if [ $LOC_S1_CONFIGURATION -eq 0 ]; then max_interfaces_to_check=$LOC_NB_UES; fi + local max_interfaces_to_check=$LOC_NB_UES + #local max_interfaces_to_check=1 + #if [ $LOC_S1_CONFIGURATION -eq 0 ]; then max_interfaces_to_check=$LOC_NB_UES; fi local j="1" while [ $j -le $max_interfaces_to_check ] do @@ -957,9 +986,9 @@ function start_rf_sim_enb { echo "cd /home/ubuntu/tmp/cmake_targets/ran_build/build/" >> $1 if [ $LOC_S1_CONFIGURATION -eq 0 ] then - echo "echo \"ulimit -c unlimited && ./lte-softmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --rfsim --log_config.global_log_options level,nocolor --noS1\" > ./my-lte-softmodem-run.sh " >> $1 + echo "echo \"ulimit -c unlimited && ./lte-softmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --rfsim --log_config.global_log_options level,nocolor --noS1 --eNBs.[0].rrc_inactivity_threshold 0\" > ./my-lte-softmodem-run.sh " >> $1 else - echo "echo \"ulimit -c unlimited && ./lte-softmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --rfsim --log_config.global_log_options level,nocolor \" > ./my-lte-softmodem-run.sh " >> $1 + echo "echo \"ulimit -c unlimited && ./lte-softmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE --rfsim --log_config.global_log_options level,nocolor --eNBs.[0].rrc_inactivity_threshold 0 --eNBs.[0].plmn_list.[0].mnc 93\" > ./my-lte-softmodem-run.sh " >> $1 fi echo "chmod 775 ./my-lte-softmodem-run.sh" >> $1 echo "cat ./my-lte-softmodem-run.sh" >> $1 @@ -1015,6 +1044,31 @@ function start_rf_sim_enb { else echo "RF-SIM eNB oaitun_enb1 is UP and CONFIGURED" fi + if [[ $LOC_CONF_FILE =~ .*mbms.* ]] + then + echo "ifconfig oaitun_enm1 | egrep -c \"inet addr\"" > $1 + # Checking oaitun_enm1 interface has now an IP address + i="0" + while [ $i -lt 10 ] + do + CONNECTED=`ssh -T -o StrictHostKeyChecking=no ubuntu@$LOC_ENB_VM_IP_ADDR < $1` + if [ $CONNECTED -eq 1 ] + then + i="100" + else + i=$[$i+1] + sleep 5 + fi + done + rm $1 + if [ $i -lt 50 ] + then + ENB_SYNC=0 + echo "RF-SIM eNB oaitun_enm1 is DOWN or NOT CONFIGURED" + else + echo "RF-SIM eNB oaitun_enm1 is UP and CONFIGURED" + fi + fi fi sleep 10 } @@ -1027,6 +1081,7 @@ function start_rf_sim_ue { local LOC_FREQUENCY=$6 # 1 is with S1 and 0 without S1 aka noS1 local LOC_S1_CONFIGURATION=$7 + local LOC_MBMS_CONFIGURATION=$8 echo "echo \"sudo apt-get --yes --quiet install daemon \"" > $1 echo "sudo apt-get --yes install daemon >> /home/ubuntu/tmp/cmake_targets/log/daemon-install.txt 2>&1" >> $1 echo "echo \"export RFSIMULATOR=${LOC_ENB_VM_IP_ADDR}\"" >> $1 @@ -1036,9 +1091,9 @@ function start_rf_sim_ue { echo "cd /home/ubuntu/tmp/cmake_targets/ran_build/build/" >> $1 if [ $LOC_S1_CONFIGURATION -eq 0 ] then - echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -C ${LOC_FREQUENCY}000000 -r $LOC_PRB --nokrnmod 1 --rfsim --log_config.global_log_options level,nocolor --noS1\" > ./my-lte-softmodem-run.sh " >> $1 + echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -C ${LOC_FREQUENCY}000000 -r $LOC_PRB --ue-rxgain 140 --ue-txgain 120 --nokrnmod 1 --rfsim --log_config.global_log_options level,nocolor --noS1\" > ./my-lte-softmodem-run.sh " >> $1 else - echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -C ${LOC_FREQUENCY}000000 -r $LOC_PRB --nokrnmod 1 --rfsim --log_config.global_log_options level,nocolor\" > ./my-lte-softmodem-run.sh " >> $1 + echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -C ${LOC_FREQUENCY}000000 -r $LOC_PRB --ue-rxgain 140 --ue-txgain 120 --nokrnmod 1 --rfsim --log_config.global_log_options level,nocolor\" > ./my-lte-softmodem-run.sh " >> $1 fi echo "chmod 775 ./my-lte-softmodem-run.sh" >> $1 echo "cat ./my-lte-softmodem-run.sh" >> $1 @@ -1093,6 +1148,31 @@ function start_rf_sim_ue { else echo "RF-SIM UE oaitun_ue1 is UP and CONFIGURED" fi + if [ $LOC_MBMS_CONFIGURATION -eq 1 ] + then + # Checking oaitun_uem1 interface has now an IP address + i="0" + echo "ifconfig oaitun_uem1 | egrep -c \"inet addr\"" > $1 + while [ $i -lt 10 ] + do + sleep 5 + CONNECTED=`ssh -T -o StrictHostKeyChecking=no ubuntu@$LOC_UE_VM_IP_ADDR < $1` + if [ $CONNECTED -eq 1 ] + then + i="100" + else + i=$[$i+1] + fi + done + rm $1 + if [ $i -lt 50 ] + then + UE_SYNC=0 + echo "RF-SIM UE oaitun_uem1 is DOWN or NOT CONFIGURED" + else + echo "RF-SIM UE oaitun_uem1 is UP and CONFIGURED" + fi + fi sleep 10 } @@ -1194,7 +1274,7 @@ function start_rf_sim_nr_ue { echo "cd /home/ubuntu/tmp/cmake_targets/ran_build/build/" >> $1 if [ $LOC_S1_CONFIGURATION -eq 0 ] then - echo "echo \"RFSIMULATOR=${LOC_GNB_VM_IP_ADDR} ./nr-uesoftmodem --numerology 1 -C ${LOC_FREQUENCY}000000 -r $LOC_PRB --nokrnmod 1 --rfsim --phy-test --rcc_config_path /home/ubuntu/tmp/ci-scripts/rcc-files --log_config.global_log_options level,nocolor --noS1\" > ./my-nr-softmodem-run.sh " >> $1 + echo "echo \"RFSIMULATOR=${LOC_GNB_VM_IP_ADDR} ./nr-uesoftmodem --nokrnmod 1 --rfsim --phy-test --rrc_config_path /home/ubuntu/tmp/ci-scripts/rrc-files --log_config.global_log_options level,nocolor --noS1\" > ./my-nr-softmodem-run.sh " >> $1 fi echo "chmod 775 ./my-nr-softmodem-run.sh" >> $1 echo "cat ./my-nr-softmodem-run.sh" >> $1 @@ -1205,7 +1285,7 @@ function start_rf_sim_nr_ue { rm $1 local i="0" - echo "egrep -c \"rfsimulator: Success\" /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE" > $1 + echo "egrep -c \"Initial sync: pbch decoded sucessfully\" /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE" > $1 while [ $i -lt 10 ] do sleep 5 @@ -1668,7 +1748,7 @@ function run_test_on_vm { fi fi - if [[ "$RUN_OPTIONS" == "complex" ]] && [[ $VM_NAME =~ .*-ru-sim.* ]] + if [[ "$RUN_OPTIONS" == "complex" ]] && [[ $VM_NAME =~ .*-rf-sim.* ]] then PING_STATUS=0 IPERF_STATUS=0 @@ -1686,13 +1766,12 @@ function run_test_on_vm { install_epc_on_vm $EPC_VM_NAME $EPC_VM_CMDS EPC_VM_IP_ADDR=`uvt-kvm ip $EPC_VM_NAME` fi - # withS1 configuration is not working #EPC_CONFIGS=("wS1" "noS1") #TRANS_MODES=("fdd" "tdd") #BW_CASES=(05 10 20) - EPC_CONFIGS=("noS1" "wS1") + EPC_CONFIGS=("wS1" "noS1") TRANS_MODES=("fdd") - BW_CASES=(05) + BW_CASES=(05 10) for CN_CONFIG in ${EPC_CONFIGS[@]} do if [[ $CN_CONFIG =~ .*wS1.* ]] @@ -1754,7 +1833,7 @@ function run_test_on_vm { echo "${CN_CONFIG} : Starting the UE" echo "############################################################" CURRENT_UE_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_ue.log - start_rf_sim_ue $UE_VM_CMDS $UE_VM_IP_ADDR $ENB_VM_IP_ADDR $CURRENT_UE_LOG_FILE $PRB $FREQUENCY $S1_NOS1_CFG + start_rf_sim_ue $UE_VM_CMDS $UE_VM_IP_ADDR $ENB_VM_IP_ADDR $CURRENT_UE_LOG_FILE $PRB $FREQUENCY $S1_NOS1_CFG 0 if [ $UE_SYNC -eq 0 ] then echo "Problem w/ eNB and UE not syncing" @@ -1762,13 +1841,13 @@ function run_test_on_vm { terminate_enb_ue_basic_sim $UE_VM_CMDS $UE_VM_IP_ADDR 2 scp -o StrictHostKeyChecking=no ubuntu@$ENB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC - if [ $S1_NOS1_CFG -eq 1 ] - then - terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR - fi - echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log + #if [ $S1_NOS1_CFG -eq 1 ] + #then + # terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR + #fi + # Now we keep running STATUS=-1 - return + break fi if [ $S1_NOS1_CFG -eq 1 ] @@ -1814,15 +1893,37 @@ function run_test_on_vm { check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 fi - if [ $S1_NOS1_CFG -eq 0 ] + if [ $S1_NOS1_CFG -eq 1 ] then - get_enb_noS1_ip_addr $ENB_VM_CMDS $ENB_VM_IP_ADDR echo "############################################################" - echo "${CN_CONFIG} : iperf DL -- UE is server and eNB is client" + echo "${CN_CONFIG} : iperf DL -- UE is server and EPC is client" echo "############################################################" IPERF_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_dl get_ue_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR 1 - THROUGHPUT=4 + THROUGHPUT=10 + generic_iperf $UE_VM_CMDS $UE_VM_IP_ADDR $UE_IP_ADDR $EPC_VM_CMDS $EPC_VM_IP_ADDR $REAL_EPC_IP_ADDR $THROUGHPUT $IPERF_LOG_FILE 1 0 + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_server.txt $ARCHIVES_LOC + scp -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_client.txt $ARCHIVES_LOC + check_iperf $ARCHIVES_LOC/$IPERF_LOG_FILE $THROUGHPUT + + echo "############################################################" + echo "${CN_CONFIG} : iperf UL -- EPC is server and UE is client" + echo "############################################################" + IPERF_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_ul + THROUGHPUT=2 + get_ue_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR 1 + generic_iperf $EPC_VM_CMDS $EPC_VM_IP_ADDR $REAL_EPC_IP_ADDR $UE_VM_CMDS $UE_VM_IP_ADDR $UE_IP_ADDR $THROUGHPUT $IPERF_LOG_FILE 1 0 + scp -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_server.txt $ARCHIVES_LOC + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_client.txt $ARCHIVES_LOC + check_iperf $ARCHIVES_LOC/$IPERF_LOG_FILE $THROUGHPUT + else + echo "############################################################" + echo "${CN_CONFIG} : iperf DL -- UE is server and eNB is client" + echo "############################################################" + get_enb_noS1_ip_addr $ENB_VM_CMDS $ENB_VM_IP_ADDR + IPERF_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_dl + get_ue_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR 1 + THROUGHPUT=10 generic_iperf $UE_VM_CMDS $UE_VM_IP_ADDR $UE_IP_ADDR $ENB_VM_CMDS $ENB_VM_IP_ADDR $ENB_IP_ADDR $THROUGHPUT $IPERF_LOG_FILE 1 0 scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_server.txt $ARCHIVES_LOC scp -o StrictHostKeyChecking=no ubuntu@$ENB_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_client.txt $ARCHIVES_LOC @@ -1852,6 +1953,70 @@ function run_test_on_vm { done done + #################### + ## MSMS CASE noS1 ## + #################### + CONF_FILE=lte-fdd-mbms-basic-sim.conf + CN_CONFIG="noS1" + S1_NOS1_CFG=0 + LTEBOX=0 + TMODE="fdd" + FREQUENCY=2680 + BW_CASES=(05) + MBMS_STATUS=0 + + for BW in ${BW_CASES[@]} + do + if [[ $BW =~ .*05.* ]]; then PRB=25; fi + if [[ $BW =~ .*10.* ]]; then PRB=50; fi + if [[ $BW =~ .*20.* ]]; then PRB=100; fi + + echo "############################################################" + echo "${CN_CONFIG} : Starting the eNB with MSMS in ${TMODE}-${BW}MHz mode" + echo "############################################################" + CURRENT_ENB_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_enb_mbms.log + start_rf_sim_enb $ENB_VM_CMDS "$ENB_VM_IP_ADDR" "$EPC_VM_IP_ADDR" $CURRENT_ENB_LOG_FILE $PRB $CONF_FILE $S1_NOS1_CFG + + echo "############################################################" + echo "${CN_CONFIG} : Starting the UE" + echo "############################################################" + CURRENT_UE_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_ue_mbms.log + start_rf_sim_ue $UE_VM_CMDS $UE_VM_IP_ADDR $ENB_VM_IP_ADDR $CURRENT_UE_LOG_FILE $PRB $FREQUENCY $S1_NOS1_CFG 1 + if [ $UE_SYNC -eq 0 ] + then + echo "Problem w/ eNB and UE not syncing" + terminate_enb_ue_basic_sim $ENB_VM_CMDS $ENB_VM_IP_ADDR 1 + terminate_enb_ue_basic_sim $UE_VM_CMDS $UE_VM_IP_ADDR 2 + scp -o StrictHostKeyChecking=no ubuntu@$ENB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC + STATUS=-1 + break + fi + + echo "############################################################" + echo "${CN_CONFIG} : iperf DL -- UE is server and eNB is client" + echo "############################################################" + get_enb_mbms_noS1_ip_addr $ENB_VM_CMDS $ENB_VM_IP_ADDR + IPERF_LOG_FILE=${TMODE}_${BW}MHz_${CN_CONFIG}_iperf_dl_mbms + get_ue_mbms_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR 1 + THROUGHPUT=2 + generic_iperf $UE_VM_CMDS $UE_VM_IP_ADDR $UE_IP_ADDR $ENB_VM_CMDS $ENB_VM_IP_ADDR $ENB_IP_ADDR $THROUGHPUT $IPERF_LOG_FILE 1 0 + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_server.txt $ARCHIVES_LOC + scp -o StrictHostKeyChecking=no ubuntu@$ENB_VM_IP_ADDR:/home/ubuntu/${IPERF_LOG_FILE}_client.txt $ARCHIVES_LOC + #check_iperf $ARCHIVES_LOC/$IPERF_LOG_FILE $THROUGHPUT + + echo "############################################################" + echo "${CN_CONFIG} : Terminate enb/ue simulators" + echo "############################################################" + terminate_enb_ue_basic_sim $ENB_VM_CMDS $ENB_VM_IP_ADDR 1 + terminate_enb_ue_basic_sim $UE_VM_CMDS $UE_VM_IP_ADDR 2 + scp -o StrictHostKeyChecking=no ubuntu@$ENB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC + NB_UE_MBMS_MESSAGES=`egrep -c "TRIED TO PUSH MBMS DATA TO" $ARCHIVES_LOC/$CURRENT_UE_LOG_FILE` + if [ $NB_UE_MBMS_MESSAGES -eq 0 ]; then MBMS_STATUS=-1; fi + + done + full_l2_sim_destroy echo "############################################################" @@ -1860,23 +2025,28 @@ function run_test_on_vm { if [ $PING_STATUS -ne 0 ]; then STATUS=-1; fi if [ $IPERF_STATUS -ne 0 ]; then STATUS=-1; fi + if [ $MBMS_STATUS -eq 0 ] + then + echo "LTE MBMS RFSIM seems OK" + else + echo "LTE MBMS RFSIM seems to FAIL" + STATUS=-1 + fi if [ $STATUS -eq 0 ] then - echo "TEST_OK" > $ARCHIVES_LOC/test_final_status.log + echo "LTE RFSIM seems OK" + echo "LTE: TEST_OK" > $ARCHIVES_LOC/test_final_status.log else - echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log + echo "LTE RFSIM seems to FAIL" + echo "LTE: TEST_KO" > $ARCHIVES_LOC/test_final_status.log fi fi if [[ "$RUN_OPTIONS" == "complex" ]] && [[ $VM_NAME =~ .*-rf-sim.* ]] then + NR_STATUS=0 PING_STATUS=0 IPERF_STATUS=0 - if [ -d $ARCHIVES_LOC ] - then - rm -Rf $ARCHIVES_LOC - fi - mkdir --parents $ARCHIVES_LOC CN_CONFIG="noS1" CONF_FILE=gnb.band78.tm1.106PRB.usrpn300.conf @@ -1904,13 +2074,14 @@ function run_test_on_vm { terminate_enb_ue_basic_sim $GNB_VM_CMDS $GNB_VM_IP_ADDR 1 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC - echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log + echo "5G-NR RFSIM seems to FAIL" + echo "5G-NR: TEST_KO" >> $ARCHIVES_LOC/test_final_status.log STATUS=-1 return fi echo "############################################################" - echo "${CN_CONFIG} : iperf DL -- UE is server and eNB is client" + echo "${CN_CONFIG} : iperf DL -- NR-UE is server and gNB is client" echo "############################################################" THROUGHPUT="30K" CURR_IPERF_LOG_BASE=tdd_${PRB}prb_${CN_CONFIG}_iperf_dl @@ -1921,6 +2092,18 @@ function run_test_on_vm { scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/${CURR_IPERF_LOG_BASE}_server.txt $ARCHIVES_LOC check_iperf $ARCHIVES_LOC/$CURR_IPERF_LOG_BASE $THROUGHPUT + echo "############################################################" + echo "${CN_CONFIG} : iperf UL -- gNB is server and NR-UE is client" + echo "############################################################" + THROUGHPUT="30K" + CURR_IPERF_LOG_BASE=tdd_${PRB}prb_${CN_CONFIG}_iperf_ul + get_enb_noS1_ip_addr $GNB_VM_CMDS $GNB_VM_IP_ADDR + get_ue_ip_addr $NR_UE_VM_CMDS $NR_UE_VM_IP_ADDR 1 + generic_iperf $GNB_VM_CMDS $GNB_VM_IP_ADDR $ENB_IP_ADDR $NR_UE_VM_CMDS $NR_UE_VM_IP_ADDR $UE_IP_ADDR $THROUGHPUT $CURR_IPERF_LOG_BASE 1 0 + scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/${CURR_IPERF_LOG_BASE}_server.txt $ARCHIVES_LOC + scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/${CURR_IPERF_LOG_BASE}_client.txt $ARCHIVES_LOC + check_iperf $ARCHIVES_LOC/$CURR_IPERF_LOG_BASE $THROUGHPUT + echo "############################################################" echo "${CN_CONFIG} : Terminate gNB/NR-UE simulators" echo "############################################################" @@ -1936,13 +2119,16 @@ function run_test_on_vm { echo "Checking run status" echo "############################################################" - if [ $PING_STATUS -ne 0 ]; then STATUS=-1; fi - if [ $IPERF_STATUS -ne 0 ]; then STATUS=-1; fi - if [ $STATUS -eq 0 ] + if [ $PING_STATUS -ne 0 ]; then NR_STATUS=-1; fi + if [ $IPERF_STATUS -ne 0 ]; then NR_STATUS=-1; fi + if [ $NR_STATUS -eq 0 ] then - echo "TEST_OK" > $ARCHIVES_LOC/test_final_status.log + echo "5G-NR RFSIM seems OK" + echo "5G-NR: TEST_OK" >> $ARCHIVES_LOC/test_final_status.log else - echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log + echo "5G-NR RFSIM seems to FAIL" + echo "5G-NR: TEST_KO" >> $ARCHIVES_LOC/test_final_status.log + STATUS=-1 fi fi @@ -2032,15 +2218,41 @@ function run_test_on_vm { if [ $S1_NOS1_CFG -eq 1 ] then - get_ue_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR 1 echo "############################################################" echo "${CN_CONFIG} : Pinging the EPC from UE(s)" echo "############################################################" - PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_epc.log - ping_epc_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR $REAL_EPC_IP_ADDR $PING_LOG_FILE 1 0 - scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/$PING_LOG_FILE $ARCHIVES_LOC - check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 + echo " --- Sequentially ---" + local j="1" + while [ $j -le $INT_NB_UES ] + do + PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_epc_seq_from_ue${j}.log + ping_epc_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR $REAL_EPC_IP_ADDR $PING_LOG_FILE ${j} 0 + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/$PING_LOG_FILE $ARCHIVES_LOC + check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 + j=$[$j+1] + done + if [ $INT_NB_UES -gt 1 ] + then + echo " --- In parallel ---" + j="1" + while [ $j -le $INT_NB_UES ] + do + PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_epc_para_from_ue${j}.log + ping_epc_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR $REAL_EPC_IP_ADDR $PING_LOG_FILE ${j} 1 + j=$[$j+1] + done + sleep 25 + j="1" + while [ $j -le $INT_NB_UES ] + do + PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_epc_para_from_ue${j}.log + scp -o StrictHostKeyChecking=no ubuntu@$UE_VM_IP_ADDR:/home/ubuntu/$PING_LOG_FILE $ARCHIVES_LOC + tail -3 $ARCHIVES_LOC/$PING_LOG_FILE + check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 + j=$[$j+1] + done + fi else get_enb_noS1_ip_addr $ENB_VM_CMDS $ENB_VM_IP_ADDR @@ -2085,10 +2297,38 @@ function run_test_on_vm { echo "############################################################" echo "${CN_CONFIG} : Pinging the UE(s) from EPC" echo "############################################################" - PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_ue.log - ping_ue_ip_addr $EPC_VM_CMDS $EPC_VM_IP_ADDR $UE_IP_ADDR $PING_LOG_FILE 0 - scp -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu/$PING_LOG_FILE $ARCHIVES_LOC - check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 + echo " --- Sequentially ---" + local j="1" + while [ $j -le $INT_NB_UES ] + do + get_ue_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR $j + PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_from_epc_seq_ue${j}.log + ping_ue_ip_addr $EPC_VM_CMDS $EPC_VM_IP_ADDR $UE_IP_ADDR $PING_LOG_FILE 0 + scp -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu/$PING_LOG_FILE $ARCHIVES_LOC + check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 + j=$[$j+1] + done + if [ $INT_NB_UES -gt 1 ] + then + echo " --- In parallel ---" + j="1" + while [ $j -le $INT_NB_UES ] + do + get_ue_ip_addr $UE_VM_CMDS $UE_VM_IP_ADDR $j + PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_from_epc_para_ue${j}.log + ping_ue_ip_addr $EPC_VM_CMDS $EPC_VM_IP_ADDR $UE_IP_ADDR $PING_LOG_FILE 1 + j=$[$j+1] + done + sleep 25 + j="1" + while [ $j -le $INT_NB_UES ] + do + PING_LOG_FILE=${TMODE}_${BW}MHz_${UES}users_${CN_CONFIG}_ping_from_epc_para_ue${j}.log + scp -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu/$PING_LOG_FILE $ARCHIVES_LOC + check_ping_result $ARCHIVES_LOC/$PING_LOG_FILE 20 + j=$[$j+1] + done + fi else echo "############################################################" echo "${CN_CONFIG} : Pinging the UE(s) from eNB" @@ -2128,7 +2368,7 @@ function run_test_on_vm { fi fi - if [ $S1_NOS1_CFG -eq 2 ] + if [ $S1_NOS1_CFG -eq 0 ] then get_enb_noS1_ip_addr $ENB_VM_CMDS $ENB_VM_IP_ADDR echo "############################################################" diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_build.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_build.xml new file mode 100644 index 0000000000..64c3517166 --- /dev/null +++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_build.xml @@ -0,0 +1,38 @@ + + + build-tab + Build + wrench + + 010101 + + + + + Build_eNB + Build eNB (USRP) + -w USRP -c --eNB + + + diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml index 3eca883aa6..581858e44e 100644 --- a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml @@ -109,8 +109,8 @@ Iperf - iperf (5MHz - UL/8Mbps/UDP)(30 sec) - -c 10.0.1.1 -u -b 8M -t 30 -i 1 -fm -B 10.0.1.2 -R + iperf (5MHz - UL/4Mbps/UDP)(30 sec) + -c 10.0.1.1 -u -b 4M -t 30 -i 1 -fm -B 10.0.1.2 -R 50 balanced diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_mbms_no_s1.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_mbms_no_s1.xml new file mode 100644 index 0000000000..b841d3bab4 --- /dev/null +++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_mbms_no_s1.xml @@ -0,0 +1,82 @@ + + + test-05-tm1-mbms-nos1-tunnel + Test-05MHz-MBMS-TM1-noS1-tunnel + tasks + 2 + + 030201 090109 + 030103 000001 090103 000002 040605 000001 090109 030201 + + + + + IdleSleep + Sleep + 10 + + + + IdleSleep + Sleep + 15 + + + + IdleSleep + Sleep + 60 + + + + Initialize_eNB + Initialize eNB (FDD/Band7/5MHz/MBMS) + -O ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf --noS1 --eNBs.[0].rrc_inactivity_threshold 0 --nokrnmod 1 --eNBs.[0].component_carriers.[0].eutra_band 7 --eNBs.[0].component_carriers.[0].downlink_frequency 2680000000 --eNBs.[0].component_carriers.[0].uplink_frequency_offset -120000000 + + + + Terminate_eNB + Terminate eNB + + + + Initialize_OAI_UE + Initialize OAI UE (FDD/Band7/5MHz/MBMS) + -C 2680000000 -r 25 --ue-rxgain 120 --ue-txgain 0 --ue-max-power 0 --ue-scan-carrier --nokrnmod 1 --noS1 + + + + Terminate_OAI_UE + Terminate OAI UE + + + + Iperf + iperf (5MHz - DL/1.5Mbps/UDP/MBMS-sink)(20 sec) + -c 10.0.2.2 -u -b 1.5M -t 20 -i 1 -fm -B 10.0.2.1 + 50 + sink + + + diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml index 9f7546cab3..2336f8e614 100644 --- a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml +++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml @@ -96,8 +96,8 @@ Iperf - iperf (5MHz - UL/8Mbps/UDP)(30 sec) - -u -b 8M -t 30 -i 1 -fm -R + iperf (5MHz - UL/4Mbps/UDP)(30 sec) + -u -b 4M -t 30 -i 1 -fm -R 50 balanced diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_ue_build.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_ue_build.xml new file mode 100644 index 0000000000..7280a87fb8 --- /dev/null +++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_ue_build.xml @@ -0,0 +1,38 @@ + + + oai-ue-build-tab + OAI-UE-Build + wrench + +090101 + + + + + Build_OAI_UE + Build OAI UE + -w USRP --UE + + + diff --git a/ci-scripts/xml_files/enb_usrp210_band13_build.xml b/ci-scripts/xml_files/enb_usrp210_band13_build.xml index 96ab517b34..888a1230ae 100644 --- a/ci-scripts/xml_files/enb_usrp210_band13_build.xml +++ b/ci-scripts/xml_files/enb_usrp210_band13_build.xml @@ -26,7 +26,6 @@ wrench 010101 - 050101 060101 070101 @@ -37,19 +36,4 @@ -w USRP -c --eNB - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - diff --git a/ci-scripts/xml_files/enb_usrp210_band13_epc_start.xml b/ci-scripts/xml_files/enb_usrp210_band13_epc_start.xml new file mode 100644 index 0000000000..0a788cb614 --- /dev/null +++ b/ci-scripts/xml_files/enb_usrp210_band13_epc_start.xml @@ -0,0 +1,48 @@ + + + epc-start-tab + EPC-Start + log-in + + 050101 060101 070101 + + + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + diff --git a/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml index d72722aa8c..680f09c435 100644 --- a/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml +++ b/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml @@ -21,8 +21,8 @@ --> - test-10-tm1 - Test-10MHz-TM1 + test-lte-m-10-tm1 + Test-LTE-M-10MHz-TM1 tasks 2 diff --git a/ci-scripts/xml_files/enb_usrp210_band40_build.xml b/ci-scripts/xml_files/enb_usrp210_band40_build.xml index fd32019bb5..64c3517166 100644 --- a/ci-scripts/xml_files/enb_usrp210_band40_build.xml +++ b/ci-scripts/xml_files/enb_usrp210_band40_build.xml @@ -26,7 +26,6 @@ wrench 010101 - 050101 060101 070101 @@ -36,19 +35,4 @@ -w USRP -c --eNB - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - diff --git a/ci-scripts/xml_files/enb_usrp210_band40_epc_start.xml b/ci-scripts/xml_files/enb_usrp210_band40_epc_start.xml new file mode 100644 index 0000000000..354cff346e --- /dev/null +++ b/ci-scripts/xml_files/enb_usrp210_band40_epc_start.xml @@ -0,0 +1,47 @@ + + + epc-start-tab + EPC-Start + log-in + + 050101 060101 070101 + + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + diff --git a/ci-scripts/xml_files/enb_usrp210_band7_build.xml b/ci-scripts/xml_files/enb_usrp210_band7_build.xml index fd32019bb5..64c3517166 100644 --- a/ci-scripts/xml_files/enb_usrp210_band7_build.xml +++ b/ci-scripts/xml_files/enb_usrp210_band7_build.xml @@ -26,7 +26,6 @@ wrench 010101 - 050101 060101 070101 @@ -36,19 +35,4 @@ -w USRP -c --eNB - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - diff --git a/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml b/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml new file mode 100644 index 0000000000..354cff346e --- /dev/null +++ b/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml @@ -0,0 +1,47 @@ + + + epc-start-tab + EPC-Start + log-in + + 050101 060101 070101 + + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + diff --git a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml index 3b07ed4950..ec6090c00c 100644 --- a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml @@ -28,101 +28,15 @@ 030201 040101 030101 040301 040501 040603 040604 040605 040606 040607 040641 040642 040643 040644 040401 040201 030201 - 030102 000010 040301 040502 000011 040302 000001 000012 040303 000002 000013 040503 040401 040201 030201 - 050102 - 030103 000020 040301 040504 000021 040302 000001 000022 040303 000002 040504 000023 040401 040201 030201 - 050202 - - IdleSleep - Waiting for 35 seconds - 35 - - - - IdleSleep - Waiting for 10 seconds - 10 - - - - CheckStatusUE - Check UE(s) status before attachment - 0 - - - - CheckStatusUE - Check UE(s) status before data disabling - 2 - - - - CheckStatusUE - Check UE(s) status after data disabling - 0 - - - - CheckStatusUE - Check UE(s) status after data re-enabling - 2 - - - - CheckStatusUE - Check UE(s) status before attachment - 0 - - - - CheckStatusUE - Check UE(s) status before data disabling - 2 - - - - CheckStatusUE - Check UE(s) status after data disabling - 0 - - - - CheckStatusUE - Check UE(s) status after data re-enabling - 2 - - - - Initialize_FlexranCtrl - Starting Flexran Controller - - - - Terminate_FlexranCtrl - Stopping Flexran Controller - - Initialize_eNB Initialize eNB (FDD/Band7/5MHz) -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf - - Initialize_eNB - Initialize eNB (FDD/Band7/5MHz) for RRC Inactivity Timer testing -- no FlexRan Ctl - -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf - - - - Initialize_eNB - Initialize eNB (FDD/Band7/5MHz) for RRC Inactivity Timer testing -- with FlexRan Ctl - -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf - - Terminate_eNB Terminate eNB @@ -148,16 +62,6 @@ Detach UE - - DataDisable_UE - Disabling Data Service on UE - - - - DataEnable_UE - Enabling Data Service on UE - - Ping ping (5MHz - 20 sec) @@ -165,34 +69,6 @@ 5 - - Ping - ping (5MHz - 20 sec) - -c 20 - 5 - - - - Ping - ping (5MHz - 20 sec) - -c 20 - 5 - - - - Ping - ping (5MHz - 20 sec) - -c 20 - 5 - - - - Ping - ping (5MHz - 20 sec) - -c 20 - 5 - - Iperf iperf (5MHz - DL/15Mbps/UDP)(30 sec)(balanced profile) diff --git a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xml b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xml new file mode 100644 index 0000000000..a28a81d970 --- /dev/null +++ b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xml @@ -0,0 +1,125 @@ + + + test-05-tm1-rrc-no-flex + Test-05MHz-TM1-RRC-Inactivity + tasks + + 030201 + 040101 + 030102 000010 040301 040502 000011 040302 000001 000012 040303 000002 000013 040503 040401 040201 030201 + + + + + IdleSleep + Waiting for 35 seconds + 35 + + + + IdleSleep + Waiting for 10 seconds + 10 + + + + CheckStatusUE + Check UE(s) status before attachment + 0 + + + + CheckStatusUE + Check UE(s) status before data disabling + 2 + + + + CheckStatusUE + Check UE(s) status after data disabling + 0 + + + + CheckStatusUE + Check UE(s) status after data re-enabling + 2 + + + + Initialize_eNB + Initialize eNB (FDD/Band7/5MHz) for RRC Inactivity Timer testing -- no FlexRan Ctl + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf + + + + Terminate_eNB + Terminate eNB + + + + Initialize_UE + Initialize UE + + + + Terminate_UE + Terminate UE + + + + Attach_UE + Attach UE + + + + Detach_UE + Detach UE + + + + DataDisable_UE + Disabling Data Service on UE + + + + DataEnable_UE + Enabling Data Service on UE + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + diff --git a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_w_flexran.xml b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_w_flexran.xml new file mode 100644 index 0000000000..07cd8fbb30 --- /dev/null +++ b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_w_flexran.xml @@ -0,0 +1,138 @@ + + + test-05-tm1-rrc-w-flex + Test-05MHz-TM1-RRC-Inactivity-FlexRan + tasks + 2 + + 030201 + 040101 + 050102 + 030103 000020 040301 040504 000021 040302 000001 000022 040303 000002 040505 000023 040401 040201 030201 + 050202 + + + + + IdleSleep + Waiting for 45 seconds + 45 + + + + IdleSleep + Waiting for 10 seconds + 10 + + + + CheckStatusUE + Check UE(s) status before attachment + 0 + + + + CheckStatusUE + Check UE(s) status before data disabling + 2 + + + + CheckStatusUE + Check UE(s) status after data disabling + 0 + + + + CheckStatusUE + Check UE(s) status after data re-enabling + 2 + + + + Initialize_FlexranCtrl + Starting Flexran Controller + + + + Terminate_FlexranCtrl + Stopping Flexran Controller + + + + Initialize_eNB + Initialize eNB (FDD/Band7/5MHz) for RRC Inactivity Timer testing -- with FlexRan Ctl + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf + + + + Terminate_eNB + Terminate eNB + + + + Initialize_UE + Initialize UE + + + + Terminate_UE + Terminate UE + + + + Attach_UE + Attach UE + + + + Detach_UE + Detach UE + + + + DataDisable_UE + Disabling Data Service on UE + + + + DataEnable_UE + Enabling Data Service on UE + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + diff --git a/ci-scripts/xml_files/enb_usrpB210_band7_50PRB.xml b/ci-scripts/xml_files/enb_usrpB210_band7_50PRB.xml deleted file mode 100644 index 56dfe2be72..0000000000 --- a/ci-scripts/xml_files/enb_usrpB210_band7_50PRB.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - 030101 040101 040301 040501 040401 040201 030201 - - - - Initialize_eNB - Initialize eNB (FDD/Band1/5MHz/info) - -O ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf - - - - Terminate_eNB - Terminate eNB - - - - Initialize_UE - Initialize UE - - - - Terminate_UE - Terminate UE - - - - Attach_UE - Attach UE - - - - Detach_UE - Detach UE - - - - Ping - ping (20 sec) - -c 20 - 5 - - - diff --git a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml index 03220ec286..f3e80c576a 100644 --- a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml +++ b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml @@ -24,7 +24,7 @@ run-oai-gnb-nr-ue Run-gNB-and-NR-UE tasks - 4 + 2 090101 000001 090102 000002 090108 090109 @@ -33,7 +33,7 @@ Initialize_eNB Initialize gNB USRP - -O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf + -O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf --phy-test NR @@ -52,7 +52,7 @@ Initialize_OAI_UE Initialize NR UE USRP - -C 3510000000 --numerology 1 -r 106 --phy-test --usrp-args "addr=192.168.30.2,clock_source=external,time_source=external" --threadoffset 16 + --phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --threadoffset 16 --rrc_config_path ci-scripts/rrc-files NR diff --git a/ci-scripts/xml_files/if4p5_usrp210_band40_build.xml b/ci-scripts/xml_files/if4p5_usrp210_band40_build.xml index 752049349f..ab221c918d 100644 --- a/ci-scripts/xml_files/if4p5_usrp210_band40_build.xml +++ b/ci-scripts/xml_files/if4p5_usrp210_band40_build.xml @@ -26,7 +26,6 @@ wrench 010101 - 050101 060101 070101 @@ -37,19 +36,4 @@ -w USRP -c --eNB - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - diff --git a/ci-scripts/xml_files/if4p5_usrp210_band40_epc_start.xml b/ci-scripts/xml_files/if4p5_usrp210_band40_epc_start.xml new file mode 100644 index 0000000000..0a788cb614 --- /dev/null +++ b/ci-scripts/xml_files/if4p5_usrp210_band40_epc_start.xml @@ -0,0 +1,48 @@ + + + epc-start-tab + EPC-Start + log-in + + 050101 060101 070101 + + + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + diff --git a/ci-scripts/xml_files/if4p5_usrp210_band7_build.xml b/ci-scripts/xml_files/if4p5_usrp210_band7_build.xml index 8cbd2d84c6..ab221c918d 100644 --- a/ci-scripts/xml_files/if4p5_usrp210_band7_build.xml +++ b/ci-scripts/xml_files/if4p5_usrp210_band7_build.xml @@ -26,7 +26,6 @@ wrench 010101 - 050101 060101 070101 040101 @@ -37,19 +36,4 @@ -w USRP -c --eNB - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - diff --git a/ci-scripts/xml_files/if4p5_usrp210_band7_epc_start.xml b/ci-scripts/xml_files/if4p5_usrp210_band7_epc_start.xml new file mode 100644 index 0000000000..e8d08de507 --- /dev/null +++ b/ci-scripts/xml_files/if4p5_usrp210_band7_epc_start.xml @@ -0,0 +1,48 @@ + + + epc-start-tab + EPC-Start + log-in + + 050101 060101 070101 040101 + + + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + diff --git a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml index 1471b9a016..0196bf1ab6 100644 --- a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml @@ -68,7 +68,7 @@ Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 diff --git a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml index dff0761bd3..c2835d0461 100644 --- a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml +++ b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml @@ -24,7 +24,7 @@ test-05-tm1-nos1-tunnelTest-05MHz-TM1-noS1-tunneltasks - 2 + 4 030201 090109 030101 000001 090101 000002 040501 040502 000001 040601 040602 040641 040642 000001 090109 030201 diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml index 776c92106d..d3e9825923 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml @@ -26,13 +26,24 @@ wrench 010101 + 010102 Build_eNB - Build eNB (USRP) + Build eNB #0 (USRP) -w USRP -c --eNB + 0 + 0 + + + + Build_eNB + Build eNB #1 (USRP) + -w USRP -c --eNB + 1 + 1 diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml index 5843539f72..964550d872 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml @@ -19,16 +19,52 @@ For more information about the OpenAirInterface (OAI) Software Alliance: contact@openairinterface.org - 030102 000002 040301 000002 040504 040605 040606 040645 040646 000001 040401 000002 030201 --> test-05-tm1 Test-05MHz-TM1 tasks - 2 + 1 - 030201 040101 - 030102 000002 040301 000002 040504 000001 040401 000002 030201 + 040101 030201 + 030103 000002 + 040301 000002 040504 040605 040606 040645 040646 040401 + 040301 000002 040505 000001 040401 + 040301 000002 040506 000001 040401 + 040301 000002 040507 000001 040401 + 040301 000002 040508 000001 040401 + 040301 000002 040509 000001 040401 + 040301 000002 040510 000001 040401 + 040301 000002 040511 000001 040401 + 040301 000002 040512 000001 040401 + 040301 000002 040513 000001 040401 + 040301 000002 040514 000001 040401 + 040301 000002 040515 000001 040401 + 040301 000002 040516 000001 040401 + 040301 000002 040517 000001 040401 + 040301 000002 040518 000001 040401 + 040301 000002 040519 000001 040401 + 040301 000002 040520 000001 040401 + 040301 000002 040521 000001 040401 + 040301 000002 040522 000001 040401 + 040301 000002 040523 000001 040401 + 040301 000002 040524 000001 040401 + 040301 000002 040525 000001 040401 + 040301 000002 040526 000001 040401 + 040301 000002 040527 000001 040401 + 040301 000002 040528 000001 040401 + 040301 000002 040529 000001 040401 + 040301 000002 040530 000001 040401 + 040301 000002 040531 000001 040401 + 040301 000002 040532 000001 040401 + 040301 000002 040533 000001 040401 + 040301 000002 040534 000001 040401 + 040301 000002 040535 000001 040401 + 040301 000002 040536 000001 040401 + 040301 000002 040537 000001 040401 + 040301 000002 040538 000001 040401 + 040301 000002 040539 000001 040401 + 040201 000002 030201 @@ -37,6 +73,11 @@ Initialize UE + + Terminate_UE + Terminate UE + + IdleSleep Sleep for 10 sec @@ -49,7 +90,7 @@ 3 - + Initialize_eNB Initialize eNB (FDD/Band7/5MHz) -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT @@ -73,7 +114,252 @@ Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 5 @@ -86,8 +372,8 @@ Iperf - iperf (5MHz - DL/12Mbps/UDP)(30 sec) - -u -b 12M -t 30 -i 1 -fm + iperf (5MHz - DL/15Mbps/UDP)(30 sec) + -u -b 15M -t 30 -i 1 -fm 50 @@ -100,8 +386,8 @@ Iperf - iperf (5MHz - UL/2Mbps/UDP)(30 sec) - -u -b 2M -t 30 -i 1 -fm -R + iperf (5MHz - UL/3.8Mbps/UDP)(30 sec) + -u -b 3.8M -t 30 -i 1 -fm -R 50 diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml new file mode 100644 index 0000000000..22f8b63266 --- /dev/null +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml @@ -0,0 +1,203 @@ + + + test-x2-ho-05-tm1 + Test-X2-Handover-05MHz-TM1 + tasks + 2 + + 040101 030201 030202 + 050102 + 030104 000002 030105 000002 + 040301 000002 + 040540 040615 040655 + 050401 000001 + 040541 040617 040657 + 040401 000001 + 040201 000002 030201 030202 + 050202 + + + + + Initialize_UE + Initialize UE + + + + Terminate_UE + Terminate UE + + + + IdleSleep + Sleep for 10 sec + 10 + + + + IdleSleep + Sleep for 3 sec + 3 + + + + Initialize_eNB + Initialize eNB #0 (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes --eNBs.[0].nr_cellid 123456 + 0 + 0 + + + + Initialize_eNB + Initialize eNB #1 (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes --eNBs.[0].nr_cellid 98765 + 1 + 1 + + + + Terminate_eNB + Terminate eNB #0 + 0 + 0 + + + + Terminate_eNB + Terminate eNB #1 + 1 + 1 + + + + Initialize_FlexranCtrl + Starting Flexran Controller + + + + Terminate_FlexranCtrl + Stopping Flexran Controller + + + + Attach_UE + Attach UE + + + + Detach_UE + Detach UE + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 50 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 50 + + + + Iperf + iperf (5MHz - DL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - DL/15Mbps/UDP)(30 sec) + -u -b 15M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - DL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - DL/15Mbps/UDP)(30 sec) + -u -b 15M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - UL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm -R + 50 + + + + Iperf + iperf (5MHz - UL/3.8Mbps/UDP)(30 sec) + -u -b 3.8M -t 30 -i 1 -fm -R + 50 + + + + Iperf + iperf (5MHz - UL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm -R + 50 + + + + Iperf + iperf (5MHz - UL/3.8Mbps/UDP)(30 sec) + -u -b 3.8M -t 30 -i 1 -fm -R + 50 + + + + Perform_X2_Handover + Doing a Flexran-Controlled X2 Handover + network + + + + Perform_X2_Handover + Doing a Flexran-Controlled X2 Handover + network + + + diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml index 0d2a122537..c5a912a33d 100644 --- a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml +++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml @@ -27,7 +27,6 @@ 010101 010102 - 050101 060101 070101 @@ -48,19 +47,4 @@ 1 - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_epc_start.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_epc_start.xml new file mode 100644 index 0000000000..0a788cb614 --- /dev/null +++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_epc_start.xml @@ -0,0 +1,48 @@ + + + epc-start-tab + EPC-Start + log-in + + 050101 060101 070101 + + + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f5e23f7383..f6fcabf82e 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -184,9 +184,9 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${CMAKE_CU ######################### # set a flag for changes in the source code # these changes are related to hardcoded path to include .h files -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -O2") - +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3") set(GIT_BRANCH "UNKNOWN") set(GIT_COMMIT_HASH "UNKNOWN") @@ -245,29 +245,21 @@ add_boolean_option(TEST_OMG False "???") add_boolean_option(DEBUG_OMG False "???") add_boolean_option(PRINT_STATS False "This adds the possibility to see the status") add_boolean_option(T_TRACER True "Activate the T tracer, a debugging/monitoring framework" ) -add_boolean_option(ENABLE_VCD True "always true now, time measurements of proc calls and var displays") add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs") add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace") add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace") -add_boolean_option(DISABLE_LOG_X False "Deactivate all LOG_* macros") -add_boolean_option(USRP_REC_PLAY False "Enable USRP record playback mode") -add_boolean_option(UE_NAS_USE_TUN False "Enable UE NAS TUN device instead of ue_ip.ko") -add_boolean_option(NOS1 False "Allows to run without a EPC") -add_boolean_option(BASIC_SIMULATOR False "Has to be True when building the basic simulator, False otherwise") add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering") -add_boolean_option(ENABLE_ITTI True "ITTI is internal messaging, should remain enabled for most targets") set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti) -if (${ENABLE_ITTI}) - add_library(ITTI - ${OCP_ITTI}/intertask_interface.cpp - ${OPENAIR_DIR}/common/utils/backtrace.c - ${OPENAIR_DIR}/common/utils/memory_pools.c - ) +add_library(ITTI + ${OCP_ITTI}/intertask_interface.cpp + ${OPENAIR_DIR}/common/utils/backtrace.c + ${OPENAIR_DIR}/common/utils/memory_pools.c + ) add_dependencies(ITTI rrc_flag) set(ITTI_LIB ITTI) set(GTPU_need_ITTI ${OPENAIR3_DIR}/GTPV1-U/gtpv1u_eNB.c) -endif (${ENABLE_ITTI}) + ################################################## # ASN.1 grammar C code generation & dependencies # @@ -320,7 +312,7 @@ set (NR_RRC_ASN1_VERSION "NR_Rel15" ) make_version(NR_RRC_VERSION 15 6 0) set (NR_RRC_GRAMMAR ${OPENAIR2_DIR}/RRC/NR/MESSAGES/asn1c/ASN1_files/nr-rrc-15.6.0.asn1) add_definitions(-DNR_RRC_VERSION=${NR_RRC_VERSION}) -set (NR_RRC_FULL_DIR ${asn1_generated_dir}/${NR_RRC_ASN1_VERSION}) +set (NR_RRC_FULL_DIR ${asn1_generated_dir}/RRC_${NR_RRC_ASN1_VERSION}) # Warning: if you modify ASN.1 source file to generate new C files, cmake should be re-run instead of make execute_process(COMMAND ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${NR_RRC_FULL_DIR}" "${NR_RRC_GRAMMAR}" "NR_" "-findirect-choice" @@ -342,7 +334,6 @@ add_library(NR_RRC_LIB ${nr_rrc_h} ${nr_rrc_source} add_dependencies(NR_RRC_LIB nr_rrc_flag) include_directories ("${NR_RRC_FULL_DIR}") - # S1AP # Same limitation as described in RRC: unknown generated file list # so we generate it at cmake time @@ -396,6 +387,145 @@ add_library(S1AP_ENB ) add_dependencies(S1AP_ENB rrc_flag s1ap_flag) + +#M2AP +# Same limitation as described in RRC/S1AP: unknown generated file list +# so we generate it at cmake time +############## +add_list1_option(M2AP_RELEASE R14 "M2AP ASN.1 grammar version" R14) + +set(M2AP_DIR ${OPENAIR2_DIR}/M2AP) +if (${M2AP_RELEASE} STREQUAL "R8") + make_version(M2AP_VERSION 8 9 0) + set(M2AP_ASN_FILES m2ap-8.9.0.asn1) +elseif (${M2AP_RELEASE} STREQUAL "R11") + make_version(M2AP_VERSION 11 9 0) + set(M2AP_ASN_FILES m2ap-11.9.0.asn1) +elseif (${M2AP_RELEASE} STREQUAL "R12") + make_version(M2AP_VERSION 12 9 0) + set(M2AP_ASN_FILES m2ap-12.9.0.asn1) +elseif (${M2AP_RELEASE} STREQUAL "R14") + make_version(M2AP_VERSION 14 0 0) + set(M2AP_ASN_FILES m2ap-14.0.0.asn1) +elseif (${M2AP_RELEASE} STREQUAL "R15") + make_version(M2AP_VERSION 15 1 0) + set(M2AP_ASN_FILES m2ap-15.1.0.asn1) +endif(${M2AP_RELEASE} STREQUAL "R8") +add_definitions(-DM2AP_VERSION=${M2AP_VERSION}) +set(M2AP_ASN_DIR ${M2AP_DIR}/MESSAGES/ASN1/${M2AP_RELEASE}) +set(M2AP_C_DIR ${asn1_generated_dir}/M2AP_${M2AP_RELEASE}) + +# Warning: if you modify ASN.1 source file to generate new C files, cmake should be re-run instead of make +execute_process(COMMAND ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${M2AP_C_DIR}" "${M2AP_ASN_DIR}/${M2AP_ASN_FILES}" "M2AP_" -fno-include-deps -DEMIT_ASN_DEBUG=1 + RESULT_VARIABLE ret) +if (NOT ${ret} STREQUAL 0) + message(FATAL_ERROR "${ret}: error") +endif (NOT ${ret} STREQUAL 0) + +file(GLOB M2AP_source ${M2AP_C_DIR}/*.c) + +add_custom_target ( + m2_flag ALL + COMMAND ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${M2AP_C_DIR}" "${M2AP_ASN_DIR}/${M2AP_ASN_FILES}" "M2AP_" -fno-include-deps + DEPENDS ${M2AP_ASN_DIR}/${M2AP_ASN_FILES} + ) + +add_library(M2AP_LIB + ${M2AP_source} + ${M2AP_DIR}/m2ap_common.c + ) +add_dependencies(M2AP_LIB rrc_flag m2_flag) + +include_directories ("${M2AP_C_DIR}") +include_directories ("${M2AP_DIR}") + +add_library(M2AP_ENB + ${M2AP_DIR}/m2ap_eNB.c + ${M2AP_DIR}/m2ap_MCE.c + ${M2AP_DIR}/m2ap_decoder.c + ${M2AP_DIR}/m2ap_encoder.c + ${M2AP_DIR}/m2ap_MCE_handler.c + ${M2AP_DIR}/m2ap_eNB_handler.c + ${M2AP_DIR}/m2ap_itti_messaging.c + ${M2AP_DIR}/m2ap_eNB_management_procedures.c + ${M2AP_DIR}/m2ap_eNB_generate_messages.c + ${M2AP_DIR}/m2ap_MCE_management_procedures.c + ${M2AP_DIR}/m2ap_MCE_generate_messages.c + ${M2AP_DIR}/m2ap_ids.c + ${M2AP_DIR}/m2ap_timers.c + ${M2AP_DIR}/m2ap_MCE_interface_management.c + ${M2AP_DIR}/m2ap_eNB_interface_management.c + ) +add_dependencies(M2AP_ENB rrc_flag m2_flag) + +#M3AP +# Same limitation as described in RRC/S1AP: unknown generated file list +# so we generate it at cmake time +############## +add_list1_option(M3AP_RELEASE R14 "M3AP ASN.1 grammar version" R14) + +set(M3AP_DIR ${OPENAIR3_DIR}/M3AP) +if (${M3AP_RELEASE} STREQUAL "R8") + make_version(M3AP_VERSION 8 9 0) + set(M3AP_ASN_FILES m3ap-8.9.0.asn1) +elseif (${M3AP_RELEASE} STREQUAL "R11") + make_version(M3AP_VERSION 11 9 0) + set(M3AP_ASN_FILES m3ap-11.9.0.asn1) +elseif (${M3AP_RELEASE} STREQUAL "R12") + make_version(M3AP_VERSION 12 9 0) + set(M3AP_ASN_FILES m3ap-12.9.0.asn1) +elseif (${M3AP_RELEASE} STREQUAL "R14") + make_version(M3AP_VERSION 14 0 0) + set(M3AP_ASN_FILES m3ap-14.0.0.asn1) +elseif (${M3AP_RELEASE} STREQUAL "R15") + make_version(M3AP_VERSION 15 1 0) + set(M3AP_ASN_FILES m3ap-15.1.0.asn1) +endif(${M3AP_RELEASE} STREQUAL "R8") +add_definitions(-DM3AP_VERSION=${M3AP_VERSION}) +set(M3AP_ASN_DIR ${M3AP_DIR}/MESSAGES/ASN1/${M3AP_RELEASE}) +set(M3AP_C_DIR ${asn1_generated_dir}/M3AP_${M3AP_RELEASE}) + +# Warning: if you modify ASN.1 source file to generate new C files, cmake should be re-run instead of make +execute_process(COMMAND ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${M3AP_C_DIR}" "${M3AP_ASN_DIR}/${M3AP_ASN_FILES}" "M3AP_" -fno-include-deps + RESULT_VARIABLE ret) +if (NOT ${ret} STREQUAL 0) + message(FATAL_ERROR "${ret}: error") +endif (NOT ${ret} STREQUAL 0) + +file(GLOB M3AP_source ${M3AP_C_DIR}/*.c) + +add_custom_target ( + m3_flag ALL + COMMAND ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${M3AP_C_DIR}" "${M3AP_ASN_DIR}/${M3AP_ASN_FILES}" "M3AP_" -fno-include-deps + DEPENDS ${M3AP_ASN_DIR}/${M3AP_ASN_FILES} + ) + +add_library(M3AP_LIB + ${M3AP_source} + ${M3AP_DIR}/m3ap_common.c + ) +add_dependencies(M3AP_LIB rrc_flag m3_flag) + +include_directories ("${M3AP_C_DIR}") +include_directories ("${M3AP_DIR}") + +add_library(M3AP_ENB + ${M3AP_DIR}/m3ap_decoder.c + ${M3AP_DIR}/m3ap_encoder.c + ${M3AP_DIR}/m3ap_MCE_handler.c + ${M3AP_DIR}/m3ap_MME_handler.c + ${M3AP_DIR}/m3ap_MME.c + ${M3AP_DIR}/m3ap_MME_management_procedures.c + ${M3AP_DIR}/m3ap_MME_interface_management.c + ${M3AP_DIR}/m3ap_MCE.c + ${M3AP_DIR}/m3ap_MCE_management_procedures.c + ${M3AP_DIR}/m3ap_MCE_interface_management.c + ${M3AP_DIR}/m3ap_itti_messaging.c + ${M3AP_DIR}/m3ap_ids.c + ${M3AP_DIR}/m3ap_timers.c + ) +add_dependencies(M3AP_ENB rrc_flag m3_flag) + #X2AP # Same limitation as described in RRC/S1AP: unknown generated file list # so we generate it at cmake time @@ -497,10 +627,8 @@ add_library(F1AP add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4") add_list1_option(NB_ANTENNAS_TX "4" "Number of antennas in transmission" "1" "2" "4") -add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "OAI_USRP" "OAI_BLADERF" "CPRIGW" "OAI_LMSSDR" "OAI_SIMU") -if (NOT ${RF_BOARD} STREQUAL "None") - add_definitions(-DMANAGED_RF=1) -endif() +add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "OAI_USRP" "OAI_BLADERF" "OAI_LMSSDR" "OAI_SIMU") + add_list2_option(TRANSP_PRO "None" "Transport protocol type" "None" "ETHERNET") @@ -517,7 +645,6 @@ set (CONFIG_LIBCONFIG_SOURCES ${CONFIG_ROOTDIR}/libconfig/config_libconfig.c ) add_library(CONFIG_LIB ${CONFIG_SOURCES}) -set(CONFIG_LIBRARIES CONFIG_LIB) add_library(params_libconfig MODULE ${CONFIG_LIBCONFIG_SOURCES} ) target_link_libraries(params_libconfig config) # shared library loader @@ -530,7 +657,6 @@ set (SHLIB_LOADER_SOURCES include_directories("${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/") set(HWLIB_USRP_SOURCE ${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp - ${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/usrp_lib_config.c ) add_library(oai_usrpdevif MODULE ${HWLIB_USRP_SOURCE} ) target_link_libraries(oai_usrpdevif uhd) @@ -599,7 +725,7 @@ Message("CPU_Affinity flag is ${CPU_AFFINITY}") ############################################################## # ???!!! TO BE DOCUMENTED OPTIONS !!!??? ############################################################## -add_boolean_option(ENABLE_USE_MME True "eNB connected to MME (INTERFACE S1-C), not standalone eNB") + add_boolean_option(NO_RRM True "DO WE HAVE A RADIO RESSOURCE MANAGER: NO") add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "set the RLC mode to AM for the default bearer") @@ -609,7 +735,6 @@ add_boolean_option(CPU_AFFINITY False "Enable CPU Affinity of threads (only vali add_boolean_option(NAS_NETLINK False "useless ??? Must be True to compile nasmesh driver without rtai ????") add_boolean_option(OAI_NW_DRIVER_USE_NETLINK True "????") -add_boolean_option(USE_MME False "this flag is used only one time in lte-softmodem.c") add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams") @@ -750,6 +875,7 @@ include_directories("${OPENAIR2_DIR}") include_directories("${OPENAIR3_DIR}/NAS/TOOLS") include_directories("${OPENAIR2_DIR}/ENB_APP") include_directories("${OPENAIR2_DIR}/GNB_APP") +include_directories("${OPENAIR2_DIR}/MCE_APP") include_directories("${OPENAIR2_DIR}/LAYER2/RLC") include_directories("${OPENAIR2_DIR}/LAYER2/RLC/AM_v9.3.0") include_directories("${OPENAIR2_DIR}/LAYER2/RLC/UM_v9.3.0") @@ -772,15 +898,19 @@ include_directories("${OPENAIR3_DIR}/SECU") include_directories("${OPENAIR3_DIR}/SCTP") include_directories("${OPENAIR3_DIR}/S1AP") include_directories("${OPENAIR2_DIR}/X2AP") +include_directories("${OPENAIR2_DIR}/M2AP") include_directories("${OPENAIR2_DIR}/F1AP") include_directories("${OPENAIR3_DIR}/UDP") include_directories("${OPENAIR3_DIR}/GTPV1-U") +include_directories("${OPENAIR3_DIR}/M3AP") +include_directories("${OPENAIR3_DIR}/MME_APP") include_directories("${OPENAIR_DIR}/targets/COMMON") include_directories("${OPENAIR_DIR}/targets/ARCH/COMMON") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PHY") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP") +include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/S1AP") include_directories("${OPENAIR2_DIR}/UTIL/OSA") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc") @@ -874,6 +1004,7 @@ add_library(FLEXRAN_AGENT ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.c ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c @@ -1170,14 +1301,35 @@ set(PHY_SMALLBLOCKSRC set(PHY_TURBOIF ${OPENAIR1_DIR}/PHY/CODING/coding_load.c ) -set(PHY_LDPCSRC + +set(PHY_LDPC_ORIG_SRC ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c ) +set(PHY_LDPC_OPTIM_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c +) +set(PHY_LDPC_OPTIM8SEG_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c +) +set(PHY_LDPC_OPTIM8SEGMULTI_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +) +set(PHY_NR_CODINGIF + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c; +) + +add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} ) +add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} ) +add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} ) +add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) + add_library(coding MODULE ${PHY_TURBOSRC} ) + set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c @@ -1343,6 +1495,8 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/dmrs_nr.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c @@ -1360,11 +1514,10 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/TOOLS/lut.c ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} - ${PHY_LDPCSRC} - ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c + ${PHY_NR_CODINGIF} + ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c ) - set(PHY_NR_UE_SRC ${OPENAIR1_DIR}/PHY/INIT/nr_parms.c ${OPENAIR1_DIR}/PHY/MODULATION/nr_modulation.c @@ -1372,7 +1525,6 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/pss_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/sss_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c - ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dmrs_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -1392,6 +1544,8 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/dmrs_nr.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold_ue.c ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1414,7 +1568,7 @@ set(PHY_SRC_UE # ${OPENAIR1_DIR}/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} - ${PHY_LDPCSRC} + ${PHY_NR_CODINGIF} ) @@ -1464,11 +1618,8 @@ set(PHY_MEX_UE ${OPENAIR_DIR}/common/utils/LOG/log.c ${OPENAIR_DIR}/common/utils/T/T.c ${OPENAIR_DIR}/common/utils/T/local_tracer.c - ${OPENAIR_DIR}/common/config/config_cmdline.c - ${OPENAIR_DIR}/common/config/config_userapi.c - ${OPENAIR_DIR}/common/config/config_load_configmodule.c ) -add_library(PHY_MEX ${PHY_MEX_UE}) +add_library(PHY_MEX ${PHY_MEX_UE} ${CONFIG_LIB}) #Layer 2 library ##################### @@ -1540,7 +1691,9 @@ set(L2_SRC ${PDCP_DIR}/pdcp_netlink.c # ${RRC_DIR}/rrc_UE.c ${RRC_DIR}/rrc_eNB.c + ${RRC_DIR}/rrc_eNB_endc.c ${RRC_DIR}/rrc_eNB_S1AP.c + ${RRC_DIR}/rrc_eNB_M2AP.c ${RRC_DIR}/rrc_eNB_UE_context.c ${RRC_DIR}/rrc_common.c ${RRC_DIR}/L2_interface.c @@ -1626,6 +1779,8 @@ set (MAC_NR_SRC ${NR_MAC_DIR}/config.c ${NR_MAC_DIR}/gNB_scheduler.c ${NR_MAC_DIR}/gNB_scheduler_bch.c + ${NR_MAC_DIR}/gNB_scheduler_dlsch.c + ${NR_MAC_DIR}/gNB_scheduler_ulsch.c ${NR_MAC_DIR}/gNB_scheduler_primitives.c ${NR_MAC_DIR}/gNB_scheduler_phytest.c ) @@ -1664,12 +1819,18 @@ set (GNB_APP_SRC ${OPENAIR2_DIR}/GNB_APP/gnb_config.c ) +set (MCE_APP_SRC + ${OPENAIR2_DIR}/MCE_APP/mce_app.c + ${OPENAIR2_DIR}/MCE_APP/mce_config.c + ) + add_library(L2 ${L2_SRC} ${MAC_SRC} ${ENB_APP_SRC} + ${MCE_APP_SRC} ) -add_dependencies(L2 rrc_flag s1ap_flag x2_flag) +add_dependencies(L2 rrc_flag s1ap_flag x2_flag m2_flag m3_flag) add_library(MAC_NR ${MAC_NR_SRC} @@ -1703,7 +1864,7 @@ add_dependencies(L2_UE rrc_flag s1ap_flag x2_flag) add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} ) -add_library( MAC_NR_COMMON ${OPENAIR2_DIR}/LAYER2/NR_MAC_gNB/nr_mac_common.c ${OPENAIR2_DIR}/LAYER2/NR_MAC_gNB/nr_compute_tbs_common.c) +add_library( MAC_NR_COMMON ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c ${OPENAIR2_DIR}/LAYER2/NR_MAC_gNB/nr_compute_tbs_common.c) include_directories("${OPENAIR2_DIR}/NR_UE_PHY_INTERFACE") include_directories("${OPENAIR2_DIR}/LAYER2/NR_MAC_UE") @@ -1734,6 +1895,13 @@ set (GTPV1U_SRC add_library(GTPV1U ${GTPV1U_SRC}) add_dependencies(GTPV1U rrc_flag) +set (MME_APP_SRC + ${OPENAIR3_DIR}/MME_APP/mme_app.c + ${OPENAIR3_DIR}/MME_APP/mme_config.c +) +add_library(MME_APP ${MME_APP_SRC}) +add_dependencies(MME_APP rrc_flag s1ap_flag x2_flag m2_flag m3_flag) + set(SCTP_SRC ${OPENAIR3_DIR}/SCTP/sctp_common.c ${OPENAIR3_DIR}/SCTP/sctp_eNB_task.c @@ -2235,6 +2403,9 @@ add_library(rfsimulator MODULE ) target_link_libraries(rfsimulator SIMU ${ATLAS_LIBRARIES}) +add_library(oai_iqplayer MODULE + ${OPENAIR_TARGETS}/ARCH/iqplayer/iqplayer_lib.c + ) set(CMAKE_MODULE_PATH "${OPENAIR_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}") #include T directory even if the T is off because T macros are in the code @@ -2281,13 +2452,10 @@ add_definitions(-DASN1_MINIMUM_VERSION=924) add_library(minimal_lib ${OPENAIR_DIR}/common/utils/backtrace.c ${OPENAIR_DIR}/common/utils/LOG/log.c - ${OPENAIR_DIR}/common/config/config_userapi.c - ${OPENAIR_DIR}/common/config/config_load_configmodule.c - ${OPENAIR_DIR}/common/config/config_cmdline.c ${OPENAIR_DIR}/common/utils/minimal_stub.c ${T_SOURCE} ) -target_link_libraries(minimal_lib pthread dl ${T_LIB}) +target_link_libraries(minimal_lib pthread dl ${T_LIB} ${CONFIG_LIB}) add_executable(nfapi_test ${OPENAIR_DIR}/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c @@ -2311,11 +2479,13 @@ add_executable(lte-softmodem ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/ru_control.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c - ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_mbms.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR_TARGETS}/ARCH/COMMON/record_player.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c @@ -2330,17 +2500,17 @@ add_executable(lte-softmodem ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} ) -add_dependencies(lte-softmodem rrc_flag s1ap_flag x2_flag) +add_dependencies(lte-softmodem rrc_flag s1ap_flag x2_flag oai_iqplayer) target_link_libraries (lte-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB + RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP M2AP_LIB M2AP_ENB X2AP_LIB X2AP_ENB M3AP_LIB M3AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT MME_APP UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 L2_LTE NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} -Wl,--end-group z dl) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) +target_link_libraries (lte-softmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem ${T_LIB}) @@ -2379,12 +2549,13 @@ add_executable(lte-uesoftmodem ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-uesoftmodem.c - ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/ru_control.c ${OPENAIR_TARGETS}/RT/USER/rfsim.c ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR_TARGETS}/ARCH/COMMON/record_player.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c @@ -2406,13 +2577,14 @@ if (NOT ${NOS1}) endif() target_link_libraries (lte-uesoftmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB F1AP F1AP_LIB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON - PHY_UE PHY_RU LFDS L2_UE L2_LTE SIMU ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES} - NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB + RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB F1AP F1AP_LIB + GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT MME_APP UDP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON + PHY_UE PHY_RU LFDS L2_UE L2_LTE LFDS7 SIMU NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB + ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ATLAS_LIBRARIES} -Wl,--end-group z dl) target_link_libraries (lte-uesoftmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-uesoftmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) +target_link_libraries (lte-uesoftmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) target_link_libraries (lte-uesoftmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-uesoftmodem ${T_LIB}) @@ -2427,9 +2599,10 @@ add_executable(nr-softmodem ${OPENAIR_DIR}/executables/nr-gnb.c ${OPENAIR_DIR}/executables/nr-ru.c ${OPENAIR_DIR}/executables/nr-softmodem.c - ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR_TARGETS}/ARCH/COMMON/record_player.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c @@ -2448,14 +2621,15 @@ target_link_libraries (nr-softmodem UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU LFDS GTPV1U SECU_CN SECU_OSA ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB L2 L2_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB - X2AP_LIB X2AP_ENB F1AP_LIB F1AP ${PROTO_AGENT_LIB} ${FSPT_MSG_LIB} + X2AP_LIB X2AP_ENB F1AP_LIB F1AP M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB ${PROTO_AGENT_LIB} ${FSPT_MSG_LIB} -Wl,--end-group z dl) target_link_libraries (nr-softmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (nr-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) +target_link_libraries (nr-softmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) target_link_libraries (nr-softmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (nr-softmodem ${T_LIB}) +add_dependencies( nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) # nr-uesoftmodem is UE implementation ####################################### @@ -2466,11 +2640,13 @@ add_executable(nr-uesoftmodem ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c ${OPENAIR_DIR}/executables/nr-uesoftmodem.c ${OPENAIR_DIR}/executables/nr-ue.c - ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR_TARGETS}/ARCH/COMMON/record_player.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c - ${OPENAIR2_DIR}/LAYER2/NR_MAC_gNB/nr_mac_common.c + ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c + ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c ${OPENAIR_DIR}/common/utils/utils.c @@ -2487,14 +2663,16 @@ target_link_libraries (nr-uesoftmodem -Wl,--start-group RRC_LIB NR_RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES} - PHY_COMMON PHY_NR_COMMON PHY_NR_UE PHY_RU LFDS L2_UE NR_L2_UE MAC_NR_COMMON NFAPI_USER_LIB S1AP_LIB S1AP_ENB + PHY_COMMON PHY_NR_COMMON PHY_UE PHY_NR_UE PHY_RU LFDS L2_UE NR_L2_UE MAC_NR_COMMON S1AP_LIB S1AP_ENB + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) target_link_libraries (nr-uesoftmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (nr-uesoftmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) +target_link_libraries (nr-uesoftmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) target_link_libraries (nr-uesoftmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (nr-uesoftmodem ${T_LIB}) +add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) # USIM process ################# @@ -2536,7 +2714,7 @@ add_executable(dlsim_tm4 ) target_link_libraries (dlsim_tm4 -Wl,--start-group SIMU UTIL SCHED_LIB SCHED_RU_LIB PHY LFDS ${ITTI_LIB} -Wl,--end-group - pthread m rt ${CONFIG_LIBRARIES} ${ATLAS_LIBRARIES} ${T_LIB} + pthread m rt ${CONFIG_LIB} ${ATLAS_LIBRARIES} ${T_LIB} ) add_executable(polartest @@ -2568,10 +2746,13 @@ target_link_libraries(smallblocktest ) add_executable(ldpctest + ${PHY_NR_CODINGIF} ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c ${T_SOURCE} ${SHLIB_LOADER_SOURCES} ) +add_dependencies( ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) + target_link_libraries(ldpctest -Wl,--start-group UTIL SIMU PHY_NR PHY_COMMON PHY_NR_COMMON CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} dl @@ -2615,12 +2796,12 @@ target_link_libraries(nr_pucchsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} ${ITTI_LIB} dl ) -#PUCCH ---> Prashanth add_executable(nr_dlsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c ${OPENAIR_DIR}/common/utils/system.c ${OPENAIR_DIR}/common/utils/nr/nr_common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${UTIL_SRC} ${T_SOURCE} ${SHLIB_LOADER_SOURCES} @@ -2629,6 +2810,7 @@ target_link_libraries(nr_dlsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON RRC_LIB NR_RRC_LIB CONFIG_LIB L2_NR -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} ${ITTI_LIB} dl ) +target_compile_definitions(nr_dlsim PUBLIC -DPHYSICAL_SIMULATOR) add_executable(nr_prachsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c @@ -2657,6 +2839,7 @@ add_executable(nr_ulsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c ${OPENAIR_DIR}/common/utils/system.c ${OPENAIR_DIR}/common/utils/nr/nr_common.c + ${OPENAIR_DIR}/executables/softmodem-common.c ${UTIL_SRC} ${T_SOURCE} ${SHLIB_LOADER_SOURCES} @@ -2665,7 +2848,7 @@ target_link_libraries(nr_ulsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_COMMON PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON RRC_LIB NR_RRC_LIB CONFIG_LIB L2_NR -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} ${ITTI_LIB} dl ) - +target_compile_definitions(nr_ulsim PUBLIC -DPHYSICAL_SIMULATOR) foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim) @@ -2681,8 +2864,9 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr ) target_link_libraries (${myExe} -Wl,--start-group SIMU UTIL SCHED_LIB SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_NR_COMMON PHY PHY_UE PHY_RU LFDS ${ITTI_LIB} LFDS7 -Wl,--end-group - pthread m rt ${CONFIG_LIBRARIES} ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${T_LIB} dl + pthread m rt ${CONFIG_LIB} ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${T_LIB} dl ) + endforeach(myExe) add_executable(test_epc_generate_scenario @@ -2694,7 +2878,7 @@ add_executable(test_epc_generate_scenario ${OPENAIR3_DIR}/S1AP/s1ap_eNB_defs.h ) target_link_libraries (test_epc_generate_scenario - -Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB F1AP_LIB F1AP GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES} + -Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB F1AP_LIB F1AP GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT MME_APP UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIB} ) add_executable(test_epc_play_scenario @@ -2713,7 +2897,7 @@ add_executable(test_epc_play_scenario ) target_include_directories(test_epc_play_scenario PUBLIC /usr/local/share/asn1c) target_link_libraries (test_epc_play_scenario - -Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB X2AP_ENB F1AP_LIB F1AP GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY_COMMON PHY_NR_COMMON PHY PHY_UE LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES} + -Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB X2AP_ENB M3AP_LIB M3AP_ENB F1AP_LIB F1AP GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT MME_APP UDP SCHED_LIB PHY_NR_COMMON PHY_COMMON PHY PHY_UE LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIB} ) @@ -2733,7 +2917,7 @@ foreach(myExe s1ap ${OPENAIR3_DIR}/TEST/test_${myExe}.c ) target_link_libraries (test_${myExe} - -Wl,--start-group SECU_CN UTIL LFDS -Wl,--end-group m rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES} + -Wl,--start-group SECU_CN UTIL LFDS -Wl,--end-group m rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIB} ) endforeach(myExe) @@ -2751,16 +2935,16 @@ if (${T_TRACER}) syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim nr_ulschsim ldpctest polartest smallblocktest cu_test du_test #all "add_library" definitions - - ITTI RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB F1AP_LIB - F1AP params_libconfig oai_exmimodevif oai_usrpdevif oai_bladerfdevif - oai_lmssdrdevif oai_eth_transpro oai_mobipass tcp_bridge tcp_bridge_oai - coding FLPT_MSG ASYNC_IF FLEXRAN_AGENT HASHTABLE MSC UTIL OMG_SUMO - SECU_OSA SECU_CN SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB - SCHED_NR_UE_LIB NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB - NFAPI_USER_LIB PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX - L2 L2_LTE L2_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_NR MAC_UE_NR CN_UTILS GTPV1U - SCTP_CLIENT UDP LIB_NAS_UE NB_IoT LFDS LFDS7 SIMU SIMU_ETH OPENAIR0_LIB) + ITTI RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB F1AP_LIB F1AP + params_libconfig oai_exmimodevif oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif oai_iqplayer + oai_eth_transpro oai_mobipass tcp_bridge tcp_bridge_oai + coding FLPT_MSG ASYNC_IF FLEXRAN_AGENT HASHTABLE MSC UTIL OMG_SUMO + SECU_OSA SECU_CN SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB default_sched remote_sched RAL + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB + PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX + L2 L2_LTE L2_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_NR MAC_UE_NR + CN_UTILS GTPV1U SCTP_CLIENT MME_APP UDP LIB_NAS_UE NB_IoT LFDS LFDS7 SIMU SIMU_ETH OPENAIR0_LIB + ldpc_orig ldpc_optim ldpc_optim8seg ldpc) if (TARGET ${i}) add_dependencies(${i} generate_T) endif() diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 6795f2d1fa..b3954db1fd 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1045,7 +1045,7 @@ $OPENAIR_DIR/targets/bin/polartest.Rel15 -q -s-10 -f0 -q -s-10 -f0 -m1 - polartest.test1 + polartest.test1 polartest.test2 BLER= 0.000000 segmentation fault|assertion|exiting|fatal 3 @@ -1082,33 +1082,31 @@ nr_dlsim Test cases. (Test1: 106 PRB), (Test2: 217 PRB), (Test3: 273 PRB), - (Test4: 106 PRB 12 CSET-Offset), - (Test5: 217 PRB 48 CSET-Offset), - (Test6: 106 PRB 25 PDSCH-Offset), - (Test7: 106 PRB 51 PDSCH-Offset), - (Test8: 217 PRB 100 PDSCH-PRBs), - (Test9: 217 PRB 80 PDSCH-Offset), - (Test10: 217 PRB 100 PDSCH-PRBs 110 PDSCH-Offset), - (Test11: 106 PRBs 50 PDSCH-PRBs MCS Index 28 + (Test4: 106 PRB 25 PDSCH-Offset), + (Test5: 106 PRB 51 PDSCH-Offset), + (Test6: 217 PRB 100 PDSCH-PRBs), + (Test7: 217 PRB 80 PDSCH-Offset), + (Test8: 217 PRB 100 PDSCH-PRBs 110 PDSCH-Offset), + (Test9: 106 PRBs 50 PDSCH-PRBs MCS Index 27) + (Test10: 106 PRBs 50 PDSCH-PRBs MCS Index 16) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/targets/bin/nr_dlsim.Rel15 - -n100 -R106 -b106 - -n100 -R217 -b217 - -n100 -R273 -b273 - -n100 -R106 -o12 - -n100 -R217 -o48 - -n100 -R106 -a25 - -n100 -R106 -a51 - -n100 -R217 -b100 - -n100 -R217 -a80 - -n100 -R217 -a110 -b100 - -n100 -e28 - nr_dlsim.test1 nr_dlsim.test2 nr_dlsim.test3 nr_dlsim.test4 nr_dlsim.test5 nr_dlsim.test6 nr_dlsim.test7 - nr_dlsim.test8 nr_dlsim.test9 nr_dlsim.test10 nr_dlsim.test11 + -n100 -R106 -b106 -s5 + -n100 -R217 -b217 -s5 + -n100 -R273 -b273 -s5 + -n100 -R106 -a25 -s5 + -n100 -R106 -a51 -s5 + -n100 -R217 -b100 -s5 + -n100 -R217 -a80 -s5 + -n100 -R217 -a110 -s5 -b100 + -n100 -e27 -s30 + -n100 -e16 -s10 + + nr_dlsim.test1 nr_dlsim.test2 nr_dlsim.test3 nr_dlsim.test4 nr_dlsim.test5 nr_dlsim.test6 nr_dlsim.test7 nr_dlsim.test8 nr_dlsim.test9 nr_dlsim.test10 PDSCH test OK segmentation fault|assertion|exiting|fatal 3 @@ -1250,11 +1248,11 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/targets/bin/nr_ulsim.Rel15 - -f100 -m9 -r106 -s10 - -f100 -m16 -s20 - -f100 -m28 -s30 - -f100 -m9 -R217 -r217 -s10 - -f100 -m9 -R273 -r273 -s10 + -n100 -m9 -r106 -s0 + -n100 -m16 -s10 + -n100 -m28 -s20 + -n100 -m9 -R217 -r217 -s0 + -n100 -m9 -R273 -r273 -s0 nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 PUSCH test OK segmentation fault|assertion|exiting|fatal diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 677095d43a..965dfaea3a 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -40,6 +40,7 @@ conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf MSC_GEN=0 XFORMS="True" +SKIP_SHARED_LIB_FLAG="False" UE_EXPANSION="False" UESIM_EXPANSION="False" PRINT_STATS="False" @@ -88,8 +89,11 @@ Options -i | --install-system-files Install OpenAirInterface required files in Linux system This option will require root password --g | --run-with-gdb - Add debugging symbols to compilation directives. It also disables any compiler optimization. Only for debugging. Do not use in normal operation! +-g | --run-with-gdb Build optional shared library, can be one or several of $OPTIONAL_LIBRARIES or \"all\" --usrp-recplay Build for I/Q record-playback modes +-k | --skip-shared-libraries + Skip build for shared libraries to reduce compilation time when building frequently for debugging purposes -h | --help Print this help @@ -191,10 +197,41 @@ function main() { echo_info "Will copy OpenAirInterface files in Linux directories" shift;; -g | --run-with-gdb) - GDB=1 - CMAKE_BUILD_TYPE="Debug" - echo_info "Will Compile with gdb symbols and disable compiler optimization" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug --trace-expand" + case "$2" in + "Release") + GDB=0 + CMAKE_BUILD_TYPE="Release" + echo_info "Will Compile without gdb symbols and with compiler optimization" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Release" + shift + ;; + "RelWithDebInfo") + GDB=0 + CMAKE_BUILD_TYPE="RelWithDebInfo" + echo_info "Will Compile with gdb symbols" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo" + shift + ;; + "MinSizeRel") + GDB=0 + CMAKE_BUILD_TYPE="MinSizeRel" + echo_info "Will Compile for minimal exec size" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=MinSizeRel" + shift + ;; + "Debug" | *) + GDB=1 + CMAKE_BUILD_TYPE="Debug" + echo_info "Will Compile with gdb symbols and disable compiler optimization" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug" + if [ "$2" == "Debug" ] ; then + shift + fi + ;; + esac + shift;; + -G | --cmaketrace) + CMAKE_CMD="$CMAKE_CMD --trace-expand" shift;; --eNB) eNB=1 @@ -367,6 +404,10 @@ function main() { USRP_REC_PLAY="True" echo_info "Enabling USRP record playback mode" shift 1;; + -k | --skip-shared-libraries) + SKIP_SHARED_LIB_FLAG="True" + echo_info "Skipping build of shared libraries, rfsimulator, basicsimulator and transport protocol libraries" + shift;; -h | --help) print_help exit 1;; @@ -513,22 +554,17 @@ function main() { echo_info "3. building the compilation directives ..." DIR=$OPENAIR_DIR/cmake_targets - - if [ "$T_TRACER" = "False" ] ; then - build_dir=ran_build_noLOG + if [ "$SIMUS_PHY" = "1" -o "$SIMUS_CORE" = "1" ] ; then + build_dir=phy_simulators else + if [ "$T_TRACER" = "False" ] ; then + build_dir=ran_build_noLOG + else build_dir=ran_build + fi fi - - if [ "$gNB" = "1" ] ; then - exec=nr-softmodem - elif [ "$nrUE" = "1" ] ; then - exec=nr-uesoftmodem - elif [ "$eNB" = "1" ] ; then - exec=lte-softmodem - elif [ "$UE" = "1" ] ; then - exec=lte-uesoftmodem - fi + [ "$CLEAN" = "1" ] && rm -rf $DIR/$build_dir/build + mkdir -p $DIR/$build_dir/build # configuration module libraries, one currently available, using libconfig config_libconfig_shlib=params_libconfig @@ -537,8 +573,7 @@ function main() { if [ "$eNB" = "1" -o "$UE" = "1" -o "$gNB" = "1" -o "$nrUE" = "1" -o "$HW" = "EXMIMO" ] ; then # softmodem compilation - [ "$CLEAN" = "1" ] && rm -rf $DIR/$build_dir/build - mkdir -p $DIR/$build_dir/build + cmake_file=$DIR/$build_dir/CMakeLists.txt echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file @@ -558,55 +593,60 @@ function main() { echo "set ( UE_DEBUG_TRACE $UE_DEBUG_TRACE )" >> $cmake_file echo "set ( UE_TIMING_TRACE $UE_TIMING_TRACE )" >> $cmake_file echo "set ( USRP_REC_PLAY $USRP_REC_PLAY )" >> $cmake_file + echo "set ( SKIP_SHARED_LIB_FLAG $SKIP_SHARED_LIB_FLAG )" >> $cmake_file echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file cd $DIR/$build_dir/build eval $CMAKE_CMD - fi - if [ "$eNB" = "1" -o "$UE" = "1" -o "$gNB" = "1" -o "$nrUE" = "1" ] ; then - echo_info "Compiling $exec" - compilations \ - $build_dir $exec \ - $exec $dbin/$exec.$REL - -# if --eNB --UE are both provided together as build options - if [ "$eNB" = "1" -a "$UE" = "1" ] ; then - echo_info "Compiling lte-uesoftmodem" - compilations \ - $build_dir lte-uesoftmodem \ - lte-uesoftmodem $dbin/lte-uesoftmodem.$REL - fi - -# if --gNB --nrUE are both provided together as build options - if [ "$gNB" = "1" -a "$nrUE" = "1" ] ; then - echo_info "Compiling nr-uesoftmodem" - compilations \ - $build_dir nr-uesoftmodem \ - nr-uesoftmodem $dbin/nr-uesoftmodem.$REL - fi + execlist="" + if [ "$eNB" = "1" ] ; then + execlist="$execlist lte-softmodem" + fi + if [ "$gNB" = "1" ] ; then + execlist="$execlist nr-softmodem" + fi + if [ "$UE" = 1 ] ; then + execlist="$execlist lte-uesoftmodem" + fi + if [ "$nrUE" = 1 ] ; then + execlist="$execlist nr-uesoftmodem" + fi + + for f in $execlist ; do + echo_info "Compiling $f..." + compilations \ + $build_dir $f \ + $f $dbin/$f.$REL + done + # mandatory shared libraries common to UE and (e/g)NB - compilations \ - $build_dir $config_libconfig_shlib \ - lib$config_libconfig_shlib.so $dbin/lib$config_libconfig_shlib.so + if [ "$SKIP_SHARED_LIB_FLAG" = "False" ]; then + echo_info "Building shared libraries common to UE and gNB" - compilations \ - $build_dir coding \ - libcoding.so $dbin/libcoding.so + compilations \ + $build_dir $config_libconfig_shlib \ + lib$config_libconfig_shlib.so $dbin/lib$config_libconfig_shlib.so - compilations \ - $build_dir nasmesh \ - CMakeFiles/nasmesh/nasmesh.ko $dbin/nasmesh.ko + compilations \ + $build_dir coding \ + libcoding.so $dbin/libcoding.so - compilations \ - $build_dir rb_tool \ - rb_tool $dbin/rb_tool + compilations \ + $build_dir nasmesh \ + CMakeFiles/nasmesh/nasmesh.ko $dbin/nasmesh.ko + + compilations \ + $build_dir rb_tool \ + rb_tool $dbin/rb_tool cp $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 $dbin + fi + fi - + if [ "$UE" = 1 ] ; then - # ue_ip driver compilation + echo_info "Compiling UE specific part" compilations \ $build_dir ue_ip \ @@ -618,11 +658,11 @@ function main() { # compilations \ # at_commands at_nas_ue \ # at_nas_ue $dbin/at_nas_ue - + [ "$CLEAN" = "1" ] && rm -rf $DIR/nas_sim_tools/build mkdir -p $DIR/nas_sim_tools/build cd $DIR/nas_sim_tools/build - + eval $CMAKE_CMD compilations \ nas_sim_tools usim \ @@ -647,11 +687,7 @@ function main() { fi if [ "$SIMUS_PHY" = "1" -o "$SIMUS_CORE" = "1" ] ; then - cd $OPENAIR_DIR/cmake_targets/phy_simulators - [ "$CLEAN" = "1" ] && rm -rf build - mkdir -p build - cd build - rm -f *sim + cd $DIR/$build_dir/build eval $CMAKE_CMD fi @@ -789,18 +825,18 @@ function main() { # link liboai_device.so with the selected RF device library if [ "$HW" == "EXMIMO" ] ; then - compilations \ + compilations \ $build_dir oai_exmimodevif \ - liboai_exmimodevif.so $dbin/liboai_exmimodevif.so.$REL + liboai_exmimodevif.so $dbin/liboai_exmimodevif.so.$REL - ln -sf liboai_exmimodevif.so liboai_device.so - ln -sf $dbin/liboai_exmimodevif.so.$REL $dbin/liboai_device.so - echo_info "liboai_device.so is linked to EXMIMO device library" - elif [ "$HW" == "OAI_USRP" ] ; then + ln -sf liboai_exmimodevif.so liboai_device.so + ln -sf $dbin/liboai_exmimodevif.so.$REL $dbin/liboai_device.so + echo_info "liboai_device.so is linked to EXMIMO device library" + elif [ "$HW" == "OAI_USRP" ] ; then compilations \ $build_dir oai_usrpdevif \ liboai_usrpdevif.so $dbin/liboai_usrpdevif.so.$REL - + ln -sf liboai_usrpdevif.so liboai_device.so ln -sf $dbin/liboai_usrpdevif.so.$REL $dbin/liboai_device.so echo_info "liboai_device.so is linked to USRP device library" @@ -844,31 +880,36 @@ function main() { echo_error "== FAILED == Unexpected Kernel $SYRIQ_KMAJ.$SYRIQ_KMIN" fi echo_info "liboai_device.so is linked to ADRV9371_ZC706 device library for Kernel $SYRIQ_KMAJ.$SYRIQ_KMIN" - else - echo_info "liboai_device.so is not linked to any device library" - fi + else + echo_info "liboai_device.so is not linked to any device library" + fi fi - + #build simulators devices - echo_info "Compiling rfsimulator" - compilations \ - $build_dir rfsimulator \ - librfsimulator.so $dbin/librfsimulator.so.$REL - - echo_info "Compiling basicsimulator" - compilations \ - $build_dir tcp_bridge_oai \ - libtcp_bridge_oai.so $dbin/libtcp_bridge_oai.so.$REL + if [ "$SKIP_SHARED_LIB_FLAG" = "False" ]; then + echo_info "Compiling rfsimulator" + compilations \ + $build_dir rfsimulator \ + librfsimulator.so $dbin/librfsimulator.so.$REL + + echo_info "Compiling basicsimulator" + compilations \ + $build_dir tcp_bridge_oai \ + libtcp_bridge_oai.so $dbin/libtcp_bridge_oai.so.$REL + fi #build transport protocol libraries (currently only ETHERNET is available) - rm -f liboai_transpro.so - rm -f $dbin/liboai_transpro.so - compilations \ - $build_dir oai_eth_transpro \ - liboai_eth_transpro.so $dbin/liboai_eth_transpro.so.$REL - ln -sf liboai_eth_transpro.so liboai_transpro.so - ln -sf $dbin/liboai_eth_transpro.so.$REL $dbin/liboai_transpro.so - echo_info "liboai_transpro.so is linked to ETHERNET transport" + if [ "$SKIP_SHARED_LIB_FLAG" = "False" ]; then + echo_info "Building transport protocol libraries" + rm -f liboai_transpro.so + rm -f $dbin/liboai_transpro.so + compilations \ + $build_dir oai_eth_transpro \ + liboai_eth_transpro.so $dbin/liboai_eth_transpro.so.$REL + ln -sf liboai_eth_transpro.so liboai_transpro.so + ln -sf $dbin/liboai_eth_transpro.so.$REL $dbin/liboai_transpro.so + echo_info "liboai_transpro.so is linked to ETHERNET transport" + fi fi ################### diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 99a2e3f589..818b1fd79c 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -102,7 +102,7 @@ check_supported_distribution() { "ubuntu14.04") return 0 ;; "fedora24") return 0 ;; "rhel7") return 0 ;; - "rhel7.6") return 0 ;; + "rhel7.6") return 0 ;; "rhel7.7") return 0 ;; "centos7") return 0 ;; esac @@ -296,8 +296,8 @@ check_install_usrp_uhd_driver(){ x=$((x + 1)) done $SUDO apt-get update - $SUDO apt-get -y --allow-unauthenticated install python python-tk libboost-all-dev libusb-1.0-0-dev - $SUDO apt-get -y --allow-unauthenticated install libuhd-dev libuhd003 uhd-host + $SUDO apt-get -y install python python-tk libboost-all-dev libusb-1.0-0-dev + $SUDO apt-get -y install libuhd-dev libuhd003 uhd-host elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then $SUDO $INSTALLER -y install python boost libusb-devel libusbx-devel boost-devel python-mako python-docutils cmake $SUDO -H pip install requests @@ -320,13 +320,13 @@ install_usrp_uhd_driver() { # quick workaround for RHE7.6 local distribution=$(get_distribution_release) if [ -z $1 ]; then - if [[ "$distribution" == "rhel7.6" ]]; then + if [[ "$OS_DISTRO" == "rhel" ]]; then $SUDO /usr/local/bin/uhd_images_downloader else $SUDO uhd_images_downloader fi else - if [[ "$distribution" == "rhel7.6" ]]; then + if [[ "$OS_DISTRO" == "rhel" ]]; then $SUDO /usr/local/bin/uhd_images_downloader -i $1 else $SUDO uhd_images_downloader -i $1 @@ -367,9 +367,9 @@ check_install_bladerf_driver(){ $SUDO add-apt-repository -y ppa:bladerf/bladerf $SUDO apt-get update fi - $SUDO apt-get install -y --allow-unauthenticated bladerf libbladerf-dev - $SUDO apt-get install -y --allow-unauthenticated bladerf-firmware-fx3 - $SUDO apt-get install -y --allow-unauthenticated bladerf-fpga-hostedx40 + $SUDO apt-get install -y bladerf libbladerf-dev + $SUDO apt-get install -y bladerf-firmware-fx3 + $SUDO apt-get install -y bladerf-fpga-hostedx40 elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then install_bladerf_driver_from_source else diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index fcee9c3238..61a3984347 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -158,7 +158,7 @@ int config_cmdlineonly_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) break; default: - fprintf(stderr,"[CONFIG] %s.%s type %i not supported\n",prefix, cfgoptions[i].optname,cfgoptions[i].type); + fprintf(stderr,"[CONFIG] %s.%s type %i not supported\n",prefix, cfgoptions[i].optname,cfgoptions[i].type); fatalerror=1; break; } /* switch on param type */ @@ -214,7 +214,7 @@ configmodule_interface_t *load_configmodule(int argc, } } - /* look for the OAI_CONFIGMODULE environement variable */ + /* look for the OAI_CONFIGMODULE environment variable */ if ( cfgparam == NULL ) { cfgparam = getenv("OAI_CONFIGMODULE"); } @@ -265,8 +265,8 @@ configmodule_interface_t *load_configmodule(int argc, atoken=strtok_r(modeparams,":",&strtokctx); while ( cfgptr->num_cfgP< CONFIG_MAX_OOPT_PARAMS && atoken != NULL) { - /* look for debug level in the config parameters, it is commom to all config mode - and will be removed frome the parameter array passed to the shared module */ + /* look for debug level in the config parameters, it is common to all config mode + and will be removed from the parameter array passed to the shared module */ char *aptr; aptr=strcasestr(atoken,"dbgl"); diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index 67fdc2c920..33d6408828 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -45,7 +45,8 @@ configmodule_interface_t *config_get_if(void) { if (cfgptr == NULL) { - CONFIG_PRINTF_ERROR("[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__); + if (isLogInitDone()) + LOG_W(ENB_APP,"[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__); } return cfgptr; @@ -223,7 +224,6 @@ int config_get(paramdef_t *params, int numparams, char *prefix) { } configmodule_interface_t *cfgif = config_get_if(); - if (cfgif != NULL) { ret = config_get_if()->get(params, numparams, prefix); diff --git a/common/ngran_types.h b/common/ngran_types.h index 224a85def5..3dfa7aa01a 100644 --- a/common/ngran_types.h +++ b/common/ngran_types.h @@ -41,11 +41,13 @@ typedef enum { ngran_ng_eNB_CU = 4, ngran_gNB_CU = 5, ngran_eNB_DU = 6, - ngran_gNB_DU = 7 + ngran_gNB_DU = 7, + ngran_eNB_MBMS_STA = 8 } ngran_node_t; #define NODE_IS_MONOLITHIC(nOdE_TyPe) ((nOdE_TyPe) == ngran_eNB || (nOdE_TyPe) == ngran_ng_eNB || (nOdE_TyPe) == ngran_gNB) #define NODE_IS_CU(nOdE_TyPe) ((nOdE_TyPe) == ngran_eNB_CU || (nOdE_TyPe) == ngran_ng_eNB_CU || (nOdE_TyPe) == ngran_gNB_CU) #define NODE_IS_DU(nOdE_TyPe) ((nOdE_TyPe) == ngran_eNB_DU || (nOdE_TyPe) == ngran_gNB_DU) +#define NODE_IS_MBMS(nOdE_TyPe) ((nOdE_TyPe) == ngran_eNB_MBMS_STA) #endif diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index 7f177b90ce..f6d57bd791 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -418,9 +418,12 @@ int logInit (void) register_log_component("eRAL","",RAL_ENB); register_log_component("mRAL","",RAL_UE); register_log_component("ENB_APP","log",ENB_APP); + register_log_component("MCE_APP","log",MCE_APP); + register_log_component("MME_APP","log",MME_APP); register_log_component("FLEXRAN_AGENT","log",FLEXRAN_AGENT); register_log_component("PROTO_AGENT","log",PROTO_AGENT); register_log_component("TMR","",TMR); + register_log_component("EMU","log",EMU); register_log_component("USIM","txt",USIM); register_log_component("SIM","txt",SIM); /* following log component are used for the localization*/ @@ -430,6 +433,8 @@ int logInit (void) register_log_component("GTPV1U","",GTPU); register_log_component("S1AP","",S1AP); register_log_component("F1AP","",F1AP); + register_log_component("M2AP","",M2AP); + register_log_component("M3AP","",M3AP); register_log_component("SCTP","",SCTP); register_log_component("X2AP","",X2AP); register_log_component("LOADER","log",LOADER); diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index 111f2c58ce..8e74f4148c 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -215,6 +215,8 @@ typedef enum { RAL_ENB, RAL_UE, ENB_APP, + MCE_APP, + MME_APP, FLEXRAN_AGENT, TMR, USIM, @@ -222,6 +224,8 @@ typedef enum { PROTO_AGENT, F1U, X2AP, + M2AP, + M3AP, GNB_APP, NR_RRC, NR_MAC, @@ -270,16 +274,6 @@ typedef struct { } log_t; -#if defined(ENABLE_ITTI) -typedef enum log_instance_type_e { - LOG_INSTANCE_UNKNOWN, - LOG_INSTANCE_ENB, - LOG_INSTANCE_UE, -} log_instance_type_t; - -void log_set_instance_type (log_instance_type_t instance); -#endif - #ifdef LOG_MAIN log_t *g_log; @@ -363,7 +357,7 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* LOG globalconfiguration parameters */ +/* LOG global configuration parameters */ /* optname help paramflags XXXptr defXXXval type numelt */ /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ #define LOG_GLOBALPARAMS_DESC { \ @@ -385,7 +379,7 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int // debugging macros #define LOG_F LOG_I /* because LOG_F was originaly to dump a message or buffer but is also used as a regular level...., to dump use LOG_DUMPMSG */ # if T_TRACER -/* per component, level dependant macros */ +/* per component, level dependent macros */ # define LOG_E(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_ERR ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_ERR, x) ;} else { T(T_LEGACY_ ## c ## _ERROR, T_PRINTF(x)) ;}} while (0) # define LOG_W(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_WARNING) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_WARNING, x) ;} else { T(T_LEGACY_ ## c ## _WARNING, T_PRINTF(x)) ;}} while (0) # define LOG_I(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_INFO ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ;} else { T(T_LEGACY_ ## c ## _INFO, T_PRINTF(x)) ;}} while (0) @@ -394,10 +388,10 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int # define VLOG(c,l, f, args) do { if (T_stdout) { if( g_log->log_component[c].level >= l ) vlogRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, l, f, args) ;} } while (0) /* macro used to dump a buffer or a message as in openair2/RRC/LTE/RRC_eNB.c, replaces LOG_F macro */ # define LOG_DUMPMSG(c, f, b, s, x...) do { if(g_log->dump_mask & f) log_dump(c, b, s, LOG_DUMP_CHAR, x) ;} while (0) /* */ -/* bitmask dependant macros, to isolate debugging code */ +/* bitmask dependent macros, to isolate debugging code */ # define LOG_DEBUGFLAG(D) (g_log->debug_mask & D) -/* bitmask dependant macros, to generate debug file such as matlab file or message dump */ +/* bitmask dependent macros, to generate debug file such as matlab file or message dump */ # define LOG_DUMPFLAG(D) (g_log->dump_mask & D) # define LOG_M(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)/* */ /* define variable only used in LOG macro's */ @@ -420,7 +414,7 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int #define GCC_NOTUSED __attribute__((unused)) #define LOG_USEDINLOG_VAR(A,B) GCC_NOTUSED A B -/* unfiltered macros, usefull for simulators or messages at init time, before log is configured */ +/* unfiltered macros, useful for simulators or messages at init time, before log is configured */ #define LOG_UM(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0) #define LOG_UI(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ; } while(0) #define LOG_UDUMPMSG(c, b, s, f, x...) do { log_dump(c, b, s, f, x) ;} while (0) /* */ diff --git a/common/utils/LOG/vcd_signal_dumper.c b/common/utils/LOG/vcd_signal_dumper.c index 3597add1b5..0043eb3238 100644 --- a/common/utils/LOG/vcd_signal_dumper.c +++ b/common/utils/LOG/vcd_signal_dumper.c @@ -470,6 +470,8 @@ const char* eurecomFunctionsNames[] = { "pdcp_fifo_read_buffer", "pdcp_fifo_flush", "pdcp_fifo_flush_buffer", + "pdcp_mbms_fifo_read", + "pdcp_mbms_fifo_read_buffer", /* RRC signals */ "rrc_rx_tx", "rrc_mac_config_req", @@ -632,9 +634,6 @@ inline static uint32_t vcd_get_write_index(void) return write_index; } -#if defined(ENABLE_ITTI) -int signal_mask(void); -#endif void *vcd_dumper_thread_rt(void *args) { @@ -643,9 +642,7 @@ void *vcd_dumper_thread_rt(void *args) struct sched_param sched_param; uint32_t data_ready_wait; -# if defined(ENABLE_ITTI) return 0; //signal_mask(); //function defined at common/utils/ocp_itti/intertask_interface.cpp -# endif sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1; sched_setscheduler(0, SCHED_FIFO, &sched_param); diff --git a/common/utils/LOG/vcd_signal_dumper.h b/common/utils/LOG/vcd_signal_dumper.h index b9cc0e4742..20588bb828 100644 --- a/common/utils/LOG/vcd_signal_dumper.h +++ b/common/utils/LOG/vcd_signal_dumper.h @@ -454,6 +454,8 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ_BUFFER, VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_FLUSH, VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_FLUSH_BUFFER, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_MBMS_FIFO_READ, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_MBMS_FIFO_READ_BUFFER, /* RRC signals */ VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX, diff --git a/common/utils/T/T_defs.h b/common/utils/T/T_defs.h index 344344710a..4cb4bf2bba 100644 --- a/common/utils/T/T_defs.h +++ b/common/utils/T/T_defs.h @@ -73,7 +73,7 @@ typedef struct { } T_cache_t; /* number of VCD functions (to be kept up to date! see in T_messages.txt) */ -#define VCD_NUM_FUNCTIONS (246) +#define VCD_NUM_FUNCTIONS (248) /* number of VCD variables (to be kept up to date! see in T_messages.txt) */ #define VCD_NUM_VARIABLES (186) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index f9d92cc418..f8b746669c 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -405,6 +405,48 @@ ID = LEGACY_X2AP_TRACE GROUP = ALL:LEGACY_X2AP:LEGACY_GROUP_TRACE:LEGACY FORMAT = string,log +ID = LEGACY_M2AP_INFO + DESC = M2AP legacy logs - info level + GROUP = ALL:LEGACY_M2AP:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_M2AP_ERROR + DESC = M2AP legacy logs - error level + GROUP = ALL:LEGACY_M2AP:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_M2AP_WARNING + DESC = M2AP legacy logs - warning level + GROUP = ALL:LEGACY_M2AP:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_M2AP_DEBUG + DESC = M2AP legacy logs - debug level + GROUP = ALL:LEGACY_M2AP:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_M2AP_TRACE + DESC = M2AP legacy logs - trace level + GROUP = ALL:LEGACY_M2AP:LEGACY_GROUP_TRACE:LEGACY + FORMAT = string,log + +ID = LEGACY_M3AP_INFO + DESC = M3AP legacy logs - info level + GROUP = ALL:LEGACY_M3AP:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_M3AP_ERROR + DESC = M3AP legacy logs - error level + GROUP = ALL:LEGACY_M3AP:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_M3AP_WARNING + DESC = M3AP legacy logs - warning level + GROUP = ALL:LEGACY_M3AP:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_M3AP_DEBUG + DESC = M3AP legacy logs - debug level + GROUP = ALL:LEGACY_M3AP:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_M3AP_TRACE + DESC = M3AP legacy logs - trace level + GROUP = ALL:LEGACY_M3AP:LEGACY_GROUP_TRACE:LEGACY + FORMAT = string,log + ID = LEGACY_RRC_INFO DESC = RRC legacy logs - info level GROUP = ALL:LEGACY_RRC:LEGACY_GROUP_INFO:LEGACY @@ -529,6 +571,47 @@ ID = LEGACY_GNB_APP_DEBUG ID = LEGACY_GNB_APP_TRACE DESC = GNB_APP legacy logs - trace level GROUP = ALL:LEGACY_GNB_APP:LEGACY_GROUP_TRACE:LEGACY + +ID = LEGACY_MCE_APP_INFO + DESC = MCE_APP legacy logs - info level + GROUP = ALL:LEGACY_MCE_APP:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_MCE_APP_ERROR + DESC = MCE_APP legacy logs - error level + GROUP = ALL:LEGACY_MCE_APP:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_MCE_APP_WARNING + DESC = MCE_APP legacy logs - warning level + GROUP = ALL:LEGACY_MCE_APP:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_MCE_APP_DEBUG + DESC = MCE_APP legacy logs - debug level + GROUP = ALL:LEGACY_MCE_APP:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_MCE_APP_TRACE + DESC = MCE_APP legacy logs - trace level + GROUP = ALL:LEGACY_MCE_APP:LEGACY_GROUP_TRACE:LEGACY + FORMAT = string,log + +ID = LEGACY_MME_APP_INFO + DESC = MME_APP legacy logs - info level + GROUP = ALL:LEGACY_MME_APP:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_MME_APP_ERROR + DESC = MME_APP legacy logs - error level + GROUP = ALL:LEGACY_MME_APP:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_MME_APP_WARNING + DESC = MME_APP legacy logs - warning level + GROUP = ALL:LEGACY_MME_APP:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_MME_APP_DEBUG + DESC = MME_APP legacy logs - debug level + GROUP = ALL:LEGACY_MME_APP:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_MME_APP_TRACE + DESC = MME_APP legacy logs - trace level + GROUP = ALL:LEGACY_MME_APP:LEGACY_GROUP_TRACE:LEGACY FORMAT = string,log ID = LEGACY_FLEXRAN_AGENT_INFO @@ -3098,6 +3181,16 @@ ID = VCD_FUNCTION_PDCP_FIFO_FLUSH_BUFFER GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value VCD_NAME = pdcp_fifo_flush_buffer +ID = VCD_FUNCTION_PDCP_MBMS_FIFO_READ + DESC = VCD function PDCP_MBMS_FIFO_READ + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value + VCD_NAME = pdcp_mbms_fifo_read +ID = VCD_FUNCTION_PDCP_MBMS_FIFO_READ_BUFFER + DESC = VCD function PDCP_MBMS_FIFO_READ_BUFFER + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value + VCD_NAME = pdcp_mbms_fifo_read_buffer ID = VCD_FUNCTION_RRC_RX_TX DESC = VCD function RRC_RX_TX GROUP = ALL:VCD:ENB:VCD_FUNCTION diff --git a/common/utils/T/local_tracer.c b/common/utils/T/local_tracer.c index 4be0b35d16..539e72b223 100644 --- a/common/utils/T/local_tracer.c +++ b/common/utils/T/local_tracer.c @@ -358,23 +358,21 @@ static void forward(void *_forwarder, char *buf, int size) { f->tail = new; #if BASIC_SIMULATOR - /* When runnng the basic simulator, the tracer may be too slow. * Let's not take too much memory in the tracee and * wait if there is too much data to send. 200MB is * arbitrary. */ - while (f->memusage > 200 * 1024 * 1024) { - if (pthread_cond_signal(&f->cond)) abort(); + while (f->memusage > 200 * 1024 * 1024) { + if (pthread_cond_signal(&f->cond)) abort(); - if (pthread_mutex_unlock(&f->lock)) abort(); + if (pthread_mutex_unlock(&f->lock)) abort(); - usleep(1000); + usleep(1000); - if (pthread_mutex_lock(&f->lock)) abort(); - } - -#endif /* BASIC_SIMULATOR */ + if (pthread_mutex_lock(&f->lock)) abort(); + } +#endif f->memusage += size+4; /* warn every 100MB */ diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index cdbf59cd76..8a236c49f9 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -37,7 +37,8 @@ int NRRIV2BW(int locationAndBandwidth,int N_RB) { int tmp = locationAndBandwidth/N_RB; int tmp2 = locationAndBandwidth%N_RB; - if (tmp <= ((N_RB>>1)-tmp2+1)) return(tmp+1); + + if (tmp <= ((N_RB>>1)+1) && (tmp+tmp2)>1)-tmp2+1)) return(tmp2); + + + if (tmp <= ((N_RB>>1)+1) && (tmp+tmp2)0 && (NPRB + RBstart <= BWPsize),"Illegal NPRB/RBstart Configuration (%d,%d)\n",NPRB,RBstart); + AssertFatal(NPRB>0 && (NPRB + RBstart <= BWPsize),"Illegal NPRB/RBstart Configuration (%d,%d) for BWPsize %d\n",NPRB,RBstart,BWPsize); + if (NPRB <= 1+(BWPsize>>1)) return(BWPsize*(NPRB-1)+RBstart); else return(BWPsize*(BWPsize+1-NPRB) + (BWPsize-1-RBstart)); } diff --git a/common/utils/ocp_itti/all_msg.h b/common/utils/ocp_itti/all_msg.h index bbbe576e1b..a2add514e1 100644 --- a/common/utils/ocp_itti/all_msg.h +++ b/common/utils/ocp_itti/all_msg.h @@ -9,6 +9,8 @@ #endif #include "openair2/COMMON/s1ap_messages_def.h" #include "openair2/COMMON/x2ap_messages_def.h" +#include "openair2/COMMON/m2ap_messages_def.h" +#include "openair2/COMMON/m3ap_messages_def.h" #include "openair2/COMMON/sctp_messages_def.h" #include "openair2/COMMON/udp_messages_def.h" #include "openair2/COMMON/gtpv1_u_messages_def.h" diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index 80493dc816..52c733752d 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -1,6 +1,6 @@ /* Author: Laurent THOMAS, Open Cells - Copyleft: OpenAirInterface software alliance and it's licence + Copyleft: OpenAirInterface software alliance and it's license */ #ifndef INTERTASK_INTERFACE_H_ #define INTERTASK_INTERFACE_H_ @@ -206,6 +206,8 @@ typedef struct IttiMsgText_s { #endif #include #include +#include +#include #include #include #include @@ -231,6 +233,7 @@ typedef struct IttiMsgText_s { #include #include #include +#include //#include #include @@ -290,9 +293,16 @@ typedef struct { TASK_DEF(TASK_RAL_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_X2AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_M2AP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_M2AP_MCE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_M3AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_M3AP_MME, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_M3AP_MCE, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_SCTP, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_ENB_APP, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_GNB_APP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_MCE_APP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_MME_APP, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_FLEXRAN_AGENT,TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_PHY_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_MAC_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ diff --git a/common/utils/system.c b/common/utils/system.c index 31c1035129..3a8fe7be3d 100644 --- a/common/utils/system.c +++ b/common/utils/system.c @@ -229,7 +229,7 @@ void configure_linux(void) { if ( (latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR)) != -1 ) { ret = write(latency_target_fd, &latency_target_value, sizeof(latency_target_value)); if (ret == 0) { - printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno)); + printf("# error setting cpu_dma_latency to %u!: %s\n", latency_target_value, strerror(errno)); close(latency_target_fd); latency_target_fd=-1; return; @@ -237,9 +237,9 @@ void configure_linux(void) { } } if (latency_target_fd != -1) - LOG_I(HW,"# /dev/cpu_dma_latency set to %dus\n", latency_target_value); + LOG_I(HW,"# /dev/cpu_dma_latency set to %u us\n", latency_target_value); else - LOG_E(HW,"Can't set /dev/cpu_dma_latency to %dus\n", latency_target_value); + LOG_E(HW,"Can't set /dev/cpu_dma_latency to %u us\n", latency_target_value); // Set CPU frequency to it's maximum if ( 0 != system("for d in /sys/devices/system/cpu/cpu[0-9]*; do cat $d/cpufreq/cpuinfo_max_freq > $d/cpufreq/scaling_min_freq; done")) diff --git a/common/utils/telnetsrv/DOC/telnetarch.md b/common/utils/telnetsrv/DOC/telnetarch.md index ebb2342c22..683b14a1b8 100644 --- a/common/utils/telnetsrv/DOC/telnetarch.md +++ b/common/utils/telnetsrv/DOC/telnetarch.md @@ -1,6 +1,15 @@ # telnet server principles -The oai telnet server is implemented in a shared library to be loaded by the [oai shared library loader](loader). The implementation includes a `telnetsrv_autoinit` function which is automatically called at load time, starts the telnet server and registers a first set of commands, which are delivered with the server (telnet, softmodem, loader). +The oai telnet server is implemented in shared libraries to be loaded by the [oai shared library loader](loader). `libtelnetsrv.so ` contains the code common to all oai softmodem executables, where `libtelnetsrv_.so` contains the code specific to the executable identified by `app`. + +| `` | executable | +| :-----: | :---------------: | +| enb | `lte-softmodem` | +| gnb | `nr-softmodem` | +| 4Gue | `lte-uesoftmodem` | +| 5Gue | `nr-uesoftmodem` | + +The implementation includes a `telnetsrv_autoinit` function which is automatically called at load time, starts the telnet server and registers a first set of commands, which are delivered with the server (telnet, softmodem, loader). it also uses the `get_softmodem_function` call to retrieve the running executable id and possibly loads the corresponding `libtelnetsrv_.so`library. Currently the telnet server only supports one user connection. The same dedicated thread is used to wait for a user connection and process the input received from this connection. @@ -12,10 +21,11 @@ The telnet server provides an API which can be used by any oai component to add telnet server source files are located in [common/utils/telnetsrv](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv) -1. [telnetsrv.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.c) contains the telnet server implementation, including the implementation of the telnet CLI command. +1. [telnetsrv.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.c) contains the telnet server implementation, including the implementation of the `telnet` CLI command. This implementation is compatible with all softmodem executables and is in charge of loading any additional `libtelnetsrv_ .so` containing code specific to the running executables. 1. [telnetsrv.h](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.h) is the telnet server include file containing both private and public data type definitions. It also contains API prototypes for functions that are used to register a new command in the server. -1. `telnetsrv\_\.c`: implementation of \ CLI command which are delivered with the telnet server. -1. `telnetsrv\_\.h`: include file for the implementation of XXX CLI command. Usually included only in the corresponding `.c`file +1. `telnetsrv_.c`: implementation of \ CLI command which are delivered with the telnet server and are common to all softmodem executables. +1. `telnetsrv_.h`: include file for the implementation of XXX CLI command. Usually included only in the corresponding `.c`file +1. `telnetsrv__.c`: implementation of \ CLI command specific to the executable identified by \.These sources are used to create `libtelnetsrv_.so` at build time. 1. [telnetsrv_CMakeLists.txt](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/telnetsrv/telnetsrv_CMakeLists.txt): CMakelists file containing the cmake instructions to build the telnet server. this file is included in the [global oai CMakelists](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/cmake_targets/CMakeLists.txt). [oai telnet server home](telnetsrv.md) diff --git a/common/utils/telnetsrv/DOC/telnetusage.md b/common/utils/telnetsrv/DOC/telnetusage.md index ec49deec73..c4777ce0d8 100644 --- a/common/utils/telnetsrv/DOC/telnetusage.md +++ b/common/utils/telnetsrv/DOC/telnetusage.md @@ -8,7 +8,7 @@ By default the embedded telnet server, which is implemented in a shared library, ./build_oai --build-lib telnetsrv ``` -This will create the `libtelnetsrv.so` file in the `targets/bin` and `cmake_targets/ran_build/build` sub directories of the oai repository. +This will create the `libtelnetsrv.so` and `libtelnetsrv_ file in the `targets/bin` and `cmake_targets/ran_build/build` sub directories of the oai repository. can be "enb", "gnb", "4GUE" or "5GUE", each library containing functions specific to a given executable. When starting the softmodem, you must specify the **_\-\-telnetsrv_** option to load and start the telnet server. The telnet server is loaded via the [oai shared library loader](loader). diff --git a/common/utils/telnetsrv/telnetsrv.c b/common/utils/telnetsrv/telnetsrv.c index 44ab07a49b..06a5d350c7 100644 --- a/common/utils/telnetsrv/telnetsrv.c +++ b/common/utils/telnetsrv/telnetsrv.c @@ -53,6 +53,7 @@ #include #include "common/utils/load_module_shlib.h" #include "common/config/config_userapi.h" +#include "executables/softmodem-common.h" #include @@ -376,6 +377,14 @@ int setgetvar(int moduleindex,char getorset,char *params) { client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; + case TELNET_VARTYPE_INT8: + client_printf("%i\n",(int)(*(int8_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr))); + break; + + case TELNET_VARTYPE_UINT: + client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); + break; + case TELNET_VARTYPE_DOUBLE: client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; @@ -404,7 +413,17 @@ int setgetvar(int moduleindex,char getorset,char *params) { *(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (short)strtol(varval,NULL,0); client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; - + + case TELNET_VARTYPE_INT8: + *(char *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (char)strtol(varval,NULL,0); + client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); + break; + + case TELNET_VARTYPE_UINT: + *(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (unsigned int)strtol(varval,NULL,0); + client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); + break; + case TELNET_VARTYPE_DOUBLE: *(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL); client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); @@ -546,6 +565,7 @@ void run_telnetsrv(void) { int readc, filled; int status; int optval = 1; + char prompt[sizeof(TELNET_PROMPT_PREFIX)+10]; pthread_setname_np(pthread_self(), "telnet"); set_sched(pthread_self(),0,telnetparams.priority); sock = socket(AF_INET, SOCK_STREAM, 0); @@ -570,6 +590,7 @@ void run_telnetsrv(void) { fprintf(stderr,"[TELNETSRV] Error %s on listen call\n",strerror(errno)); using_history(); + int plen=sprintf(prompt,"%s_%s> ",TELNET_PROMPT_PREFIX,get_softmodem_function(NULL)); printf("\nInitializing telnet server...\n"); while( (telnetparams.new_socket = accept(sock, &cli_addr, &cli_len)) ) { @@ -613,9 +634,9 @@ void run_telnetsrv(void) { HIST_ENTRY *hisentry = history_get(strtol(buf+1,NULL,0)); if (hisentry) { - char msg[TELNET_MAX_MSGLENGTH + sizeof(TELNET_PROMPT) +10]; + char msg[TELNET_MAX_MSGLENGTH + plen +10]; sprintf(buf,"%s",hisentry->line); - sprintf(msg,"%s %s\n",TELNET_PROMPT, hisentry->line); + sprintf(msg,"%s %s\n",prompt, hisentry->line); send(telnetparams.new_socket, msg, strlen(msg), MSG_NOSIGNAL); } } @@ -635,7 +656,7 @@ void run_telnetsrv(void) { add_history(buf); } - send(telnetparams.new_socket, TELNET_PROMPT, sizeof(TELNET_PROMPT), MSG_NOSIGNAL); + send(telnetparams.new_socket, prompt, strlen(prompt), MSG_NOSIGNAL); } else { printf ("[TELNETSRV] Closing telnet connection...\n"); break; @@ -653,7 +674,7 @@ void run_telnetsrv(void) { } /*------------------------------------------------------------------------------------------------*/ -/* set_telnetmodule loads the commands delivered with the telnet server +/* load the commands delivered with the telnet server * * * @@ -709,10 +730,17 @@ int add_sharedmodules(void) { return ret; } +/* autoinit functions is called by the loader when the telnet shared library is + dynamically loaded +*/ int telnetsrv_autoinit(void) { memset(&telnetparams,0,sizeof(telnetparams)); config_get( telnetoptions,sizeof(telnetoptions)/sizeof(paramdef_t),"telnetsrv"); - + /* possibly load a exec specific shared lib */ + char *execfunc=get_softmodem_function(NULL); + char libname[64]; + sprintf(libname,"telnetsrv_%s",execfunc); + load_module_shlib(libname,NULL,0,NULL); if(pthread_create(&telnetparams.telnet_pthread,NULL, (void *(*)(void *))run_telnetsrv, NULL) != 0) { fprintf(stderr,"[TELNETSRV] Error %s on pthread_create call\n",strerror(errno)); return -1; diff --git a/common/utils/telnetsrv/telnetsrv.h b/common/utils/telnetsrv/telnetsrv.h index 89f6a8dda1..debb9f02ec 100644 --- a/common/utils/telnetsrv/telnetsrv.h +++ b/common/utils/telnetsrv/telnetsrv.h @@ -35,7 +35,7 @@ #define TELNET_PORT 9090 #define TELNET_MAX_MSGLENGTH 2048 -#define TELNET_PROMPT "softmodem> " +#define TELNET_PROMPT_PREFIX "softmodem" #define TELNET_MAXCMD 20 #define TELNET_CMD_MAXSIZE 20 #define TELNET_HELPSTR_SIZE 80 diff --git a/common/utils/telnetsrv/telnetsrv_CMakeLists.txt b/common/utils/telnetsrv/telnetsrv_CMakeLists.txt index 05c99aabb8..519a1a72ff 100644 --- a/common/utils/telnetsrv/telnetsrv_CMakeLists.txt +++ b/common/utils/telnetsrv/telnetsrv_CMakeLists.txt @@ -2,20 +2,32 @@ set(TELNETROOT ${OPENAIR_DIR}/common/utils/telnetsrv ) set(TELNETSRV_SOURCE ${TELNETROOT}/telnetsrv.c - ${TELNETROOT}/telnetsrv_phycmd.c ${TELNETROOT}/telnetsrv_proccmd.c ${TELNETROOT}/telnetsrv_loader.c ${TELNETROOT}/telnetsrv_measurements.c ) - -#set(TELNETSRV_ETHDEVCMD_SOURCE -# ${APPROOT}/telnetsrv/telnetsrv_ethdevcmd.c -# ) - + add_library(telnetsrv MODULE ${TELNETSRV_SOURCE} ) -#add_library(telnetsrv_ethdevcmd MODULE ${TELNETSRV_ETHDEVCMD_SOURCE} ) target_link_libraries(telnetsrv PRIVATE history) +foreach(TELNETLIB enb gnb 4gUE 5gUE) + set(TELNETLIB_SRCS "") + foreach(TELNETLIB_ASRC measurements phycmd) + set(TELNETLIB_SRC ${OPENAIR_DIR}/common/utils/telnetsrv/telnetsrv_${TELNETLIB}_${TELNETLIB_ASRC}.c) + if (EXISTS ${TELNETLIB_SRC}) + set( TELNETLIB_SRCS "${TELNETLIB_SRC};${TELNETLIB_SRCS}") + endif() + endforeach() + if(NOT "${TELNETLIB_SRCS}" STREQUAL "") + message("Add ${TELNETLIB} specific telnet functions in libtelnetsrv_${TELNETLIB}.so") + add_library(telnetsrv_${TELNETLIB} MODULE ${TELNETLIB_SRCS} ) + add_dependencies(telnetsrv telnetsrv_${TELNETLIB}) + install(TARGETS telnetsrv_${TELNETLIB} DESTINATION bin) + else() + message("No specific telnet functions for ${TELNETLIB}") + endif() +endforeach() + install(TARGETS telnetsrv DESTINATION bin) if (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build") diff --git a/common/utils/telnetsrv/telnetsrv_enb_measurements.c b/common/utils/telnetsrv/telnetsrv_enb_measurements.c new file mode 100644 index 0000000000..9c5c5b675b --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_enb_measurements.c @@ -0,0 +1,179 @@ +/* + * 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 common/utils/telnetsrv/telnetsrv_measurements.c + * \brief: implementation of telnet commands related to eNB measurments + * \author Francois TABURET + * \date 2019 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + + + + +#define TELNETSERVERCODE +#include "telnetsrv.h" + +#include "common/utils/LOG/log.h" +#include "common/config/config_userapi.h" +#include "telnetsrv_measurements.h" +#include "telnetsrv_ltemeasur_def.h" +#include "telnetsrv_cpumeasur_def.h" +#include "openair2/LAYER2/MAC/mac.h" +#include "openair1/PHY/phy_extern.h" + +void measurcmd_display_macstats(telnet_printfunc_t prnt); +void measurcmd_display_macstats_ue(telnet_printfunc_t prnt); +void measurcmd_display_rlcstats(telnet_printfunc_t prnt); +void measurcmd_display_phycpu(telnet_printfunc_t prnt); +void measurcmd_display_maccpu(telnet_printfunc_t prnt); +void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt); + + +static telnet_measurgroupdef_t enbmeasurgroups[] = { + {"enb", GROUP_LTESTATS,0, measurcmd_display_macstats, {NULL}}, + {"enbues",GROUP_LTESTATS,0, measurcmd_display_macstats_ue,{NULL}}, + {"rlc", GROUP_LTESTATS,0, measurcmd_display_rlcstats, {NULL}}, + {"phycpu",GROUP_CPUSTATS,0, measurcmd_display_phycpu, {NULL}}, + {"maccpu",GROUP_CPUSTATS,0, measurcmd_display_maccpu, {NULL}}, + {"pdcpcpu",GROUP_CPUSTATS,0, measurcmd_display_pdcpcpu, {NULL}}, +}; +#define TELNET_NUM_ENBMEASURGROUPS (sizeof(enbmeasurgroups)/sizeof(telnet_measurgroupdef_t)) + +static int eNB_id =0; +static double cpufreq; + + +#define HDR "---------------------------------" + + +int get_measurgroups(telnet_measurgroupdef_t **measurgroups) { + *measurgroups = enbmeasurgroups; + return TELNET_NUM_ENBMEASURGROUPS; +} + + +void measurcmd_display_phycpu(telnet_printfunc_t prnt) { + PHY_VARS_eNB *phyvars = RC.eNB[eNB_id][0]; + telnet_cpumeasurdef_t cpumeasur[]=CPU_PHYENB_MEASURE; + prnt("%s cpu (%1.1g GHz) measurements: PHY (cpustats %s) %s\n",HDR,cpufreq, + PRINT_CPUMEAS_STATE,HDR); + measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t)); +} + +void measurcmd_display_maccpu(telnet_printfunc_t prnt) { + eNB_MAC_INST *macvars = RC.mac[eNB_id]; + telnet_cpumeasurdef_t cpumeasur[]=CPU_MACENB_MEASURE; + prnt("%s cpu (%1.1g GHz) measurements: MAC (cpustats %s) %s\n",HDR,cpufreq, + PRINT_CPUMEAS_STATE,HDR); + measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t)); +} + +void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt) { + pdcp_stats_t *pdcpvars = &(eNB_pdcp_stats[eNB_id]); + telnet_cpumeasurdef_t cpumeasur[]=CPU_PDCPENB_MEASURE; + prnt("%s cpu (%1.1g GHz) measurements: PDCP (cpustats %s) %s \n",HDR,cpufreq, + PRINT_CPUMEAS_STATE,HDR); + measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t)); +} +/*----------------------------------------------------------------------------------------------------*/ + + +void measurcmd_display_macstats_ue(telnet_printfunc_t prnt) { + UE_list_t *UE_list = &(RC.mac[eNB_id]->UE_list); + + for (int UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + for (int i=0; inumactiveCCs[UE_id]; i++) { + int CC_id = UE_list->ordered_CCids[i][UE_id]; + prnt("%s UE %i Id %i CCid %i %s\n",HDR,i,UE_id,CC_id,HDR); + eNB_UE_STATS *macuestatptr = &(UE_list->eNB_UE_stats[CC_id][UE_id]); + telnet_ltemeasurdef_t statsptr[]=LTEMAC_UEMEASURE; + measurcmd_display_measures(prnt, statsptr, sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t)); + } + } +} /* measurcmd_display_macstats_ue */ + +void measurcmd_display_macstats(telnet_printfunc_t prnt) { + for (int CC_id=0 ; CC_id < MAX_NUM_CCs; CC_id++) { + eNB_STATS *macstatptr=&(RC.mac[eNB_id]->eNB_stats[CC_id]); + telnet_ltemeasurdef_t statsptr[]=LTEMAC_MEASURE; + prnt("%s eNB %i mac stats CC %i frame %u %s\n", + HDR, eNB_id, CC_id, RC.mac[eNB_id]->frame,HDR); + measurcmd_display_measures(prnt,statsptr,sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t)); + } +} /* measurcmd_display_macstats */ + + +void measurcmd_display_one_rlcstat(telnet_printfunc_t prnt, int UE_id, telnet_ltemeasurdef_t *statsptr, int num_rlcmeasure, unsigned int *rlcstats, + char *rbid_str, protocol_ctxt_t *ctxt, const srb_flag_t srb_flagP, const rb_id_t rb_idP) + +{ + int rlc_status = rlc_stat_req(ctxt,srb_flagP,rb_idP, + rlcstats, rlcstats+1, rlcstats+2, rlcstats+3, rlcstats+4, rlcstats+5, + rlcstats+6, rlcstats+7, rlcstats+8, rlcstats+9, rlcstats+10, rlcstats+11, + rlcstats+12, rlcstats+13, rlcstats+14, rlcstats+15, rlcstats+16, rlcstats+17, + rlcstats+18, rlcstats+19, rlcstats+20, rlcstats+21, rlcstats+22, rlcstats+23, + rlcstats+24, rlcstats+25, rlcstats+26, rlcstats+27); + + if (rlc_status == RLC_OP_STATUS_OK) { + prnt("%s UE %i RLC %s mode %s %s\n",HDR,UE_id, rbid_str, + (rlcstats[0]==RLC_MODE_AM)? "AM": (rlcstats[0]==RLC_MODE_UM)?"UM":"NONE",HDR); + measurcmd_display_measures(prnt, statsptr, num_rlcmeasure); + } +} /* status measurcmd_rlc_stat_req */ + + +void measurcmd_display_rlcstats(telnet_printfunc_t prnt) { + protocol_ctxt_t ctxt; + UE_list_t *UE_list = &(RC.mac[eNB_id]->UE_list); + telnet_ltemeasurdef_t statsptr[]=LTE_RLCMEASURE; + int num_rlcmeasure = sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t ); + unsigned int *rlcstats = malloc(num_rlcmeasure*sizeof(unsigned int)); + eNB_MAC_INST *eNB = RC.mac[eNB_id]; + + for(int i=0; i head; UE_id>=0; UE_id=UE_list->next[UE_id]) { +#define NB_eNB_INST 1 + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt,eNB_id, ENB_FLAG_YES,UE_list->eNB_UE_stats[0][UE_id].crnti, + eNB->frame,eNB->subframe,eNB_id); + measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DCCH", &ctxt, SRB_FLAG_YES, DCCH); + measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DTCH", &ctxt, SRB_FLAG_NO, DTCH-2); + } +} /* measurcmd_display_macstats_ue */ + + + + diff --git a/common/utils/telnetsrv/telnetsrv_phycmd.c b/common/utils/telnetsrv/telnetsrv_enb_phycmd.c similarity index 52% rename from common/utils/telnetsrv/telnetsrv_phycmd.c rename to common/utils/telnetsrv/telnetsrv_enb_phycmd.c index c60126f1c7..f7deec1801 100644 --- a/common/utils/telnetsrv/telnetsrv_phycmd.c +++ b/common/utils/telnetsrv/telnetsrv_enb_phycmd.c @@ -29,7 +29,7 @@ * \note * \warning */ -#define _GNU_SOURCE +#define _GNU_SOURCE #include #include @@ -39,104 +39,85 @@ #define TELNETSRV_PHYCMD_MAIN #include "telnetsrv_phycmd.h" char *prnbuff; -extern int dump_eNB_stats(PHY_VARS_eNB *eNB, char* buffer, int length); +extern int dump_eNB_stats(PHY_VARS_eNB *eNB, char *buffer, int length); -void init_phytelnet(void) -{ -prnbuff=malloc(get_phybsize() ); -if (prnbuff == NULL) - { - fprintf(stderr,"Error %s on malloc in init_phytelnet()\n",strerror(errno)); - } +void init_phytelnet(void) { + prnbuff=malloc(get_phybsize() ); + + if (prnbuff == NULL) { + fprintf(stderr,"Error %s on malloc in init_phytelnet()\n",strerror(errno)); + } } -void display_uestatshead( telnet_printfunc_t prnt) -{ -prnt("cc ue rnti Dmcs Umcs tao tau Dbr Dtb \n"); +void display_uestatshead( telnet_printfunc_t prnt) { + prnt("cc ue rnti Dmcs Umcs tao tau Dbr Dtb \n"); } -void dump_uestats(int debug, telnet_printfunc_t prnt, uint8_t prntflag) -{ - -int p; - - p=dump_eNB_l2_stats( prnbuff, 0); - if(prntflag>=1) - prnt("%s\n",prnbuff); - if(debug>=1) - prnt("%i bytes printed\n",p); +void dump_uestats(int debug, telnet_printfunc_t prnt, uint8_t prntflag) { + int p; + p=dump_eNB_l2_stats( prnbuff, 0); + if(prntflag>=1) + prnt("%s\n",prnbuff); + if(debug>=1) + prnt("%i bytes printed\n",p); } -void display_uestats(int debug, telnet_printfunc_t prnt, int ue) -{ - for (int cc=0; cc<1 ; cc++) - { - - - } +void display_uestats(int debug, telnet_printfunc_t prnt, int ue) { + for (int cc=0; cc<1 ; cc++) { + } } -void display_phycounters(char *buf, int debug, telnet_printfunc_t prnt) -{ - prnt(" DLSCH kb DLSCH kb/s\n"); - - dump_uestats(debug, prnt,0); - +void display_phycounters(char *buf, int debug, telnet_printfunc_t prnt) { + prnt(" DLSCH kb DLSCH kb/s\n"); + dump_uestats(debug, prnt,0); } -int dump_phyvars(char *buf, int debug, telnet_printfunc_t prnt) -{ - - +int dump_phyvars(char *buf, int debug, telnet_printfunc_t prnt) { + if (debug > 0) + prnt("phy interface module received %s\n",buf); - if (debug > 0) - prnt("phy interface module received %s\n",buf); - if (strcasestr(buf,"phycnt") != NULL) - { - display_phycounters(buf, debug, prnt); - } - if (strcasestr(buf,"uestat") != NULL) - { - char *cptr=strcasestr(buf+sizeof("uestat"),"UE"); - display_uestatshead(prnt); - if (cptr != NULL) - { - int ueidx = strtol( cptr+sizeof("UE"), NULL, 10); - if (ueidx < NUMBER_OF_UE_MAX && ueidx >= 0) - { - display_uestats(debug, prnt,ueidx); - } - } /* if cptr != NULL */ - else - { - for (int ue=0; ue= 0) { + display_uestats(debug, prnt,ueidx); + } + } /* if cptr != NULL */ + else { + for (int ue=0; ue]", dump_phyvars}, + {"disp","[phycnt,uedump,uestat UE]", dump_phyvars}, - {"","",NULL}, + {"","",NULL}, }; /*-------------------------------------------------------------------------------------*/ -void add_phy_cmds(void) -{ - - init_phytelnet(); - add_telnetcmd("phy", phy_vardef, phy_cmdarray); +void add_phy_cmds(void) { + init_phytelnet(); + add_telnetcmd("phy", phy_vardef, phy_cmdarray); } diff --git a/common/utils/telnetsrv/telnetsrv_measurements.c b/common/utils/telnetsrv/telnetsrv_measurements.c index 7cfc656225..4a11e7c2dd 100644 --- a/common/utils/telnetsrv/telnetsrv_measurements.c +++ b/common/utils/telnetsrv/telnetsrv_measurements.c @@ -20,9 +20,9 @@ */ /*! \file common/utils/telnetsrv/telnetsrv_measurements.c - * \brief: implementation of telnet commands related to measurments + * \brief: implementation of telnet measurement functions common to all softmodems * \author Francois TABURET - * \date 2019 + * \date 2020 * \version 0.1 * \company NOKIA BellLabs France * \email: francois.taburet@nokia-bell-labs.com @@ -47,40 +47,18 @@ #include "common/utils/LOG/log.h" #include "common/config/config_userapi.h" #include "telnetsrv_measurements.h" -#include "telnetsrv_ltemeasur_def.h" -#include "telnetsrv_cpumeasur_def.h" -#include "openair2/LAYER2/MAC/mac.h" -#include "openair1/PHY/phy_extern.h" - -void measurcmd_display_macstats(telnet_printfunc_t prnt); -void measurcmd_display_macstats_ue(telnet_printfunc_t prnt); -void measurcmd_display_rlcstats(telnet_printfunc_t prnt); -void measurcmd_display_phycpu(telnet_printfunc_t prnt); -void measurcmd_display_maccpu(telnet_printfunc_t prnt); -void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt); -static telnet_measurgroupdef_t measurgroups[] = { - {"enb", GROUP_LTESTATS,0, measurcmd_display_macstats, {NULL}}, - {"enbues",GROUP_LTESTATS,0, measurcmd_display_macstats_ue,{NULL}}, - {"rlc", GROUP_LTESTATS,0, measurcmd_display_rlcstats, {NULL}}, - {"phycpu",GROUP_CPUSTATS,0, measurcmd_display_phycpu, {NULL}}, - {"maccpu",GROUP_CPUSTATS,0, measurcmd_display_maccpu, {NULL}}, - {"pdcpcpu",GROUP_CPUSTATS,0, measurcmd_display_pdcpcpu, {NULL}}, -}; -#define TELNET_NUM_MEASURGROUPS (sizeof(measurgroups)/sizeof(telnet_measurgroupdef_t)) - -static int eNB_id =0; static char *grouptypes[] = {"ltestats","cpustats"}; static double cpufreq; #define TELNET_NUM_MEASURTYPES (sizeof(grouptypes)/sizeof(char *)) #define HDR "---------------------------------" -void measurcmd_display_groups(telnet_printfunc_t prnt) { +void measurcmd_display_groups(telnet_printfunc_t prnt,telnet_measurgroupdef_t *measurgroups,int groups_size) { prnt(" %*s %10s %s\n",TELNET_MAXMEASURNAME_LEN-1,"name","type","nombre de mesures"); - for(int i=0; iUE_list); - for (int UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - for (int i=0; inumactiveCCs[UE_id]; i++) { - int CC_id = UE_list->ordered_CCids[i][UE_id]; - prnt("%s UE %i Id %i CCid %i %s\n",HDR,i,UE_id,CC_id,HDR); - eNB_UE_STATS *macuestatptr = &(UE_list->eNB_UE_stats[CC_id][UE_id]); - telnet_ltemeasurdef_t statsptr[]=LTEMAC_UEMEASURE; - measurcmd_display_measures(prnt, statsptr, sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t)); - } - } -} /* measurcmd_display_macstats_ue */ - -void measurcmd_display_macstats(telnet_printfunc_t prnt) { - for (int CC_id=0 ; CC_id < MAX_NUM_CCs; CC_id++) { - eNB_STATS *macstatptr=&(RC.mac[eNB_id]->eNB_stats[CC_id]); - telnet_ltemeasurdef_t statsptr[]=LTEMAC_MEASURE; - prnt("%s eNB %i mac stats CC %i frame %u %s\n", - HDR, eNB_id, CC_id, RC.mac[eNB_id]->frame,HDR); - measurcmd_display_measures(prnt,statsptr,sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t)); - } -} /* measurcmd_display_macstats */ - - -void measurcmd_display_one_rlcstat(telnet_printfunc_t prnt, int UE_id, telnet_ltemeasurdef_t *statsptr, int num_rlcmeasure, unsigned int *rlcstats, - char *rbid_str, protocol_ctxt_t *ctxt, const srb_flag_t srb_flagP, const rb_id_t rb_idP) - -{ - int rlc_status = rlc_stat_req(ctxt,srb_flagP,rb_idP, - rlcstats, rlcstats+1, rlcstats+2, rlcstats+3, rlcstats+4, rlcstats+5, - rlcstats+6, rlcstats+7, rlcstats+8, rlcstats+9, rlcstats+10, rlcstats+11, - rlcstats+12, rlcstats+13, rlcstats+14, rlcstats+15, rlcstats+16, rlcstats+17, - rlcstats+18, rlcstats+19, rlcstats+20, rlcstats+21, rlcstats+22, rlcstats+23, - rlcstats+24, rlcstats+25, rlcstats+26, rlcstats+27); - - if (rlc_status == RLC_OP_STATUS_OK) { - prnt("%s UE %i RLC %s mode %s %s\n",HDR,UE_id, rbid_str, - (rlcstats[0]==RLC_MODE_AM)? "AM": (rlcstats[0]==RLC_MODE_UM)?"UM":"NONE",HDR); - measurcmd_display_measures(prnt, statsptr, num_rlcmeasure); - } -} /* status measurcmd_rlc_stat_req */ - - -void measurcmd_display_rlcstats(telnet_printfunc_t prnt) { - protocol_ctxt_t ctxt; - UE_list_t *UE_list = &(RC.mac[eNB_id]->UE_list); - telnet_ltemeasurdef_t statsptr[]=LTE_RLCMEASURE; - int num_rlcmeasure = sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t ); - unsigned int *rlcstats = malloc(num_rlcmeasure*sizeof(unsigned int)); - eNB_MAC_INST *eNB = RC.mac[eNB_id]; - - for(int i=0; i head; UE_id>=0; UE_id=UE_list->next[UE_id]) { -#define NB_eNB_INST 1 - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt,eNB_id, ENB_FLAG_YES,UE_list->eNB_UE_stats[0][UE_id].crnti, - eNB->frame,eNB->subframe,eNB_id); - measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DCCH", &ctxt, SRB_FLAG_YES, DCCH); - measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DTCH", &ctxt, SRB_FLAG_NO, DTCH-2); - } -} /* measurcmd_display_macstats_ue */ /*------------------------------------------------------------------------------------------------------------------------*/ /* function called by the telnet server when measur command is entered */ @@ -238,20 +130,24 @@ int measurcmd_show(char *buf, int debug, telnet_printfunc_t prnt) { if (debug > 0) prnt(" measurcmd_show received %s\n",buf); - - // char tmp[20480]; - // dump_eNB_l2_stats(tmp, 0); - // prnt("%s\n",tmp); + int (*fptr)(telnet_measurgroupdef_t **) = dlsym(RTLD_DEFAULT,"get_measurgroups"); + if ( fptr == NULL) { + prnt("No measures available for this softmodem\n"); + return 0; + } + telnet_measurgroupdef_t *measurgroups; + int num_measurgroups = fptr( &measurgroups); + int s = sscanf(buf,"%ms %i-%i\n",&subcmd, &idx1,&idx2); if (s>0) { if ( strcmp(subcmd,"groups") == 0) { - measurcmd_display_groups(prnt); + measurcmd_display_groups(prnt,measurgroups,num_measurgroups); badcmd=0; } else { for (int i=0; i #include "telnetsrv.h" #include "openair1/PHY/defs_eNB.h" -#ifdef TELNETSRV_MEASURMENTS_MAIN + #define TELNET_MAXMEASURNAME_LEN 30 #define TELNET_MAXMEASURGROUPS 10 -telnetshell_vardef_t measur_vardef[] = { - {"",0,NULL} -}; - +#define PRINT_CPUMEAS_STATE ((cpumeas(CPUMEAS_GETSTATE))?"enabled":"disabled") typedef struct cpumeasurdef { char statname[TELNET_MAXMEASURNAME_LEN]; time_stats_t *astatptr; @@ -75,6 +72,7 @@ typedef struct mesurgroupdef { #define LTEMAC_MEASURGROUP_NAME "ltemac" #define PHYCPU_MEASURGROUP_NAME "phycpu" +#ifdef TELNETSRV_MEASURMENTS_MAIN int measurcmd_show(char *buf, int debug, telnet_printfunc_t prnt); int measurcmd_cpustats(char *buf, int debug, telnet_printfunc_t prnt); telnetshell_cmddef_t measur_cmdarray[] = { @@ -83,6 +81,19 @@ telnetshell_cmddef_t measur_cmdarray[] = { {"","",NULL} }; +telnetshell_vardef_t measur_vardef[] = { + {"",0,NULL} +}; +/* function to be implemented in any telnetsrv_xxx_measurements.c sources + to allow common measurment code to access measurments data */ +extern int get_measurgroups(telnet_measurgroupdef_t **measurgroups); +/* */ + #else -extern void add_measur_cmds(void); +extern void add_measur_cmds(void); +extern void measurcmd_display_groups(telnet_printfunc_t prnt,telnet_measurgroupdef_t *measurgroups,int groups_size); +extern void measurcmd_display_cpumeasures(telnet_printfunc_t prnt, telnet_cpumeasurdef_t *cpumeasure, int cpumeasure_size) ; +extern uint64_t measurcmd_getstatvalue(telnet_ltemeasurdef_t *measur,telnet_printfunc_t prnt); +extern void measurcmd_display_measures(telnet_printfunc_t prnt, telnet_ltemeasurdef_t *statsptr, int stats_size); + #endif /* TELNETSRV_MEASURCMD_MAIN */ diff --git a/doc/BUILD.md b/doc/BUILD.md index 388f9f2658..9ada32e532 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -18,22 +18,33 @@ This page is valid on tags starting from **`2019.w09`**. oai EPC is developed in a distinct project with it's own [documentation](https://github.com/OPENAIRINTERFACE/openair-cn/wiki) , it is not described here. -OAI UE and eNodeB sources can be downloaded from the Eurecom [gitlab repository](./GET_SOURCES.md). +OAI softmodem sources, which aim to implement 3GPP compliant UEs, eNodeB and gNodeB can be downloaded from the Eurecom [gitlab repository](./GET_SOURCES.md). Sources come with a build script [build_oai](../cmake_targets/build_oai) located at the root of the `openairinterface5g/cmake_targets` directory. This script is developed to build the oai binaries (executables,shared libraries) for different hardware platforms, and use cases. The main oai binaries, which are tested by the Continuous Integration process are: - The LTE UE: `lte-uesoftmodem` +- The 5G UE: `nr-uesoftmodem` - The LTE eNodeB: `lte-softmodem` -- The PHY simulators: `dlsim` and `ulsim` +- The 5G gNodeB: `nr-softmodem` +- The LTE PHY simulators: `dlsim` and `ulsim` +- The 5G PHY simulators: `nr_dlschsim` `nr_dlsim` `nr_pbchsim` `nr_pucchsim` `nr_ulschsim` `nr_ulsim` `polartest` `smallblocktest` + `ulsim` `ldpctest` + +Running the [build_oai](../cmake_targets/build_oai) script also generates some utilities required to build and/or run the oai softmodem binaries: + +- `con2uedata`: a binary used to build the UE data from a configuration file. The created file emulates the sim card of a 3GPP compliant phone. +- `nvram`: a binary used to build UE (IMEI...) and EMM (IMSI, registered PLMN) non volatile data. +- `rb_tool`: radio bearer utility +- `genids` T Tracer utility, used at build time to generate T_IDs.h include file. This binary is located in the [T Tracer source file directory](../common/utils/T) . The build system for OAI uses [cmake](https://cmake.org/) which is a tool to generate makefiles. The `build_oai` script is a wrapper using cmake, make and standard linux shell commands to ease the oai build and use . The file describing how to build the executables from source files is the [CMakeLists.txt](../cmake_targets/CMakeLists.txt), it is used as input by cmake to generate the makefiles. The oai softmodem supports many use cases, and new ones are regularly added. Most of them are accessible using the configuration file or the command line options and continuous effort is done to avoid introducing build options as it makes tests and usage more complicated than run-time options. The following functionalities, originally requiring a specific build are now accessible by configuration or command line options: - s1, noS1 -- all simulators, with exception of PHY simulators, which are distinct executables. +- all simulators as the rfsimulator, the L2 simulator, with exception of PHY simulators, which are distinct executables. Calling the `build_oai` script with the -h option gives the list of all available options, but a process to simplify and check the requirements of all these options is on-going. Check the [table](BUILD.md "# `build_oai` options") At the end of this page to know the status of `buid_oai` options which are not described hereafter. @@ -42,25 +53,27 @@ Calling the `build_oai` script with the -h option gives the list of all availabl Detailed information about these simulators can be found [in this dedicated page](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/OpenAirLTEPhySimul) -# Building UE and eNodeB Executables +# Building UEs, eNodeB and gNodeB Executables -After downloading the source files, a single build command can be used to get the binaries supporting all the oai softmodem use cases (UE and eNodeB): +After downloading the source files, a single build command can be used to get the binaries supporting all the oai softmodem use cases (UE and [eg]NodeB): ``` cd /openairinterface5g/ source oaienv cd cmake_targets/ -./build_oai -I -w USRP --eNB --UE +./build_oai -I -w USRP --eNB --UE --nrUE --gNB ``` - The `-I` option is to install pre-requisites, you only need it the first time you build the softmodem or when some oai dependencies have changed. -- The `-w` option is to select the radio head support you want to include in your build. Radio head support is provided via a shared library, which is called the "oai device" The build script creates a soft link from `liboai_device.so` to the true device which will be used at run-time (here the USRP one,`liboai_usrpdevif.so` . USRP is the only hardware tested today in the Continuous Integration process. The RF simulator[RF simulator](../targets/ARCH/rfsimulator/README.md) is implemented as a specific device replacing RF hardware, it can be build using `-w SIMU` option. +- The `-w` option is to select the radio head support you want to include in your build. Radio head support is provided via a shared library, which is called the "oai device" The build script creates a soft link from `liboai_device.so` to the true device which will be used at run-time (here the USRP one,`liboai_usrpdevif.so` . USRP is the only hardware tested today in the Continuous Integration process. The RF simulator[RF simulator](../targets/ARCH/rfsimulator/README.md) is implemented as a specific device replacing RF hardware, it can be specifically built using `-w SIMU` option, but is also built during any softmodem build. - `--eNB` is to build the `lte-softmodem` executable and all required shared libraries +- `--gNB` is to build the `nr-softmodem` executable and all required shared libraries - `--UE` is to build the `lte-uesoftmodem` executable and all required shared libraries +- `--nrUE` is to build the `nr-uesoftmodem` executable and all required shared libraries -You can build the eNodeB and the UE separately, you may not need both of them depending on your oai usage. +You can build any oai softmodem executable separately, you may not need all of them depending on your oai usage. -After completing the build, the binaries are available in the `cmake_targets/ran_build/build` directory. A copy is also available in the `target/bin` directory, with all binaries suffixed by the 3GPP release number, today .Rel14 by default. It must be noticed that the option for building for a specific 3GPP release number is not tested by the CI and may be removed in the future. +After completing the build, the binaries are available in the `cmake_targets/ran_build/build` directory. A copy is also available in the `target/bin` directory, with all binaries suffixed by the 3GPP release number, today .Rel15. ## Issue when building `nasmeh` module ## @@ -92,6 +105,20 @@ Install it: $ sudo apt-get install --yes linux-headers-your-version ``` +On CentOS or RedHat Entreprise Linux: + +```bash +$ uname -r +3.10.0-1062.9.1.rt56.1033.el7.x86_64 +$ yum list installed | grep kernel | grep devel +kernel-devel.x86_64 3.10.0-1062.9.1.el7 @rhel-7-server-rpms +kernel-rt-devel.x86_64 3.10.0-1062.9.1.rt56.1033.el7 +``` + +If your kernel is generic, install `kernel-devel` package: `sudo yum install kernel-devel` + +In most case, your kernel is real-time. Install `kernel-rt-devel` package: `sudo yum install kernel-rt-devel` + # Building Optional Binaries ## Telnet Server @@ -106,13 +133,13 @@ or You can get documentation about the telnet server [here](common/utils/telnetsrv/DOC/telnetsrv.md) -## USRP record player -The USRP record player today needs a specific build. Work to make it available as a run time option is under consideration ## Other optional libraries -Using the help option of the build script you can get the list of available optional libraries. Those which haven't been mentioned above are known to need more tests and documentation +Using the help option of the build script you can get the list of available optional libraries. Those which haven't been mentioned above are known to need more tests and documentation. + +`./build_oai --build-lib all` will build all available optional libraries. # `build_oai` options @@ -122,30 +149,30 @@ Using the help option of the build script you can get the list of available opti | -c | maintained | erase all previously built files for this target before starting the new build. | | -C | maintained, needs improvement | erase all previously built files for any target before starting the new build. | | --verbose-compile | maintained | get compilation messages, as when running `make` or `gcc` directly. | -| --cflags_processor | maintained | used to pass options to the compiler | +| --cflags_processor | maintained | used to pass options to the compiler. | | --clean-kernel | unknown | no code in the script corresponding to this option | | --install-system-files | maintained | install oai built binaries in linux system files repositories | | -w | maintained and tested in CI for USRP device | build corresponding oai device and create the soft link to enforce this device usage at run-time | -| --phy_simulators | maintained, tested in CI | build all PHY simulators, a set of executables allowing unitary tests of LTE channel implementation within oai. | +| --phy_simulators | maintained, tested in CI | build all PHY simulators, a set of executables allowing unitary tests of LTE and 5G channel implementation within oai. | | --core_simulators | | | | -s | | | | --run-group | | | | -I | maintained, tested in CI | install external dependencies before starting the build | -| --install-optional-packages | maintained | install optional packages, useful for developing and testing. look at the | -| | | check_install_additional_tools function in cmake_targets/tools/build_helper script to get the list | -| -g | maintained | build binaries with gdb support. | +| --install-optional-packages | maintained | install optional packages, useful for developing and testing. look at the check_install_additional_tools function in cmake_targets/tools/build_helper script to get the list | +| -g | maintained | Specifies the level of debugging options used to build the binaries. Available levels are `Release`, `RelWithDebInfo`, `MinSizeRe` and `Debug`. If -g is not specified, `Release` is used, if -g is used without any level, `Debug` is used. | +| -G | maintained | Display Cmake debugging messages | | --eNB | maintained and tested in CI | build `lte-softmodem` the LTE eNodeB | | --UE | maintained and tested in CI | build `lte-uesoftmodem` the LTE UE | -| --usrp-recplay | maintained | build with support for the record player. Implementation will be soon reviewed to switch to a run-time option. | -| --build-lib | maintained | build optional shared library(ies), which can then be loaded at run time via command line option. Use the --help option to get the list of supported optional libraries. | -| --UE-conf-nvram | | | -| --UE-gen-nvram | | | -| -r | unknown, to be removed | specifies which 3GPP release to build for. Only the default (today rel14) is tested in CI and it is likely that future oai release will remove this option | +| --gNB | maintained and tested in CI | build `nr-softmodem` the 5G gNodeB | +| --nrUE | maintained and tested in CI | build `nr-uesoftmodem` the 5G UE | +| --usrp-recplay | deprecated | use the USRP configuration parameters to use the record player. | +| --build-lib | maintained | build optional shared library(ies), which can then be loaded at run time via command line option. Use the --help option to get the list of supported optional libraries. `all` can be used to build all available optional libraries. | +| --UE-conf-nvram | maintained | Specifies the path to the input file used by the conf2uedata utility. defaults to [openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf](../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf) | +| --UE-gen-nvram | maintained | Specifies the path where the output file created by the conf2uedata utility will be placed. Defaults to `target/bin` | | -V | deprecated | Used to build with support for synchronization diagram utility. This is now available via the T-Tracer and is included if T-Tracer is not disabled. | | --build-doxygen | unknown | build doxygen documentation, many oai source files do not include doxygen comments | | --disable-deadline --enable-deadline --disable-cpu-affinity | deprecated | These options were used to activate or de-activate specific code depending on the choice of a specific linux scheduling mode. This has not been tested for a while and should be implemented as configuration options | | --disable-T-Tracer | maintained, to be tested | Remove T_Tracer and console LOG messages except error messages. | -| --disable-hardware-dependency | | | | --ue-autotest-trace --ue-timing --ue-trace | deprecated | Were used to enable conditional code implementing debugging messages or debugging statistics. These functionalities are now either available from run-time options or not maintained. | | --build-eclipse | unknown | | | | | | diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index e9355e51d2..f71b9acb33 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -7,15 +7,18 @@ 4. [eNB PDCP Layer](#enb-pdcp-layer) 5. [eNB RRC Layer](#enb-rrc-layer) 6. [eNB X2AP](#enb-x2ap) - 7. [eNB Advanced Features](#enb-advanced-features) -2. [OpenAirInterface UE Feature Set](#openairinterface-ue-feature-set) + 7. [eNB/MCE M2AP](#enbmce-m2ap) + 8. [MCE/MME M3AP](#mcemme-m3ap) + 9. [eNB Advanced Features](#enb-advanced-features) +2. [OpenAirInterface Functional Split](#openairinterface-functional-split) +3. [OpenAirInterface UE Feature Set](#openairinterface-ue-feature-set) 1. [LTE UE PHY Layer](#lte-ue-phy-layer) 2. [LTE UE MAC Layer](#lte-ue-mac-layer) 3. [LTE UE RLC Layer](#lte-ue-rlc-layer) 4. [LTE UE PDCP Layer](#lte-ue-pdcp-layer) 5. [LTE UE RRC Layer](#lte-ue-rrc-layer) -3. [OpenAirInterface Functional Split](#openairinterface-functional-split) -4. [OpenAirInterface 5G-NR Feature Set](#openairinterface-5g-nr-feature-set) +4. [OpenAirInterface Functional Split](#openairinterface-functional-split) +5. [OpenAirInterface 5G-NR Feature Set](#openairinterface-5g-nr-feature-set) 1. [General Parameters](#general-parameters) 2. [gNB Features](#gnb-features) 1. [gNB Physical Layer](#gnb-phy-layer) @@ -148,6 +151,26 @@ The X2AP layer is based on **3GPP 36.423** v14.6.0 and implements the following - Handover Cancel - X2-U interface implemented +## eNB/MCE M2AP ## + +The M2AP layer is based on **3GPP 36.443** v14.0.1: + - M2 Setup Request + - M2 Setup Response + - M2 Setup Failure + - M2 Scheduling Information + - M2 Scheduling Information Response + - M2 Session Start Request + - M2 Session Start Response + +## MCE/MME M3AP ## + +The M3AP layer is based on **3GPP 36.444** v14.0.1: + - M3 Setup Request + - M3 Setup Response + - M3 Setup Failure + - M3 Session Start Request + - M3 Session Start Response + ## eNB Advanced Features ## **To be completed** @@ -283,4 +306,4 @@ For more details see [this document](https://gitlab.eurecom.fr/oai/openairinterf [OAI softmodem build procedure](BUILD.md) -[Running the OAI softmodem ](RUNMODEM.md) \ No newline at end of file +[Running the OAI softmodem ](RUNMODEM.md) diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index 71354e663a..0c66b58547 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -20,19 +20,18 @@ See the [dedicated page](BASIC_SIM.md). # RF Simulator -The rf simulator is a oai device replacing the radio heads (for example the USRP device). It allows connecting the oai UE and the oai eNodeB through a network interface carrying the time-domain samples, getting rid of over the air unpredictable perturbations. This is the ideal tool to check signal processing algorithms and protocols implementation. +The rf simulator is a oai device replacing the radio heads (for example the USRP device). It allows connecting the oai UE (LTE or 5G) and respectively the oai eNodeB or gNodeB through a network interface carrying the time-domain samples, getting rid of over the air unpredictable perturbations. This is the ideal tool to check signal processing algorithms and protocols implementation. The rf simulator has some preliminary support for channel modeling. It is planned to enhance this simulator with the following functionalities: -- Support for multiple UE connections,each UE being a `lte-uesoftmodem` instance. -- Support for multiple eNodeB for hand-over tests -- Support for channel modeling +- Support for multiple UE connections,each UE being a `lte-uesoftmodem` or `nr_uesoftmodem` instance. +- Support for multiple eNodeB's or gNodeB's for hand-over tests This is an easy use-case to setup and test, as no specific hardware is required. The [rfsimulator page](../targets/ARCH/rfsimulator/README.md ) contains the detailed documentation. # L2 nFAPI Simulator -This simulator connects a eNodeB and UEs through a nfapi interface, short-cutting the L1 layer. The objective of this simulator is to allow multi UEs simulation, with a large number of UEs (ideally up to 255 ) .Here to ease the platform setup, UEs are simulated via a single `lte-uesoftmodem` instance. Today the CI tests just with one UE and architecture has to be reviewed to allow a number of UE above about 16. This work is on-going. +This simulator connects a eNodeB and UEs through a nfapi interface, short-cutting the L1 layer. The objective of this simulator is to allow multi UEs simulation, with a large number of UEs (ideally up to 255 ) .Here to ease the platform setup, UEs are simulated via a single `lte-uesoftmodem` instance. Today the CI tests just with one UE and architecture has to be reviewed to allow a number of UE above about 16. This work is on-going. As for the rf simulator, no specific hardware is required. The [L2 nfapi simlator page](L2NFAPI.md) contains the detailed documentation. diff --git a/d2d_emulator_setup.txt b/doc/d2d_emulator_setup.txt similarity index 100% rename from d2d_emulator_setup.txt rename to doc/d2d_emulator_setup.txt diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 318ec73621..8022ef8276 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -63,7 +63,7 @@ #include "LAYER2/MAC/mac.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/MAC/mac_proto.h" #include "RRC/LTE/rrc_extern.h" #include "PHY_INTERFACE/phy_interface.h" @@ -80,14 +80,9 @@ #include "UTIL/OTG/otg_extern.h" #endif -#if defined(ENABLE_ITTI) - #if defined(ENABLE_USE_MME) - #include "s1ap_eNB.h" - #ifdef PDCP_USE_NETLINK - #include "SIMULATION/ETH_TRANSPORT/proto.h" - #endif - #endif -#endif +#include "s1ap_eNB.h" +#include "SIMULATION/ETH_TRANSPORT/proto.h" + #include "T.h" @@ -98,18 +93,16 @@ // extern openair0_device openair0; -#if defined(ENABLE_ITTI) - extern volatile int start_gNB; - extern volatile int start_UE; -#endif +extern volatile int start_gNB; +extern volatile int start_UE; extern volatile int oai_exit; extern openair0_config_t openair0_cfg[MAX_CARDS]; extern int transmission_mode; -uint16_t sl_ahead=6; -uint16_t sf_ahead=6; +extern uint16_t sf_ahead; +extern uint16_t sl_ahead; //pthread_t main_gNB_thread; time_stats_t softmodem_stats_mt; // main thread @@ -152,6 +145,7 @@ extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); static inline int rxtx(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int frame_tx, int slot_tx, char *thread_name) { + sl_ahead = sf_ahead*gNB->frame_parms.slots_per_subframe; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; start_meas(&softmodem_stats_rxtx_sf); @@ -216,7 +210,7 @@ static inline int rxtx(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int frame_t if (oai_exit) return(-1); // ***************************************** - // TX processing for subframe n+sl_ahead + // TX processing for subframe n+sf_ahead // run PHY TX procedures the one after the other for all CCs to avoid race conditions // (may be relaxed in the future for performance reasons) // ***************************************** @@ -374,7 +368,7 @@ static void *gNB_L1_thread( void *param ) { } -#if 0 //defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) +#if 0 // Wait for gNB application initialization to be complete (gNB registration to MME) static void wait_system_ready (char *message, volatile int *start_flag) { static char *indicator[] = {". ", ".. ", "... ", ".... ", ".....", @@ -404,14 +398,15 @@ void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, char *string, struct RU_proc_t *ru_proc=&ru->proc; proc->frame_rx = frame_rx; proc->slot_rx = slot_rx; + sl_ahead = sf_ahead*fp->slots_per_subframe; if (!oai_exit) { T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->slot_rx)); - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot); + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_subframe); L1_proc->frame_rx = ru_proc->frame_rx; L1_proc->slot_rx = ru_proc->tti_rx; - L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; - L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame; + L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->slot_tx = (L1_proc->slot_rx + (fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; if (rxtx(gNB,L1_proc->frame_rx,L1_proc->slot_rx,L1_proc->frame_tx,L1_proc->slot_tx,string) < 0) LOG_E(PHY,"gNB %d CC_id %d failed during execution\n",gNB->Mod_id,gNB->CC_id); @@ -426,23 +421,29 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot RU_t *ru; RU_proc_t *ru_proc; - int waitret,ret; - + int waitret = 0, ret = 0, time_ns = 1000*1000; + struct timespec now, abstime; - -// note this should depend on the numerology used by the TX L1 thread, set here for 500us slot time + // note this should depend on the numerology used by the TX L1 thread, set here for 500us slot time VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL,1); + time_ns = time_ns/gNB->frame_parms.slots_per_subframe; AssertFatal((ret = pthread_mutex_lock(&proc->mutex_RUs_tx))==0,"mutex_lock returns %d\n",ret); while (proc->instance_cnt_RUs < 0) { - pthread_cond_wait(&proc->cond_RUs,&proc->mutex_RUs_tx); // this unlocks mutex_rxtx while waiting and then locks it again + clock_gettime(CLOCK_REALTIME, &now); + abstime.tv_sec = now.tv_sec; + abstime.tv_nsec = now.tv_nsec + time_ns; + + if (abstime.tv_nsec >= 1000*1000*1000) { + abstime.tv_nsec -= 1000*1000*1000; + abstime.tv_sec += 1; + } + if((waitret = pthread_cond_timedwait(&proc->cond_RUs,&proc->mutex_RUs_tx,&abstime)) == 0) break; // this unlocks mutex_rxtx while waiting and then locks it again } proc->instance_cnt_RUs = -1; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); AssertFatal((ret = pthread_mutex_unlock(&proc->mutex_RUs_tx))==0,"mutex_unlock returns %d\n",ret); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL,0); - - if (waitret == ETIMEDOUT) { LOG_W(PHY,"Dropping TX slot (%d.%d) because FH is blocked more than 1 slot times (500us)\n",frame_tx,slot_tx); @@ -465,7 +466,6 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot ru = gNB->RU_list[i]; ru_proc = &ru->proc; - //AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_gNBs))==0,"ERROR pthread_mutex_lock failed on mutex_gNBs L1_thread_tx with ret=%d\n",ret); if (ru_proc->instance_cnt_gNBs == 0) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE, 1); @@ -473,13 +473,11 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot AssertFatal((ret=pthread_mutex_lock(&gNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); gNB->proc.RU_mask_tx = 0; AssertFatal((ret=pthread_mutex_unlock(&gNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); - //AssertFatal((ret=pthread_mutex_unlock( &ru_proc->mutex_gNBs ))==0,"mutex_unlock return %d\n",ret); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE, 0); return(-1); } - - AssertFatal((ret=pthread_mutex_lock(&ru_proc->mutex_gNBs))==0,"mutex_lock returned %d\n",ret); + AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_gNBs))==0,"ERROR pthread_mutex_lock failed on mutex_gNBs L1_thread_tx with ret=%d\n",ret); ru_proc->instance_cnt_gNBs = 0; ru_proc->timestamp_tx = timestamp_tx; @@ -571,7 +569,7 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { abstime.tv_sec += 1; } - // wake up TX for subframe n+sl_ahead + // wake up TX for subframe n+sf_ahead // lock the TX mutex and make sure the thread is ready AssertFatal((ret=pthread_mutex_timedlock(&L1_proc->mutex, &abstime)) == 0,"mutex_lock returns %d\n", ret); @@ -587,15 +585,15 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired // transmitted timestamp of the next TX slot (first). // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, - // we want to generate subframe (n+sl_ahead), so TS_tx = TX_rx+sl_ahead*samples_per_tti, - // and proc->slot_tx = proc->slot_rx+sl_ahead - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot); + // we want to generate subframe (n+sf_ahead), so TS_tx = TX_rx+sf_ahead*samples_per_tti, + // and proc->slot_tx = proc->slot_rx+sf_ahead + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_subframe); L1_proc->frame_rx = ru_proc->frame_rx; L1_proc->slot_rx = ru_proc->tti_rx; - L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; - L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame; + L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->slot_tx = (L1_proc->slot_rx + (fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; - LOG_D(PHY,"wakeupL1: passing parameter IC = %d, RX: %d.%d, TX: %d.%d to L1 sl_ahead = %d\n", L1_proc->instance_cnt, L1_proc->frame_rx, L1_proc->slot_rx, L1_proc->frame_tx, L1_proc->slot_tx, sl_ahead); + LOG_D(PHY,"wakeupL1: passing parameter IC = %d, RX: %d.%d, TX: %d.%d to L1 sf_ahead = %d\n", L1_proc->instance_cnt, L1_proc->frame_rx, L1_proc->slot_rx, L1_proc->frame_tx, L1_proc->slot_tx, sf_ahead); pthread_mutex_unlock( &L1_proc->mutex ); @@ -932,7 +930,6 @@ void init_gNB(int single_thread_flag,int wait_for_sync) { int inst; PHY_VARS_gNB *gNB; - LOG_I(PHY,"[nr-softmodem.c] gNB (%p) structure about to allocated RC.nb_nr_L1_inst:%d\n",RC.gNB,RC.nb_nr_L1_inst); if (RC.gNB == NULL) { RC.gNB = (PHY_VARS_gNB **) malloc((1+RC.nb_nr_L1_inst)*sizeof(PHY_VARS_gNB *)); diff --git a/executables/nr-ru.c b/executables/nr-ru.c index b2eb471016..fe10988462 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -50,6 +50,7 @@ #include #include #include +#include #undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all @@ -72,7 +73,7 @@ #include "SCHED_NR/sched_nr.h" #include "LAYER2/MAC/mac.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/MAC/mac_proto.h" #include "RRC/LTE/rrc_extern.h" #include "PHY_INTERFACE/phy_interface.h" @@ -81,7 +82,7 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "enb_config.h" -#include +#include #ifdef SMBV #include "PHY/TOOLS/smbv.h" @@ -104,14 +105,10 @@ static int DEFBFW[] = {0x00007fff}; #include "UTIL/OTG/otg_extern.h" #endif -#if defined(ENABLE_ITTI) - #if defined(ENABLE_USE_MME) - #include "s1ap_eNB.h" - #ifdef PDCP_USE_NETLINK - #include "SIMULATION/ETH_TRANSPORT/proto.h" - #endif - #endif -#endif +#include "s1ap_eNB.h" +#include "SIMULATION/ETH_TRANSPORT/proto.h" + + #include "T.h" #include "nfapi_interface.h" @@ -134,7 +131,8 @@ void configure_rru(int idx, void *arg); int attach_rru(RU_t *ru); int connect_rau(RU_t *ru); -extern uint16_t sl_ahead; +uint16_t sf_ahead; +uint16_t sl_ahead; extern int emulate_rf; extern int numerology; @@ -331,8 +329,9 @@ void fh_if5_south_in(RU_t *ru, NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; RU_proc_t *proc = &ru->proc; recv_IF5(ru, &proc->timestamp_rx, *tti, IF5_RRH_GW_UL); - proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_slot*20))&1023; - proc->tti_rx = (proc->timestamp_rx / fp->samples_per_slot)%20; + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023; + uint32_t idx_sf = proc->timestamp_rx / fp->samples_per_subframe; + proc->tti_rx = (idx_sf * fp->slots_per_subframe + (int)round((float)(proc->timestamp_rx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); if (proc->first_rx == 0) { if (proc->tti_rx != *tti) { @@ -390,12 +389,12 @@ void fh_if4p5_south_in(RU_t *ru, } while(proc->symbol_mask[sl] != symbol_mask_full); //caculate timestamp_rx, timestamp_tx based on frame and subframe - proc->tti_rx = sl; - proc->frame_rx = f; - proc->timestamp_rx = ((proc->frame_rx * fp->slots_per_frame) + proc->tti_rx ) * fp->samples_per_slot ; + proc->tti_rx = sl; + proc->frame_rx = f; + proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0); // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe); - proc->tti_tx = (sl+sl_ahead)%fp->slots_per_frame; - proc->frame_tx = (sl>(fp->slots_per_frame-sl_ahead)) ? (f+1)&1023 : f; + proc->tti_tx = (sl+(fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; + proc->frame_tx = (sl>(fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (f+1)&1023 : f; if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { @@ -502,8 +501,9 @@ void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *slot) { openair0_timestamp timestamp_tx; recv_IF5(ru, ×tamp_tx, *slot, IF5_RRH_GW_DL); // printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx); - tti_tx = (timestamp_tx/fp->samples_per_slot)%fp->slots_per_frame; - frame_tx = (timestamp_tx/(fp->samples_per_slot*fp->slots_per_frame))&1023; + frame_tx = (timestamp_tx / (fp->samples_per_subframe*10))&1023; + uint32_t idx_sf = timestamp_tx / fp->samples_per_subframe; + tti_tx = (idx_sf * fp->slots_per_subframe + (int)round((float)(timestamp_tx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); if (proc->first_tx != 0) { *slot = tti_tx; @@ -556,12 +556,12 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { if ((nr_slot_select(cfg,frame_tx,slot_tx) & NR_DOWNLINK_SLOT)>0) stop_meas(&ru->rx_fhaul); - proc->tti_tx = slot_tx; - proc->frame_tx = frame_tx; + proc->tti_tx = slot_tx; + proc->frame_tx = frame_tx; if ((frame_tx == 0)&&(slot_tx == 0)) proc->frame_tx_unwrap += 1024; - proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * fp->slots_per_frame) + (uint64_t)slot_tx) * (uint64_t)fp->samples_per_slot; + proc->timestamp_tx = (((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(slot_tx, fp, 0); LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,slot_tx); // dump VCD output for first RU in list @@ -628,26 +628,27 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { void *rxp[ru->nb_rx]; unsigned int rxs; int i; + uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp); openair0_timestamp ts,old_ts; AssertFatal(*slotslots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame); for (i=0; inb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][*slot*fp->samples_per_slot]; + rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)]; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); old_ts = proc->timestamp_rx; - LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",fp->samples_per_slot,*slot,rxp[0]); + LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",samples_per_slot,*slot,rxp[0]); if(emulate_rf) { wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - rxs = fp->samples_per_slot; + rxs = samples_per_slot; ts = old_ts + rxs; } else { rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, - fp->samples_per_slot, + samples_per_slot, ru->nb_rx); } @@ -657,21 +658,22 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { //AssertFatal(rxs == fp->samples_per_subframe, //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_subframe,rxs); - if (rxs != fp->samples_per_slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_slot,rxs); + if (rxs != samples_per_slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",samples_per_slot,rxs); if (proc->first_rx == 1) { ru->ts_offset = proc->timestamp_rx; proc->timestamp_rx = 0; } else { - if (proc->timestamp_rx - old_ts != fp->samples_per_slot) { - LOG_D(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_slot,ru->ts_offset); - ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_slot); + if (proc->timestamp_rx - old_ts != fp->get_samples_per_slot((*slot-1)%fp->slots_per_frame,fp)) { + LOG_D(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - samples_per_slot,ru->ts_offset); + ru->ts_offset += (proc->timestamp_rx - old_ts - samples_per_slot); proc->timestamp_rx = ts-ru->ts_offset; } } - proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_slot*fp->slots_per_frame))&1023; - proc->tti_rx = (proc->timestamp_rx / fp->samples_per_slot)%fp->slots_per_frame; + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023; + uint32_t idx_sf = proc->timestamp_rx / fp->samples_per_subframe; + proc->tti_rx = (idx_sf * fp->slots_per_subframe + (int)round((float)(proc->timestamp_rx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); // synchronize first reception to frame 0 subframe 0 LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n", ru->idx, @@ -687,7 +689,7 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { - LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot); + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, slot %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot); exit_fun("Exiting"); } @@ -704,7 +706,7 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); - if (rxs != fp->samples_per_slot) { + if (rxs != samples_per_slot) { //exit_fun( "problem receiving samples" ); LOG_E(PHY, "problem receiving samples\n"); } @@ -719,13 +721,13 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { unsigned int txs; int i,txsymb; T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(frame), T_INT(slot), - T_INT(0), T_BUFFER(&ru->common.txdata[0][slot * fp->samples_per_slot], fp->samples_per_slot * 4)); + T_INT(0), T_BUFFER(&ru->common.txdata[0][fp->get_samples_slot_timestamp(slot,fp,0)], fp->samples_per_subframe * 4)); int slot_type = nr_slot_select(cfg,frame,slot%fp->slots_per_frame); int prevslot_type = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame); int nextslot_type = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame); int sf_extension = 0; //sf_extension = ru->sf_extension; - int siglen=fp->samples_per_slot; + int siglen=fp->get_samples_per_slot(slot,fp); int flags=1; //nr_subframe_t SF_type = nr_slot_select(cfg,slot%fp->slots_per_frame); @@ -738,7 +740,10 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { txsymb++; } AssertFatal(txsymb>0,"illegal txsymb %d\n",txsymb); - siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples); + if(slot%(fp->slots_per_subframe/2)) + siglen = txsymb * (fp->ofdm_symbol_size + fp->nb_prefix_samples); + else + siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples); //+ ru->end_of_burst_delay; flags=3; // end of burst } @@ -754,12 +759,26 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { nextslot_type == NR_UPLINK_SLOT) { flags = 3; // end of burst } - + + if (fp->freq_range==nr_FR2) { + // the beam index is written in bits 8-10 of the flags + // bit 11 enables the gpio programming + int beam=0; + if (slot==0) beam = 11; //3 for boresight & 8 to enable + /* + if (slot==0 || slot==40) beam=0&8; + if (slot==10 || slot==50) beam=1&8; + if (slot==20 || slot==60) beam=2&8; + if (slot==30 || slot==70) beam=3&8; + */ + flags |= beam<<8; + } + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot ); for (i=0; inb_tx; i++) - txp[i] = (void *)&ru->common.txdata[i][(slot*fp->samples_per_slot)-sf_extension]; + txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot,fp,0)-sf_extension]; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp-ru->openair0_cfg.tx_sample_advance)&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); @@ -983,7 +1002,7 @@ void wakeup_gNB_L1s(RU_t *ru) { if (ru->num_gNB==1 && ru->gNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { // call gNB function directly char string[20]; - sprintf(string,"Incoming RU %d",ru->idx); + sprintf(string,"Incoming RU %u",ru->idx); LOG_D(PHY,"RU %d Call gNB_top\n",ru->idx); ru->gNB_top(gNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string,ru); } else { @@ -1181,7 +1200,7 @@ int setup_RU_buffers(RU_t *ru) { for (i=0; inb_rx; i++) { card = i/4; ant = i%4; - printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + printf("Mapping RU id %u, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); free(ru->common.rxdata[i]); ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant]; printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]); @@ -1195,7 +1214,7 @@ int setup_RU_buffers(RU_t *ru) { for (i=0; inb_tx; i++) { card = i/4; ant = i%4; - printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + printf("Mapping RU id %u, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); free(ru->common.txdata[i]); ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant]; printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]); @@ -1259,13 +1278,6 @@ void *ru_thread_tx( void *param ) { wait_on_condition(&proc->mutex_FH1,&proc->cond_FH1,&proc->instance_cnt_FH1,"ru_thread_tx"); printf( "ru_thread_tx ready\n"); - - if(ru->rfdevice.uhd_set_thread_priority != NULL) - { - LOG_I(PHY,"set ru_thread_tx uhd priority \n"); - ru->rfdevice.uhd_set_thread_priority(); - } - while (!oai_exit) { LOG_D(PHY,"ru_thread_tx: Waiting for TX processing\n"); @@ -1348,7 +1360,7 @@ void *ru_thread_tx( void *param ) { for (int j=0; jnum_RU; j++) { if (ru == gNB->RU_list[j]) { if ((gNB_proc->RU_mask_tx&(1< 0) - LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n", + LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n", gNB->Mod_id,gNB_proc->frame_rx,gNB_proc->slot_rx,ru->idx,gNB->num_RU,gNB_proc->RU_mask_tx); gNB_proc->RU_mask_tx |= (1<idx); + sprintf(threadname,"ru_thread %u",ru->idx); LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]); @@ -1442,6 +1454,7 @@ void *ru_thread( void *param ) { } } + sf_ahead = (uint16_t) ceil((float)6/(0x01<numerology_index)); LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); pthread_mutex_lock(&RC.ru_mutex); RC.ru_mask &= ~(1<idx); @@ -2026,7 +2039,7 @@ void set_function_spec_param(RU_t *ru) { reset_meas(&ru->compression); reset_meas(&ru->transport); ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + printf("openair0_transport_init returns %d for ru_id %u\n", ret, ru->idx); if (ret<0) { printf("Exiting, cannot initialize transport protocol\n"); @@ -2050,7 +2063,7 @@ void set_function_spec_param(RU_t *ru) { reset_meas(&ru->compression); reset_meas(&ru->transport); ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + printf("openair0_transport_init returns %d for ru_id %u\n", ret, ru->idx); if (ret<0) { printf("Exiting, cannot initialize transport protocol\n"); @@ -2073,7 +2086,7 @@ void set_function_spec_param(RU_t *ru) { ru->fh_south_out = tx_rf; // local synchronous RF TX ru->start_rf = start_rf; // need to start the local RF interface ru->stop_rf = stop_rf; - printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); + printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf); /* if (ru->function == gNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise fill_rf_config(ru,rf_config_file); @@ -2103,7 +2116,7 @@ void set_function_spec_param(RU_t *ru) { ru->ifdevice.eth_params = &ru->eth_params; ru->ifdevice.configure_rru = configure_ru; ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + printf("openair0_transport_init returns %d for ru_id %u\n", ret, ru->idx); if (ret<0) { printf("Exiting, cannot initialize transport protocol\n"); @@ -2129,7 +2142,7 @@ void set_function_spec_param(RU_t *ru) { ru->ifdevice.eth_params = &ru->eth_params; ru->ifdevice.configure_rru = configure_ru; ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + printf("openair0_transport_init returns %d for ru_id %u\n", ret, ru->idx); if (ret<0) { printf("Exiting, cannot initialize transport protocol\n"); @@ -2361,7 +2374,7 @@ void RCconfig_RU(void) RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); - RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].uptr); + RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].u64ptr); if (config_isparamset(RUParamList.paramarray[j], RU_BF_WEIGHTS_LIST_IDX)) { RC.ru[j]->nb_bfw = RUParamList.paramarray[j][RU_BF_WEIGHTS_LIST_IDX].numelt; diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index ad9b38ce7e..ccb3f28d98 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -131,7 +131,6 @@ extern uint64_t downlink_frequency[MAX_NUM_CCs][4]; extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; extern int rx_input_level_dBm; -extern uint8_t exit_missed_slots; extern uint64_t num_missed_slots; // counter for the number of missed slots extern int oaisim_flag; @@ -144,9 +143,7 @@ extern int sync_var; extern int transmission_mode; extern double cpuf; -#if defined(ENABLE_ITTI) - extern volatile int start_eNB; - extern volatile int start_UE; -#endif +extern volatile int start_eNB; +extern volatile int start_UE; #endif diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index a60420af33..04c515e556 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -71,9 +71,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "UTIL/OTG/otg_vars.h" #endif -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "PHY/INIT/phy_init.h" @@ -86,6 +84,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "executables/softmodem-common.h" #include "executables/thread-common.h" #include "NB_IoT_interface.h" +#include "x2ap_eNB.h" short nr_mod_table[NR_MOD_TABLE_SIZE_SHORT] = {0,0,16384,16384,-16384,-16384,16384,16384,16384,-16384,-16384,16384,-16384,-16384,7327,7327,7327,21981,21981,7327,21981,21981,7327,-7327,7327,-21981,21981,-7327,21981,-21981,-7327,7327,-7327,21981,-21981,7327,-21981,21981,-7327,-7327,-7327,-21981,-21981,-7327,-21981,-21981,10726,10726,10726,3576,3576,10726,3576,3576,10726,17876,10726,25027,3576,17876,3576,25027,17876,10726,17876,3576,25027,10726,25027,3576,17876,17876,17876,25027,25027,17876,25027,25027,10726,-10726,10726,-3576,3576,-10726,3576,-3576,10726,-17876,10726,-25027,3576,-17876,3576,-25027,17876,-10726,17876,-3576,25027,-10726,25027,-3576,17876,-17876,17876,-25027,25027,-17876,25027,-25027,-10726,10726,-10726,3576,-3576,10726,-3576,3576,-10726,17876,-10726,25027,-3576,17876,-3576,25027,-17876,10726,-17876,3576,-25027,10726,-25027,3576,-17876,17876,-17876,25027,-25027,17876,-25027,25027,-10726,-10726,-10726,-3576,-3576,-10726,-3576,-3576,-10726,-17876,-10726,-25027,-3576,-17876,-3576,-25027,-17876,-10726,-17876,-3576,-25027,-10726,-25027,-3576,-17876,-17876,-17876,-25027,-25027,-17876,-25027,-25027,8886,8886,8886,12439,12439,8886,12439,12439,8886,5332,8886,1778,12439,5332,12439,1778,5332,8886,5332,12439,1778,8886,1778,12439,5332,5332,5332,1778,1778,5332,1778,1778,8886,19547,8886,15993,12439,19547,12439,15993,8886,23101,8886,26655,12439,23101,12439,26655,5332,19547,5332,15993,1778,19547,1778,15993,5332,23101,5332,26655,1778,23101,1778,26655,19547,8886,19547,12439,15993,8886,15993,12439,19547,5332,19547,1778,15993,5332,15993,1778,23101,8886,23101,12439,26655,8886,26655,12439,23101,5332,23101,1778,26655,5332,26655,1778,19547,19547,19547,15993,15993,19547,15993,15993,19547,23101,19547,26655,15993,23101,15993,26655,23101,19547,23101,15993,26655,19547,26655,15993,23101,23101,23101,26655,26655,23101,26655,26655,8886,-8886,8886,-12439,12439,-8886,12439,-12439,8886,-5332,8886,-1778,12439,-5332,12439,-1778,5332,-8886,5332,-12439,1778,-8886,1778,-12439,5332,-5332,5332,-1778,1778,-5332,1778,-1778,8886,-19547,8886,-15993,12439,-19547,12439,-15993,8886,-23101,8886,-26655,12439,-23101,12439,-26655,5332,-19547,5332,-15993,1778,-19547,1778,-15993,5332,-23101,5332,-26655,1778,-23101,1778,-26655,19547,-8886,19547,-12439,15993,-8886,15993,-12439,19547,-5332,19547,-1778,15993,-5332,15993,-1778,23101,-8886,23101,-12439,26655,-8886,26655,-12439,23101,-5332,23101,-1778,26655,-5332,26655,-1778,19547,-19547,19547,-15993,15993,-19547,15993,-15993,19547,-23101,19547,-26655,15993,-23101,15993,-26655,23101,-19547,23101,-15993,26655,-19547,26655,-15993,23101,-23101,23101,-26655,26655,-23101,26655,-26655,-8886,8886,-8886,12439,-12439,8886,-12439,12439,-8886,5332,-8886,1778,-12439,5332,-12439,1778,-5332,8886,-5332,12439,-1778,8886,-1778,12439,-5332,5332,-5332,1778,-1778,5332,-1778,1778,-8886,19547,-8886,15993,-12439,19547,-12439,15993,-8886,23101,-8886,26655,-12439,23101,-12439,26655,-5332,19547,-5332,15993,-1778,19547,-1778,15993,-5332,23101,-5332,26655,-1778,23101,-1778,26655,-19547,8886,-19547,12439,-15993,8886,-15993,12439,-19547,5332,-19547,1778,-15993,5332,-15993,1778,-23101,8886,-23101,12439,-26655,8886,-26655,12439,-23101,5332,-23101,1778,-26655,5332,-26655,1778,-19547,19547,-19547,15993,-15993,19547,-15993,15993,-19547,23101,-19547,26655,-15993,23101,-15993,26655,-23101,19547,-23101,15993,-26655,19547,-26655,15993,-23101,23101,-23101,26655,-26655,23101,-26655,26655,-8886,-8886,-8886,-12439,-12439,-8886,-12439,-12439,-8886,-5332,-8886,-1778,-12439,-5332,-12439,-1778,-5332,-8886,-5332,-12439,-1778,-8886,-1778,-12439,-5332,-5332,-5332,-1778,-1778,-5332,-1778,-1778,-8886,-19547,-8886,-15993,-12439,-19547,-12439,-15993,-8886,-23101,-8886,-26655,-12439,-23101,-12439,-26655,-5332,-19547,-5332,-15993,-1778,-19547,-1778,-15993,-5332,-23101,-5332,-26655,-1778,-23101,-1778,-26655,-19547,-8886,-19547,-12439,-15993,-8886,-15993,-12439,-19547,-5332,-19547,-1778,-15993,-5332,-15993,-1778,-23101,-8886,-23101,-12439,-26655,-8886,-26655,-12439,-23101,-5332,-23101,-1778,-26655,-5332,-26655,-1778,-19547,-19547,-19547,-15993,-15993,-19547,-15993,-15993,-19547,-23101,-19547,-26655,-15993,-23101,-15993,-26655,-23101,-19547,-23101,-15993,-26655,-19547,-26655,-15993,-23101,-23101,-23101,-26655,-26655,-23101,-26655,-26655}; @@ -101,9 +100,7 @@ pthread_mutex_t sync_mutex; int sync_var=-1; //!< protected by mutex \ref sync_mutex. int config_sync_var=-1; -#if defined(ENABLE_ITTI) - volatile int start_gNB = 0; -#endif +volatile int start_gNB = 0; volatile int oai_exit = 0; static int wait_for_sync = 0; @@ -116,12 +113,10 @@ static int8_t threequarter_fs=0; uint64_t downlink_frequency[MAX_NUM_CCs][4]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; -//Temp fix for inexisting NR upper layer +//Temp fix for inexistent NR upper layer unsigned char NB_gNB_INST = 1; -#if defined(ENABLE_ITTI) - static char *itti_dump_file = NULL; -#endif +static char *itti_dump_file = NULL; int UE_scan = 1; int UE_scan_carrier = 0; @@ -148,11 +143,9 @@ double bw = 10.0e6; static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; -char rf_config_file[1024]="/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat"; int chain_offset=0; -int phy_test = 0; -uint8_t usim_test = 0; + uint8_t dci_Format = 0; uint8_t agregation_Level =0xFF; @@ -176,7 +169,6 @@ int otg_enabled; uint32_t target_dl_mcs = 28; //maximum allowed mcs uint32_t target_ul_mcs = 20; uint32_t timing_advance = 0; -uint8_t exit_missed_slots=1; uint64_t num_missed_slots=0; // counter for the number of missed slots @@ -189,7 +181,6 @@ int transmission_mode=1; int emulate_rf = 0; int numerology = 0; -static softmodem_params_t softmodem_params; static char *parallel_config = NULL; static char *worker_config = NULL; @@ -270,39 +261,13 @@ unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); } -#if !defined(ENABLE_ITTI) -void signal_handler(int sig) { - void *array[10]; - size_t size; - if (sig==SIGSEGV) { - // get void*'s for all entries on the stack - size = backtrace(array, 10); - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, 2); - exit(-1); - } else { - printf("trying to exit gracefully...\n"); - oai_exit = 1; - } -} -#endif #define KNRM "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KBLU "\x1B[34m" #define RESET "\033[0m" -#if defined(ENABLE_ITTI) -void signal_handler_itti(int sig) { - // Call exit function - char msg[256]; - memset(msg, 0, 256); - sprintf(msg, "caught signal %s\n", strsignal(sig)); - exit_function(__FILE__, __FUNCTION__, __LINE__, msg); -} -#endif void exit_function(const char *file, const char *function, const int line, const char *s) { int ru_id; @@ -329,13 +294,10 @@ void exit_function(const char *file, const char *function, const int line, const } sleep(1); //allow lte-softmodem threads to exit first -#if defined(ENABLE_ITTI) - itti_terminate_tasks (TASK_UNKNOWN); -#endif exit(1); } -#if defined(ENABLE_ITTI) + void *l2l1_task(void *arg) { MessageDef *message_p = NULL; int result; @@ -354,7 +316,7 @@ void *l2l1_task(void *arg) { switch (ITTI_MSG_ID(message_p)) { case INITIALIZE_MESSAGE: - /* Start eNB thread */ + /* Start gNB thread */ LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p)); start_gNB = 1; break; @@ -408,10 +370,9 @@ void *l2l1_task(void *arg) { */ return NULL; } -#endif int create_gNB_tasks(uint32_t gnb_nb) { - LOG_D(GNB_APP, "%s(gnb_nb:%d\n", __FUNCTION__, gnb_nb); + LOG_D(GNB_APP, "%s(gnb_nb:%d)\n", __FUNCTION__, gnb_nb); itti_wait_ready(1); if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { @@ -425,10 +386,22 @@ int create_gNB_tasks(uint32_t gnb_nb) { LOG_E(GNB_APP, "Create task for gNB APP failed\n"); return -1; } + if(itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0){ + LOG_E(SCTP, "Create task for SCTP failed\n"); + return -1; + } + if (is_x2ap_enabled()) { + if(itti_create_task(TASK_X2AP, x2ap_task, NULL) < 0){ + LOG_E(X2AP, "Create task for X2AP failed\n"); + } + } + else { + LOG_I(X2AP, "X2AP is disabled.\n"); + } } /* - # if defined(ENABLE_USE_MME) + if (EPC_MODE_ENABLED) { if (gnb_nb > 0) { if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) { LOG_E(SCTP, "Create task for SCTP failed\n"); @@ -452,7 +425,7 @@ int create_gNB_tasks(uint32_t gnb_nb) { } } - # endif + } */ if (gnb_nb > 0) { @@ -469,44 +442,21 @@ int create_gNB_tasks(uint32_t gnb_nb) { static void get_options(void) { - int tddflag, nonbiotflag; - uint32_t online_log_messages; - uint32_t glog_level, glog_verbosity; - uint32_t start_telnetsrv = 0; - uint32_t noS1; - uint32_t nokrnmod; + + paramdef_t cmdline_params[] = CMDLINE_PARAMS_DESC_GNB ; - paramdef_t cmdline_logparams[] = CMDLINE_LOGPARAMS_DESC_NR ; + config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); - config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL); - - if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) { - set_glog_onlinelog(online_log_messages); - } - - if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) { - set_glog(glog_level); - } - - if (start_telnetsrv) { - load_module_shlib("telnetsrv",NULL,0,NULL); - } - -#if T_TRACER - paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ; - config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL); -#endif - if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) { memset((void *)&RC,0,sizeof(RC)); /* Read RC configuration file */ NRRCConfig(); NB_gNB_INST = RC.nb_nr_inst; NB_RU = RC.nb_RU; - printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %d\n",NB_gNB_INST,RC.nb_nr_L1_inst,NB_RU); + printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %hhu\n",NB_gNB_INST,RC.nb_nr_L1_inst,NB_RU); } if(parallel_config != NULL) set_parallel_conf(parallel_config); @@ -516,14 +466,6 @@ static void get_options(void) { } -#if T_TRACER - int T_nowait = 0; /* by default we wait for the tracer */ - int T_port = 2021; /* default port to listen to to wait for the tracer */ - int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ -#endif - - - void set_default_frame_parms(nfapi_nr_config_request_scf_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { @@ -653,7 +595,7 @@ void init_openair0(void) { openair0_cfg[card].rx_gain[i] = RC.gNB[0]->rx_total_gain_dB; - openair0_cfg[card].configFilename = rf_config_file; + openair0_cfg[card].configFilename = get_softmodem_params()->rf_config_file; printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", card,i, openair0_cfg[card].tx_gain[i], openair0_cfg[card].rx_gain[i], @@ -699,12 +641,11 @@ void wait_gNBs(void) { printf("gNB L1 are configured\n"); } -#if defined(ENABLE_ITTI) /* * helper function to terminate a certain ITTI task */ void terminate_task(task_id_t task_id, module_id_t mod_id) { - LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); + LOG_I(GNB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); MessageDef *msg; msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE); itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); @@ -714,11 +655,11 @@ void terminate_task(task_id_t task_id, module_id_t mod_id) { extern void nr_phy_free_RU(RU_t *); int stop_L1L2(module_id_t gnb_id) { - LOG_W(ENB_APP, "stopping nr-softmodem\n"); + LOG_W(GNB_APP, "stopping nr-softmodem\n"); oai_exit = 1; if (!RC.ru) { - LOG_F(ENB_APP, "no RU configured\n"); + LOG_F(GNB_APP, "no RU configured\n"); return -1; } @@ -726,28 +667,28 @@ int stop_L1L2(module_id_t gnb_id) { if (RC.ru[gnb_id]) { if (RC.ru[gnb_id]->rfdevice.trx_stop_func) { RC.ru[gnb_id]->rfdevice.trx_stop_func(&RC.ru[gnb_id]->rfdevice); - LOG_I(ENB_APP, "turned off RU rfdevice\n"); + LOG_I(GNB_APP, "turned off RU rfdevice\n"); } else { - LOG_W(ENB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceding anyway!\n"); + LOG_W(GNB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceeding anyway!\n"); } if (RC.ru[gnb_id]->ifdevice.trx_stop_func) { RC.ru[gnb_id]->ifdevice.trx_stop_func(&RC.ru[gnb_id]->ifdevice); - LOG_I(ENB_APP, "turned off RU ifdevice\n"); + LOG_I(GNB_APP, "turned off RU ifdevice\n"); } else { - LOG_W(ENB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceding anyway!\n"); + LOG_W(GNB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceeding anyway!\n"); } } else { - LOG_W(ENB_APP, "no RU found for index %d\n", gnb_id); + LOG_W(GNB_APP, "no RU found for index %d\n", gnb_id); return -1; } /* these tasks need to pick up new configuration */ terminate_task(TASK_RRC_ENB, gnb_id); terminate_task(TASK_L2L1, gnb_id); - LOG_I(ENB_APP, "calling kill_gNB_proc() for instance %d\n", gnb_id); + LOG_I(GNB_APP, "calling kill_gNB_proc() for instance %d\n", gnb_id); kill_gNB_proc(gnb_id); - LOG_I(ENB_APP, "calling kill_NR_RU_proc() for instance %d\n", gnb_id); + LOG_I(GNB_APP, "calling kill_NR_RU_proc() for instance %d\n", gnb_id); kill_NR_RU_proc(gnb_id); oai_exit = 0; @@ -767,7 +708,7 @@ int restart_L1L2(module_id_t gnb_id) { RU_t *ru = RC.ru[gnb_id]; int cc_id; MessageDef *msg_p = NULL; - LOG_W(ENB_APP, "restarting nr-softmodem\n"); + LOG_W(GNB_APP, "restarting nr-softmodem\n"); /* block threads */ sync_var = -1; @@ -779,7 +720,7 @@ int restart_L1L2(module_id_t gnb_id) { /* TODO this should be done for all RUs associated to this gNB */ memcpy(&ru->nr_frame_parms, &RC.gNB[gnb_id]->frame_parms, sizeof(NR_DL_FRAME_PARMS)); set_function_spec_param(RC.ru[gnb_id]); - LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); + LOG_I(GNB_APP, "attempting to create ITTI tasks\n"); if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { LOG_E(RRC, "Create task for RRC eNB failed\n"); @@ -815,7 +756,6 @@ int restart_L1L2(module_id_t gnb_id) { pthread_mutex_unlock(&sync_mutex); return 0; } -#endif static void wait_nfapi_init(char *thread_name) { printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name); @@ -862,7 +802,7 @@ int main( int argc, char **argv ) if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == NULL) { exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); } - + set_softmodem_sighandler(); #ifdef DEBUG_CONSOLE setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); @@ -874,7 +814,7 @@ int main( int argc, char **argv ) configure_linux(); printf("Reading in command-line options\n"); get_options (); - get_common_options(); + get_common_options(SOFTMODEM_GNB_BIT ); if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { fprintf(stderr,"Getting configuration failed\n"); @@ -895,26 +835,22 @@ int main( int argc, char **argv ) } cpuf=get_cpu_freq_GHz(); -#if defined(ENABLE_ITTI) itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); // initialize mscgen log after ITTI MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); -#endif + init_opt(); #ifdef PDCP_USE_NETLINK +if(!IS_SOFTMODEM_NOS1) netlink_init(); #if defined(PDCP_USE_NETLINK_QUEUES) pdcp_netlink_init(); #endif #endif -#if !defined(ENABLE_ITTI) - // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); -#endif + #ifndef PACKAGE_VERSION # define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" #endif @@ -923,7 +859,6 @@ init_opt(); if(IS_SOFTMODEM_NOS1) init_pdcp(); - if (RC.nb_nr_inst > 0) { // don't create if node doesn't connect to RRC/S1/GTP AssertFatal(create_gNB_tasks(1) == 0,"cannot create ITTI tasks\n"); @@ -932,8 +867,6 @@ init_opt(); RCconfig_L1(); } - - /* Start the agent. If it is turned off in the configuration, it won't start */ /* RCconfig_nr_flexran(); @@ -999,7 +932,7 @@ init_opt(); if (RC.nb_RU >0) { printf("Initializing RU threads\n"); - init_NR_RU(rf_config_file); + init_NR_RU(get_softmodem_params()->rf_config_file); for (ru_id=0; ru_idrf_map.card=0; @@ -1047,20 +980,34 @@ init_opt(); // wait for end of program printf("TYPE TO TERMINATE\n"); //getchar(); -#if defined(ENABLE_ITTI) printf("Entering ITTI signals handler\n"); itti_wait_tasks_end(); printf("Returned from ITTI signal handler\n"); oai_exit=1; printf("oai_exit=%d\n",oai_exit); -#else - while (oai_exit==0) - sleep(1); + // stop threads +/*#ifdef XFORMS - printf("Terminating application - oai_exit=%d\n",oai_exit); -#endif - // stop threads + printf("waiting for XFORMS thread\n"); + + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); + + fl_hide_form(form_stats_l2->stats_form); + fl_free_form(form_stats_l2->stats_form); + + for(UE_id=0; UE_idphy_scope_gNB); + fl_free_form(form_enb[CC_id][UE_id]->phy_scope_gNB); + } + } + } + +#endif*/ printf("stopping MODEM threads\n"); // cleanup stop_gNB(NB_gNB_INST); diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h index d7b121ecd2..27e3ba1e3e 100644 --- a/executables/nr-softmodem.h +++ b/executables/nr-softmodem.h @@ -18,10 +18,6 @@ /* optname helpstr paramflags XXXptr defXXXval type numelt */ /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ #define CMDLINE_PARAMS_DESC_GNB { \ - {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)},\ - {"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \ - {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \ - {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \ {"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \ {"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&wait_for_sync, defintval:0, TYPE_INT, 0}, \ {"single-thread-disable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:1, TYPE_INT, 0}, \ @@ -34,34 +30,13 @@ {"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ {"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ - {"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \ - {"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \ {"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&numerology, defintval:0, TYPE_INT, 0}, \ {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&emulate_rf, defintval:0, TYPE_INT, 0}, \ {"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \ {"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \ {"s" , CONFIG_HLP_SNR, 0, dblptr:&snr_dB, defdblval:25, TYPE_DOUBLE, 0}, \ - {"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, iptr:&nonbiotflag, defintval:0, TYPE_INT, 0}, \ - {"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, uptr:&noS1, defintval:0, TYPE_INT, 0}, \ - {"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0} \ } -#define SOFTMODEM_NOS1_BIT (1<<0) -#define SOFTMODEM_NOKRNMOD_BIT (1<<1) -#define SOFTMODEM_RFSIM_BIT (1<<10) - -#define IS_SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT) -#define IS_SOFTMODEM_NOKRNMOD ( get_softmodem_optmask() & SOFTMODEM_NOKRNMOD_BIT) - -#define IS_SOFTMODEM_RFSIM ( get_softmodem_optmask() & SOFTMODEM_RFSIM_BIT) -extern uint64_t get_softmodem_optmask(void); -extern void get_common_options(void); - -extern int T_port; -extern int T_nowait; -extern int T_dont_fork; - - #include "threads_t.h" extern threads_t threads; diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d79c1028fd..131710ee02 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -18,7 +18,7 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ - +#include "executables/thread-common.h" #include "executables/nr-uesoftmodem.h" #include "LAYER2/NR_MAC_UE/mac.h" @@ -55,6 +55,9 @@ extern char do_forms; #endif +// Missing stuff? +int next_ra_frame = 0; +module_id_t next_Mod_id = 0; extern double cpuf; //static nfapi_nr_config_request_t config_t; @@ -239,7 +242,8 @@ static void UE_synch(void *arg) { if (nr_initial_sync( &syncD->proc, UE, UE->mode,2) == 0) { freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync - hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_slot; + hw_slot_offset = ((UE->rx_offset<<1) / UE->frame_parms.samples_per_subframe * UE->frame_parms.slots_per_subframe) + + round((float)((UE->rx_offset<<1) % UE->frame_parms.samples_per_subframe)/UE->frame_parms.samples_per_slot0); LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %lu, UL %lu), UE_scan_carrier %d\n", hw_slot_offset, freq_offset, @@ -441,7 +445,7 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { proc->frame_rx = dcireq.dl_config_req.sfn; } scheduled_response.frame = proc->frame_rx; - scheduled_response.slot = proc->nr_tti_rx; + scheduled_response.slot = proc->nr_tti_rx; nr_ue_scheduled_response(&scheduled_response); } @@ -456,6 +460,7 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { LOG_D(PHY,"phy_procedures_nrUE_RX: slot:%d, time %lu\n", proc->nr_tti_rx, (rdtsc()-a)/3500); //printf(">>> nr_ue_pdcch_procedures ended\n"); #endif + if(IS_SOFTMODEM_NOS1){ //&& proc->nr_tti_rx==1 //Hardcoded rnti value protocol_ctxt_t ctxt; @@ -463,7 +468,6 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { 0x1234, proc->frame_rx, proc->nr_tti_rx, 0); pdcp_run(&ctxt); - pdcp_fifo_flush_sdus(&ctxt); } } @@ -503,63 +507,85 @@ void UE_processing(void *arg) { UE_nr_rxtx_proc_t *proc = &rxtxD->proc; PHY_VARS_NR_UE *UE = rxtxD->UE; + uint8_t gNB_id = 0; + + // params for UL time alignment procedure + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id]; + uint8_t numerology = UE->frame_parms.numerology_index; + uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL; + int slot_tx = proc->nr_tti_tx; + int frame_tx = proc->frame_tx; + + /* UL time alignment + // If the current tx frame and slot match the TA configuration in ul_time_alignment + // then timing advance is processed and set to be applied in the next UL transmission */ + if (UE->mac_enabled == 1) { + + if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot){ + LOG_D(PHY,"Applying timing advance -- frame %d -- slot %d\n", frame_tx, slot_tx); + + //if (nfapi_mode!=3){ + nr_process_timing_advance(UE->Mod_id, UE->CC_id, ul_time_alignment->ta_command, numerology, bwp_ul_NB_RB); + ul_time_alignment->ta_frame = -1; + ul_time_alignment->ta_slot = -1; + //} + } + } + processSlotRX(UE, proc); processSlotTX(UE, proc); } -void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { - void *rxp[NB_ANTENNAS_RX]; +void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) { void *dummy_tx[UE->frame_parms.nb_antennas_tx]; for (int i=0; iframe_parms.nb_antennas_tx; i++) - dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4); + dummy_tx[i]=malloc16_clear(writeBlockSize*4); - for(int x=0; x<20; x++) { // two frames for initial sync - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = ((void *)&UE->common_vars.rxdata[i][0]) + 4*x*UE->frame_parms.samples_per_subframe; - - AssertFatal( UE->frame_parms.samples_per_subframe == - UE->rfdevice.trx_read_func(&UE->rfdevice, - timestamp, - rxp, - UE->frame_parms.samples_per_subframe, - UE->frame_parms.nb_antennas_rx), ""); - } + AssertFatal( writeBlockSize == + UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp, + dummy_tx, + writeBlockSize, + UE->frame_parms.nb_antennas_tx, + 4),""); for (int i=0; iframe_parms.nb_antennas_tx; i++) free(dummy_tx[i]); } -void trashFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { - void *dummy_tx[UE->frame_parms.nb_antennas_tx]; +void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) { - for (int i=0; iframe_parms.nb_antennas_tx; i++) - dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4); + void *rxp[NB_ANTENNAS_RX]; - void *dummy_rx[UE->frame_parms.nb_antennas_rx]; + for(int x=0; x<20; x++) { // two frames for initial sync + for (int slot=0; slotframe_parms.slots_per_subframe; slot ++ ) { + for (int i=0; iframe_parms.nb_antennas_rx; i++) { + if (toTrash) + rxp[i]=malloc16(UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms)*4); + else + rxp[i] = ((void *)&UE->common_vars.rxdata[i][0]) + + 4*((x*UE->frame_parms.samples_per_subframe)+ + UE->frame_parms.get_samples_slot_timestamp(slot,&UE->frame_parms,0)); + } + + AssertFatal( UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms) == + UE->rfdevice.trx_read_func(&UE->rfdevice, + timestamp, + rxp, + UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms), + UE->frame_parms.nb_antennas_rx), ""); - for (int i=0; iframe_parms.nb_antennas_rx; i++) - dummy_rx[i]=malloc16(UE->frame_parms.samples_per_subframe*4); - - for (int sf=0; sfrfdevice.trx_read_func(&UE->rfdevice, - timestamp, - dummy_rx, - UE->frame_parms.samples_per_subframe, - UE->frame_parms.nb_antennas_rx); - if (IS_SOFTMODEM_RFSIM ) { - usleep(1000); // slow down, as would do actuall rf to let cpu for the synchro thread + if (IS_SOFTMODEM_RFSIM) + dummyWrite(UE,*timestamp, UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms)); + if (toTrash) + for (int i=0; iframe_parms.nb_antennas_rx; i++) + free(rxp[i]); } } - for (int i=0; iframe_parms.nb_antennas_tx; i++) - free(dummy_tx[i]); - - for (int i=0; iframe_parms.nb_antennas_rx; i++) - free(dummy_rx[i]); } void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { @@ -567,22 +593,21 @@ void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); void *dummy_tx[UE->frame_parms.nb_antennas_tx]; - for (int i=0; iframe_parms.nb_antennas_tx; i++) - dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4); - + *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms); for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) { int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ; + // we write before read becasue gNB waits for UE to write and both executions halt + // this happens here as the read size is samples_per_subframe which is very much larger than samp_per_slot + if (IS_SOFTMODEM_RFSIM) dummyWrite(UE,*timestamp, unitTransfer); AssertFatal(unitTransfer == UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, UE->frame_parms.nb_antennas_rx),""); + *timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write } - for (int i=0; iframe_parms.nb_antennas_tx; i++) - free(dummy_tx[i]); - } int computeSamplesShift(PHY_VARS_NR_UE *UE) { @@ -608,6 +633,22 @@ int computeSamplesShift(PHY_VARS_NR_UE *UE) { return 0; } +static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) { + if (fp->numerology_index == 0) + return fp->nb_prefix_samples0 + fp->ofdm_symbol_size; + int num_samples = (slot%(fp->slots_per_subframe/2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; + num_samples += fp->ofdm_symbol_size; + return num_samples; +} + +static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) { + int rem_samples = fp->get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp); + int next_slot_first_symbol = 0; + if (slot < (fp->slots_per_frame-1)) + next_slot_first_symbol = get_firstSymSamp(slot+1, fp); + return rem_samples + next_slot_first_symbol; +} + void *UE_thread(void *arg) { //this thread should be over the processing thread to keep in real time PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg; @@ -624,6 +665,7 @@ void *UE_thread(void *arg) { int thread_idx=0; notifiedFIFO_t freeBlocks; initNotifiedFIFO_nothreadSafe(&freeBlocks); + NR_UE_MAC_INST_t *mac = get_mac_inst(0); for (int i=0; iproc.decoded_frame_rx+trashed_frames) % MAX_FRAME_NUMBER; + decoded_frame_rx=(tmp->proc.decoded_frame_rx + (!UE->init_sync_frame) + trashed_frames) % MAX_FRAME_NUMBER; delNotifiedFIFO_elt(res); } else { - trashFrame(UE, ×tamp); - trashed_frames++; + readFrame(UE, ×tamp, true); + trashed_frames+=2; continue; } } - AssertFatal( !syncRunning, "At this point synchronisation can't be running\n"); + AssertFatal( !syncRunning, "At this point synchronization can't be running\n"); if (!UE->is_synchronized) { - readFrame(UE, ×tamp); + readFrame(UE, ×tamp, false); notifiedFIFO_elt_t *Msg=newNotifiedFIFO_elt(sizeof(syncData_t),0,&nf,UE_synch); syncData_t *syncMsg=(syncData_t *)NotifiedFifoData(Msg); syncMsg->UE=UE; @@ -679,8 +721,8 @@ void *UE_thread(void *arg) { // we have the decoded frame index in the return of the synch process // and we shifted above to the first slot of next frame decoded_frame_rx++; - // we do ++ first in the regular processing, so it will be beging of frame; - absolute_slot=decoded_frame_rx*nb_slot_frame + nb_slot_frame -1; + // we do ++ first in the regular processing, so it will be begin of frame; + absolute_slot=decoded_frame_rx*nb_slot_frame -1; continue; } @@ -717,26 +759,25 @@ void *UE_thread(void *arg) { }*/ #endif + int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms); for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.ofdm_symbol_size+ - UE->frame_parms.nb_prefix_samples0+ - slot_nr*UE->frame_parms.samples_per_slot]; + rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp+ + UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)]; for (int i=0; iframe_parms.nb_antennas_tx; i++) - txp[i] = (void *)&UE->common_vars.txdata[i][((curMsg->proc.nr_tti_rx + DURATION_RX_TO_TX)%nb_slot_frame)*UE->frame_parms.samples_per_slot]; + txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp( + ((curMsg->proc.nr_tti_rx + DURATION_RX_TO_TX)%nb_slot_frame),&UE->frame_parms,0)]; int readBlockSize, writeBlockSize; if (slot_nr<(nb_slot_frame - 1)) { - readBlockSize=UE->frame_parms.samples_per_slot; - writeBlockSize=UE->frame_parms.samples_per_slot; + readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms); + writeBlockSize=UE->frame_parms.get_samples_per_slot(curMsg->proc.nr_tti_tx,&UE->frame_parms); } else { UE->rx_offset_diff = computeSamplesShift(UE); - readBlockSize=UE->frame_parms.samples_per_slot - - UE->frame_parms.ofdm_symbol_size - - UE->frame_parms.nb_prefix_samples0 - + readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) - UE->rx_offset_diff; - writeBlockSize=UE->frame_parms.samples_per_slot - + writeBlockSize=UE->frame_parms.get_samples_per_slot(curMsg->proc.nr_tti_tx,&UE->frame_parms) - UE->rx_offset_diff; } @@ -750,8 +791,8 @@ void *UE_thread(void *arg) { AssertFatal( writeBlockSize == UE->rfdevice.trx_write_func(&UE->rfdevice, timestamp+ - (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot) - - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - + UE->frame_parms.get_samples_slot_timestamp(slot_nr, + &UE->frame_parms,DURATION_RX_TO_TX) - firstSymSamp - openair0_cfg[0].tx_sample_advance, txp, writeBlockSize, @@ -760,7 +801,7 @@ void *UE_thread(void *arg) { if( slot_nr==(nb_slot_frame-1)) { // read in first symbol of next frame and adjust for timing drift - int first_symbols=writeBlockSize-readBlockSize; + int first_symbols=UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0; // first symbol of every frames if ( first_symbols > 0 ) AssertFatal(first_symbols == @@ -774,8 +815,9 @@ void *UE_thread(void *arg) { } curMsg->proc.timestamp_tx = timestamp+ - (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot)- - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; + UE->frame_parms.get_samples_slot_timestamp(slot_nr, + &UE->frame_parms,DURATION_RX_TO_TX) - firstSymSamp; + notifiedFIFO_elt_t *res; while (nbSlotProcessing >= RX_NB_TH) { @@ -784,7 +826,8 @@ void *UE_thread(void *arg) { processingData_t *tmp=(processingData_t *)res->msgData; if (tmp->proc.decoded_frame_rx != -1) - decoded_frame_rx=tmp->proc.decoded_frame_rx; + decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx); + //decoded_frame_rx=tmp->proc.decoded_frame_rx; pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); } @@ -810,7 +853,8 @@ void *UE_thread(void *arg) { processingData_t *tmp=(processingData_t *)res->msgData; if (tmp->proc.decoded_frame_rx != -1) - decoded_frame_rx=tmp->proc.decoded_frame_rx; + decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx); + //decoded_frame_rx=tmp->proc.decoded_frame_rx; pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); } @@ -849,3 +893,16 @@ void init_NR_UE_threads(int nb_inst) { } } + +/* HACK: this function is needed to compile the UE + * fix it somehow + */ +int8_t find_dlsch(uint16_t rnti, + PHY_VARS_eNB *eNB, + find_type_t type) +{ + printf("you cannot read this\n"); + abort(); +} + +void multicast_link_write_sock(int groupP, char *dataP, uint32_t sizeP) {} diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 63b1df0bd9..53e407923f 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -27,6 +27,7 @@ #include "assertions.h" #include "PHY/types.h" #include "PHY/defs_nr_UE.h" +#include "SCHED_NR_UE/defs.h" #include "common/ran_context.h" #include "common/config/config_userapi.h" //#include "common/utils/threadPool/thread-pool.h" @@ -82,7 +83,7 @@ unsigned short config_frames[4] = {2,9,11,13}; /* Callbacks, globals and object handlers */ extern void reset_stats( FL_OBJECT *, long ); -//extern void initTpool(char *params,tpool_t *pool, bool performanceMeas); +//extern void initTpool(char *params, tpool_t *pool, bool performanceMeas); /* Forms and Objects */ @@ -111,6 +112,16 @@ static pthread_t forms_thread; //xforms #include "executables/softmodem-common.h" #include "executables/thread-common.h" +// Raphael : missing +pthread_cond_t nfapi_sync_cond; +pthread_mutex_t nfapi_sync_mutex; +int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex +uint16_t sf_ahead=6; //??? value ??? +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. +int config_sync_var=-1; + RAN_CONTEXT_t RC; volatile int start_eNB = 0; volatile int start_UE = 0; @@ -124,6 +135,7 @@ int threequarter_fs=0; uint64_t downlink_frequency[MAX_NUM_CCs][4]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; +//int32_t uplink_counter = 0; extern int16_t nr_dlsch_demod_shift; @@ -152,11 +164,9 @@ double bw = 10.0e6; static int tx_max_power[MAX_NUM_CCs] = {0}; -char rf_config_file[1024]; int chain_offset=0; -int phy_test = 0; -uint8_t usim_test = 0; + uint8_t dci_Format = 0; uint8_t agregation_Level =0xFF; @@ -167,7 +177,6 @@ uint8_t nb_antenna_rx = 1; char ref[128] = "internal"; char channels[128] = "0"; -static softmodem_params_t softmodem_params; static char *parallel_config = NULL; static char *worker_config = NULL; @@ -186,7 +195,6 @@ int16_t node_synch_ref[MAX_NUM_CCs]; uint32_t target_dl_mcs = 28; //maximum allowed mcs uint32_t target_ul_mcs = 20; uint32_t timing_advance = 0; -uint8_t exit_missed_slots=1; uint64_t num_missed_slots=0; // counter for the number of missed slots @@ -206,6 +214,10 @@ int oaisim_flag=0; int emulate_rf = 0; tpool_t *Tpool; +#ifdef UE_DLSCH_PARALLELISATION +tpool_t *Tpool_dl; +#endif + char *usrp_args=NULL; @@ -260,7 +272,7 @@ void exit_function(const char *file, const char *function, const int line, const } sleep(1); //allow lte-softmodem threads to exit first - itti_terminate_tasks (TASK_UNKNOWN); + exit(1); } @@ -323,8 +335,6 @@ void init_scope(void) { } - -#if defined(ENABLE_ITTI) void *l2l1_task(void *arg) { MessageDef *message_p = NULL; int result; @@ -364,7 +374,7 @@ void *l2l1_task(void *arg) { return NULL; } -#endif + int16_t dlsch_demod_shift; @@ -373,28 +383,12 @@ static void get_options(void) { int tddflag=0, nonbiotflag, vcdflag=0; char *loopfile=NULL; int dumpframe=0; - uint32_t online_log_messages; - uint32_t glog_level, glog_verbosity; - uint32_t start_telnetsrv=0; + //uint32_t noS1; //uint32_t nokrnmod; paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC_UE ; - paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC_NR ; config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); - config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL); - - if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) { - set_glog_onlinelog(online_log_messages); - } - - if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) { - set_glog(glog_level); - } - - if (start_telnetsrv) { - load_module_shlib("telnetsrv",NULL,0,NULL); - } paramdef_t cmdline_uemodeparams[] = CMDLINE_UEMODEPARAMS_DESC; paramdef_t cmdline_ueparams[] = CMDLINE_NRUEPARAMS_DESC; @@ -435,19 +429,19 @@ static void get_options(void) { /*if (frame_parms[0]->N_RB_DL !=0) { if ( frame_parms[0]->N_RB_DL < 6 ) { frame_parms[0]->N_RB_DL = 6; - printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL); + printf ( "%i: Invalid number of resource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL); } if ( frame_parms[0]->N_RB_DL > 100 ) { frame_parms[0]->N_RB_DL = 100; - printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL); + printf ( "%i: Invalid number of resource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL); } if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) { frame_parms[0]->N_RB_DL = 50; - printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL); + printf ( "%i: Invalid number of resource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL); } if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) { frame_parms[0]->N_RB_DL = 25; - printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL); + printf ( "%i: Invalid number of resource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL); } UE_scan = 0; frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL; @@ -463,10 +457,6 @@ static void get_options(void) { tx_gain[0][CC_id] = tx_gain[0][0]; } -#if T_TRACER - paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ; - config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL); -#endif if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) && (!(CONFIG_ISFLAGSET(CONFIG_NOOOPT))) ) { // Here the configuration file is the XER encoded UE capabilities @@ -477,11 +467,6 @@ static void get_options(void) { } /* UE with config file */ } -#if T_TRACER - int T_nowait = 0; /* by default we wait for the tracer */ - int T_port = 2021; /* default port to listen to to wait for the tracer */ - int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ -#endif void set_default_frame_parms(NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { int CC_id; @@ -527,6 +512,14 @@ void init_openair0(void) { LOG_E(PHY,"Unsupported numerology! FR2 supports only 120KHz SCS for now.\n"); exit(-1); } + }else if(frame_parms[0]->N_RB_DL == 32) { + if (numerology==3) { + openair0_cfg[card].sample_rate=61.44e6; + openair0_cfg[card].samples_per_frame = 614400; + } else { + LOG_E(PHY,"Unsupported numerology! FR2 supports only 120KHz SCS for now.\n"); + exit(-1); + } }else if(frame_parms[0]->N_RB_DL == 217) { if (numerology==1) { if (frame_parms[0]->threequarter_fs) { @@ -566,7 +559,7 @@ void init_openair0(void) { } else if (numerology==1) { if (frame_parms[0]->threequarter_fs) { openair0_cfg[card].sample_rate=46.08e6; - openair0_cfg[card].samples_per_frame = 480800; + openair0_cfg[card].samples_per_frame = 460800; } else { openair0_cfg[card].sample_rate=61.44e6; @@ -599,7 +592,7 @@ void init_openair0(void) { else //FDD openair0_cfg[card].duplex_mode = duplex_mode_FDD; - printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, + printf("HW: Configuring card %d, nb_antennas_tx/rx %hhu/%hhu\n",card, PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx, PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx); openair0_cfg[card].Mod_id = 0; @@ -622,7 +615,7 @@ void init_openair0(void) { openair0_cfg[card].autocal[i] = 1; openair0_cfg[card].tx_gain[i] = tx_gain[0][i]; openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB - rx_gain_off; - openair0_cfg[card].configFilename = rf_config_file; + openair0_cfg[card].configFilename = get_softmodem_params()->rf_config_file; printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", card,i, openair0_cfg[card].tx_gain[i], openair0_cfg[card].rx_gain[i], @@ -665,7 +658,7 @@ int main( int argc, char **argv ) { if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == NULL) { exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); } - + set_softmodem_sighandler(); CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); set_default_frame_parms(frame_parms); mode = normal_txrx; @@ -675,7 +668,7 @@ int main( int argc, char **argv ) { logInit(); // get options and fill parameters from configuration file get_options (); //Command-line options, enb_properties - get_common_options(); + get_common_options(SOFTMODEM_5GUE_BIT ); #if T_TRACER T_Config_Init(); #endif @@ -685,10 +678,17 @@ int main( int argc, char **argv ) { Tpool = &pool; char params[]="-1,-1"; initTpool(params, Tpool, false); +#ifdef UE_DLSCH_PARALLELISATION + tpool_t pool_dl; + Tpool_dl = &pool_dl; + char params_dl[]="-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1"; + initTpool(params_dl, Tpool_dl, false); +#endif cpuf=get_cpu_freq_GHz(); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); init_opt() ; + load_nrLDPClib(); if (ouput_vcd) { vcd_signal_dumper_init("/tmp/openair_dump_nrUE.vcd"); @@ -725,6 +725,7 @@ int main( int argc, char **argv ) { LOG_I(PHY,"Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms[CC_id]->nb_antennas_rx, frame_parms[CC_id]->nb_antennas_tx); PHY_vars_UE_g[0][CC_id] = (PHY_VARS_NR_UE *)malloc(sizeof(PHY_VARS_NR_UE)); + UE[CC_id] = PHY_vars_UE_g[0][CC_id]; memset(UE[CC_id],0,sizeof(PHY_VARS_NR_UE)); @@ -734,9 +735,18 @@ int main( int argc, char **argv ) { fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config; nr_init_frame_parms_ue(frame_parms[CC_id],nrUE_config,NORMAL); + + // Overwrite DL frequency (for FR2 testing) + if (downlink_frequency[0][0]!=0) + frame_parms[CC_id]->dl_CarrierFreq = downlink_frequency[0][0]; init_nr_ue_vars(UE[CC_id],frame_parms[CC_id],0,abstraction_flag); + if (get_softmodem_params()->phy_test==1) + UE[CC_id]->mac_enabled = 0; + else + UE[CC_id]->mac_enabled = 1; + UE[CC_id]->mac_enabled = 1; UE[CC_id]->if_inst = nr_ue_if_module_init(0); UE[CC_id]->UE_scan = UE_scan; diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index f79f56b333..7fad43e897 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -54,29 +54,22 @@ {"usrp-args", CONFIG_HLP_USRP_ARGS, 0, strptr:(char **)&usrp_args, defstrval:"type=b200", TYPE_STRING, 0} \ } -#define DEFAULT_DLF 2680000000 - /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /* command line parameters common to eNodeB and UE */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ #define CMDLINE_PARAMS_DESC_UE { \ - {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)},\ - {"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \ - {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \ - {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \ {"clock-source", CONFIG_HLP_EXCCLK, 0, iptr:&clock_source, defintval:0, TYPE_INT, 0}, \ {"single-thread-disable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:1, TYPE_INT, 0}, \ {"nr-dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&nr_dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \ {"A" , CONFIG_HLP_TADV, 0, uptr:&timing_advance, defintval:0, TYPE_UINT, 0}, \ - {"C" , CONFIG_HLP_DLF, 0, u64ptr:&(downlink_frequency[0][0]), defuintval:2680000000, TYPE_UINT64, 0}, \ + {"C" , CONFIG_HLP_DLF, 0, u64ptr:&(downlink_frequency[0][0]), defuintval:0,TYPE_UINT64, 0}, \ {"a" , CONFIG_HLP_CHOFF, 0, iptr:&chain_offset, defintval:0, TYPE_INT, 0}, \ {"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:&do_forms, defintval:0, TYPE_INT, 0}, \ {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, iptr:&threequarter_fs, defintval:0, TYPE_INT, 0}, \ {"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ {"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ - {"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \ {"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \ {"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, iptr:&vcdflag, defintval:0, TYPE_INT, 0}, \ {"numerology" , CONFIG_HLP_NUMEROLOGY, 0, iptr:&numerology, defintval:0, TYPE_INT, 0}, \ @@ -105,4 +98,5 @@ extern void print_opp_meas(void); void *UE_thread(void *arg); void init_nr_ue_vars(PHY_VARS_NR_UE *ue, NR_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, uint8_t abstraction_flag); extern tpool_t *Tpool; +extern tpool_t *Tpool_dl; #endif diff --git a/targets/RT/USER/lte-softmodem-common.c b/executables/softmodem-common.c similarity index 52% rename from targets/RT/USER/lte-softmodem-common.c rename to executables/softmodem-common.c index 6bd8835a92..f714fa2bd4 100644 --- a/targets/RT/USER/lte-softmodem-common.c +++ b/executables/softmodem-common.c @@ -20,26 +20,34 @@ */ /*! \file lte-softmodem-common.c - * \brief Top-level threads for eNodeB + * \brief common code for 5G and LTE softmodem main xNB and UEs source (nr-softmodem.c, lte-softmodem.c...) * \author Nokia BellLabs France, francois Taburet - * \date 2012 + * \date 2020 * \version 0.1 - * \company Eurecom + * \company Nokia BellLabs France * \email: francois.taburet@nokia-bell-labs.com * \note * \warning */ - -#include "lte-softmodem.h" +#include +#include +#include #include "UTIL/OPT/opt.h" #include "common/config/config_userapi.h" #include "common/utils/load_module_shlib.h" +#include "common/utils/telnetsrv/telnetsrv.h" #include "executables/thread-common.h" -#include +#include "common/utils/LOG/log.h" +#include "softmodem-common.h" + static softmodem_params_t softmodem_params; char *parallel_config=NULL; char *worker_config=NULL; + +static mapping softmodem_funcs[] = MAPPING_SOFTMODEM_FUNCTIONS; +static struct timespec start; + uint64_t get_softmodem_optmask(void) { return softmodem_params.optmask; } @@ -53,7 +61,26 @@ softmodem_params_t *get_softmodem_params(void) { return &softmodem_params; } -void get_common_options(void) { +int32_t check_execmask(uint64_t execmask) { + char *softmodemfunc=map_int_to_str(softmodem_funcs, execmask); + if (softmodemfunc != NULL) { + set_softmodem_optmask(execmask); + return 0; + } + return -1; +} +char *get_softmodem_function(uint64_t *sofmodemfunc_mask_ptr) { + uint64_t fmask=(get_softmodem_optmask()&SOFTMODEM_FUNC_BITS); + char *softmodemfunc=map_int_to_str(softmodem_funcs, fmask); + if (sofmodemfunc_mask_ptr != NULL) + *sofmodemfunc_mask_ptr=fmask; + if (softmodemfunc != NULL) { + return softmodemfunc; + } + return "???"; +} + +void get_common_options(uint32_t execmask) { uint32_t online_log_messages; uint32_t glog_level ; uint32_t start_telnetsrv = 0; @@ -63,6 +90,7 @@ void get_common_options(void) { paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ; paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ; checkedparam_t cmdline_log_CheckParams[] = CMDLINE_LOGPARAMS_CHECK_DESC; + check_execmask(execmask); config_get( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); config_set_checkfunctions(cmdline_logparams, cmdline_log_CheckParams, sizeof(cmdline_logparams)/sizeof(paramdef_t)); @@ -92,7 +120,7 @@ void get_common_options(void) { } if (nokrnmod) { - printf("nokrnmod bit enabled \n"); + printf("nokrnmod bit enabled \n"); set_softmodem_optmask(SOFTMODEM_NOKRNMOD_BIT); } @@ -112,21 +140,67 @@ void get_common_options(void) { set_softmodem_optmask(SOFTMODEM_DOFORMS_BIT); } -#if BASIC_SIMULATOR - set_softmodem_optmask(SOFTMODEM_BASICSIM_BIT); -#endif - if(parallel_config != NULL) set_parallel_conf(parallel_config); if(worker_config != NULL) set_worker_conf(worker_config); } +void softmodem_printresources(int sig, telnet_printfunc_t pf) { + struct rusage usage; + struct timespec stop; -unsigned int is_nos1exec(char *exepath) { - if ( strcmp( basename(exepath), "lte-softmodem-nos1") == 0) - return 1; + clock_gettime(CLOCK_BOOTTIME, &stop); - if ( strcmp( basename(exepath), "lte-uesoftmodem-nos1") == 0) - return 1; + uint64_t elapse = (stop.tv_sec - start.tv_sec) ; // in seconds - return 0; + + int st = getrusage(RUSAGE_SELF,&usage); + if (!st) { + pf("\nRun time: %lluh %llus\n",(unsigned long long)elapse/3600,(unsigned long long)(elapse - (elapse/3600))); + pf("\tTime executing user inst.: %lds %ldus\n",(long)usage.ru_utime.tv_sec,(long)usage.ru_utime.tv_usec); + pf("\tTime executing system inst.: %lds %ldus\n",(long)usage.ru_stime.tv_sec,(long)usage.ru_stime.tv_usec); + pf("\tMax. Phy. memory usage: %ldkB\n",(long)usage.ru_maxrss); + pf("\tPage fault number (no io): %ld\n",(long)usage.ru_minflt); + pf("\tPage fault number (requiring io): %ld\n",(long)usage.ru_majflt); + pf("\tNumber of file system read: %ld\n",(long)usage.ru_inblock); + pf("\tNumber of filesystem write: %ld\n",(long)usage.ru_oublock); + pf("\tNumber of context switch (process origin, io...): %ld\n",(long)usage.ru_nvcsw); + pf("\tNumber of context switch (os origin, priority...): %ld\n",(long)usage.ru_nivcsw); + } } + +void signal_handler(int sig) { + void *array[10]; + size_t size; + + if (sig==SIGSEGV) { + // get void*'s for all entries on the stack + size = backtrace(array, 10); + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, 2); + exit(-1); + } else { + if(sig==SIGINT ||sig==SOFTMODEM_RTSIGNAL) + softmodem_printresources(sig,(telnet_printfunc_t)printf); + if (sig != SOFTMODEM_RTSIGNAL) { + printf("Linux signal %s...\n",strsignal(sig)); + exit_function(__FILE__, __FUNCTION__, __LINE__,"softmodem starting exit procedure\n"); + } + } +} + + + +void set_softmodem_sighandler(void) { + struct sigaction act,oldact; + clock_gettime(CLOCK_BOOTTIME, &start); + memset(&act,0,sizeof(act)); + act.sa_handler=signal_handler; + sigaction(SOFTMODEM_RTSIGNAL,&act,&oldact); + printf("Send signal %d to display resource usage...\n",SIGRTMIN+1); + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGABRT, signal_handler); +} + diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index f6ba3a6beb..cfed951469 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -1,9 +1,195 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file lte-softmodem-common.h + * \brief Top-level threads for eNodeB + * \author + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: + * \note + * \warning + */ #ifndef SOFTMODEM_COMMON_H #define SOFTMODEM_COMMON_H +#include "openair1/PHY/defs_common.h" +#ifdef __cplusplus +extern "C" +{ +#endif +/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ +#define CONFIG_HLP_RFCFGF "Configuration file for front-end (e.g. LMS7002M)\n" +#define CONFIG_HLP_ULMAXE "set the eNodeB max ULSCH erros\n" +#define CONFIG_HLP_CALUER "set UE RX calibration\n" +#define CONFIG_HLP_CALUERM "" +#define CONFIG_HLP_CALUERB "" +#define CONFIG_HLP_DBGUEPR "UE run normal prach power ramping, but don't continue random-access\n" +#define CONFIG_HLP_CALPRACH "UE run normal prach with maximum power, but don't continue random-access\n" +#define CONFIG_HLP_NOL2CN "bypass L2 and upper layers\n" + + +#define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n" +#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n" +#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n" +#define CONFIG_HLP_EXTS "tells hardware to use an external timing reference\n" +#define CONFIG_HLP_DMRSSYNC "tells RU to insert DMRS in subframe 1 slot 0" +#define CONFIG_HLP_CLK "tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)\n" +#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n" +#define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n" +#define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n" +#define CONFIG_HLP_CHOFF "Channel id offset\n" +#define CONFIG_HLP_SOFTS "Enable soft scope and L1 and L2 stats (Xforms)\n" +#define CONFIG_HLP_EXMCAL "Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n" +#define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" +#define CONFIG_HLP_DLMCS "Set the maximum downlink MCS\n" +#define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" + + +//#define CONFIG_HLP_NUMUES "Set the number of UEs for the emulation" +#define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" +#define CONFIG_HLP_ULMCS "Set the maximum uplink MCS\n" + +#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n" +#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n" +#define CONFIG_HLP_TPORT "tracer port\n" +#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n" +#define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n" + +#define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n" +#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n" +#define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n" +#define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n" +#define CONFIG_HLP_NOS1 "Disable s1 interface\n" +#define CONFIG_HLP_RFSIM "Run in rf simulator mode (also known as basic simulator)\n" +#define CONFIG_HLP_NOKRNMOD "(noS1 only): Use tun instead of namesh module \n" +#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" + +/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters common to eNodeB and UE */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define RF_CONFIG_FILE softmodem_params.rf_config_file +#define PHY_TEST softmodem_params.phy_test +#define WAIT_FOR_SYNC softmodem_params.wait_for_sync +#define SINGLE_THREAD_FLAG softmodem_params.single_thread_flag +#define CHAIN_OFFSET softmodem_params.chain_offset +#define NUMEROLOGY softmodem_params.numerology +#define EMULATE_RF softmodem_params.emulate_rf +#define CLOCK_SOURCE softmodem_params.clock_source +#define TIMING_SOURCE softmodem_params.timing_source +#define SEND_DMRSSYNC softmodem_params.send_dmrs_sync +#define USIM_TEST softmodem_params.usim_test + +#define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat"; + +#define CMDLINE_PARAMS_DESC { \ + {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)},\ + {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \ + {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \ + {"clock", CONFIG_HLP_CLK, 0, uptr:&CLOCK_SOURCE, defintval:0, TYPE_UINT, 0}, \ + {"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&WAIT_FOR_SYNC, defintval:0, TYPE_INT, 0}, \ + {"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&SINGLE_THREAD_FLAG, defintval:0, TYPE_INT, 0}, \ + {"C" , CONFIG_HLP_DLF, 0, u64ptr:&(downlink_frequency[0][0]), defuintval:0, TYPE_UINT64, 0}, \ + {"a" , CONFIG_HLP_CHOFF, 0, iptr:&CHAIN_OFFSET, defintval:0, TYPE_INT, 0}, \ + {"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \ + {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ + {"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&NUMEROLOGY, defintval:0, TYPE_INT, 0}, \ + {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&EMULATE_RF, defintval:0, TYPE_INT, 0}, \ + {"parallel-config", CONFIG_HLP_PARALLEL_CMD, 0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \ + {"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \ + {"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, uptr:&noS1, defintval:0, TYPE_INT, 0}, \ + {"rfsim", CONFIG_HLP_RFSIM, PARAMFLAG_BOOL, uptr:&rfsim, defintval:0, TYPE_INT, 0}, \ + {"basicsim", CONFIG_HLP_RFSIM, PARAMFLAG_BOOL, uptr:&basicsim, defintval:0, TYPE_INT, 0}, \ + {"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0}, \ + {"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, uptr:&nonbiot, defuintval:0, TYPE_INT, 0}, \ + } + + +#define CONFIG_HLP_FLOG "Enable online log \n" +#define CONFIG_HLP_LOGL "Set the global log level, valid options: (4:trace, 3:debug, 2:info, 1:warn, (0:error))\n" +#define CONFIG_HLP_LOGV "Set the global log verbosity \n" +#define CONFIG_HLP_TELN "Start embedded telnet server \n" +#define CONFIG_HLP_MSC "Enable the MSC tracing utility \n" +/*----------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters for LOG utility */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*----------------------------------------------------------------------------------------------------------------------------*/ +#define START_MSC softmodem_params.start_msc +#define CMDLINE_LOGPARAMS_DESC { \ + {"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \ + {"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \ + {"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \ + {"msc", CONFIG_HLP_MSC, PARAMFLAG_BOOL, uptr:&START_MSC, defintval:0, TYPE_UINT, 0}, \ + {"log-mem", NULL, 0, strptr:(char **)&logmem_filename, defstrval:NULL, TYPE_STRING, 0}, \ + } + +#define CMDLINE_ONLINELOG_IDX 0 +#define CMDLINE_GLOGLEVEL_IDX 1 +#define CMDLINE_GLOGVERBO_IDX 2 +#define CMDLINE_STARTTELN_IDX 3 + +/* check function for global log level */ +#define CMDLINE_LOGPARAMS_CHECK_DESC { \ + { .s5= {NULL} } , \ + { .s2= {config_check_intrange, {0,4}}}, \ + { .s5= {NULL} } , \ + { .s5= {NULL} } , \ + { .s5= {NULL} } , \ + } + +/***************************************************************************************************************************************/ + +#define SOFTMODEM_NOS1_BIT (1<<0) +#define SOFTMODEM_NOKRNMOD_BIT (1<<1) +#define SOFTMODEM_NONBIOT_BIT (1<<2) +#define SOFTMODEM_RFSIM_BIT (1<<10) +#define SOFTMODEM_BASICSIM_BIT (1<<11) +#define SOFTMODEM_SIML1_BIT (1<<12) +#define SOFTMODEM_DOFORMS_BIT (1<<15) +#define SOFTMODEM_RECPLAY_BIT (1<<16) +#define SOFTMODEM_ENB_BIT (1<<20) +#define SOFTMODEM_GNB_BIT (1<<21) +#define SOFTMODEM_4GUE_BIT (1<<22) +#define SOFTMODEM_5GUE_BIT (1<<23) +#define SOFTMODEM_FUNC_BITS (SOFTMODEM_ENB_BIT | SOFTMODEM_GNB_BIT | SOFTMODEM_5GUE_BIT | SOFTMODEM_4GUE_BIT) +#define MAPPING_SOFTMODEM_FUNCTIONS {{"enb",SOFTMODEM_ENB_BIT},{"gnb",SOFTMODEM_GNB_BIT},{"4Gue",SOFTMODEM_4GUE_BIT},{"5Gue",SOFTMODEM_5GUE_BIT}} + + +#define IS_SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT) +#define IS_SOFTMODEM_NOKRNMOD ( get_softmodem_optmask() & SOFTMODEM_NOKRNMOD_BIT) +#define IS_SOFTMODEM_NONBIOT ( get_softmodem_optmask() & SOFTMODEM_NONBIOT_BIT) +#define IS_SOFTMODEM_RFSIM ( get_softmodem_optmask() & SOFTMODEM_RFSIM_BIT) +#define IS_SOFTMODEM_BASICSIM ( get_softmodem_optmask() & SOFTMODEM_BASICSIM_BIT) +#define IS_SOFTMODEM_SIML1 ( get_softmodem_optmask() & SOFTMODEM_SIML1_BIT) +#define IS_SOFTMODEM_DOFORMS ( get_softmodem_optmask() & SOFTMODEM_DOFORMS_BIT) +#define IS_SOFTMODEM_IQPLAYER ( get_softmodem_optmask() & SOFTMODEM_RECPLAY_BIT) +#define IS_SOFTMODEM_ENB_BIT ( get_softmodem_optmask() & SOFTMODEM_ENB_BIT) +#define IS_SOFTMODEM_GNB_BIT ( get_softmodem_optmask() & SOFTMODEM_GNB_BIT) +#define IS_SOFTMODEM_4GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_4GUE_BIT) +#define IS_SOFTMODEM_5GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) typedef struct { uint64_t optmask; - THREAD_STRUCT thread_struct; + //THREAD_STRUCT thread_struct; char rf_config_file[1024]; int phy_test; uint8_t usim_test; @@ -19,4 +205,15 @@ typedef struct { uint32_t send_dmrs_sync; } softmodem_params_t; +extern uint64_t get_softmodem_optmask(void); +extern uint64_t set_softmodem_optmask(uint64_t bitmask); +extern softmodem_params_t *get_softmodem_params(void); +extern void get_common_options(uint32_t execmask); +extern char *get_softmodem_function(uint64_t *sofmodemfunc_mask_ptr); +#define SOFTMODEM_RTSIGNAL (SIGRTMIN+1) +extern void set_softmodem_sighandler(void); +extern uint64_t downlink_frequency[MAX_NUM_CCs][4]; +#ifdef __cplusplus +} +#endif #endif diff --git a/nfapi/open-nFAPI/nfapi/inc/nfapi.h b/nfapi/open-nFAPI/nfapi/inc/nfapi.h index 29a0e50438..0f09efa78a 100644 --- a/nfapi/open-nFAPI/nfapi/inc/nfapi.h +++ b/nfapi/open-nFAPI/nfapi/inc/nfapi.h @@ -44,10 +44,14 @@ uint8_t pulls32(uint8_t **in, int32_t *out, uint8_t *end); uint32_t pullarray8(uint8_t **in, uint8_t out[], uint32_t max_len, uint32_t len, uint8_t *end); uint32_t pullarray16(uint8_t **in, uint16_t out[], uint32_t max_len, uint32_t len, uint8_t *end); uint32_t pullarrays16(uint8_t **in, int16_t out[], uint32_t max_len, uint32_t len, uint8_t *end); +uint32_t pullarray32(uint8_t **in, uint32_t out[], uint32_t max_len, uint32_t len, uint8_t *end); +uint32_t pullarrays32(uint8_t **in, int32_t out[], uint32_t max_len, uint32_t len, uint8_t *end); uint32_t pusharray8(uint8_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); uint32_t pusharray16(uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); uint32_t pusharrays16(int16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); +uint32_t pusharray32(uint32_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); +uint32_t pusharrays32(int32_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); typedef uint8_t (*pack_array_elem_fn)(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end); uint8_t packarray(void* array, uint16_t elem_size, uint16_t max_count, uint16_t count, uint8_t **ppWritePackedMsg, uint8_t *end, pack_array_elem_fn fn); diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h index 2c31af4bc1..32a31a99f6 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h @@ -735,6 +735,23 @@ typedef struct { #define NFAPI_PUCCH_CONFIG_N_AN_CS_TAG 0x003E #define NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG 0x003F +typedef struct{ + nfapi_uint8_tlv_t mbsfn_area_idx; + nfapi_uint16_tlv_t mbsfn_area_id_r9; +} nfapi_embms_sib13_config_t; +#define NFAPI_EMBMS_MBSFN_CONFIG_AREA_IDX_TAG 0x0039 +#define NFAPI_EMBMS_MBSFN_CONFIG_AREA_IDR9_TAG 0x0040 + +typedef struct { + nfapi_tl_t tl; + uint16_t num_mbsfn_config; + uint16_t radioframe_allocation_period[8]; + uint16_t radioframe_allocation_offset[8]; + uint8_t fourframes_flag[8]; + int32_t mbsfn_subframeconfig[8]; +} nfapi_embms_mbsfn_config_t; +#define NFAPI_EMBMS_MBSFN_CONFIG_TAG 0x0041 + typedef struct { nfapi_uint8_tlv_t radioframe_allocation_period; nfapi_uint8_tlv_t radioframe_allocation_offset; @@ -1143,6 +1160,9 @@ typedef struct { nfapi_prach_config_t prach_config; nfapi_pusch_config_t pusch_config; nfapi_pucch_config_t pucch_config; + // addition nfpai tlvs for embms MBSFN config //TOBE REVIEWED + nfapi_embms_sib13_config_t embms_sib13_config; + nfapi_embms_mbsfn_config_t embms_mbsfn_config; nfapi_fembms_config_t fembms_config; nfapi_srs_config_t srs_config; nfapi_uplink_reference_signal_config_t uplink_reference_signal_config; @@ -1165,6 +1185,9 @@ typedef struct { nfapi_prach_config_t prach_config; nfapi_pusch_config_t pusch_config; nfapi_pucch_config_t pucch_config; + // addition nfpai tlvs for embms MBSFN config //TOBE REVIEWED + nfapi_embms_sib13_config_t embms_sib13_config; + nfapi_embms_mbsfn_config_t embms_mbsfn_config; nfapi_fembms_config_t fembms_config; nfapi_srs_config_t srs_config; nfapi_uplink_reference_signal_config_t uplink_reference_signal_config; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index 5f12fc55b9..5fe1c53a54 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -548,7 +548,6 @@ typedef struct { uint8_t frame_offset; uint16_t number_symbols; uint16_t start_symbol; - uint8_t nb_re_dmrs; uint8_t length_dmrs; nr_pusch_freq_hopping_t pusch_freq_hopping; uint8_t mcs; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 941150be4d..33951a2751 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1123,10 +1123,10 @@ typedef struct uint16_t data_scrambling_id; uint8_t nrOfLayers; //DMRS - uint8_t ul_dmrs_symb_pos; + uint16_t ul_dmrs_symb_pos; uint8_t dmrs_config_type; uint16_t ul_dmrs_scrambling_id; - uint8_t scid;// + uint8_t scid; uint8_t num_dmrs_cdm_grps_no_data; uint16_t dmrs_ports;//DMRS ports. [TS38.212 7.3.1.1.2] provides description between DCI 0-1 content and DMRS ports. Bitmap occupying the 11 LSBs with: bit 0: antenna port 1000 bit 11: antenna port 1011 and for each bit 0: DMRS port not used 1: DMRS port used //Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2] diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi.c b/nfapi/open-nFAPI/nfapi/src/nfapi.c index 3f017bc9a4..156a48ec05 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi.c @@ -405,7 +405,116 @@ uint32_t pusharrays16(int16_t in[], uint32_t max_len, uint32_t len, uint8_t **ou return 0; } } +uint32_t pullarray32(uint8_t **in, uint32_t out[], uint32_t max_len, uint32_t len, uint8_t *end) +{ + if(len == 0) + return 1; + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*in)) >= sizeof(uint32_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + if(!pull32(in, &out[idx], end)) + return 0; + } + + return sizeof(uint32_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint32_t pullarrays32(uint8_t **in, int32_t out[], uint32_t max_len, uint32_t len, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*in)) >= sizeof(uint32_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + if(!pulls32(in, &out[idx], end)) + return 0; + } + + return sizeof(uint32_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} +uint32_t pusharray32(uint32_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*out)) >= sizeof(uint32_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + if(!push32(in[idx], out, end)) + return 0; + } + return sizeof(uint32_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} +uint32_t pusharrays32(int32_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*out)) >= sizeof(uint32_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + pushs32(in[idx], out, end); + } + return sizeof(uint32_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} uint32_t pullarray8(uint8_t **in, uint8_t out[], uint32_t max_len, uint32_t len, uint8_t *end) { if(len == 0) diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c index 54e27123d9..a8ac0f0a65 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c @@ -404,7 +404,26 @@ static uint8_t unpack_nmm_frequency_bands_value(void* tlv, uint8_t **ppReadPacke return ( pull16(ppReadPackedMsg, &value->number_of_rf_bands, end) && pullarray16(ppReadPackedMsg, value->bands, NFAPI_MAX_NMM_FREQUENCY_BANDS, value->number_of_rf_bands, end)); } - +static uint8_t pack_embms_mbsfn_config_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_embms_mbsfn_config_t* value = (nfapi_embms_mbsfn_config_t*)tlv; + + return ( push16(value->num_mbsfn_config, ppWritePackedMsg, end) && + pusharray16(value->radioframe_allocation_period, 8,value->num_mbsfn_config ,ppWritePackedMsg, end) && + pusharray16(value->radioframe_allocation_offset, 8,value->num_mbsfn_config ,ppWritePackedMsg, end) && + pusharray8(value->fourframes_flag, 8,value->num_mbsfn_config,ppWritePackedMsg, end) && + pusharrays32(value->mbsfn_subframeconfig, 8, value->num_mbsfn_config, ppWritePackedMsg, end)); +} +//static uint8_t unpack_embms_mbsfn_config_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t* end) +//{ +// nfapi_embms_mbsfn_config_t* value = (nfapi_embms_mbsfn_config_t*)tlv; +// +// return ( pull16(ppReadPackedMsg, &value->num_mbsfn_config, end) && +// pull16(ppReadPackedMsg, &value->radioframe_allocation_period, end) && +// pull16(ppReadPackedMsg, &value->radioframe_allocation_offset, end) && +// pull8(ppReadPackedMsg, &value->fourframes_flag, end) && +// pullarrays32(ppReadPackedMsg, value->mbsfn_subframeconfig, 8, value->num_mbsfn_config, end)); +//} static uint8_t pack_param_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) { nfapi_param_response_t *pNfapiMsg = (nfapi_param_response_t*)msg; @@ -461,6 +480,11 @@ static uint8_t pack_param_response(void *msg, uint8_t **ppWritePackedMsg, uint8_ pack_tlv(NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, &(pNfapiMsg->pucch_config.n_an_cs), ppWritePackedMsg, end, &pack_uint16_tlv_value) && pack_tlv(NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, &(pNfapiMsg->pucch_config.n1_pucch_an), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMBMS_MBSFN_CONFIG_AREA_IDX_TAG, &(pNfapiMsg->embms_sib13_config.mbsfn_area_idx), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_EMBMS_MBSFN_CONFIG_AREA_IDR9_TAG, &(pNfapiMsg->embms_sib13_config.mbsfn_area_id_r9), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_EMBMS_MBSFN_CONFIG_TAG, &(pNfapiMsg->embms_mbsfn_config), ppWritePackedMsg, end, &pack_embms_mbsfn_config_value) && + pack_tlv(NFAPI_FEMBMS_CONFIG_RADIOFRAME_ALLOCATION_PERIOD_TAG, &(pNfapiMsg->fembms_config.radioframe_allocation_period), ppWritePackedMsg, end, &pack_uint8_tlv_value) && pack_tlv(NFAPI_FEMBMS_CONFIG_RADIOFRAME_ALLOCATION_OFFSET_TAG, &(pNfapiMsg->fembms_config.radioframe_allocation_offset), ppWritePackedMsg, end, &pack_uint8_tlv_value) && pack_tlv(NFAPI_FEMBMS_CONFIG_NON_MBSFN_FLAG_TAG, &(pNfapiMsg->fembms_config.non_mbsfn_config_flag), ppWritePackedMsg, end, &pack_uint8_tlv_value) && diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md new file mode 100644 index 0000000000..89ae6b4dbb --- /dev/null +++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md @@ -0,0 +1,26 @@ +#LDPC coder/decoder implementation +The LDPC coder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time. + +## Selecting the LDPC library at run time + +By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below: + +>loading `libldpc_optim8seg.so` instead of `libldpc.so` + +``` +./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _optim8seg +....................... +[CONFIG] loader.ldpc.shlibversion set to default value "" +[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) +[CONFIG] shlibversion set to _optim8seg from command line +[CONFIG] loader.ldpc 1 options set from command line +[LOADER] library libldpc_optim8seg.so successfully loaded +........................ +``` + +Today, this mechanism is not available in the `ldpctest` phy simulator which doesn't initialize the [configuration module](file://../../../../common/config/DOC/config.md). loads `libldpc.so` and `libldpc_orig.so` to compare the performance of the two implementations. + +###LDPC libraries +Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement two functions: `nrLDPC_decod` and `nrLDPC_encod`. The prototypes for these functions is defined in [nrLDPC_defs.h](file://nrLDPC_defs.h). + +[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c index 95ee3fed17..552af99c41 100644 --- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c +++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c @@ -25,8 +25,7 @@ #include #include "assertions.h" #include "SIMULATION/TOOLS/sim.h" -#include "PHY/CODING/nrLDPC_encoder/defs.h" -#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h" +#include "PHY/CODING/nrLDPC_extern.h" #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h" #define MAX_NUM_DLSCH_SEGMENTS 16 @@ -85,6 +84,7 @@ typedef struct { RAN_CONTEXT_t RC; PHY_VARS_UE ***PHY_vars_UE_g; uint16_t NB_UE_INST = 1; +nrLDPC_encoderfunc_t encoder_orig; short lift_size[51]= {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,22,24,26,28,30,32,36,40,44,48,52,56,60,64,72,80,88,96,104,112,120,128,144,160,176,192,208,224,240,256,288,320,352,384}; @@ -286,16 +286,19 @@ int test_ldpc(short No_iteration, no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*(1/((float)nom_rate/(float)denom_rate)))/Zc; // printf("puncture:%d\n",no_punctured_columns); removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length/((float)nom_rate/(float)denom_rate)); + encoder_implemparams_t impp=INIT0_LDPCIMPLEMPARAMS; + + impp.gen_code=1; if (ntrials==0) - ldpc_encoder_orig(test_input[0],channel_input[0], Zc, BG, block_length, BG, 1); - + encoder_orig(test_input,channel_input, Zc, BG, block_length, BG, &impp); + impp.gen_code=0; for (trial=0; trial < ntrials; trial++) { segment_bler = 0; //// encoder start_meas(&time); for(j=0;j #include -#include "nrLDPC_defs.h" +#include "nrLDPCdecoder_defs.h" #include "nrLDPC_types.h" #include "nrLDPC_init.h" #include "nrLDPC_mPass.h" @@ -47,7 +47,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, uint32_t numLLR, t_nrLDPC_lut* p_lut, t_nrLDPC_dec_params* p_decParams, t_nrLDPC_time_stats* p_profiler); -int32_t nrLDPC_decoder(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler) +int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler) { uint32_t numLLR; uint32_t numIter = 0; diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h index 82462c6d95..ea031dc2da 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h @@ -32,7 +32,7 @@ #define __NR_LDPC_INIT__H__ #include "nrLDPC_lut.h" -#include "nrLDPC_defs.h" +#include "nrLDPCdecoder_defs.h" /** \brief Initializes the decoder and sets correct LUTs diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h index bdaa118e1f..3292c0debe 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h @@ -32,7 +32,6 @@ #define __NR_LDPC_INIT_MEM__H__ #include -#include "nrLDPC_defs.h" #include "nrLDPC_types.h" #ifndef malloc32_clear diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h index 5470ab7973..10b45ac0e7 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h @@ -32,7 +32,7 @@ #define __NR_LDPC_MPASS__H__ #include -#include "nrLDPC_defs.h" +#include "nrLDPCdecoder_defs.h" /** \brief Circular memcpy diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h index 34322a7780..e5b99246d5 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h @@ -32,8 +32,7 @@ #define __NR_LDPC_TYPES__H__ #include "PHY/TOOLS/time_meas.h" -#include "nrLDPC_defs.h" - +#include "nrLDPCdecoder_defs.h" // ============================================================================== // TYPES @@ -103,4 +102,6 @@ typedef struct nrLDPC_procBuf { int8_t* llrProcBuf; /**< LLR processing buffer */ } t_nrLDPC_procBuf; + + #endif diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h similarity index 99% rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h rename to openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h index 597e27cb08..c35f93e0fe 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h @@ -19,7 +19,7 @@ * contact@openairinterface.org */ -/*!\file nrLDPC_defs.h +/*!\file nrLDPCdecoder_defs.h * \brief Defines all constants and buffers for the LDPC decoder * \author Sebastian Wagner (TCL Communications) Email: * \date 27-03-2018 diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h new file mode 100644 index 0000000000..b96067f4b6 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_defs.h @@ -0,0 +1,59 @@ +/* + * 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 + */ +//============================================================================================================================ +// encoder interface +#ifndef __NRLDPC_DEFS__H__ +#define __NRLDPC_DEFS__H__ +#include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" +/** + \brief LDPC encoder + \param 1 input + \param 2 channel_input + \param 3 int Zc + \param 4 int Kb + \param 5 short block_length + \param 6 short BG + \param 7 int n_segment + \param 8 unsigned int macro_num + \param 9-12 time_stats_t *tinput,*tprep, *tparity,*toutput +*/ +typedef struct { + int n_segments; // optim8seg + unsigned int macro_num; // optim8segmulti + unsigned char gen_code; //orig + time_stats_t *tinput; + time_stats_t *tprep; + time_stats_t *tparity; + time_stats_t *toutput; +}encoder_implemparams_t; +#define INIT0_LDPCIMPLEMPARAMS {0,0,0,NULL,NULL,NULL,NULL} +typedef int(*nrLDPC_encoderfunc_t)(unsigned char **,unsigned char **,int,int,short, short, encoder_implemparams_t*); +//============================================================================================================================ +// decoder interface +/** + \brief LDPC decoder API type definition + \param p_decParams LDPC decoder parameters + \param p_llr Input LLRs + \param p_llrOut Output vector + \param p_profiler LDPC profiler statistics +*/ +typedef int32_t(*nrLDPC_decoderfunc_t)(t_nrLDPC_dec_params* , int8_t*, int8_t* , t_nrLDPC_procBuf* , t_nrLDPC_time_stats* ); +#endif \ No newline at end of file diff --git a/openair1/PHY/CODING/nrLDPC_encoder/defs.h b/openair1/PHY/CODING/nrLDPC_encoder/defs.h deleted file mode 100644 index 85cb852fe5..0000000000 --- a/openair1/PHY/CODING/nrLDPC_encoder/defs.h +++ /dev/null @@ -1,54 +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 defs.h - * \brief LDPC encoder forward declarations - * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom) - * \email openair_tech@eurecom.fr - * \date 27-03-2018 - * \version 1.0 - * \note - * \warning - */ - -#include "PHY/TOOLS/time_meas.h" - -/*ldpc_encoder.c*/ -int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length); - -/*ldpc_encoder2.c*/ -void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb); -int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput); -int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length,short BG,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput); -int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, int n_segments,unsigned int macro_num, time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput); - -/*ldpc_generate_coefficient.c*/ -int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,unsigned char gen_code); - -/* -int encode_parity_check_part(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb); -int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length); -int ldpc_encoder(unsigned char *test_input,unsigned char *channel_input,short block_length, double rate); -int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,short block_length,int nom_rate,int denom_rate,unsigned char gen_code); -int ldpc_encoder_multi_segment(unsigned char **test_input,unsigned char **channel_input,short block_length,double rate,uint8_t n_segments); -int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,short block_length,int nom_rate,int denom_rate,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput); -int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,short block_length,int nom_rate,int denom_rate,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput); -*/ diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c new file mode 100644 index 0000000000..738fd49b7d --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c @@ -0,0 +1,201 @@ +/* + * 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 ldpc_encode_parity_check.c + * \brief Parity check function used by ldpc encoders + * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom) + * \email openair_tech@eurecom.fr + * \date 27-03-2018 + * \version 1.0 + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include "assertions.h" +#include "common/utils/LOG/log.h" + + +//#define DEBUG_LDPC + +#include "ldpc384_byte.c" +#include "ldpc352_byte.c" +#include "ldpc320_byte.c" +#include "ldpc288_byte.c" +#include "ldpc256_byte.c" +#include "ldpc240_byte.c" +#include "ldpc224_byte.c" +#include "ldpc208_byte.c" +#include "ldpc192_byte.c" +#include "ldpc176_byte.c" +#include "ldpc_BG2_Zc384_byte.c" +#include "ldpc_BG2_Zc352_byte.c" +#include "ldpc_BG2_Zc320_byte.c" +#include "ldpc_BG2_Zc288_byte.c" +#include "ldpc_BG2_Zc256_byte.c" +#include "ldpc_BG2_Zc240_byte.c" +#include "ldpc_BG2_Zc224_byte.c" +#include "ldpc_BG2_Zc208_byte.c" +#include "ldpc_BG2_Zc192_byte.c" +#include "ldpc_BG2_Zc176_byte.c" +#include "ldpc_BG2_Zc160_byte.c" +#include "ldpc_BG2_Zc144_byte.c" +#include "ldpc_BG2_Zc128_byte.c" +#include "ldpc_BG2_Zc120_byte.c" +#include "ldpc_BG2_Zc112_byte.c" +#include "ldpc_BG2_Zc104_byte.c" +#include "ldpc_BG2_Zc96_byte.c" +#include "ldpc_BG2_Zc88_byte.c" +#include "ldpc_BG2_Zc80_byte.c" +#include "ldpc_BG2_Zc72_byte.c" + + + +static inline void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb) +{ + + if (BG==1) + { + switch (Zc) + { + case 2: break; + case 3: break; + case 4: break; + case 5: break; + case 6: break; + case 7: break; + case 8: break; + case 9: break; + case 10: break; + case 11: break; + case 12: break; + case 13: break; + case 14: break; + case 15: break; + case 16: break; + case 18: break; + case 20: break; + case 22: break; + case 24: break; + case 26: break; + case 28: break; + case 30: break; + case 32: break; + case 36: break; + case 40: break; + case 44: break; + case 48: break; + case 52: break; + case 56: break; + case 60: break; + case 64: break; + case 72: break; + case 80: break; + case 88: break; + case 96: break; + case 104: break; + case 112: break; + case 120: break; + case 128: break; + case 144: break; + case 160: break; + case 176: ldpc176_byte(c,d); break; + case 192: ldpc192_byte(c,d); break; + case 208: ldpc208_byte(c,d); break; + case 224: ldpc224_byte(c,d); break; + case 240: ldpc240_byte(c,d); break; + case 256: ldpc256_byte(c,d); break; + case 288: ldpc288_byte(c,d); break; + case 320: ldpc320_byte(c,d); break; + case 352: ldpc352_byte(c,d); break; + case 384: ldpc384_byte(c,d); break; + default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break; + } + } + else if (BG==2) { + switch (Zc) + { + case 2: break; + case 3: break; + case 4: break; + case 5: break; + case 6: break; + case 7: break; + case 8: break; + case 9: break; + case 10: break; + case 11: break; + case 12: break; + case 13: break; + case 14: break; + case 15: break; + case 16: break; + case 18: break; + case 20: break; + case 22: break; + case 24: break; + case 26: break; + case 28: break; + case 30: break; + case 32: break; + case 36: break; + case 40: break; + case 44: break; + case 48: break; + case 52: break; + case 56: break; + case 60: break; + case 64: break; + case 72: ldpc_BG2_Zc72_byte(c,d); break; + case 80: ldpc_BG2_Zc80_byte(c,d); break; + case 88: ldpc_BG2_Zc88_byte(c,d); break; + case 96: ldpc_BG2_Zc96_byte(c,d); break; + case 104: ldpc_BG2_Zc104_byte(c,d); break; + case 112: ldpc_BG2_Zc112_byte(c,d); break; + case 120: ldpc_BG2_Zc120_byte(c,d); break; + case 128: ldpc_BG2_Zc128_byte(c,d); break; + case 144: ldpc_BG2_Zc144_byte(c,d); break; + case 160: ldpc_BG2_Zc160_byte(c,d); break; + case 176: ldpc_BG2_Zc176_byte(c,d); break; + case 192: ldpc_BG2_Zc192_byte(c,d); break; + case 208: ldpc_BG2_Zc208_byte(c,d); break; + case 224: ldpc_BG2_Zc224_byte(c,d); break; + case 240: ldpc_BG2_Zc240_byte(c,d); break; + case 256: ldpc_BG2_Zc256_byte(c,d); break; + case 288: ldpc_BG2_Zc288_byte(c,d); break; + case 320: ldpc_BG2_Zc320_byte(c,d); break; + case 352: ldpc_BG2_Zc352_byte(c,d); break; + case 384: ldpc_BG2_Zc384_byte(c,d); break; + default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break; + } + } + else { + AssertFatal(0,"BG %d is not supported yet\n",BG); + } + +} + + + diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c index 6ded22d8ca..76f92574ba 100644 --- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c @@ -37,77 +37,247 @@ #include #include #include "defs.h" +#include "assertions.h" +#include "openair1/PHY/CODING/nrLDPC_defs.h" +#include "ldpc_generate_coefficient.c" -short *choose_generator_matrix(short BG,short Zc); -extern short no_shift_values_BG1[1012],pointer_shift_values_BG1[1012],no_shift_values_BG2[2109],pointer_shift_values_BG2[2019]; -int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length) +int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length, short BG,unsigned char gen_code) { - short *Gen_shift_values=choose_generator_matrix(BG,Zc); - short *no_shift_values, *pointer_shift_values; - int no_punctured_columns; - short nrows,ncols,rate=3; - int i1,i2,i3,i4,i5,temp_prime; + unsigned char c[22*384]; //padded input, unpacked, max size + unsigned char d[68*384]; //coded output, unpacked, max size unsigned char channel_temp,temp; + short *Gen_shift_values, *no_shift_values, *pointer_shift_values; + short nrows = 46;//parity check bits + short ncols = 22;//info bits + + + int i,i1,i2,i3,i4,i5,temp_prime,var; + int no_punctured_columns,removed_bit,rate=3; + int nind=0; + int indlist[1000]; + int indlist2[1000]; + + //determine number of bits in codeword + //if (block_length>3840) + if (BG==1) + { + nrows=46; //parity check bits + ncols=22; //info bits + rate=3; + } + //else if (block_length<=3840) + else if (BG==2) + { + //BG=2; + nrows=42; //parity check bits + ncols=10; // info bits + rate=5; + } + + Gen_shift_values=choose_generator_matrix(BG,Zc); + if (Gen_shift_values==NULL) { + printf("ldpc_encoder_orig: could not find generator matrix\n"); + return(-1); + } + + //printf("ldpc_encoder_orig: BG %d, Zc %d, Kb %d\n",BG, Zc, Kb); + + // load base graph of generator matrix if (BG==1) { no_shift_values=(short *) no_shift_values_BG1; pointer_shift_values=(short *) pointer_shift_values_BG1; - nrows=46; //parity check bits - ncols=22; //info bits - rate=3; } else if (BG==2) { no_shift_values=(short *) no_shift_values_BG2; pointer_shift_values=(short *) pointer_shift_values_BG2; - nrows=42; //parity check bits - ncols=10; //info bits - rate=5; } else { - printf("problem with BG\n"); - return(-1); + AssertFatal(0,"BG %d is not supported yet\n",BG); } - - + no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc; + removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(block_length*rate); + //printf("%d\n",no_punctured_columns); + //printf("%d\n",removed_bit); + // unpack input + memset(c,0,sizeof(unsigned char) * ncols * Zc); + memset(d,0,sizeof(unsigned char) * nrows * Zc); - //printf("no_punctured_columns = %d\n",no_punctured_columns); - - for (i2=0; i2 < Zc; i2++) + for (i=0; i>7&1; + c[i]=(test_input[i/8]&(128>>(i&7)))>>(7-(i&7)); + } - //rotate matrix here - for (i5=0; i5 < Kb; i5++) - { - temp = c[i5*Zc]; - memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char)); - c[i5*Zc+Zc-1] = temp; + // parity check part + + if (gen_code==1) + { + char fname[100]; + sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc); + FILE *fd=fopen(fname,"w"); + AssertFatal(fd!=NULL,"cannot open %s\n",fname); + sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc); + FILE *fd2=fopen(fname,"w"); + AssertFatal(fd2!=NULL,"cannot open %s\n",fname); + + int shift; + char data_type[100]; + char xor_command[100]; + int mask; + + + + + fprintf(fd,"#include \"PHY/sse_intrin.h\"\n"); + fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n"); + + if ((Zc&31)==0) { + shift=5; // AVX2 - 256-bit SIMD + mask=31; + strcpy(data_type,"__m256i"); + strcpy(xor_command,"_mm256_xor_si256"); } + else if ((Zc&15)==0) { + shift=4; // SSE4 - 128-bit SIMD + mask=15; + strcpy(data_type,"__m128i"); + strcpy(xor_command,"_mm_xor_si128"); - // calculate each row in base graph - for (i1=0; i1 < nrows-no_punctured_columns; i1++) + } + else if ((Zc&7)==0) { + shift=3; // MMX - 64-bit SIMD + mask=7; + strcpy(data_type,"__m64"); + strcpy(xor_command,"_mm_xor_si64"); + } + else { + shift=0; // no SIMD + mask=0; + strcpy(data_type,"uint8_t"); + strcpy(xor_command,"scalar_xor"); + fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n"); + fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n"); + } + fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc); + fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc); + fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc); + fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc); + fprintf(fd," %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type); + fprintf(fd2," %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type); + fprintf(fd," %s *c2,*d2;\n\n",data_type); + fprintf(fd2," %s *c2,*d2;\n\n",data_type); + fprintf(fd," int i2;\n"); + fprintf(fd2," int i2;\n"); + fprintf(fd," for (i2=0; i2<%d; i2++) {\n",Zc>>shift); + if (shift > 0) + fprintf(fd2," for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1)); + for (i2=0; i2 < 1; i2++) { - channel_temp=0; - for (i3=0; i3 < Kb; i3++) - { - temp_prime=i1 * ncols + i3; + //t=Kb*Zc+i2; + + // calculate each row in base graph + - for (i4=0; i4 < no_shift_values[temp_prime]; i4++) + fprintf(fd," c2=&csimd[i2];\n"); + fprintf(fd," d2=&dsimd[i2];\n"); + fprintf(fd2," c2=&csimd[i2];\n"); + fprintf(fd2," d2=&dsimd[i2];\n"); + + for (i1=0; i1 < nrows; i1++) + + { + channel_temp=0; + fprintf(fd,"\n//row: %d\n",i1); + fprintf(fd2,"\n//row: %d\n",i1); + fprintf(fd," d2[%d]=",(Zc*i1)>>shift); + fprintf(fd2," d2[%d]=",(Zc*i1)>>(shift-1)); + + nind=0; + + for (i3=0; i3 < ncols; i3++) { - channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ]; + temp_prime=i1 * ncols + i3; + + + for (i4=0; i4 < no_shift_values[temp_prime]; i4++) + { + + var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc); + int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc; + + indlist[nind] = ((index&mask)*((2*Zc)>>shift)*Kb)+(index>>shift); + indlist2[nind++] = ((index&(mask>>1))*((2*Zc)>>(shift-1))*Kb)+(index>>(shift-1)); + + } + + } + for (i4=0;i4gen_code); +} \ No newline at end of file diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c index fb516549ed..5ab55514ce 100644 --- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c @@ -35,6 +35,7 @@ #include #include #include "assertions.h" +#include "common/utils/LOG/log.h" #include "PHY/TOOLS/time_meas.h" #include "defs.h" @@ -482,13 +483,14 @@ int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **cha //Table of possible lifting sizes char temp; int simd_size; - int macro_segment, macro_segment_end; - + unsigned int macro_segment, macro_segment_end; + macro_segment = 8*macro_num; macro_segment_end = (n_segments > 8*(macro_num+1)) ? 8*(macro_num+1) : n_segments; - ///printf("macro_segment: %d\n", macro_segment); - ///printf("macro_segment_end: %d\n", macro_segment_end ); + //macro_segment_end = macro_segment + (n_segments > 8 ? 8 : n_segments); + //printf("macro_segment: %d\n", macro_segment); + //printf("macro_segment_end: %d\n", macro_segment_end ); #ifdef __AVX2__ __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000); @@ -506,7 +508,7 @@ int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **cha masks[7] = _mm256_set1_epi8(0x80); #endif - ///AssertFatal(n_segments>0&&n_segments<=8,"0 < n_segments %d <= 8\n",n_segments); + //determine number of bits in codeword if (BG==1) diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c new file mode 100644 index 0000000000..7da265494a --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c @@ -0,0 +1,146 @@ +/* + * 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 ldpc_encoder2.c + * \brief Defines the optimized LDPC encoder + * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom) + * \email openair_tech@eurecom.fr + * \date 27-03-2018 + * \version 1.0 + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include "assertions.h" +#include "common/utils/LOG/log.h" +#include "PHY/TOOLS/time_meas.h" +#include "openair1/PHY/CODING/nrLDPC_defs.h" +#include "ldpc_encode_parity_check.c" +#include "ldpc_generate_coefficient.c" +//#define DEBUG_LDPC + + + + + +int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp) +{ + + short nrows=0,ncols=0; + int i,i1,rate=3; + int no_punctured_columns,removed_bit; + + int simd_size; + + //determine number of bits in codeword + //if (block_length>3840) + if (BG==1) + { + //BG=1; + nrows=46; //parity check bits + ncols=22; //info bits + rate=3; + } + //else if (block_length<=3840) + else if (BG==2) + { + //BG=2; + nrows=42; //parity check bits + ncols=10; // info bits + rate=5; + + } + + +#ifdef DEBUG_LDPC + LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d\n",BG,Zc,Kb,block_length); + LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]); +#endif + + if ((Zc&31) > 0) simd_size = 16; + else simd_size = 32; + + unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size + unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size + + unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32))); //double size matrix of c + + // calculate number of punctured bits + no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc; + removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate); + // printf("%d\n",no_punctured_columns); + // printf("%d\n",removed_bit); + // unpack input + memset(c,0,sizeof(unsigned char) * ncols * Zc); + memset(d,0,sizeof(unsigned char) * nrows * Zc); + + if(impp->tinput != NULL) start_meas(impp->tinput); + for (i=0; i>(i&7)))>>(7-(i&7)); + //printf("c(%d,%d)=%d\n",j,i,temp); + } + + if(impp->tinput != NULL) stop_meas(impp->tinput); + + if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { + // extend matrix + if(impp->tprep != NULL) start_meas(impp->tprep); + for (i1=0; i1 < ncols; i1++) + { + memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char)); + memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char)); + } + for (i1=1;i1tprep != NULL) stop_meas(impp->tprep); + //parity check part + if(impp->tparity != NULL) start_meas(impp->tparity); + encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb); + if(impp->tparity != NULL) stop_meas(impp->tparity); + } + else { + if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) { + printf("Problem with encoder\n"); + return(-1); + } + } + if(impp->toutput != NULL) start_meas(impp->toutput); + // information part and puncture columns + memcpy(&channel_input[0][0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char)); + memcpy(&channel_input[0][block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char)); + + if(impp->toutput != NULL) stop_meas(impp->toutput); + return 0; +} + + diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c new file mode 100644 index 0000000000..a974e86e27 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c @@ -0,0 +1,225 @@ +/* + * 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 ldpc_encoder2.c + * \brief Defines the optimized LDPC encoder + * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom) + * \email openair_tech@eurecom.fr + * \date 27-03-2018 + * \version 1.0 + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include "assertions.h" +#include "common/utils/LOG/log.h" +#include "PHY/TOOLS/time_meas.h" +#include "openair1/PHY/CODING/nrLDPC_defs.h" +//#define DEBUG_LDPC +#include "ldpc_encode_parity_check.c" +#include "ldpc_generate_coefficient.c" + + + +int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp) +{ + + short nrows=0,ncols=0; + int i,i1,j,rate=3; + int no_punctured_columns,removed_bit; + char temp; + int simd_size; + +#ifdef __AVX2__ + __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000); + __m256i andmask = _mm256_set1_epi64x(0x0102040810204080); // every 8 bits -> 8 bytes, pattern repeats. + __m256i zero256 = _mm256_setzero_si256(); + __m256i masks[8]; + register __m256i c256; + masks[0] = _mm256_set1_epi8(0x1); + masks[1] = _mm256_set1_epi8(0x2); + masks[2] = _mm256_set1_epi8(0x4); + masks[3] = _mm256_set1_epi8(0x8); + masks[4] = _mm256_set1_epi8(0x10); + masks[5] = _mm256_set1_epi8(0x20); + masks[6] = _mm256_set1_epi8(0x40); + masks[7] = _mm256_set1_epi8(0x80); +#endif + + AssertFatal((impp->n_segments>0&&impp->n_segments<=8),"0 < n_segments %d <= 8\n",impp->n_segments); + + //determine number of bits in codeword + //if (block_length>3840) + if (BG==1) + { + nrows=46; //parity check bits + ncols=22; //info bits + rate=3; + } + //else if (block_length<=3840) + else if (BG==2) + { + //BG=2; + nrows=42; //parity check bits + ncols=10; // info bits + rate=5; + + } + +#ifdef DEBUG_LDPC + LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments); + LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]); +#endif + + AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length); + + if ((Zc&31) > 0) simd_size = 16; + else simd_size = 32; + + unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size + unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size + + unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32))); //double size matrix of c + + // calculate number of punctured bits + no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc; + removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate); + // printf("%d\n",no_punctured_columns); + // printf("%d\n",removed_bit); + // unpack input + memset(c,0,sizeof(unsigned char) * ncols * Zc); + memset(d,0,sizeof(unsigned char) * nrows * Zc); + + if(impp->tinput != NULL) start_meas(impp->tinput); +#if 0 + for (i=0; i>(i&7)))>>(7-(i&7)); + //printf("c(%d,%d)=%d\n",j,i,temp); + c[i] |= (temp << j); + } + } +#else +#ifdef __AVX2__ + for (i=0; i>5; i++) { + c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[0])[i]), shufmask),andmask),zero256),masks[0]); + for (j=1; jn_segments; j++) { + c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j]),c256); + } + ((__m256i *)c)[i] = c256; + } + + for (i=(block_length>>5)<<5;in_segments; j++) { + + temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7)); + //printf("c(%d,%d)=%d\n",j,i,temp); + c[i] |= (temp << j); + } + } +#else + AssertFatal(1==0,"Need AVX2 for this\n"); +#endif +#endif + + if(impp->tinput != NULL) stop_meas(impp->tinput); + + if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { + // extend matrix + if(impp->tprep != NULL) start_meas(impp->tprep); + for (i1=0; i1 < ncols; i1++) + { + memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char)); + memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char)); + } + for (i1=1;i1tprep != NULL) stop_meas(impp->tprep); + //parity check part + if(impp->tparity != NULL) start_meas(impp->tparity); + encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb); + if(impp->tparity != NULL) stop_meas(impp->tparity); + } + else { + if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) { + printf("Problem with encoder\n"); + return(-1); + } + } + if(impp->toutput != NULL) start_meas(impp->toutput); + // information part and puncture columns + /* + memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char)); + memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char)); + */ +#ifdef __AVX2__ + if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) { + //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n"); + //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n"); + uint32_t l1 = (block_length-(2*Zc))>>5; + uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5; + __m256i *c256p = (__m256i *)&c[2*Zc]; + __m256i *d256p = (__m256i *)&d[0]; + // if (((block_length-(2*Zc))&31)>0) l1++; + + for (i=0;in_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]); + + // if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++; + + for (i1=0;i1n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]); + } + else { +#ifdef DEBUG_LDPC + LOG_W(PHY,"using non-optimized version\n"); +#endif + // do non-SIMD version + for (i=0;i<(block_length-2*Zc);i++) + for (j=0; jn_segments; j++) + channel_input[j][i] = (c[2*Zc+i]>>j)&1; + for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++) + for (j=0; jn_segments; j++) + channel_input[j][block_length-2*Zc+i] = (d[i]>>j)&1; + } + +#else + AssertFatal(1==0,"Need AVX2 for now\n"); +#endif + + if(impp->toutput != NULL) stop_meas(impp->toutput); + return 0; +} + + diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c new file mode 100644 index 0000000000..b21f875b32 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c @@ -0,0 +1,237 @@ +/* + * 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 ldpc_encoder2.c + * \brief Defines the optimized LDPC encoder + * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom) + * \email openair_tech@eurecom.fr + * \date 27-03-2018 + * \version 1.0 + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include "assertions.h" +#include "common/utils/LOG/log.h" +#include "PHY/TOOLS/time_meas.h" +#include "openair1/PHY/CODING/nrLDPC_defs.h" + +//#define DEBUG_LDPC + +#include "ldpc_encode_parity_check.c" +#include "ldpc_generate_coefficient.c" + + +int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp) +{ + + short nrows=0,ncols=0; + int i,i1,j,rate=3; + int no_punctured_columns,removed_bit; + //Table of possible lifting sizes + char temp; + int simd_size; + unsigned int macro_segment, macro_segment_end; + + + macro_segment = 8*impp->macro_num; + macro_segment_end = (impp->n_segments > 8*(impp->macro_num+1)) ? 8*(impp->macro_num+1) : impp->n_segments; + ///printf("macro_segment: %d\n", macro_segment); + ///printf("macro_segment_end: %d\n", macro_segment_end ); + +#ifdef __AVX2__ + __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000); + __m256i andmask = _mm256_set1_epi64x(0x0102040810204080); // every 8 bits -> 8 bytes, pattern repeats. + __m256i zero256 = _mm256_setzero_si256(); + __m256i masks[8]; + register __m256i c256; + masks[0] = _mm256_set1_epi8(0x1); + masks[1] = _mm256_set1_epi8(0x2); + masks[2] = _mm256_set1_epi8(0x4); + masks[3] = _mm256_set1_epi8(0x8); + masks[4] = _mm256_set1_epi8(0x10); + masks[5] = _mm256_set1_epi8(0x20); + masks[6] = _mm256_set1_epi8(0x40); + masks[7] = _mm256_set1_epi8(0x80); +#endif + + + + //determine number of bits in codeword + if (BG==1) + { + nrows=46; //parity check bits + ncols=22; //info bits + rate=3; + } + else if (BG==2) + { + nrows=42; //parity check bits + ncols=10; // info bits + rate=5; + } + +#ifdef DEBUG_LDPC + LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments); + LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]); +#endif + + AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length); + + if ((Zc&31) > 0) simd_size = 16; + else simd_size = 32; + + unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size + unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size + + unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32))); //double size matrix of c + + // calculate number of punctured bits + no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc; + removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate); + //printf("%d\n",no_punctured_columns); + //printf("%d\n",removed_bit); + // unpack input + memset(c,0,sizeof(unsigned char) * ncols * Zc); + memset(d,0,sizeof(unsigned char) * nrows * Zc); + + if(impp->tinput != NULL) start_meas(impp->tinput); +#if 0 + for (i=0; i>(i&7); + //printf("c(%d,%d)=%d\n",j,i,temp); + c[i] |= (temp << (j-macro_segment)); + } + } +#else +#ifdef __AVX2__ + for (i=0; i>5; i++) { + c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[macro_segment])[i]), shufmask),andmask),zero256),masks[0]); + //for (j=1; j>5)<<5;i>(i&7)))>>(7-(i&7)); + //printf("c(%d,%d)=%d\n",j,i,temp); + c[i] |= (temp << (j-macro_segment)); + } + } +#else + AssertFatal(1==0,"Need AVX2 for this\n"); +#endif +#endif + + if(impp->tinput != NULL) stop_meas(impp->tinput); + + if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { + // extend matrix + if(impp->tprep != NULL) start_meas(impp->tprep); + for (i1=0; i1 < ncols; i1++) + { + memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char)); + memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char)); + } + for (i1=1;i1tprep != NULL) stop_meas(impp->tprep); + //parity check part + if(impp->tparity != NULL) start_meas(impp->tparity); + encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb); + if(impp->tparity != NULL) stop_meas(impp->tparity); + } + else { + if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) { + printf("Problem with encoder\n"); + return(-1); + } + } + if(impp->toutput != NULL) start_meas(impp->toutput); + // information part and puncture columns + /* + memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char)); + memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char)); + */ +#ifdef __AVX2__ + if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) { + //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n"); + //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n"); + uint32_t l1 = (block_length-(2*Zc))>>5; + uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5; + __m256i *c256p = (__m256i *)&c[2*Zc]; + __m256i *d256p = (__m256i *)&d[0]; + // if (((block_length-(2*Zc))&31)>0) l1++; + + for (i=0;i0) l2++; + + for (i1=0;i1>(j-macro_segment))&1; + for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++) + //for (j=0; j>(j-macro_segment))&1; + } + +#else + AssertFatal(1==0,"Need AVX2 for now\n"); +#endif + + if(impp->toutput != NULL) stop_meas(impp->toutput); + return 0; +} + diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c index 5988c9067d..3d26a19063 100644 --- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c @@ -35,9 +35,8 @@ #include #include "Gen_shift_value.h" #include "assertions.h" -#include "defs.h" -short *choose_generator_matrix(short BG,short Zc) +static inline short *choose_generator_matrix(short BG,short Zc) { short *Gen_shift_values = NULL; @@ -361,237 +360,70 @@ short *choose_generator_matrix(short BG,short Zc) return Gen_shift_values; } -int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length, short BG,unsigned char gen_code) +static inline int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length) { - unsigned char c[22*384]; //padded input, unpacked, max size - unsigned char d[68*384]; //coded output, unpacked, max size + short *Gen_shift_values=choose_generator_matrix(BG,Zc); + short *no_shift_values, *pointer_shift_values; + int no_punctured_columns; + short nrows,ncols,rate=3; + int i1,i2,i3,i4,i5,temp_prime; unsigned char channel_temp,temp; - short *Gen_shift_values, *no_shift_values, *pointer_shift_values; - short nrows = 46;//parity check bits - short ncols = 22;//info bits - - - int i,i1,i2,i3,i4,i5,temp_prime,var; - int no_punctured_columns,removed_bit,rate=3; - int nind=0; - int indlist[1000]; - int indlist2[1000]; - - //determine number of bits in codeword - //if (block_length>3840) - if (BG==1) - { - nrows=46; //parity check bits - ncols=22; //info bits - rate=3; - } - //else if (block_length<=3840) - else if (BG==2) - { - //BG=2; - nrows=42; //parity check bits - ncols=10; // info bits - rate=5; - } - - Gen_shift_values=choose_generator_matrix(BG,Zc); - if (Gen_shift_values==NULL) { - printf("ldpc_encoder_orig: could not find generator matrix\n"); - return(-1); - } - - //printf("ldpc_encoder_orig: BG %d, Zc %d, Kb %d\n",BG, Zc, Kb); - - // load base graph of generator matrix if (BG==1) { no_shift_values=(short *) no_shift_values_BG1; pointer_shift_values=(short *) pointer_shift_values_BG1; + nrows=46; //parity check bits + ncols=22; //info bits + rate=3; } else if (BG==2) { no_shift_values=(short *) no_shift_values_BG2; pointer_shift_values=(short *) pointer_shift_values_BG2; + nrows=42; //parity check bits + ncols=10; //info bits + rate=5; } else { - AssertFatal(0,"BG %d is not supported yet\n",BG); + printf("problem with BG\n"); + return(-1); } - + + no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc; - removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(block_length*rate); - //printf("%d\n",no_punctured_columns); - //printf("%d\n",removed_bit); - // unpack input - memset(c,0,sizeof(unsigned char) * ncols * Zc); - memset(d,0,sizeof(unsigned char) * nrows * Zc); - for (i=0; i>7&1; - c[i]=(test_input[i/8]&(128>>(i&7)))>>(7-(i&7)); - } + //t=Kb*Zc+i2; - // parity check part - - if (gen_code==1) - { - char fname[100]; - sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc); - FILE *fd=fopen(fname,"w"); - AssertFatal(fd!=NULL,"cannot open %s\n",fname); - sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc); - FILE *fd2=fopen(fname,"w"); - AssertFatal(fd2!=NULL,"cannot open %s\n",fname); - - int shift; - char data_type[100]; - char xor_command[100]; - int mask; - - - - - fprintf(fd,"#include \"PHY/sse_intrin.h\"\n"); - fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n"); - - if ((Zc&31)==0) { - shift=5; // AVX2 - 256-bit SIMD - mask=31; - strcpy(data_type,"__m256i"); - strcpy(xor_command,"_mm256_xor_si256"); - } - else if ((Zc&15)==0) { - shift=4; // SSE4 - 128-bit SIMD - mask=15; - strcpy(data_type,"__m128i"); - strcpy(xor_command,"_mm_xor_si128"); - - } - else if ((Zc&7)==0) { - shift=3; // MMX - 64-bit SIMD - mask=7; - strcpy(data_type,"__m64"); - strcpy(xor_command,"_mm_xor_si64"); - } - else { - shift=0; // no SIMD - mask=0; - strcpy(data_type,"uint8_t"); - strcpy(xor_command,"scalar_xor"); - fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n"); - fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n"); - } - fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc); - fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc); - fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc); - fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc); - fprintf(fd," %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type); - fprintf(fd2," %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type); - fprintf(fd," %s *c2,*d2;\n\n",data_type); - fprintf(fd2," %s *c2,*d2;\n\n",data_type); - fprintf(fd," int i2;\n"); - fprintf(fd2," int i2;\n"); - fprintf(fd," for (i2=0; i2<%d; i2++) {\n",Zc>>shift); - if (shift > 0) - fprintf(fd2," for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1)); - for (i2=0; i2 < 1; i2++) + //rotate matrix here + for (i5=0; i5 < Kb; i5++) { - //t=Kb*Zc+i2; - - // calculate each row in base graph - - - fprintf(fd," c2=&csimd[i2];\n"); - fprintf(fd," d2=&dsimd[i2];\n"); - fprintf(fd2," c2=&csimd[i2];\n"); - fprintf(fd2," d2=&dsimd[i2];\n"); - - for (i1=0; i1 < nrows; i1++) - - { - channel_temp=0; - fprintf(fd,"\n//row: %d\n",i1); - fprintf(fd2,"\n//row: %d\n",i1); - fprintf(fd," d2[%d]=",(Zc*i1)>>shift); - fprintf(fd2," d2[%d]=",(Zc*i1)>>(shift-1)); - - nind=0; - - for (i3=0; i3 < ncols; i3++) - { - temp_prime=i1 * ncols + i3; - - - for (i4=0; i4 < no_shift_values[temp_prime]; i4++) - { - - var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc); - int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc; - - indlist[nind] = ((index&mask)*((2*Zc)>>shift)*Kb)+(index>>shift); - indlist2[nind++] = ((index&(mask>>1))*((2*Zc)>>(shift-1))*Kb)+(index>>(shift-1)); - - } - - - } - for (i4=0;i4 +#include +#include +#include "assertions.h" +#include "common/utils/LOG/log.h" +#define LDPC_LOADER +#include "PHY/CODING/nrLDPC_extern.h" +#include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" + + +/* function description array, to be used when loading the encoding/decoding shared lib */ +static loader_shlibfunc_t shlib_fdesc[2]; + +char *arg[64]={"ldpctest","-O","cmdlineonly::dbgl0"}; + +int load_nrLDPClib(void) { + char *ptr = (char*)config_get_if(); + if ( ptr==NULL ) {// phy simulators, config module possibly not loaded + load_configmodule(3,(char **)arg,CONFIG_ENABLECMDLINEONLY) ; + logInit(); + } + shlib_fdesc[0].fname = "nrLDPC_decod"; + shlib_fdesc[1].fname = "nrLDPC_encod"; + int ret=load_module_shlib("ldpc",shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t),NULL); + AssertFatal( (ret >= 0),"Error loading ldpc decoder"); + nrLDPC_decoder = (nrLDPC_decoderfunc_t)shlib_fdesc[0].fptr; + nrLDPC_encoder = (nrLDPC_encoderfunc_t)shlib_fdesc[1].fptr; +return 0; +} + +int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_ptr) { + loader_shlibfunc_t shlib_encoder_fdesc; + + shlib_encoder_fdesc.fname = "nrLDPC_encod"; + char libpath[64]; + sprintf(libpath,"ldpc%s",libversion); + int ret=load_module_shlib(libpath,&shlib_encoder_fdesc,1,NULL); + AssertFatal( (ret >= 0),"Error loading ldpc encoder %s\n",libpath); + *nrLDPC_encoder_ptr = (nrLDPC_encoderfunc_t)shlib_encoder_fdesc.fptr; +return 0; +} + + diff --git a/openair1/PHY/CODING/nr_segmentation.c b/openair1/PHY/CODING/nr_segmentation.c index 462cdee1fc..1d80a83131 100644 --- a/openair1/PHY/CODING/nr_segmentation.c +++ b/openair1/PHY/CODING/nr_segmentation.c @@ -30,13 +30,13 @@ //#define DEBUG_SEGMENTATION int32_t nr_segmentation(unsigned char *input_buffer, - unsigned char **output_buffers, - unsigned int B, - unsigned int *C, - unsigned int *K, - unsigned int *Zout, // [hna] Zout is Zc - unsigned int *F, - uint8_t BG) + unsigned char **output_buffers, + unsigned int B, + unsigned int *C, + unsigned int *K, + unsigned int *Zout, // [hna] Zout is Zc + unsigned int *F, + uint8_t BG) { unsigned int L,Bprime,Z,r,Kcb,Kb,k,s,crc,Kprime; diff --git a/openair1/PHY/INIT/init_top.c b/openair1/PHY/INIT/init_top.c index 6421eebe28..0990a58266 100644 --- a/openair1/PHY/INIT/init_top.c +++ b/openair1/PHY/INIT/init_top.c @@ -19,7 +19,7 @@ contact@openairinterface.org */ -/*!\brief Initilization and reconfiguration routines for LTE PHY */ +/*!\brief Initialization and reconfiguration routines for LTE PHY */ #include "phy_init.h" #include "PHY/phy_extern.h" #include "PHY/CODING/coding_extern.h" diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index d754d26134..2d65521ab3 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -69,6 +69,9 @@ l1_north_init_eNB () { LOG_I(PHY,"%s() RC.eNB[%d][%d] installing callbacks\n", __FUNCTION__, i, j); RC.eNB[i][j]->if_inst->PHY_config_req = phy_config_request; RC.eNB[i][j]->if_inst->schedule_response = schedule_response; + RC.eNB[i][j]->if_inst->PHY_config_update_sib2_req = phy_config_update_sib2_request; + RC.eNB[i][j]->if_inst->PHY_config_update_sib13_req = phy_config_update_sib13_request; + } } } else { @@ -283,7 +286,51 @@ void phy_config_request(PHY_Config_t *phy_config) { LOG_I (PHY, "eNB %d/%d configured\n", Mod_id, CC_id); } +void phy_config_update_sib2_request(PHY_Config_t *phy_config) { + uint8_t Mod_id = phy_config->Mod_id; + int CC_id = phy_config->CC_id; + int i; + nfapi_config_request_t *cfg = phy_config->cfg; + LOG_I(PHY,"Configure sib2 Mod_id(%d), CC_id(%d) cfg %p\n",Mod_id,CC_id,cfg); + + LTE_DL_FRAME_PARMS *fp = &RC.eNB[Mod_id][CC_id]->frame_parms; + + fp->num_MBSFN_config = cfg->embms_mbsfn_config.num_mbsfn_config; + for( i=0; i < cfg->embms_mbsfn_config.num_mbsfn_config; i++){ + fp->MBSFN_config[i].radioframeAllocationPeriod = cfg->embms_mbsfn_config.radioframe_allocation_period[i]; + fp->MBSFN_config[i].radioframeAllocationOffset = cfg->embms_mbsfn_config.radioframe_allocation_offset[i]; + fp->MBSFN_config[i].fourFrames_flag = cfg->embms_mbsfn_config.fourframes_flag[i]; + fp->MBSFN_config[i].mbsfn_SubframeConfig = cfg->embms_mbsfn_config.mbsfn_subframeconfig[i]; // 6-bit subframe configuration + LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } + + + +} +void phy_config_update_sib13_request(PHY_Config_t *phy_config) { + + uint8_t Mod_id = phy_config->Mod_id; + int CC_id = phy_config->CC_id; + nfapi_config_request_t *cfg = phy_config->cfg; + + LOG_I(PHY,"configure sib3 Mod_id(%d), CC_id(%d) cfg %p\n",Mod_id,CC_id,cfg); + LTE_DL_FRAME_PARMS *fp = &RC.eNB[Mod_id][CC_id]->frame_parms; + LOG_I (PHY, "[eNB%d] Applying MBSFN_Area_id %d for index %d\n", Mod_id, (uint16_t)cfg->embms_sib13_config.mbsfn_area_id_r9.value, (uint8_t)cfg->embms_sib13_config.mbsfn_area_idx.value); + + //cfg->embms_sib13_config.mbsfn_area_idx; + //cfg->embms_sib13_config.mbsfn_area_id_r9; + + AssertFatal((uint8_t)cfg->embms_sib13_config.mbsfn_area_idx.value == 0, "Fix me: only called when mbsfn_Area_idx == 0\n"); + if (cfg->embms_sib13_config.mbsfn_area_idx.value == 0) { + fp->Nid_cell_mbsfn = (uint16_t)cfg->embms_sib13_config.mbsfn_area_id_r9.value; + LOG_I(PHY,"Fix me: only called when mbsfn_Area_idx == 0)\n"); + } + lte_gold_mbsfn (fp, RC.eNB[Mod_id][CC_id]->lte_gold_mbsfn_table, fp->Nid_cell_mbsfn); + + lte_gold_mbsfn_khz_1dot25 (fp, RC.eNB[Mod_id][CC_id]->lte_gold_mbsfn_khz_1dot25_table, fp->Nid_cell_mbsfn); +} void phy_config_sib13_eNB(module_id_t Mod_id,int CC_id,int mbsfn_Area_idx, long mbsfn_AreaId_r9) { diff --git a/openair1/PHY/INIT/lte_init_ue.c b/openair1/PHY/INIT/lte_init_ue.c index 6c9ca73754..1a6f0081e1 100644 --- a/openair1/PHY/INIT/lte_init_ue.c +++ b/openair1/PHY/INIT/lte_init_ue.c @@ -154,6 +154,42 @@ void phy_config_sib2_ue(module_id_t Mod_id,int CC_id, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2, VCD_FUNCTION_OUT); } +void phy_config_mbsfn_list_ue(module_id_t Mod_id, + int CC_id, + struct LTE_MBSFN_SubframeConfigList *mbsfn_SubframeConfigList){ + // MBSFN + + PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id]; + LTE_DL_FRAME_PARMS *fp = &ue->frame_parms; + int i; + + if (mbsfn_SubframeConfigList != NULL) { + + fp->num_MBSFN_config = mbsfn_SubframeConfigList->list.count; + + for (i=0; ilist.count; i++) { + fp->MBSFN_config[i].radioframeAllocationPeriod = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationPeriod; + fp->MBSFN_config[i].radioframeAllocationOffset = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationOffset; + + if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { + fp->MBSFN_config[i].fourFrames_flag = 0; + fp->MBSFN_config[i].mbsfn_SubframeConfig = mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration + LOG_I(PHY, "[CONFIG] LTE_MBSFN_SubframeConfig[%d] pattern is %d\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } else if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration + fp->MBSFN_config[i].fourFrames_flag = 1; + fp->MBSFN_config[i].mbsfn_SubframeConfig = + mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]| + (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| + (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]<<16); + LOG_I(PHY, "[CONFIG] LTE_MBSFN_SubframeConfig[%d] pattern is %x\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } + } + } +} + + void phy_config_sib13_ue(module_id_t Mod_id,int CC_id,uint8_t eNB_id,int mbsfn_Area_idx, long mbsfn_AreaId_r9) { LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; @@ -578,7 +614,8 @@ int init_lte_ue_signal(PHY_VARS_UE *ue, LTE_UE_PDSCH **const pdsch_vars_SI = ue->pdsch_vars_SI; LTE_UE_PDSCH **const pdsch_vars_ra = ue->pdsch_vars_ra; LTE_UE_PDSCH **const pdsch_vars_p = ue->pdsch_vars_p; - LTE_UE_PDSCH **const pdsch_vars_mch = ue->pdsch_vars_MCH; + //LTE_UE_PDSCH **const pdsch_vars_mch = ue->pdsch_vars_MCH; + LTE_UE_PDSCH* (*pdsch_vars_MCH_th)[][NUMBER_OF_CONNECTED_eNB_MAX] = &ue->pdsch_vars_MCH; LTE_UE_PDSCH* (*pdsch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX+1] = &ue->pdsch_vars; LTE_UE_PDCCH* (*pdcch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX] = &ue->pdcch_vars; LTE_UE_PBCH **const pbch_vars = ue->pbch_vars; @@ -660,6 +697,7 @@ int init_lte_ue_signal(PHY_VARS_UE *ue, for (eNB_id=0; eNB_idn_connected_eNB; eNB_id++) { for (th_id=0; th_idllr[1] = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); (*pdsch_vars_th)[th_id][eNB_id]->llr128_2ndstream = (int16_t **)malloc16_clear( sizeof(int16_t *) ); (*pdsch_vars_th)[th_id][eNB_id]->rho = (int32_t **)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t *) ); + + (*pdsch_vars_MCH_th)[th_id][eNB_id]->llr_shifts = (uint8_t *)malloc16_clear(7*2*fp->N_RB_DL*12); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->llr_shifts_p = (*pdsch_vars_th)[0][eNB_id]->llr_shifts; + (*pdsch_vars_MCH_th)[th_id][eNB_id]->llr[1] = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->llr128_2ndstream = (int16_t **)malloc16_clear( sizeof(int16_t *) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->rho = (int32_t **)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t *) ); + } for (int i=0; inb_antennas_rx; i++) { for (th_id=0; th_idrho[i] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->rho[i] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); } } for (th_id=0; th_iddl_ch_rho2_ext = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_rho2_ext = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); } for (i=0; inb_antennas_rx; i++) @@ -702,6 +750,7 @@ int init_lte_ue_signal(PHY_VARS_UE *ue, for (th_id=0; th_iddl_ch_rho2_ext[idx] = (int32_t *)malloc16_clear( sizeof(int32_t) * num ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_rho2_ext[idx] = (int32_t *)malloc16_clear( sizeof(int32_t) * num ); } } @@ -713,6 +762,11 @@ int init_lte_ue_signal(PHY_VARS_UE *ue, (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + + (*pdsch_vars_MCH_th)[th_id][eNB_id]->rxdataF_comp1[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_mag1[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_magb1[k][l] = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); } for (int i=0; inb_antennas_rx; i++) @@ -724,6 +778,11 @@ int init_lte_ue_signal(PHY_VARS_UE *ue, (*pdsch_vars_th)[th_id][eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_MCH_th)[th_id][eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t *)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); } } } @@ -732,7 +791,7 @@ int init_lte_ue_signal(PHY_VARS_UE *ue, phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp ); phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp ); phy_init_lte_ue__PDSCH( pdsch_vars_p[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp ); + //phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp ); // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE for (th_id=0; th_id @@ -112,6 +113,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_gNB][MOD %02"PRIu8"][]\n", gNB->Mod_id); crcTableInit(); init_dfts(); + load_nrLDPClib(); // PBCH DMRS gold sequences generation nr_init_pbch_dmrs(gNB); //PDCCH DMRS init @@ -150,8 +152,31 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, } } + nr_init_pdsch_dmrs(gNB, cfg->cell_config.phy_cell_id.value); + //PUSCH DMRS init + gNB->nr_gold_pusch_dmrs = (uint32_t ****)malloc16(2*sizeof(uint32_t ***)); + uint32_t ****pusch_dmrs = gNB->nr_gold_pusch_dmrs; + + for(int nscid=0; nscid<2; nscid++) { + pusch_dmrs[nscid] = (uint32_t ***)malloc16(fp->slots_per_frame*sizeof(uint32_t **)); + AssertFatal(pusch_dmrs[nscid]!=NULL, "NR init: pusch_dmrs for nscid %d - malloc failed\n", nscid); + + for (int slot=0; slotslots_per_frame; slot++) { + pusch_dmrs[nscid][slot] = (uint32_t **)malloc16(fp->symbols_per_slot*sizeof(uint32_t *)); + AssertFatal(pusch_dmrs[nscid][slot]!=NULL, "NR init: pusch_dmrs for slot %d - malloc failed\n", slot); + + for (int symb=0; symbsymbols_per_slot; symb++) { + pusch_dmrs[nscid][slot][symb] = (uint32_t *)malloc16(NR_MAX_PUSCH_DMRS_INIT_LENGTH_DWORD*sizeof(uint32_t)); + AssertFatal(pusch_dmrs[nscid][slot][symb]!=NULL, "NR init: pusch_dmrs for slot %d symbol %d - malloc failed\n", slot, symb); + } + } + } + + uint32_t Nid_pusch[2] = {cfg->cell_config.phy_cell_id.value,cfg->cell_config.phy_cell_id.value}; + nr_gold_pusch(gNB, &Nid_pusch[0]); + /// Transport init necessary for NR synchro init_nr_transport(gNB); @@ -216,6 +241,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->rxdataF_ext2 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_estimates = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_estimates_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_estimates_time = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->rxdataF_comp = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_mag0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); @@ -231,6 +258,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->ul_ch_estimates_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->ul_ch_estimates_time[i] = (int32_t *)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size ); + pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); // max intensity in freq is 1 sc every 2 RBs + pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->rxdataF_comp[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); @@ -299,6 +328,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_ext[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_time[i]); + free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates[i]); + free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext[i]); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0[i]); @@ -311,6 +342,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ext2); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_ext); + free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates); + free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_time); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0); @@ -347,12 +380,16 @@ void nr_phy_config_request_sim(PHY_VARS_gNB *gNB, nfapi_nr_config_request_scf_t *gNB_config = &gNB->gNB_config; //overwrite for new NR parameters + uint64_t rev_burst=0; + for (int i=0; i<64; i++) + rev_burst |= (((position_in_burst>>(63-i))&0x01)<cell_config.phy_cell_id.value = Nid_cell; gNB_config->ssb_config.scs_common.value = mu; gNB_config->ssb_table.ssb_subcarrier_offset.value = 0; gNB_config->ssb_table.ssb_offset_point_a.value = (N_RB_DL-20)>>1; - gNB_config->ssb_table.ssb_mask_list[0].ssb_mask.value = position_in_burst; - gNB_config->ssb_table.ssb_mask_list[1].ssb_mask.value = position_in_burst>>32; + gNB_config->ssb_table.ssb_mask_list[1].ssb_mask.value = (rev_burst)&(0xFFFFFFFF); + gNB_config->ssb_table.ssb_mask_list[0].ssb_mask.value = (rev_burst>>32)&(0xFFFFFFFF); gNB_config->cell_config.frame_duplex_type.value = TDD; gNB_config->ssb_table.ssb_period.value = 1; //10ms gNB_config->carrier_config.dl_grid_size[mu].value = N_RB_DL; @@ -368,6 +405,9 @@ void nr_phy_config_request_sim(PHY_VARS_gNB *gNB, fp->ul_CarrierFreq = 3500000000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000); fp->nr_band = 78; fp->threequarter_fs= 0; + + gNB_config->carrier_config.dl_bandwidth.value = config_bandwidth(mu, N_RB_DL, fp->nr_band); + nr_init_frame_parms(gNB_config, fp); gNB->configured = 1; LOG_I(PHY,"gNB configured\n"); @@ -486,8 +526,7 @@ void init_nr_transport(PHY_VARS_gNB *gNB) { rel15_ul->ulsch_pdu_rel15.number_rbs = 50; rel15_ul->ulsch_pdu_rel15.start_symbol = 2; rel15_ul->ulsch_pdu_rel15.number_symbols = 12; - rel15_ul->ulsch_pdu_rel15.nb_re_dmrs = 6; - rel15_ul->ulsch_pdu_rel15.length_dmrs = 1; + rel15_ul->ulsch_pdu_rel15.length_dmrs = gNB->dmrs_UplinkConfig.pusch_maxLength; rel15_ul->ulsch_pdu_rel15.Qm = 2; rel15_ul->ulsch_pdu_rel15.R = 679; rel15_ul->ulsch_pdu_rel15.mcs = 9; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index b588782772..4ed5be2119 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -357,6 +357,7 @@ void phy_config_dedicated_scell_ue(uint8_t Mod_id, } #endif +#if 0 void phy_config_harq_ue(module_id_t Mod_id, int CC_id, uint8_t eNB_id, @@ -368,6 +369,7 @@ void phy_config_harq_ue(module_id_t Mod_id, for (num_of_code_words=0; num_of_code_wordsulsch[num_of_threads][eNB_id][num_of_code_words]->Mlimit = max_harq_tx; } +#endif extern uint16_t beta_cqi[16]; @@ -649,11 +651,14 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int i,j,k,l,slot,symb,q; int eNB_id; int th_id; - int k_ssb=0; uint32_t ****pusch_dmrs; uint16_t N_n_scid[2] = {0,1}; // [HOTFIX] This is a temporary implementation of scramblingID0 and scramblingID1 which are given by DMRS-UplinkConfig int n_scid; abstraction_flag = 0; + fp->nb_antennas_tx = 1; + fp->nb_antennas_rx=1; + dmrs_UplinkConfig_t *dmrs_Uplink_Config = &ue->pusch_config.dmrs_UplinkConfig; + ptrs_UplinkConfig_t *ptrs_Uplink_Config = &ue->pusch_config.dmrs_UplinkConfig.ptrs_UplinkConfig; printf("Initializing UE vars (abstraction %"PRIu8") for eNB TXant %"PRIu8", UE RXant %"PRIu8"\n",abstraction_flag,fp->nb_antennas_tx,fp->nb_antennas_rx); //LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_eNB_INST); phy_init_nr_top(ue); @@ -696,14 +701,24 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, for (i=0; ipusch_config.pusch_TimeDomainResourceAllocation[i] = (PUSCH_TimeDomainResourceAllocation_t *)malloc16(sizeof(PUSCH_TimeDomainResourceAllocation_t)); - ue->pusch_config.pusch_TimeDomainResourceAllocation[i]->mappingType = typeA; + ue->pusch_config.pusch_TimeDomainResourceAllocation[i]->mappingType = typeB; + } + + for (i=0;iPDSCH_Config.pdsch_TimeDomainResourceAllocation[i] = (NR_PDSCH_TimeDomainResourceAllocation_t *)malloc16(sizeof(NR_PDSCH_TimeDomainResourceAllocation_t)); + ue->PDSCH_Config.pdsch_TimeDomainResourceAllocation[i]->mappingType = typeA; } //------------- config DMRS parameters--------------// - ue->dmrs_UplinkConfig.pusch_dmrs_type = pusch_dmrs_type1; - ue->dmrs_UplinkConfig.pusch_dmrs_AdditionalPosition = pusch_dmrs_pos0; - ue->dmrs_UplinkConfig.pusch_maxLength = pusch_len1; + dmrs_Uplink_Config->pusch_dmrs_type = pusch_dmrs_type1; + dmrs_Uplink_Config->pusch_dmrs_AdditionalPosition = pusch_dmrs_pos0; + dmrs_Uplink_Config->pusch_maxLength = pusch_len1; //-------------------------------------------------// + ue->dmrs_DownlinkConfig.pdsch_dmrs_type = pdsch_dmrs_type1; + ue->dmrs_DownlinkConfig.pdsch_dmrs_AdditionalPosition = pdsch_dmrs_pos0; + ue->dmrs_DownlinkConfig.pdsch_maxLength = pdsch_len1; + //-------------------------------------------------// + ue->nr_gold_pusch_dmrs = (uint32_t ****)malloc16(fp->slots_per_frame*sizeof(uint32_t ***)); pusch_dmrs = ue->nr_gold_pusch_dmrs; n_scid = 0; // This quantity is indicated by higher layer parameter dmrs-SeqInitialization @@ -727,6 +742,23 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, /////////// //////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////PUSCH PTRS init///////////////////////// + /////////// + + ue->ptrs_configured = 0; // flag to be toggled by RCC + + //------------- config PTRS parameters--------------// + ptrs_Uplink_Config->timeDensity.ptrs_mcs1 = 0; // setting MCS values to 0 indicate abscence of time_density field in the configuration + ptrs_Uplink_Config->timeDensity.ptrs_mcs2 = 0; + ptrs_Uplink_Config->timeDensity.ptrs_mcs3 = 0; + ptrs_Uplink_Config->frequencyDensity.n_rb0 = 0; // setting N_RB values to 0 indicate abscence of frequency_density field in the configuration + ptrs_Uplink_Config->frequencyDensity.n_rb1 = 0; + ptrs_Uplink_Config->resourceElementOffset = 0; + //-------------------------------------------------// + + /////////// + //////////////////////////////////////////////////////////////////////////////////////////// + for (i=0; i<10; i++) ue->tx_power_dBm[i]=-127; diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 246e3323ee..c3fe9c54b1 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -83,7 +83,7 @@ int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp) return symbol; } -void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) +void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, uint16_t bw) { switch(mu) { @@ -99,23 +99,21 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) // selection of SS block pattern according to TS 38101-1 Table 5.4.3.3-1 for SCS 30kHz if (fp->nr_band == 5 || fp->nr_band == 66) - fp->ssb_type = nr_ssb_type_B; + fp->ssb_type = nr_ssb_type_B; else{ if (fp->nr_band == 41 || ( fp->nr_band > 76 && fp->nr_band < 80) ) - fp->ssb_type = nr_ssb_type_C; + fp->ssb_type = nr_ssb_type_C; else - AssertFatal(1==0,"NR Operating Band n%d not available for SS block SCS with mu=%d\n", fp->nr_band, mu); + AssertFatal(1==0,"NR Operating Band n%d not available for SS block SCS with mu=%d\n", fp->nr_band, mu); } - switch(fp->N_RB_DL){ - case 11: - case 24: - case 38: - case 78: - case 51: - case 65: - - case 106: //40 MHz + switch(bw){ + case 5: + case 15: + case 20: + case 25: + case 30: + case 40: //40 MHz if (fp->threequarter_fs) { fp->ofdm_symbol_size = 1536; fp->first_carrier_offset = 900; //1536 - ( (106*12) / 2 ) @@ -130,11 +128,11 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) } break; - case 133: - case 162: - case 189: + case 50: + case 60: + case 70: - case 217: //80 MHz + case 80: //80 MHz if (fp->threequarter_fs) { fp->ofdm_symbol_size = 3072; fp->first_carrier_offset = 1770; //3072 - ( (217*12) / 2 ) @@ -149,22 +147,22 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) } break; - case 245: - AssertFatal(fp->threequarter_fs==0,"3/4 sampling impossible for N_RB %d and MU %d\n",fp->N_RB_DL,mu); + case 90: + AssertFatal(fp->threequarter_fs==0,"3/4 sampling impossible for %d MHz band and MU %d\n",bw,mu); fp->ofdm_symbol_size = 4096; fp->first_carrier_offset = 2626; //4096 - ( (245*12) / 2 ) fp->nb_prefix_samples0 = 352; fp->nb_prefix_samples = 288; break; - case 273: - AssertFatal(fp->threequarter_fs==0,"3/4 sampling impossible for N_RB %d and MU %d\n",fp->N_RB_DL,mu); + case 100: + AssertFatal(fp->threequarter_fs==0,"3/4 sampling impossible for %d MHz band and MU %d\n",bw,mu); fp->ofdm_symbol_size = 4096; fp->first_carrier_offset = 2458; //4096 - ( (273*12) / 2 ) fp->nb_prefix_samples0 = 352; fp->nb_prefix_samples = 288; break; default: - AssertFatal(1==0,"Number of resource blocks %d undefined for mu %d, frame parms = %p\n", fp->N_RB_DL, mu, fp); + AssertFatal(1==0,"%d MHz band undefined for mu %d, frame parms = %p\n", bw, mu, fp); } break; @@ -172,21 +170,21 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_2]; fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_2]; - switch(fp->N_RB_DL){ //FR1 bands only - case 11: - case 18: - case 38: - case 24: - case 31: - case 51: - case 65: - case 79: - case 93: - case 107: - case 121: - case 135: + switch(bw){ //FR1 bands only + case 10: + case 15: + case 20: + case 25: + case 30: + case 40: + case 50: + case 60: + case 70: + case 80: + case 90: + case 100: default: - AssertFatal(1==0,"Number of resource blocks %d undefined for mu %d, frame parms = %p\n", fp->N_RB_DL, mu, fp); + AssertFatal(1==0,"%d MHz band undefined for mu %d, frame parms = %p\n", bw, mu, fp); } break; @@ -194,21 +192,21 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_3]; fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_3]; fp->ssb_type = nr_ssb_type_D; - switch(fp->N_RB_DL){ - case 66: + switch(bw){ + case 100: fp->ofdm_symbol_size = 1024; fp->first_carrier_offset = 628; //1024 - ( (66*12) / 2 ) - fp->nb_prefix_samples0 = 88; + fp->nb_prefix_samples0 = 136; fp->nb_prefix_samples = 72; break; - case 32: + case 50: fp->ofdm_symbol_size = 512; fp->first_carrier_offset = 320; //1024 - ( (66*12) / 2 ) - fp->nb_prefix_samples0 = 44; + fp->nb_prefix_samples0 = 68; fp->nb_prefix_samples = 36; break; default: - AssertFatal(1==0,"Number of resource blocks %d undefined for mu %d, frame parms = %p\n", fp->N_RB_DL, mu, fp); + AssertFatal(1==0,"%d MHz band undefined for mu %d, frame parms = %p\n", bw, mu, fp); } break; @@ -223,22 +221,48 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu) } } +uint32_t get_samples_per_slot(int slot, NR_DL_FRAME_PARMS* fp) +{ + uint32_t samp_count; -int nr_init_frame_parms0(NR_DL_FRAME_PARMS *fp, - nfapi_nr_config_request_scf_t* cfg, - int mu0, - int Ncp, - int N_RB_DL, - int N_RB_UL) + if(fp->numerology_index == 0) + samp_count = fp->samples_per_subframe; + else + samp_count = (slot%(fp->slots_per_subframe/2)) ? fp->samples_per_slotN0 : fp->samples_per_slot0; + return samp_count; +} + +uint32_t get_samples_slot_timestamp(int slot, NR_DL_FRAME_PARMS* fp, uint8_t sl_ahead) +{ + uint32_t samp_count = 0; + + if(!sl_ahead) { + for(uint8_t idx_slot = 0; idx_slot < slot; idx_slot++) + samp_count += fp->get_samples_per_slot(idx_slot, fp); + } else { + for(uint8_t idx_slot = slot; idx_slot < slot+sl_ahead; idx_slot++) + samp_count += fp->get_samples_per_slot(idx_slot, fp); + } + return samp_count; +} + +int nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, + NR_DL_FRAME_PARMS *fp) { - int mu = cfg!= NULL ? cfg->ssb_config.scs_common.value : mu0; + fp->frame_type = cfg->cell_config.frame_duplex_type.value; + fp->L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value)<<32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value ; + fp->N_RB_DL = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value; + fp->N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value; + + int Ncp = NFAPI_CP_NORMAL; + int mu = cfg!= NULL ? cfg->ssb_config.scs_common.value : 0; #if DISABLE_LOG_X - printf("Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, N_RB_DL, Ncp); + printf("Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, fp->N_RB_DL, Ncp); #else - LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, N_RB_DL, Ncp); + LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, fp->N_RB_DL, Ncp); #endif if (Ncp == NFAPI_CP_EXTENDED) @@ -246,11 +270,8 @@ int nr_init_frame_parms0(NR_DL_FRAME_PARMS *fp, fp->half_frame_bit = 0; // half frame bit initialized to 0 here fp->numerology_index = mu; - fp->Ncp = Ncp; - fp->N_RB_DL = N_RB_DL; - fp->N_RB_UL = N_RB_UL; - set_scs_parameters(fp, mu); + set_scs_parameters(fp, mu, cfg->carrier_config.dl_bandwidth.value); fp->slots_per_frame = 10* fp->slots_per_subframe; @@ -262,12 +283,17 @@ int nr_init_frame_parms0(NR_DL_FRAME_PARMS *fp, fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe; fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP; fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size; - fp->samples_per_slot = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size); - fp->samples_per_subframe = (fp->samples_per_subframe_wCP + (fp->nb_prefix_samples0 * fp->slots_per_subframe) + - (fp->nb_prefix_samples * fp->slots_per_subframe * (fp->symbols_per_slot - 1))); + fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot; + fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size); + fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 + + (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2); + fp->get_samples_per_slot = &get_samples_per_slot; + fp->get_samples_slot_timestamp = &get_samples_slot_timestamp; fp->samples_per_frame = 10 * fp->samples_per_subframe; fp->freq_range = (fp->dl_CarrierFreq < 6e9)? nr_FR1 : nr_FR2; + fp->Ncp = Ncp; + // definition of Lmax according to ts 38.213 section 4.1 if (fp->dl_CarrierFreq < 6e9) { if(fp->frame_type && (fp->ssb_type==2)) @@ -285,22 +311,7 @@ int nr_init_frame_parms0(NR_DL_FRAME_PARMS *fp, fp->N_ssb += ((fp->L_ssb >> p) & 0x01); return 0; -} -int nr_init_frame_parms(nfapi_nr_config_request_scf_t* config, - NR_DL_FRAME_PARMS *fp) -{ - - fp->frame_type = config->cell_config.frame_duplex_type.value; - fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[1].ssb_mask.value)<<32) | config->ssb_table.ssb_mask_list[0].ssb_mask.value ; - int N_RB_DL = config->carrier_config.dl_grid_size[config->ssb_config.scs_common.value].value; - int N_RB_UL = config->carrier_config.ul_grid_size[config->ssb_config.scs_common.value].value; - return nr_init_frame_parms0(fp, - config, - 0, - NFAPI_CP_NORMAL, - N_RB_DL, - N_RB_UL); } int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, @@ -336,7 +347,7 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fp->Ncp = Ncp; - set_scs_parameters(fp,fp->numerology_index); + set_scs_parameters(fp,fp->numerology_index,config->carrier_config.dl_bandwidth); fp->slots_per_frame = 10* fp->slots_per_subframe; @@ -348,13 +359,21 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe; fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP; fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size; - fp->samples_per_slot = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size); - fp->samples_per_subframe = (fp->samples_per_subframe_wCP + (fp->nb_prefix_samples0 * fp->slots_per_subframe) + - (fp->nb_prefix_samples * fp->slots_per_subframe * (fp->symbols_per_slot - 1))); + fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot; + fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size); + fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 + + (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2); + fp->get_samples_per_slot = &get_samples_per_slot; + fp->get_samples_slot_timestamp = &get_samples_slot_timestamp; fp->samples_per_frame = 10 * fp->samples_per_subframe; fp->freq_range = (fp->dl_CarrierFreq < 6e9)? nr_FR1 : nr_FR2; - fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + config->ssb_table.ssb_subcarrier_offset); + uint8_t sco = 0; + if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset<24)) || + ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset<12)) ) + sco = config->ssb_table.ssb_subcarrier_offset; + + fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + sco); // definition of Lmax according to ts 38.213 section 4.1 if (fp->dl_CarrierFreq < 6e9) { @@ -366,7 +385,7 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fp->Lmax = 64; } - fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[1].ssb_mask)<<32) | config->ssb_table.ssb_mask_list[0].ssb_mask; + fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[1].ssb_mask)<<32) | config->ssb_table.ssb_mask_list[1].ssb_mask; fp->N_ssb = 0; for (int p=0; pLmax; p++) diff --git a/openair1/PHY/INIT/phy_init.h b/openair1/PHY/INIT/phy_init.h index ca136b6a69..1862d5f8e0 100644 --- a/openair1/PHY/INIT/phy_init.h +++ b/openair1/PHY/INIT/phy_init.h @@ -178,6 +178,18 @@ void phy_config_sib2_ue(module_id_t Mod_id, LTE_AdditionalSpectrumEmission_t *additionalSpectrumEmission, struct LTE_MBSFN_SubframeConfigList *mbsfn_SubframeConfigList); + /*! + \fn void phy_config_mbsfn_list_ue(module_id_t Mod_id,uint8_t CC_id + struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList) + \brief Configure LTE_DL_FRAME_PARMS with components derived after reception of MBSFN config list from SIB2 (at UE). + @param Mod_id Instance id + @param CC_id + @param mbsfn_SubframeConfigList MBSFN subframe configuration + */ +void phy_config_mbsfn_list_ue(module_id_t Mod_id, + int CC_id, + struct LTE_MBSFN_SubframeConfigList *mbsfn_SubframeConfigList); + /*! \fn phy_config_afterHO_ue @@ -374,6 +386,9 @@ void phy_config_dedicated_scell_eNB(uint8_t Mod_id, void phy_cleanup(void); void phy_config_request(PHY_Config_t *phy_config); +void phy_config_update_sib2_request(PHY_Config_t *phy_config); +void phy_config_update_sib13_request(PHY_Config_t *phy_config); + int init_frame_parms(LTE_DL_FRAME_PARMS *frame_parms,uint8_t osf); void dump_frame_parms(LTE_DL_FRAME_PARMS *frame_parms); diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 2b6d998b73..ce409de131 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -2014,10 +2014,8 @@ void fill_ulsch(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_ulsch_pdu *ulsch_pdu ulsch->harq_processes[harq_pid]->frame = frame; ulsch->harq_processes[harq_pid]->subframe = subframe; ulsch->harq_processes[harq_pid]->handled = 0; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) ulsch->harq_processes[harq_pid]->repetition_number = ulsch_pdu->ulsch_pdu_rel13.repetition_number ; ulsch->harq_processes[harq_pid]->total_number_of_repetitions = ulsch_pdu->ulsch_pdu_rel13.total_number_of_repetitions ; -#endif ulsch->harq_processes[harq_pid]->first_rb = ulsch_pdu->ulsch_pdu_rel8.resource_block_start; ulsch->harq_processes[harq_pid]->nb_rb = ulsch_pdu->ulsch_pdu_rel8.number_of_resource_blocks; ulsch->harq_processes[harq_pid]->dci_alloc = 1; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 8a3649cf87..04a49d062a 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -1946,11 +1946,11 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, case 2: //QPSK // LOG_I(PHY,"%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - ((int16_t*)&txdataF[4][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i + ((int16_t*)&txdataF[0][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; - ((int16_t*)&txdataF[4][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} + ((int16_t*)&txdataF[0][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} *jj = *jj + 1; @@ -1989,8 +1989,8 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, *jj=*jj+1; - ((int16_t *)&txdataF[4][tti_offset])[0]=qam_table_s[qam16_table_offset_re];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - ((int16_t *)&txdataF[4][tti_offset])[1]=qam_table_s[qam16_table_offset_im];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + ((int16_t *)&txdataF[0][tti_offset])[0]=qam_table_s[qam16_table_offset_re];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t *)&txdataF[0][tti_offset])[1]=qam_table_s[qam16_table_offset_im];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); break; @@ -2029,8 +2029,8 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, *jj=*jj+1; - ((int16_t *)&txdataF[4][tti_offset])[0]=qam_table_s[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[4][tti_offset])[1]=qam_table_s[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + ((int16_t *)&txdataF[0][tti_offset])[0]=qam_table_s[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[0][tti_offset])[1]=qam_table_s[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; default: diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index fcbf639a7e..1e0dd9db1b 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -41,9 +41,992 @@ //#define DEBUG_UL_MOBIPASS #define SUBFRAME_SKIP_NUM_MOBIPASS 8 -const uint8_t lin2alaw_if5[65536] = {213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85}; +const uint8_t lin2alaw_if5[65536] = {213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, +42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, +43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, +33, 33, 33, 33, 33, 33, 33, 33, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, +39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, +59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, +62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, +62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, +62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, +62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, +62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, +62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, +60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, +61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, +50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, +55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, +52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, +53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, +53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, +53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, +53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, +53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, +53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, +9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, +9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4, +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, +5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, +5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, +5, 5, 5, 5, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, +30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, +30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, +31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, +31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, +19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, +19, 19, 19, 19, 19, 19, 19, 19, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 20, 20, 20, 20, 20, +20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 98, 98, 98, 98, 98, 98, 98, 98, +98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, +99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, +96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, +97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 78, 78, +78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, +66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, +71, 71, 71, 71, 71, 71, 71, 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 88, 88, 88, +88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, +92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, +81, 81, 81, 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85}; -const uint16_t alaw2lin_if5[256] = {60032, 60288, 59520, 59776, 61056, 61312, 60544, 60800, 57984, 58240, 57472, 57728, 59008, 59264, 58496, 58752, 62784, 62912, 62528, 62656, 63296, 63424, 63040, 63168, 61760, 61888, 61504, 61632, 62272, 62400, 62016, 62144, 43520, 44544, 41472, 42496, 47616, 48640, 45568, 46592, 35328, 36352, 33280, 34304, 39424, 40448, 37376, 38400, 54528, 55040, 53504, 54016, 56576, 57088, 55552, 56064, 50432, 50944, 49408, 49920, 52480, 52992, 51456, 51968, 65192, 65208, 65160, 65176, 65256, 65272, 65224, 65240, 65064, 65080, 65032, 65048, 65128, 65144, 65096, 65112, 65448, 65464, 65416, 65432, 65512, 65528, 65480, 65496, 65320, 65336, 65288, 65304, 65384, 65400, 65352, 65368, 64160, 64224, 64032, 64096, 64416, 64480, 64288, 64352, 63648, 63712, 63520, 63584, 63904, 63968, 63776, 63840, 64848, 64880, 64784, 64816, 64976, 65008, 64912, 64944, 64592, 64624, 64528, 64560, 64720, 64752, 64656, 64688, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848}; +const uint16_t alaw2lin_if5[256] = {60032, 60288, 59520, 59776, 61056, 61312, 60544, 60800, 57984, 58240, 57472, 57728, 59008, 59264, 58496, 58752, 62784, 62912, 62528, 62656, 63296, 63424, 63040, 63168, 61760, 61888, 61504, 61632, 62272, 62400, 62016, 62144, 43520, 44544, 41472, 42496, 47616, +48640, 45568, 46592, 35328, 36352, 33280, 34304, 39424, 40448, 37376, 38400, 54528, 55040, 53504, 54016, 56576, 57088, 55552, 56064, 50432, 50944, 49408, 49920, 52480, 52992, 51456, 51968, 65192, 65208, 65160, 65176, 65256, 65272, 65224, 65240, 65064, 65080, 65032, 65048, 65128, 65144, 65096, +65112, 65448, 65464, 65416, 65432, 65512, 65528, 65480, 65496, 65320, 65336, 65288, 65304, 65384, 65400, 65352, 65368, 64160, 64224, 64032, 64096, 64416, 64480, 64288, 64352, 63648, 63712, 63520, 63584, 63904, 63968, 63776, 63840, 64848, 64880, 64784, 64816, 64976, 65008, 64912, 64944, 64592, +64624, 64528, 64560, 64720, 64752, 64656, 64688, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, +30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, +152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848}; struct timespec start_comp, start_decomp, end_comp, end_decomp; int dummy_cnt = 0; diff --git a/openair1/PHY/LTE_TRANSPORT/pmch.c b/openair1/PHY/LTE_TRANSPORT/pmch.c index 6fab3dc59b..f48ee629a1 100644 --- a/openair1/PHY/LTE_TRANSPORT/pmch.c +++ b/openair1/PHY/LTE_TRANSPORT/pmch.c @@ -96,13 +96,17 @@ void generate_mch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,uint8_t *a) get_Qm(eNB->dlsch_MCH->harq_processes[0]->mcs),1, 2,proc->frame_tx,subframe,0); + eNB->dlsch_MCH->harq_processes[0]->Qm = get_Qm(eNB->dlsch_MCH->harq_processes[0]->mcs); + generate_mbsfn_pilot(eNB,proc, eNB->common_vars.txdataF, AMP); + AssertFatal(eNB->dlsch_MCH->harq_processes[0]->pdu != NULL, "attempt to encode a NULL harq PDU\n"); AssertFatal(dlsch_encoding(eNB, - a, + // a, + eNB->dlsch_MCH->harq_processes[0]->pdu, 1, eNB->dlsch_MCH, proc->frame_tx, diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index 8c19f44d2f..e142d2f29f 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -36,7 +36,7 @@ #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" - +#include "executables/softmodem-common.h" //uint8_t ncs_cell[20][7]; //#define DEBUG_PUCCH_TXS @@ -801,9 +801,8 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, for (j=0; jpucch1_stats_cnt[j][i]=0; eNB->pucch1ab_stats_cnt[j][i]=0; -#if defined(USRP_REC_PLAY) // not 100% sure - eNB->pucch1_stats_thres[j][i]=0; -#endif + if ( IS_SOFTMODEM_IQPLAYER) + eNB->pucch1_stats_thres[j][i]=0; } } @@ -1193,15 +1192,13 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, stat_re=0; stat_im=0; // Do detection now -#if defined(USRP_REC_PLAY) - // It looks like the value is a bit messy when RF is replayed. + + // It looks like the pucch1_thres value is a bit messy when RF is replayed. // For instance i assume to skip pucch1_thres from the test below. // Not 100% sure - if (sigma2_dB<(dB_fixed(stat_max))) {// -#else - if (sigma2_dB<(dB_fixed(stat_max)-pucch1_thres)) {// -#endif + + if (sigma2_dB<(dB_fixed(stat_max) - (IS_SOFTMODEM_IQPLAYER?0:pucch1_thres)) ) {// chL = (nsymb>>1)-4; chest_mag=0; cfo = (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase_max] : &cfo_pucch_ep[12*phase_max]; @@ -1339,11 +1336,7 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, if (fmt==pucch_format1b) *(1+payload) = (stat_im<0) ? 1 : 2; } else { // insufficient energy on PUCCH so NAK -#if defined(USRP_REC_PLAY) - LOG_D(PHY,"PUCCH 1a/b: NAK subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); -#else LOG_D(PHY,"In pucch.c PUCCH 1a/b: NAK subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); -#endif *payload = 4; // DTX ((int16_t *)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[0] = (int16_t)(stat_re); ((int16_t *)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[1] = (int16_t)(stat_im); diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index a80023c744..7b9004ba80 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -314,12 +314,10 @@ typedef struct { // int calibration_flag; /// delta_TF for power control int32_t delta_TF; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) // PUSCH Repetition Number for the current SF uint32_t repetition_number ; // PUSCH Total number of repetitions uint32_t total_number_of_repetitions; -#endif } LTE_UL_eNB_HARQ_t; typedef struct { diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c index 412cd3fbef..2fd84f563c 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c @@ -547,10 +547,10 @@ int rx_pdsch(PHY_VARS_UE *ue, pdsch_vars[eNB_id]->log2_maxh, measurements); // log2_maxh+I0_shift - if (symbol == 5) { - LOG_M("rxF_comp_d.m","rxF_c_d",&pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol*frame_parms->N_RB_DL*12],frame_parms->N_RB_DL*12,1,1); - } - +// if (symbol == 5) { +// LOG_M("rxF_comp_d.m","rxF_c_d",&pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol*frame_parms->N_RB_DL*12],frame_parms->N_RB_DL*12,1,1); +// } +// if ((rx_type==rx_IC_single_stream) && (eNB_id_in_connected_eNB)) { dlsch_channel_compensation(pdsch_vars[eNB_id_i]->rxdataF_ext, diff --git a/openair1/PHY/LTE_UE_TRANSPORT/drs_modulation.c b/openair1/PHY/LTE_UE_TRANSPORT/drs_modulation.c index a15166eed5..77c0d9ca7a 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/drs_modulation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/drs_modulation.c @@ -62,11 +62,10 @@ int generate_drs_pusch(PHY_VARS_UE *ue, LTE_DL_FRAME_PARMS *fp = (ue==NULL) ? frame_parms : &ue->frame_parms; int32_t *txF = (ue==NULL) ? txdataF[ant] : ue->common_vars.txdataF[ant]; uint32_t u,v,alpha_ind; - uint32_t u0 = (ue==NULL) ? 0 : frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[subframe<<1]; - uint32_t u1 = (ue==NULL) ? 0 : frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[1+(subframe<<1)]; - uint32_t v0 = (ue==NULL) ? 0 : frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[subframe<<1]; - uint32_t v1 = (ue==NULL) ? 0 : frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[1+(subframe<<1)]; - + uint32_t u0=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[subframe<<1]; + uint32_t u1=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[1+(subframe<<1)]; + uint32_t v0=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[subframe<<1]; + uint32_t v1=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[1+(subframe<<1)]; int32_t ref_re,ref_im; uint8_t harq_pid = (proc == NULL) ? 0: subframe2harq_pid(fp,proc->frame_tx,subframe); @@ -82,10 +81,6 @@ int generate_drs_pusch(PHY_VARS_UE *ue, fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[(subframe<<1)+1]+ ((ue->ulsch[0]->cooperation_flag==2)?10:0)+ ant*6) % 12; - u0=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[subframe<<1]; - u1=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[1+(subframe<<1)]; - v0=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[subframe<<1]; - v1=fp->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[1+(subframe<<1)]; } diff --git a/openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c index 287f76ac91..69aa1c06a3 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c @@ -57,10 +57,10 @@ void dump_mch(PHY_VARS_UE *ue,uint8_t eNB_id,uint16_t coded_bits_per_codeword,in #define NSYMB_PMCH 12 sprintf(fname,"mch_rxF_ext0.m"); sprintf(vname,"pmch_rxF_ext0"); - LOG_M(fname,vname,ue->pdsch_vars_MCH[eNB_id]->rxdataF_ext[0],12*(ue->frame_parms.N_RB_DL)*12,1,1); + LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->rxdataF_ext[0],12*(ue->frame_parms.N_RB_DL)*12,1,1); sprintf(fname,"mch_ch_ext00.m"); sprintf(vname,"pmch_ch_ext00"); - LOG_M(fname,vname,ue->pdsch_vars_MCH[eNB_id]->dl_ch_estimates_ext[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); + LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->dl_ch_estimates_ext[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); /* LOG_M("dlsch%d_ch_ext01.m","dl01_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*NSYMB_PMCH,1,1); LOG_M("dlsch%d_ch_ext10.m","dl10_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[2],12*N_RB_DL*NSYMB_PMCH,1,1); @@ -69,16 +69,16 @@ void dump_mch(PHY_VARS_UE *ue,uint8_t eNB_id,uint16_t coded_bits_per_codeword,in */ sprintf(fname,"mch_rxF_comp0.m"); sprintf(vname,"pmch_rxF_comp0"); - LOG_M(fname,vname,ue->pdsch_vars_MCH[eNB_id]->rxdataF_comp0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); + LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->rxdataF_comp0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); sprintf(fname,"mch_rxF_llr.m"); sprintf(vname,"pmch_llr"); - LOG_M(fname,vname, ue->pdsch_vars_MCH[eNB_id]->llr[0],coded_bits_per_codeword,1,0); + LOG_M(fname,vname, ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->llr[0],coded_bits_per_codeword,1,0); sprintf(fname,"mch_mag1.m"); sprintf(vname,"pmch_mag1"); - LOG_M(fname,vname,ue->pdsch_vars_MCH[eNB_id]->dl_ch_mag0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); + LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->dl_ch_mag0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); sprintf(fname,"mch_mag2.m"); sprintf(vname,"pmch_mag2"); - LOG_M(fname,vname,ue->pdsch_vars_MCH[eNB_id]->dl_ch_magb0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); + LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->dl_ch_magb0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1); LOG_M("mch00_ch0.m","pmch00_ch0", &(ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][0][0]), ue->frame_parms.ofdm_symbol_size*12,1,1); @@ -96,6 +96,7 @@ void dump_mch(PHY_VARS_UE *ue,uint8_t eNB_id,uint16_t coded_bits_per_codeword,in void fill_UE_dlsch_MCH(PHY_VARS_UE *ue,int mcs,int ndi,int rvidx,int eNB_id) { LTE_UE_DLSCH_t *dlsch = ue->dlsch_MCH[eNB_id]; LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms; + dlsch->Mdlharq = 1; // dlsch->rnti = M_RNTI; dlsch->harq_processes[0]->mcs = mcs; dlsch->harq_processes[0]->rvidx = rvidx; @@ -242,15 +243,16 @@ void mch_channel_level(int **dl_ch_estimates_ext, for (i=0; i<(nre>>2); i++) { #if defined(__x86_64__) || defined(__i386__) - avg128 = _mm_add_epi32(avg128,_mm_madd_epi16(dl_ch128[0],dl_ch128[0])); + avg128 = _mm_add_epi32(avg128,_mm_srai_epi32(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),log2_approx(nre>>2)-1)); #elif defined(__arm__) #endif } - avg[aarx] = (((int *)&avg128)[0] + - ((int *)&avg128)[1] + - ((int *)&avg128)[2] + - ((int *)&avg128)[3])/nre; + avg[aarx] = (((((int*)&avg128)[0] + + ((int*)&avg128)[1] + + ((int*)&avg128)[2] + + ((int*)&avg128)[3])/(nre>>factor2(nre)))*(1<<(log2_approx(nre>>2)-1-factor2(nre)))); + // printf("Channel level : %d\n",avg[(aatx<<1)+aarx]); } @@ -289,16 +291,21 @@ void mch_channel_level_khz_1dot25(int **dl_ch_estimates_ext, for (i=0; i<(nre>>2); i++) { #if defined(__x86_64__) || defined(__i386__) - avg128 = _mm_add_epi32(avg128,_mm_madd_epi16(dl_ch128[0],dl_ch128[0])); + //avg128 = _mm_add_epi32(avg128,_mm_madd_epi16(dl_ch128[0],dl_ch128[0])); + avg128 = _mm_add_epi32(avg128,_mm_srai_epi32(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),log2_approx(nre>>2)-1)); #elif defined(__arm__) #endif } - avg[aarx] = (((int *)&avg128)[0] + - ((int *)&avg128)[1] + - ((int *)&avg128)[2] + - ((int *)&avg128)[3])/nre; - //printf("Channel level : %d\n",avg[(aatx<<1)+aarx]); + // avg[aarx] = (((int*)&avg128)[0] + + // ((int*)&avg128)[1] + + // ((int*)&avg128)[2] + + // ((int*)&avg128)[3])/nre; + avg[aarx] = (((((int*)&avg128)[0] + + ((int*)&avg128)[1] + + ((int*)&avg128)[2] + + ((int*)&avg128)[3])/(nre>>factor2(nre)))*(1<<(log2_approx(nre>>2)-1-factor2(nre)))); + //printf("Channel level : %d\n",avg[(aatx<<1)+aarx]); } #if defined(__x86_64__) || defined(__i386__) @@ -1215,7 +1222,7 @@ int rx_pmch(PHY_VARS_UE *ue, uint8_t subframe, unsigned char symbol) { LTE_UE_COMMON *common_vars = &ue->common_vars; - LTE_UE_PDSCH **pdsch_vars = &ue->pdsch_vars_MCH[eNB_id]; + LTE_UE_PDSCH **pdsch_vars = &ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]; LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; LTE_UE_DLSCH_t **dlsch = &ue->dlsch_MCH[eNB_id]; int avgs,aarx; @@ -1301,7 +1308,7 @@ int rx_pmch_khz_1dot25(PHY_VARS_UE *ue, ,int mcs) { // currently work around TOFIX //unsigned int symbol; LTE_UE_COMMON *common_vars = &ue->common_vars; - LTE_UE_PDSCH **pdsch_vars = &ue->pdsch_vars_MCH[eNB_id]; + LTE_UE_PDSCH **pdsch_vars = &ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]; LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; //LTE_UE_DLSCH_t **dlsch = &ue->dlsch_MCH[eNB_id]; int avgs,aarx; diff --git a/openair1/PHY/MODULATION/modulation_UE.h b/openair1/PHY/MODULATION/modulation_UE.h index 1199a91baa..228299095f 100644 --- a/openair1/PHY/MODULATION/modulation_UE.h +++ b/openair1/PHY/MODULATION/modulation_UE.h @@ -54,6 +54,12 @@ int nr_slot_fep(PHY_VARS_NR_UE *phy_vars_ue, int sample_offset, int no_prefix); +int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue, + unsigned char symbol, + unsigned char Ns, + int sample_offset, + int no_prefix); + int slot_fep_mbsfn(PHY_VARS_UE *phy_vars_ue, unsigned char l, int subframe, diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 930eee39fb..f2e5d24bad 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -46,6 +46,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, unsigned char aa; unsigned int nb_prefix_samples; unsigned int nb_prefix_samples0; + unsigned int abs_symbol; if (ue->is_synchronized) { nb_prefix_samples = (no_prefix ? 0 : frame_parms->nb_prefix_samples); nb_prefix_samples0 = (no_prefix ? 0 : frame_parms->nb_prefix_samples0); @@ -109,7 +110,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, if (no_prefix) { slot_offset = frame_parms->ofdm_symbol_size * (frame_parms->symbols_per_slot) * (Ns); } else { - slot_offset = (frame_parms->samples_per_slot) * (Ns); + slot_offset = frame_parms->get_samples_slot_timestamp(Ns,frame_parms,0); } /*if (l<0 || l>=7-frame_parms->Ncp) { @@ -125,7 +126,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, for (aa=0; aanb_antennas_rx; aa++) { memset(&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],0,frame_parms->ofdm_symbol_size*sizeof(int)); - rx_offset = sample_offset + slot_offset + nb_prefix_samples0 - SOFFSET; + rx_offset = sample_offset + slot_offset - SOFFSET; // Align with 256 bit // rx_offset = rx_offset&0xfffffff8; @@ -135,8 +136,16 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, ue->proc.proc_rxtx[(Ns)&1].frame_rx, Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples); #endif - if (symbol==0) { + abs_symbol = Ns * frame_parms->symbols_per_slot + symbol; + + for (int idx_symb = Ns*frame_parms->symbols_per_slot; idx_symb < abs_symbol; idx_symb++) + rx_offset += (idx_symb%(0x7<numerology_index)) ? nb_prefix_samples : nb_prefix_samples0; + rx_offset += frame_parms->ofdm_symbol_size * symbol; + + if (abs_symbol%(0x7<numerology_index)) { + + rx_offset += nb_prefix_samples; if (rx_offset > (frame_length_samples - frame_parms->ofdm_symbol_size)) memcpy((short*) &common_vars->rxdata[aa][frame_length_samples], (short*) &common_vars->rxdata[aa][0], @@ -161,9 +170,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, } } else { - rx_offset += (frame_parms->ofdm_symbol_size+nb_prefix_samples)*symbol; - // + (frame_parms->ofdm_symbol_size+nb_prefix_samples)*(l-1); - + rx_offset += nb_prefix_samples0; if (rx_offset > (frame_length_samples - frame_parms->ofdm_symbol_size)) memcpy((void *) &common_vars->rxdata[aa][frame_length_samples], (void *) &common_vars->rxdata[aa][0], @@ -197,6 +204,181 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, } +#ifdef DEBUG_FEP + printf("slot_fep: done\n"); +#endif + return(0); +} + +int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue, + unsigned char symbol, + unsigned char Ns, + int sample_offset, + int no_prefix) +{ + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + NR_UE_COMMON *common_vars = &ue->common_vars; + unsigned char aa; + unsigned int nb_prefix_samples; + unsigned int nb_prefix_samples0; + unsigned int abs_symbol; + if (ue->is_synchronized) { + nb_prefix_samples = (no_prefix ? 0 : frame_parms->nb_prefix_samples); + nb_prefix_samples0 = (no_prefix ? 0 : frame_parms->nb_prefix_samples0); + } + else { + nb_prefix_samples = (no_prefix ? 0 : frame_parms->nb_prefix_samples); + nb_prefix_samples0 = (no_prefix ? 0 : frame_parms->nb_prefix_samples); + } + //unsigned int subframe_offset;//,subframe_offset_F; + unsigned int slot_offset; + //int i; + unsigned int frame_length_samples = frame_parms->samples_per_subframe * 10; + unsigned int rx_offset; + + + void (*dft)(int16_t *,int16_t *, int); + int tmp_dft_in[8192] __attribute__ ((aligned (32))); // This is for misalignment issues for 6 and 15 PRBs + + switch (frame_parms->ofdm_symbol_size) { + case 128: + dft = dft128; + break; + + case 256: + dft = dft256; + break; + + case 512: + dft = dft512; + break; + + case 1024: + dft = dft1024; + break; + + case 1536: + dft = dft1536; + break; + + case 2048: + dft = dft2048; + break; + + case 3072: + dft = dft3072; + break; + + case 4096: + dft = dft4096; + break; + + case 8192: + dft = dft8192; + break; + + default: + printf("unsupported ofdm symbol size \n"); + assert(0); + } + + if (no_prefix) { + slot_offset = frame_parms->ofdm_symbol_size * (frame_parms->symbols_per_slot) * (Ns); + } else { + slot_offset = frame_parms->get_samples_slot_timestamp(Ns,frame_parms,0); + } + + /*if (l<0 || l>=7-frame_parms->Ncp) { + printf("slot_fep: l must be between 0 and %d\n",7-frame_parms->Ncp); + return(-1); + }*/ + + if (Ns<0 || Ns>(frame_parms->slots_per_frame-1)) { + printf("slot_fep: Ns must be between 0 and %d\n",frame_parms->slots_per_frame-1); + return(-1); + } + + for (aa=0; aanb_antennas_rx; aa++) { + memset(&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],0,frame_parms->ofdm_symbol_size*sizeof(int)); + + rx_offset = sample_offset + slot_offset - SOFFSET; + // Align with 256 bit + // rx_offset = rx_offset&0xfffffff8; + +#ifdef DEBUG_FEP + // if (ue->frame <100) + /*LOG_I(PHY,*/printf("slot_fep: frame %d: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n", + ue->proc.proc_rxtx[(Ns)&1].frame_rx, Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples); +#endif + + abs_symbol = Ns * frame_parms->symbols_per_slot + symbol; + + for (int idx_symb = Ns*frame_parms->symbols_per_slot; idx_symb < abs_symbol; idx_symb++) + rx_offset += (abs_symbol%(0x7<numerology_index)) ? nb_prefix_samples : nb_prefix_samples0; + + rx_offset += frame_parms->ofdm_symbol_size * symbol; + + if (abs_symbol%(0x7<numerology_index)) { + + rx_offset += nb_prefix_samples; + if (rx_offset > (frame_length_samples - frame_parms->ofdm_symbol_size)) + memcpy((short*) &common_vars->rxdata[aa][frame_length_samples], + (short*) &common_vars->rxdata[aa][0], + frame_parms->ofdm_symbol_size*sizeof(int)); + + if ((rx_offset&7)!=0) { // if input to dft is not 256-bit aligned, issue for size 6,15 and 25 PRBs + memcpy((void *)tmp_dft_in, + (void *) &common_vars->rxdata[aa][rx_offset], + frame_parms->ofdm_symbol_size*sizeof(int)); + dft((int16_t *)tmp_dft_in, + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); + } else { // use dft input from RX buffer directly +#if UE_TIMING_TRACE + start_meas(&ue->rx_dft_stats); +#endif + + dft((int16_t *) &common_vars->rxdata[aa][rx_offset], + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); +#if UE_TIMING_TRACE + stop_meas(&ue->rx_dft_stats); +#endif + } + } else { + + rx_offset += nb_prefix_samples0; + if (rx_offset > (frame_length_samples - frame_parms->ofdm_symbol_size)) + memcpy((void *) &common_vars->rxdata[aa][frame_length_samples], + (void *) &common_vars->rxdata[aa][0], + frame_parms->ofdm_symbol_size*sizeof(int)); +#if UE_TIMING_TRACE + start_meas(&ue->rx_dft_stats); +#endif + + if ((rx_offset&7)!=0) { // if input to dft is not 128-bit aligned, issue for size 6 and 15 PRBs + memcpy((void *)tmp_dft_in, + (void *) &common_vars->rxdata[aa][rx_offset], + frame_parms->ofdm_symbol_size*sizeof(int)); + dft((int16_t *)tmp_dft_in, + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); + } else { // use dft input from RX buffer directly + + dft((int16_t *) &common_vars->rxdata[aa][rx_offset], + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); + } +#if UE_TIMING_TRACE + stop_meas(&ue->rx_dft_stats); +#endif + + + } + + #ifdef DEBUG_FEP + // if (ue->frame <100) + printf("slot_fep: frame %d: symbol %d rx_offset %u\n", ue->proc.proc_rxtx[(Ns)&1].frame_rx, symbol, rx_offset); + #endif + } + + #ifdef DEBUG_FEP printf("slot_fep: done\n"); #endif @@ -258,7 +440,7 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms, break; } - slot_offset = Ns * frame_parms->samples_per_slot; + slot_offset = frame_parms->get_samples_slot_timestamp(Ns,frame_parms,0); if(symbol == 0) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 5460e2b4f1..0d7732599f 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -23,6 +23,7 @@ #include #include "nr_ul_estimation.h" +#include "PHY/sse_intrin.h" #include "PHY/NR_REFSIG/nr_refsig.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" @@ -30,23 +31,21 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, - uint8_t gNB_offset, unsigned char Ns, unsigned short p, unsigned char symbol, unsigned short bwp_start_subcarrier, - unsigned short nb_rb_pusch) -{ + nfapi_nr_pusch_pdu_t *pusch_pdu) { + int pilot[3280] __attribute__((aligned(16))); unsigned char aarx; unsigned short k; - unsigned int pilot_cnt; - int16_t ch[2],*pil,*rxF,*ul_ch; + unsigned int pilot_cnt,re_cnt; + int16_t ch[2],ch_r[2],ch_l[2],*pil,*rxF,*ul_ch; int16_t *fl,*fm,*fr,*fml,*fmr,*fmm,*fdcl,*fdcr,*fdclh,*fdcrh; - int ch_offset,symbol_offset, length_dmrs, UE_id = 0; - unsigned short n_idDMRS[2] = {0,1}; //to update from pusch config - int32_t temp_in_ifft_0[8192*2] __attribute__((aligned(32))); + int ch_offset,symbol_offset, UE_id = 0; int32_t **ul_ch_estimates_time = gNB->pusch_vars[UE_id]->ul_ch_estimates_time; + __m128i *ul_ch_128; #ifdef DEBUG_CH FILE *debug_ch_est; @@ -69,9 +68,11 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, k = bwp_start_subcarrier; int re_offset = k; + uint16_t nb_rb_pusch = pusch_pdu->rb_size; + /* #ifdef DEBUG_CH - printf("PUSCH Channel Estimation : gNB_offset %d ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, l=%d, Ns=%d, k=%d symbol %d\n", gNB_offset,ch_offset,symbol_offset,gNB->frame_parms.ofdm_symbol_size, + printf("PUSCH Channel Estimation : ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, l=%d, Ns=%d, k=%d symbol %d\n", ,ch_offset,symbol_offset,gNB->frame_parms.ofdm_symbol_size, gNB->frame_parms.Ncp,l,Ns,k, symbol); #endif */ @@ -115,11 +116,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, //------------------generate DMRS------------------// - length_dmrs = 1; //to update from pusch config - - nr_gold_pusch(gNB, symbol, n_idDMRS, length_dmrs); - - nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch[gNB_offset][Ns][0], &pilot[0], 1000, 0, nb_rb_pusch); + nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, pusch_pdu->dmrs_config_type); //------------------------------------------------// @@ -139,6 +136,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, #endif //if ((gNB->frame_parms.N_RB_UL&1)==0) { + if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1){ + // Treat first 2 pilots specially (left edge) ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -148,6 +147,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, printf("pilot 0 : rxF - > (%d,%d) addr %p ch -> (%d,%d), pil -> (%d,%d) \n",rxF[0],rxF[1],&rxF[0],ch[0],ch[1],pil[0],pil[1]); printf("data 0 : rxF - > (%d,%d) addr %p ch -> (%d,%d), pil -> (%d,%d) \n",rxF[2],rxF[3],&rxF[2],ch[0],ch[1],pil[0],pil[1]); #endif + multadd_real_vector_complex_scalar(fl, ch, ul_ch, @@ -196,28 +196,33 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); -#ifdef DEBUG_CH - fprintf(debug_ch_est, "pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); - //printf("pilot %d : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); -#endif - multadd_real_vector_complex_scalar(fm, + + #ifdef DEBUG_PUSCH + printf("pilot 1 : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); + #endif + multadd_real_vector_complex_scalar(fml, ch, ul_ch, 8); - pil+=2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; - + //printf("ul_ch addr %p\n",ul_ch); + ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); -#ifdef DEBUG_PUSCH - printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); -#endif + + #ifdef DEBUG_PUSCH + printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); + #endif multadd_real_vector_complex_scalar(fmm, ch, ul_ch, 8); + + //for (int i= 0; i<16; i++) + //printf("ul_ch addr %p %d\n", ul_ch+i, *(ul_ch+i)); + pil+=2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; @@ -226,10 +231,10 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } // Treat first 2 pilots specially (right edge) - ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); + ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); #ifdef DEBUG_PUSCH - printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); + printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]); #endif multadd_real_vector_complex_scalar(fm, ch, @@ -332,65 +337,153 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, printf("%d\n",idxP); } #endif + + } else { //pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d| + + // Treat first DMRS specially (left edge) + + rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + + ul_ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); + ul_ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); + + pil+=2; + ul_ch+=2; + re_offset = (re_offset + 1)%gNB->frame_parms.ofdm_symbol_size; + ch_offset++; + + for (re_cnt = 1; re_cnt < (nb_rb_pusch*NR_NB_SC_PER_RB) - 5; re_cnt+=6){ + + rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + + ch_l[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); + ch_l[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); + + ul_ch[0] = ch_l[0]; + ul_ch[1] = ch_l[1]; + + pil+=2; + ul_ch+=2; + ch_offset++; + + multadd_real_four_symbols_vector_complex_scalar(filt8_ml2, + ch_l, + ul_ch); + + re_offset = (re_offset+5)%gNB->frame_parms.ofdm_symbol_size; + + rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + + ch_r[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); + ch_r[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); + + + multadd_real_four_symbols_vector_complex_scalar(filt8_mr2, + ch_r, + ul_ch); + + //for (int re_idx = 0; re_idx < 8; re_idx+=2) + //printf("ul_ch = %d + j*%d\n", ul_ch[re_idx], ul_ch[re_idx+1]); + + ul_ch+=8; + ch_offset+=4; + + ul_ch[0] = ch_r[0]; + ul_ch[1] = ch_r[1]; + + pil+=2; + ul_ch+=2; + ch_offset++; + re_offset = (re_offset + 1)%gNB->frame_parms.ofdm_symbol_size; + + } + + // Treat last pilot specially (right edge) + + rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + + ch_l[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); + ch_l[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); + + ul_ch[0] = ch_l[0]; + ul_ch[1] = ch_l[1]; + + ul_ch+=2; + ch_offset++; + + multadd_real_four_symbols_vector_complex_scalar(filt8_rr1, + ch_l, + ul_ch); + + multadd_real_four_symbols_vector_complex_scalar(filt8_rr2, + ch_r, + ul_ch); + + ul_ch_128 = (__m128i *)&ul_ch_estimates[aarx][ch_offset]; + + ul_ch_128[0] = _mm_slli_epi16 (ul_ch_128[0], 2); + } + + + // Convert to time domain - memset(temp_in_ifft_0, 0, gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t)); - memcpy(temp_in_ifft_0, &ul_ch_estimates[aarx][symbol_offset], nb_rb_pusch * NR_NB_SC_PER_RB * sizeof(int32_t)); - switch (gNB->frame_parms.ofdm_symbol_size) { - case 128: - idft128((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + switch (gNB->frame_parms.ofdm_symbol_size) { + case 128: + idft128((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 256: - idft256((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 256: + idft256((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 512: - idft512((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 512: + idft512((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 1024: - idft1024((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 1024: + idft1024((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 1536: - idft1536((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 1536: + idft1536((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 2048: - idft2048((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 2048: + idft2048((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 4096: - idft4096((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 4096: + idft4096((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; - case 8192: - idft8192((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; + case 8192: + idft8192((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; + + default: + idft512((int16_t*) &ul_ch_estimates[aarx][symbol_offset], + (int16_t*) ul_ch_estimates_time[aarx], + 1); + break; + } - default: - idft512((int16_t*) temp_in_ifft_0, - (int16_t*) ul_ch_estimates_time[aarx], - 1); - break; - } } #ifdef DEBUG_CH diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 125c166f7d..a7789c9224 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -39,13 +39,12 @@ \param nb_rb_pusch, number of allocated RBs for this UE */ - int32_t nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, - uint8_t gNB_offset, - unsigned char Ns, - unsigned short p, - unsigned char symbol, - unsigned short bwp_start_subcarrier, - unsigned short nb_rb_pusch); +int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, + unsigned char Ns, + unsigned short p, + unsigned char symbol, + unsigned short bwp_start_subcarrier, + nfapi_nr_pusch_pdu_t *pusch_pdu); int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); diff --git a/openair1/PHY/NR_UE_TRANSPORT/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c similarity index 59% rename from openair1/PHY/NR_UE_TRANSPORT/dmrs_nr.c rename to openair1/PHY/NR_REFSIG/dmrs_nr.c index 4d77854a70..ed37a79d0f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dmrs_nr.c +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c @@ -33,6 +33,146 @@ #include "PHY/NR_REFSIG/ss_pbch_nr.h" #include "PHY/NR_REFSIG/dmrs_nr.h" +/***********************************************************************/ + +// TS 38.211 Table 6.4.1.1.3-3: PUSCH DMRS positions l' within a slot for single-symbol DMRS and intra-slot frequency hopping disabled. +// The first 4 colomns are PUSCH mapping type A and the last 4 colomns are PUSCH mapping type B. +// When l' = l0, it is represented by 1 +// E.g. when symbol duration is 12 in colomn 7, value 1057 ('10000100001') which means l' = l0, 5, 10. + +int32_t table_6_4_1_1_3_3_pusch_dmrs_positions_l [12][8] = { // Duration in symbols +{-1, -1, -1, -1, 1, 1, 1, 1}, //<4 // (DMRS l' position) +{1, 1, 1, 1, 1, 1, 1, 1}, //4 // (DMRS l' position) +{1, 1, 1, 1, 1, 5, 5, 5}, //5 // (DMRS l' position) +{1, 1, 1, 1, 1, 5, 5, 5}, //6 // (DMRS l' position) +{1, 1, 1, 1, 1, 5, 5, 5}, //7 // (DMRS l' position) +{1, 129, 129, 129, 1, 65, 73, 73}, //8 // (DMRS l' position) +{1, 129, 129, 129, 1, 65, 73, 73}, //9 // (DMRS l' position) +{1, 513, 577, 577, 1, 257, 273, 585}, //10 // (DMRS l' position) +{1, 513, 577, 577, 1, 257, 273, 585}, //11 // (DMRS l' position) +{1, 513, 577, 2337, 1, 1025, 1057, 585}, //12 // (DMRS l' position) +{1, 2049, 2177, 2337, 1, 1025, 1057, 585}, //13 // (DMRS l' position) +{1, 2049, 2177, 2337, 1, 1025, 1057, 585}, //14 // (DMRS l' position) +}; + + +// TS 38.211 Table 6.4.1.1.3-4: PUSCH DMRS positions l' within a slot for double-symbol DMRS and intra-slot frequency hopping disabled. +// The first 4 colomns are PUSCH mapping type A and the last 4 colomns are PUSCH mapping type B. +// When l' = l0, it is represented by 1 + +int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l [12][8] = { // Duration in symbols +{-1, -1, -1, -1, -1, -1, -1, -1}, //<4 // (DMRS l' position) +{1, 1, -1, -1, -1, -1, -1, -1}, //4 // (DMRS l' position) +{1, 1, -1, -1, 1, 1, -1, -1}, //5 // (DMRS l' position) +{1, 1, -1, -1, 1, 1, -1, -1}, //6 // (DMRS l' position) +{1, 1, -1, -1, 1, 1, -1, -1}, //7 // (DMRS l' position) +{1, 1, -1, -1, 1, 33, -1, -1}, //8 // (DMRS l' position) +{1, 1, -1, -1, 1, 33, -1, -1}, //9 // (DMRS l' position) +{1, 257, -1, -1, 1, 129, -1, -1}, //10 // (DMRS l' position) +{1, 257, -1, -1, 1, 129, -1, -1}, //11 // (DMRS l' position) +{1, 257, -1, -1, 1, 513, -1, -1}, //12 // (DMRS l' position) +{1, 1025, -1, -1, 1, 513, -1, -1}, //13 // (DMRS l' position) +{1, 1025, -1, -1, 1, 513, -1, -1}, //14 // (DMRS l' position) +}; + +int32_t get_l_prime(uint8_t duration_in_symbols, uint8_t mapping_type, pusch_dmrs_AdditionalPosition_t additional_pos, pusch_maxLength_t pusch_maxLength) { + + uint8_t row, colomn; + int32_t l_prime; + + colomn = additional_pos; + + if (mapping_type == typeB) + colomn += 4; + + if (duration_in_symbols < 4) + row = 0; + else + row = duration_in_symbols - 3; + + if (pusch_maxLength == pusch_len1) + l_prime = table_6_4_1_1_3_3_pusch_dmrs_positions_l[row][colomn]; + else + l_prime = table_6_4_1_1_3_4_pusch_dmrs_positions_l[row][colomn]; + + AssertFatal(l_prime>0,"invalid l_prime < 0\n"); + + return l_prime; +} + +/******************************************************************* +* +* NAME : is_dmrs_symbol +* +* PARAMETERS : l ofdm symbol index within slot +* k subcarrier index +* start_sc first subcarrier index +* k_prime index alternating 0 and 1 +* n index starting 0,1,... +* delta see Table 6.4.1.1.3 +* duration_in_symbols number of scheduled PUSCH ofdm symbols +* dmrs_UplinkConfig DMRS uplink configuration +* mapping_type PUSCH mapping type (A or B) +* ofdm_symbol_size IFFT size +* +* RETURN : 0 if symbol(k,l) is data, or 1 if symbol(k,l) is dmrs +* +* DESCRIPTION : 3GPP TS 38.211 6.4.1.1 Demodulation reference signal for PUSCH +* +*********************************************************************/ + +uint8_t is_dmrs_symbol(uint8_t l, + uint16_t k, + uint16_t start_sc, + uint8_t k_prime, + uint16_t n, + uint8_t delta, + uint8_t duration_in_symbols, + uint8_t dmrs_type, + uint16_t ofdm_symbol_size) { + + uint8_t is_dmrs_freq, is_dmrs_time, l0; + int32_t l_prime_mask; + pusch_dmrs_AdditionalPosition_t additional_pos = pusch_dmrs_pos0; + pusch_maxLength_t pusch_maxLength = pusch_len1; + uint8_t mapping_type = typeB; + + is_dmrs_freq = 0; + is_dmrs_time = 0; + + + l0 = get_l0_ul(mapping_type, 2); + l_prime_mask = get_l_prime(duration_in_symbols, mapping_type, additional_pos, pusch_maxLength); + + if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%ofdm_symbol_size)) + is_dmrs_freq = 1; + + + if (l_prime_mask == 1){ + + if (l == l0) + is_dmrs_time = 1; + + } else if ( (l==l0) || (((l_prime_mask>>l)&1) == 1 && l!=0) ) + is_dmrs_time = 1; + + if (pusch_maxLength == pusch_len2){ + + if (((l_prime_mask>>(l-1))&1) == 1 && l!=0 && l!=1) + is_dmrs_time = 1; + + if (l-1 == l0) + is_dmrs_time = 1; + + } + + if (is_dmrs_time && is_dmrs_freq) + return 1; + else + return 0; + +} + /******************************************************************* * * NAME : pseudo_random_gold_sequence diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.h b/openair1/PHY/NR_REFSIG/dmrs_nr.h index 5c4f218512..f1dfffff8b 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.h +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.h @@ -57,6 +57,18 @@ void generate_dmrs_pbch(uint32_t dmrs_pbch_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_H uint8_t get_l0_ul(uint8_t mapping_type, uint8_t dmrs_typeA_position); uint16_t get_dmrs_freq_idx_ul(uint16_t n, uint8_t k_prime, uint8_t delta, uint8_t dmrs_type); +int32_t get_l_prime(uint8_t duration_in_symbols, uint8_t mapping_type, pusch_dmrs_AdditionalPosition_t additional_pos, pusch_maxLength_t pusch_maxLength); + +uint8_t is_dmrs_symbol(uint8_t l, + uint16_t k, + uint16_t start_sc, + uint8_t k_prime, + uint16_t n, + uint8_t delta, + uint8_t duration_in_symbols, + uint8_t dmrs_type, + uint16_t ofdm_symbol_size); + #undef EXTERN #endif /* DMRS_NR_H */ diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 182f8b6215..f933a8c7ab 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -56,9 +56,10 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, int32_t *output, unsigned short p, unsigned char lp, - unsigned short nb_pusch_rb) + unsigned short nb_pusch_rb, + uint8_t dmrs_type) { - int8_t w,config_type; + int8_t w; short *mod_table; unsigned char idx=0; @@ -66,18 +67,16 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, array_of_w *wf; array_of_w *wt; - config_type = 0; //to be updated by higher layer + wf = (dmrs_type==pusch_dmrs_type1) ? wf1 : wf2; + wt = (dmrs_type==pusch_dmrs_type1) ? wt1 : wt2; - wf = (config_type==0) ? wf1 : wf2; - wt = (config_type==0) ? wt1 : wt2; + if (dmrs_type > 2) + LOG_E(PHY,"Bad PUSCH DMRS config type %d\n", dmrs_type); - if (config_type > 1) - LOG_E(PHY,"Bad PUSCH DMRS config type %d\n", config_type); - - if ((p>=1000) && (p<((config_type==0) ? 1008 : 1012))) { + if ((p>=1000) && (p<((dmrs_type==pusch_dmrs_type1) ? 1008 : 1012))) { if (gNB->frame_parms.Ncp == NORMAL) { - for (int i=0; i>5], (((nr_gold_pusch[(i<<1)>>5])>>((i<<1)&0x1f))&1), (((nr_gold_pusch[((i<<1)+1)>>5])>>(((i<<1)+1)&0x1f))&1), ((int16_t*)output)[i<<1], ((int16_t*)output)[(i<<1)+1]); diff --git a/openair1/PHY/NR_REFSIG/nr_gold.c b/openair1/PHY/NR_REFSIG/nr_gold.c index 7057adef21..472d03e649 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold.c +++ b/openair1/PHY/NR_REFSIG/nr_gold.c @@ -104,56 +104,27 @@ void nr_init_pdsch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid) } -void nr_gold_pusch(PHY_VARS_gNB* gNB, unsigned short lbar,unsigned short *n_idDMRS, unsigned short length_dmrs) -{ +void nr_gold_pusch(PHY_VARS_gNB* gNB, uint32_t *Nid) { - unsigned char ns,l; - unsigned int n,x1,x2,x2tmp0; - int nscid; + unsigned char ns; + unsigned int n,x1,x2; + int nscid, reset; unsigned int nid; - - /// to be updated from higher layer - //unsigned short lbar = 0; + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + unsigned short l; for (nscid=0; nscid<2; nscid++) { - if (n_idDMRS) - nid = n_idDMRS[nscid]; - else - nid = gNB->frame_parms.Nid_cell; - - //printf("gold pdsch nid %d lbar %d\n",nid,lbar); - - for (ns=0; ns<20; ns++) { - - for (l=0; l>1) ^ (x2>>2) ^ (x2>>3))<<31); - - // skip first 50 double words (1600 bits) - for (n=1; n<50; n++) { - x1 = (x1>>1) ^ (x1>>4); - x1 = x1 ^ (x1<<31) ^ (x1<<28); - x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); - x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); - //printf("x1 : %x, x2 : %x\n",x1,x2); - } + nid = Nid[nscid]; + for (ns=0; nsslots_per_frame; ns++) { + for (l=0; lsymbols_per_slot; l++) { + reset = 1; + x2 = ((1<<17) * (fp->symbols_per_slot*ns+l+1) * ((nid<<1)+1) +((nid<<1)+nscid)); + LOG_D(PHY,"DMRS slot %d, symb %d x2 %x\n",ns,l,x2); for (n=0; n>1) ^ (x1>>4); - x1 = x1 ^ (x1<<31) ^ (x1<<28); - x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); - x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); - gNB->nr_gold_pusch[nscid][ns][l][n] = x1^x2; - // if ((ns==2)&&(l==0)) - //printf("n=%d : c %x\n",n,x1^x2); + gNB->nr_gold_pusch_dmrs[nscid][ns][l][n] = lte_gold_generic(&x1, &x2, reset); + reset = 0; } - } } } diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index e1bfa1420d..5af0e88099 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -39,7 +39,7 @@ void nr_init_pbch_dmrs(PHY_VARS_gNB* gNB); void nr_init_pdcch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid); void nr_init_pdsch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid); -void nr_gold_pusch(PHY_VARS_gNB* gNB, unsigned short lbar,unsigned short *n_idDMRS, unsigned short length_dmrs); +void nr_gold_pusch(PHY_VARS_gNB* gNB, uint32_t *Nid); int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned int Ns, @@ -47,5 +47,6 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, int32_t *output, unsigned short p, unsigned char lp, - unsigned short nb_pusch_rb); + unsigned short nb_pusch_rb, + uint8_t dmrs_type); #endif diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.c b/openair1/PHY/NR_REFSIG/ptrs_nr.c new file mode 100644 index 0000000000..12f76b950f --- /dev/null +++ b/openair1/PHY/NR_REFSIG/ptrs_nr.c @@ -0,0 +1,423 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : ptrs_nr.c +* +* MODULE : phase tracking reference signals +* +* DESCRIPTION : resource element mapping of ptrs sequences +* 3GPP TS 38.211 and 3GPP TS 38.214 +* +************************************************************************/ + +#include +#include +#include "dmrs_nr.h" +#include "PHY/NR_REFSIG/ptrs_nr.h" + +/***********************************************************************/ + + + //#define max(a,b) (((a) > (b)) ? (a) : (b)) + +// TS 38.211 Table 6.4.1.2.2.1-1: The parameter kRE_ref. +// The first 4 colomns are DM-RS Configuration type 1 and the last 4 colomns are DM-RS Configuration type 2. + +int16_t table_6_4_1_2_2_1_1_pusch_ptrs_kRE_ref [6][8] = { +{ 0, 2, 6, 8, 0, 1, 6, 7}, +{ 2, 4, 8, 10, 1, 6, 7, 0}, +{ 1, 3, 7, 9, 2, 3, 8, 9}, +{ 3, 5, 9, 11, 3, 8, 9, 2}, +{-1, -1, -1, -1, 4, 5, 10, 11}, +{-1, -1, -1, -1, 5, 10, 11, 4}, +}; + + +/******************************************************************* +* +* NAME : get_kRE_ref +* +* PARAMETERS : dmrs_antenna_port DMRS antenna port +* pusch_dmrs_type PUSCH DMRS type +* resourceElementOffset the parameter resourceElementOffset +* +* RETURN : the parameter k_RE_ref +* +* DESCRIPTION : 3GPP TS 38.211 Table 6.4.1.2.2.1-1 +* +*********************************************************************/ + +int16_t get_kRE_ref(uint8_t dmrs_antenna_port, uint8_t pusch_dmrs_type, uint8_t resourceElementOffset) { + + uint8_t colomn; + int16_t k_RE_ref; + + colomn = resourceElementOffset; + + if (pusch_dmrs_type == 2) + colomn += 4; + + k_RE_ref = table_6_4_1_2_2_1_1_pusch_ptrs_kRE_ref[dmrs_antenna_port][colomn]; + + AssertFatal(k_RE_ref>=0,"invalid k_RE_ref < 0. Check PTRS Configuration\n"); + + return k_RE_ref; +} + + +/******************************************************************* +* +* NAME : get_K_ptrs +* +* PARAMETERS : ptrs_UplinkConfig PTRS uplink configuration +* N_RB number of RBs scheduled for PUSCH +* +* RETURN : the parameter K_ptrs +* +* DESCRIPTION : 3GPP TS 38.214 6.2.3 Table 6.2.3.1-2 +* +*********************************************************************/ + +uint8_t get_K_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint16_t N_RB){ + + uint16_t nrb0, nrb1; + + nrb0 = ptrs_UplinkConfig->frequencyDensity.n_rb0; + nrb1 = ptrs_UplinkConfig->frequencyDensity.n_rb1; + + if (nrb0 == 0 || nrb0 == 0) + return 2; + + if (N_RB < nrb0){ + LOG_I(PHY,"PUSH PT-RS is not present.\n"); + return 0; + } + else if (N_RB >= nrb0 && N_RB < nrb1) + return 2; + else + return 4; +} + +/******************************************************************* +* +* NAME : set_ptrs_symb_idx +* +* PARAMETERS : ptrs_symbols PTRS OFDM symbol indicies bit mask +* duration_in_symbols number of scheduled PUSCH ofdm symbols +* start_symbol first ofdm symbol of PUSCH within slot +* L_ptrs the parameter L_ptrs +* ofdm_symbol_size FFT size +* +* RETURN : sets the bit map of PTRS ofdm symbol indicies +* +* DESCRIPTION : 3GPP TS 38.211 6.4.1.2.2.1 +* +*********************************************************************/ + +void set_ptrs_symb_idx(uint16_t *ptrs_symbols, + uint8_t duration_in_symbols, + uint8_t start_symbol, + uint8_t dmrs_type, + uint8_t L_ptrs, + uint8_t pusch_maxLength, + uint16_t ofdm_symbol_size) { + + uint8_t i, last_symbol, is_dmrs_symbol1, is_dmrs_symbol2; + int16_t l_ref; + + *ptrs_symbols = 0; + i = 0; + is_dmrs_symbol1 = 0; + is_dmrs_symbol2 = 0; + l_ref = start_symbol; + last_symbol = start_symbol + duration_in_symbols - 1; + + while ( (l_ref + i*L_ptrs) <= last_symbol) { + + is_dmrs_symbol1 = is_dmrs_symbol(max((l_ref + (i-1)*L_ptrs + 1), l_ref), + 0, + 0, + 0, + 0, + 0, + duration_in_symbols, + dmrs_type, + ofdm_symbol_size); + + is_dmrs_symbol2 = is_dmrs_symbol(l_ref + i*L_ptrs, + 0, + 0, + 0, + 0, + 0, + duration_in_symbols, + dmrs_type, + ofdm_symbol_size); + + if ( is_dmrs_symbol1 + is_dmrs_symbol2 > 0 ) { + + if (pusch_maxLength == 2) + l_ref = l_ref + i*L_ptrs + 1; + else + l_ref = l_ref + i*L_ptrs; + + i = 1; + + continue; + + } + + *ptrs_symbols = *ptrs_symbols | (1<<(l_ref + i*L_ptrs)); + i++; + } +} + +/******************************************************************* +* +* NAME : get_L_ptrs +* +* PARAMETERS : ptrs_UplinkConfig PTRS uplink configuration +* I_mcs MCS index used for PUSCH +* +* RETURN : the parameter L_ptrs +* +* DESCRIPTION : 3GPP TS 38.214 6.2.3 Table 6.2.3.1-1 +* +*********************************************************************/ + +uint8_t get_L_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint8_t I_mcs) { + + uint8_t mcs1, mcs2, mcs3; + + mcs1 = ptrs_UplinkConfig->timeDensity.ptrs_mcs1; + mcs2 = ptrs_UplinkConfig->timeDensity.ptrs_mcs2; + mcs3 = ptrs_UplinkConfig->timeDensity.ptrs_mcs3; + + if (mcs1 == 0 || mcs2 == 0 || mcs3 == 0) + return 1; + + if (I_mcs < mcs1){ + LOG_I(PHY,"PUSH PT-RS is not present.\n"); + return 0; + } + else if (I_mcs >= mcs1 && I_mcs < mcs2) + return 4; + else if (I_mcs >= mcs2 && I_mcs < mcs3) + return 2; + else + return 1; +} + +/******************************************************************* +* +* NAME : is_ptrs_subcarrier +* +* PARAMETERS : k subcarrier index +* K_ptrs the parameter K_ptrs +* n_rnti UE CRNTI +* N_RB number of RBs scheduled for PUSCH +* k_RE_ref the parameter k_RE_ref +* start_sc first subcarrier index +* ofdm_symbol_size FFT size +* +* RETURN : 1 if subcarrier k is PTRS, or 0 otherwise +* +* DESCRIPTION : 3GPP TS 38.211 6.4.1.2 Phase-tracking reference signal for PUSCH +* +*********************************************************************/ + +uint8_t is_ptrs_subcarrier(uint16_t k, uint8_t K_ptrs, uint16_t n_rnti, uint16_t N_RB, int16_t k_RE_ref, uint16_t start_sc, uint16_t ofdm_symbol_size) { + + uint16_t k_RB_ref, i, sc; + + i = 0; + sc = 0; + k_RB_ref = 0; + + if (N_RB % K_ptrs == 0) + k_RB_ref = n_rnti % K_ptrs; + else + k_RB_ref = n_rnti % (N_RB % K_ptrs); + + while (k > sc){ + + sc = (start_sc + k_RE_ref + (i*K_ptrs + k_RB_ref)*NR_NB_SC_PER_RB)%ofdm_symbol_size; + i++; + + } + + if (k == sc) + return 1; + else + return 0; + +} + +/******************************************************************* +* +* NAME : is_ptrs_symbol +* +* PARAMETERS : l ofdm symbol index within slot +* k subcarrier index +* n_rnti UE CRNTI +* N_RB number of RBs scheduled for PUSCH +* duration_in_symbols number of scheduled PUSCH ofdm symbols +* dmrs_antenna_port DMRS antenna port +* K_ptrs the parameter K_ptrs +* ptrs_symbols bit mask of ptrs +* start_sc first subcarrier index +* ofdm_symbol_size FFT size +* pusch_dmrs_type PUSCH DMRS type (1 or 2) +* ptrs_UplinkConfig PTRS uplink configuration +* +* RETURN : 0 if symbol(k,l) is data, or 1 if symbol(k,l) is ptrs +* +* DESCRIPTION : 3GPP TS 38.211 6.4.1.2 Phase-tracking reference signal for PUSCH +* +*********************************************************************/ + +uint8_t is_ptrs_symbol(uint8_t l, + uint16_t k, + uint16_t n_rnti, + uint16_t N_RB, + uint8_t duration_in_symbols, + uint8_t dmrs_antenna_port, + uint8_t K_ptrs, + uint16_t ptrs_symbols, + uint16_t start_sc, + uint16_t ofdm_symbol_size, + pusch_dmrs_type_t pusch_dmrs_type, + uint8_t resourceElementOffset) { + + uint8_t is_ptrs_freq, is_ptrs_time; + int16_t k_RE_ref; + + is_ptrs_freq = 0; + is_ptrs_time = 0; + + k_RE_ref = get_kRE_ref(dmrs_antenna_port, pusch_dmrs_type, resourceElementOffset); + + is_ptrs_freq = is_ptrs_subcarrier(k, K_ptrs, n_rnti, N_RB, k_RE_ref, start_sc, ofdm_symbol_size); + + if (is_ptrs_freq == 0) + return 0; + + if (((ptrs_symbols>>l)&1) == 1) + is_ptrs_time = 1; + + if (is_ptrs_time && is_ptrs_freq) + return 1; + else + return 0; + +} + +/* +int main(int argc, char const *argv[]) +{ + + dmrs_UplinkConfig_t dmrs_Uplink_Config; + ptrs_UplinkConfig_t ptrs_Uplink_Config; + uint8_t resourceElementOffset; + uint8_t dmrs_antenna_port; + uint8_t L_ptrs, K_ptrs; + int16_t k_RE_ref; + uint16_t N_RB, ptrs_symbols, ofdm_symbol_size, k; + uint8_t duration_in_symbols, I_mcs; + uint8_t start_symbol, l; + uint8_t ptrs_symbol_flag; + uint16_t n_rnti; + + dmrs_Uplink_Config.pusch_dmrs_type = pusch_dmrs_type1; + dmrs_Uplink_Config.pusch_dmrs_AdditionalPosition = pusch_dmrs_pos1; + dmrs_Uplink_Config.pusch_maxLength = pusch_len2; + + ptrs_Uplink_Config.timeDensity.ptrs_mcs1 = 0; // setting MCS values to 0 indicate abscence of time_density field in the configuration + ptrs_Uplink_Config.timeDensity.ptrs_mcs2 = 0; + ptrs_Uplink_Config.timeDensity.ptrs_mcs3 = 0; + ptrs_Uplink_Config.frequencyDensity.n_rb0 = 0; // setting N_RB values to 0 indicate abscence of frequency_density field in the configuration + ptrs_Uplink_Config.frequencyDensity.n_rb1 = 0; + ptrs_Uplink_Config.resourceElementOffset = 0; + + n_rnti = 0x1234; + resourceElementOffset = 0; + ptrs_symbols = 0; + dmrs_antenna_port = 0; + N_RB = 50; + duration_in_symbols = 14; + ofdm_symbol_size = 2048; + I_mcs = 9; + start_symbol = 0; + ptrs_symbol_flag = 0; + + k_RE_ref = get_kRE_ref(dmrs_antenna_port, dmrs_Uplink_Config.pusch_dmrs_type, resourceElementOffset); + + K_ptrs = get_K_ptrs(&ptrs_Uplink_Config, N_RB); + + L_ptrs = get_L_ptrs(&ptrs_Uplink_Config, I_mcs); + + set_ptrs_symb_idx(&ptrs_symbols, + &ptrs_Uplink_Config, + &dmrs_Uplink_Config, + 1, + duration_in_symbols, + start_symbol, + L_ptrs, + ofdm_symbol_size); + + printf("PTRS OFDM symbol indicies: "); + + for (l = start_symbol; l < start_symbol + duration_in_symbols; l++){ + + ptrs_symbol_flag = is_ptrs_symbol(l, + 0, + n_rnti, + N_RB, + duration_in_symbols, + dmrs_antenna_port, + K_ptrs, + ptrs_symbols, + dmrs_Uplink_Config.pusch_dmrs_type, + &ptrs_Uplink_Config); + + if (ptrs_symbol_flag == 1) + printf(" %d ", l); + + } + + printf("\n"); + + printf("PTRS subcarrier indicies: "); + + for (k = 0; k < N_RB*12; k++){ + + if (is_ptrs_subcarrier(k, K_ptrs, n_rnti, N_RB, k_RE_ref) == 1) + printf(" %d ", k); + + } + + printf("\n"); + + return 0; +} +*/ diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.h b/openair1/PHY/NR_REFSIG/ptrs_nr.h new file mode 100644 index 0000000000..291ff4a555 --- /dev/null +++ b/openair1/PHY/NR_REFSIG/ptrs_nr.h @@ -0,0 +1,81 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : dmrs.h +* +* MODULE : demodulation reference signals +* +* DESCRIPTION : generation of dmrs sequences for NR 5G +* 3GPP TS 38.211 +* +************************************************************************/ + +#ifndef PTRS_NR_H +#define PTRS_NR_H + +#include "PHY/defs_nr_UE.h" + +/************** CODE GENERATION ***********************************/ + +/************** DEFINE ********************************************/ + + +/************* STRUCTURES *****************************************/ + + +/************** VARIABLES *****************************************/ + +/************** FUNCTION ******************************************/ + +int16_t get_kRE_ref(uint8_t dmrs_antenna_port, uint8_t pusch_dmrs_type, uint8_t resourceElementOffset); + +uint8_t get_K_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint16_t N_RB); + +void set_ptrs_symb_idx(uint16_t *ptrs_symbols, + uint8_t duration_in_symbols, + uint8_t start_symbol, + uint8_t dmrs_type, + uint8_t L_ptrs, + uint8_t pusch_maxLength, + uint16_t ofdm_symbol_size); + +uint8_t get_L_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint8_t I_mcs); + +uint8_t is_ptrs_subcarrier(uint16_t k, uint8_t K_ptrs, uint16_t n_rnti, uint16_t N_RB, int16_t k_RE_ref, uint16_t start_sc, uint16_t ofdm_symbol_size); + +uint8_t is_ptrs_symbol(uint8_t l, + uint16_t k, + uint16_t n_rnti, + uint16_t N_RB, + uint8_t duration_in_symbols, + uint8_t dmrs_antenna_port, + uint8_t K_ptrs, + uint16_t ptrs_symbols, + uint16_t start_sc, + uint16_t ofdm_symbol_size, + pusch_dmrs_type_t pusch_dmrs_type, + uint8_t resourceElementOffset); + + + +#endif /* PTRS_NR_H */ diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index c269618743..d62687bd9c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -166,7 +166,7 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu, int k,l,k_prime,dci_idx, dmrs_idx; /*First iteration: single DCI*/ - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15=NULL; // find coreset descriptor @@ -243,8 +243,8 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu, printf("Encoded Payload (length:%d dwords):\n", encoded_length>>5); for (int i=0; i>5; i++) - printf("[%d]->0x%08x \t", i,encoder_output[i]); - + printf("[%d]->0x%08x \t", i,encoder_output[i]); + printf("\n"); #endif /// Scrambling @@ -273,9 +273,10 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu, /*Reorder REG list for a freq first mapping*/ uint8_t nb_regs = pdcch_pdu_rel15->AggregationLevel[d]*NR_NB_REG_PER_CCE; + uint8_t reg_idx0 = pdcch_pdu_rel15->CceIndex[d]*NR_NB_REG_PER_CCE; /*Mapping the encoded DCI along with the DMRS */ - for (int reg_idx=0; reg_idx= frame_parms.ofdm_symbol_size) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 20d995f69c..856a7863f4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -35,13 +35,12 @@ #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/coding_defs.h" #include "PHY/CODING/lte_interleaver_inline.h" -#include "PHY/CODING/nrLDPC_encoder/defs.h" +#include "PHY/CODING/nrLDPC_extern.h" #include "PHY/NR_TRANSPORT/nr_transport.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "SCHED_NR/sched_nr.h" -#include "defs.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/LOG/log.h" #include @@ -441,11 +440,16 @@ int nr_dlsch_encoding(unsigned char *a, //ldpc_encoder_orig((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],dlsch->harq_processes[harq_pid]->d[r],*Zc,Kb,Kr,BG,0); //ldpc_encoder_optim((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],(unsigned char*)&dlsch->harq_processes[harq_pid]->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL); } + encoder_implemparams_t impp; + impp.n_segments=dlsch->harq_processes[harq_pid]->C; + impp.tprep = tprep; + impp.tinput = tinput; + impp.tparity = tparity; + impp.toutput = toutput; - for(int j=0;j<((dlsch->harq_processes[harq_pid]->C-1)/8+1);j++) { - ldpc_encoder_optim_8seg_multi(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,BG, - dlsch->harq_processes[harq_pid]->C,j, - tinput,tprep,tparity,toutput); + for(int j=0;j<(dlsch->harq_processes[harq_pid]->C/8+1);j++) { + impp.macro_num=j; + nrLDPC_encoder(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,BG,&impp); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index ff1f841e47..2e6fc707bd 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -333,24 +333,9 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, ulsch->harq_mask |= 1<harq_process_id[slot] = harq_pid; - nfapi_nr_ul_config_ulsch_pdu *rel15_ul = &ulsch->harq_processes[harq_pid]->ulsch_pdu; + memcpy((void*)&ulsch->harq_processes[harq_pid]->ulsch_pdu, (void*)ulsch_pdu, sizeof(nfapi_nr_pusch_pdu_t)); LOG_D(PHY,"Initializing nFAPI for ULSCH, UE %d, harq_pid %d\n",ulsch_id,harq_pid); - - - //FK this is still a bad hack. We need to replace the L1 FAPI structures with the new scf ones as well. - rel15_ul->rnti = ulsch_pdu->rnti; - rel15_ul->ulsch_pdu_rel15.start_rb = ulsch_pdu->rb_start; - rel15_ul->ulsch_pdu_rel15.number_rbs = ulsch_pdu->rb_size; - rel15_ul->ulsch_pdu_rel15.start_symbol = ulsch_pdu->start_symbol_index; - rel15_ul->ulsch_pdu_rel15.number_symbols = ulsch_pdu->nr_of_symbols; - rel15_ul->ulsch_pdu_rel15.nb_re_dmrs = 6; //where should this come from? - rel15_ul->ulsch_pdu_rel15.length_dmrs = 1; //where should this come from? - rel15_ul->ulsch_pdu_rel15.Qm = ulsch_pdu->qam_mod_order; - rel15_ul->ulsch_pdu_rel15.mcs = ulsch_pdu->mcs_index; - rel15_ul->ulsch_pdu_rel15.rv = ulsch_pdu->pusch_data.rv_index; - rel15_ul->ulsch_pdu_rel15.n_layers = ulsch_pdu->nrOfLayers; - rel15_ul->ulsch_pdu_rel15.R = ulsch_pdu->target_code_rate; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 268f2f5fcf..5710499e1a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -65,7 +65,7 @@ void rx_nr_prach_ru(RU_t *ru, AssertFatal(ru->if_south == LOCAL_RF,"we shouldn't call this if if_south != LOCAL_RF\n"); for (int aa=0; aanb_rx; aa++) - prach[aa] = (int16_t*)&ru->common.rxdata[aa][(subframe*fp->samples_per_slot<<1)-ru->N_TA_offset]; + prach[aa] = (int16_t*)&ru->common.rxdata[aa][(subframe*fp->samples_per_subframe)-ru->N_TA_offset]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c index ad2edadb5f..04045380eb 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c @@ -32,7 +32,6 @@ #include "nr_sch_dmrs.h" - /*Table 7.4.1.1.2-1 and 7.4.1.1.2-2 38211 Columns: ap - CDM group - Delta - Wf(0) - Wf(1) - Wt(0) - Wt(1)*/ /*Table 6.4.1.1.3-1 is identical to Table 7.4.1.1.2-1 and Table 6.4.1.1.3-2 is identical to Table 7.4.1.1.2-2. UL DMRS can reuse these tables*/ int8_t pdsch_dmrs_1[8][7] = {{0,0,0,1,1,1,1}, @@ -57,11 +56,6 @@ int8_t pdsch_dmrs_2[12][7] = {{0,0,0,1,1,1,1}, {10,2,4,1,1,1,-1}, {11,2,4,1,-1,1,-1}}; -void get_l_prime(uint8_t *l_prime, uint8_t n_symbs) { - for (int i=0; i0,"Nl is 0\n"); AssertFatal(Qm>0,"Qm is 0\n"); - + LOG_D(PHY,"nr_get_E : (G %d, C %d, Qm %d, Nl %d, r %d)\n",G, C, Qm, Nl, r); if (r <= Cprime - ((G/(Nl*Qm))%Cprime) - 1) E = Nl*Qm*(G/(Nl*Qm*Cprime)); else diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport.h b/openair1/PHY/NR_TRANSPORT/nr_transport.h index ba0791d33a..1717cb9501 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport.h @@ -138,9 +138,8 @@ void nr_decode_pucch1(int32_t **rxdataF, uint8_t timeDomainOCC, uint8_t nr_bit); -void nr_decode_pucch0(int32_t **rxdataF, - NR_DL_FRAME_PARMS *frame_parms, - int slot, +void nr_decode_pucch0(PHY_VARS_gNB *gNB, + int slot, nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu, nfapi_nr_pucch_pdu_t* pucch_pdu); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 971018e734..9ce56421fc 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -62,17 +62,14 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, @param start_rb The starting RB in the RB allocation (used for Resource Allocation Type 1 in NR) @param nb_rb_pusch The number of RBs allocated (used for Resource Allocation Type 1 in NR) @param frame_parms, Pointer to frame descriptor structure + @param is_dmrs_symbol, flag to indicate wether this OFDM symbol contains DMRS symbols or not. */ -void nr_ulsch_extract_rbs_single(int **rxdataF, - int **ul_ch_estimates, - int **rxdataF_ext, - int **ul_ch_estimates_ext, - uint32_t rxdataF_ext_offset, - // unsigned int *rb_alloc, [hna] Resource Allocation Type 1 is assumed only for the moment +void nr_ulsch_extract_rbs_single(int32_t **rxdataF, + NR_gNB_PUSCH *pusch_vars, unsigned char symbol, - unsigned short start_rb, - unsigned short nb_rb_pusch, + uint8_t is_dmrs_symbol, + nfapi_nr_pusch_pdu_t *pusch_pdu, NR_DL_FRAME_PARMS *frame_parms); void nr_ulsch_scale_channel(int32_t **ul_ch_estimates_ext, @@ -80,7 +77,8 @@ void nr_ulsch_scale_channel(int32_t **ul_ch_estimates_ext, NR_gNB_ULSCH_t **ulsch_gNB, uint8_t symbol, uint8_t start_symbol, - uint16_t nb_rb); + uint16_t nb_rb, + pusch_dmrs_type_t pusch_dmrs_type); /** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal @@ -118,7 +116,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, int **rho, NR_DL_FRAME_PARMS *frame_parms, unsigned char symbol, - uint8_t pilots, + uint8_t is_dmrs_symbol, unsigned char mod_order, unsigned short nb_rb, unsigned char output_shift); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h index d49f5c8d00..7ff52ae692 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h @@ -34,7 +34,7 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t **ulsch,uint8_t N_RB_UL); -NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag); +NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint16_t N_RB_UL, uint8_t abstraction_flag); /*! \brief Perform PUSCH decoding. TS 38.212 V15.4.0 subclause 6.2 @@ -43,6 +43,7 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8 @param ulsch_llr, Pointer to received llr in ulsch @param frame_parms, Pointer to frame descriptor structure @param nb_symb_sch, number of symbols used in the uplink shared channel + @param nb_re_dmrs, number of DMRS resource elements in one RB @param nr_tti_rx, current received TTI @param harq_pid, harq process id @param is_crnti @@ -52,11 +53,11 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, uint8_t UE_id, short *ulsch_llr, NR_DL_FRAME_PARMS *frame_parms, + nfapi_nr_pusch_pdu_t *pusch_pdu, uint32_t frame, - uint16_t nb_symb_sch, uint8_t nr_tti_rx, uint8_t harq_pid, - uint8_t is_crnti); + uint32_t G); /*! \brief Perform PUSCH unscrambling. TS 38.211 V15.4.0 subclause 6.3.1.1 diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 1c6285a69d..e8a961360f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -37,8 +37,7 @@ #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/coding_defs.h" #include "PHY/CODING/lte_interleaver_inline.h" -#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h" -#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" +#include "PHY/CODING/nrLDPC_extern.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" @@ -112,7 +111,7 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t **ulschptr,uint8_t N_RB_UL) } -NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag) +NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint16_t N_RB_UL, uint8_t abstraction_flag) { NR_gNB_ULSCH_t *ulsch; @@ -122,7 +121,7 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8 if (N_RB_UL != 273) { a_segments = a_segments*N_RB_UL; a_segments = a_segments/273; - } + } uint16_t ulsch_bytes = a_segments*1056; // allocated bytes per segment @@ -185,10 +184,8 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8 if (exit_flag==0) return(ulsch); } - - printf("new_gNB_ulsch with size %zu: exit_flag = %u\n",sizeof(NR_UL_gNB_HARQ_t), exit_flag); + printf("new_gNB_ulsch with size %zu: exit_flag = %hhu\n",sizeof(NR_UL_gNB_HARQ_t), exit_flag); free_gNB_ulsch(&ulsch,N_RB_UL); - return(NULL); } @@ -298,14 +295,13 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, uint8_t UE_id, short *ulsch_llr, NR_DL_FRAME_PARMS *frame_parms, + nfapi_nr_pusch_pdu_t *pusch_pdu, uint32_t frame, - uint16_t nb_symb_sch, uint8_t nr_tti_rx, uint8_t harq_pid, - uint8_t is_crnti) -{ + uint32_t G) { + uint32_t A,E; - uint32_t G; uint32_t ret, offset; int32_t no_iteration_ldpc, length_dec; uint32_t r,r_offset=0,Kr=8424,Kr_bytes,K_bytes_F,err_flag=0; @@ -319,7 +315,6 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, NR_gNB_ULSCH_t *ulsch = phy_vars_gNB->ulsch[UE_id][0]; NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_processes[harq_pid]; - nfapi_nr_ul_config_ulsch_pdu_rel15_t *nfapi_ulsch_pdu_rel15 = &harq_process->ulsch_pdu.ulsch_pdu_rel15; t_nrLDPC_dec_params decParams; t_nrLDPC_dec_params* p_decParams = &decParams; @@ -339,14 +334,11 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, double Coderate = 0.0; // ------------------------------------------------------------------ - uint16_t nb_rb = nfapi_ulsch_pdu_rel15->number_rbs; - uint16_t number_symbols = nfapi_ulsch_pdu_rel15->number_symbols; - uint8_t Qm = nfapi_ulsch_pdu_rel15->Qm; - uint16_t R = nfapi_ulsch_pdu_rel15->R; - uint8_t mcs = nfapi_ulsch_pdu_rel15->mcs; - uint8_t n_layers = nfapi_ulsch_pdu_rel15->n_layers; - uint8_t nb_re_dmrs = nfapi_ulsch_pdu_rel15->nb_re_dmrs; - uint8_t length_dmrs = nfapi_ulsch_pdu_rel15->length_dmrs; + uint16_t nb_rb = pusch_pdu->rb_size; + uint8_t Qm = pusch_pdu->qam_mod_order; + uint16_t R = pusch_pdu->target_code_rate; + uint8_t mcs = pusch_pdu->mcs_index; + uint8_t n_layers = pusch_pdu->nrOfLayers; // ------------------------------------------------------------------ uint32_t i,j; @@ -366,19 +358,20 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, } // harq_process->trials[nfapi_ulsch_pdu_rel15->round]++; - harq_process->TBS = nr_compute_tbs(Qm, R, nb_rb, number_symbols, nb_re_dmrs*length_dmrs, 0, n_layers); + harq_process->TBS = pusch_pdu->pusch_data.tb_size; - A = harq_process->TBS; + A = (harq_process->TBS)<<3; ret = ulsch->max_ldpc_iterations + 1; - G = nr_get_G(nb_rb, number_symbols, nb_re_dmrs, length_dmrs, Qm, n_layers); - - LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, mcs, n_layers, nb_symb_sch,nb_rb); + LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, n_layers %d\n",harq_pid,A,G, mcs, n_layers, nb_rb, Qm, n_layers); if (harq_process->round == 0) { // This is a new packet, so compute quantities regarding segmentation - harq_process->B = A+24; + if (A > 3824) + harq_process->B = A+24; + else + harq_process->B = A+16; if (R<1024) Coderate = (float) R /(float) 1024; @@ -415,20 +408,20 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, } } - // [hna] Perform nr_segmenation with input and output set to NULL to calculate only (B, C, K, Z, F) - nr_segmentation(NULL, - NULL, - harq_process->B, - &harq_process->C, - &harq_process->K, - &harq_process->Z, // [hna] Z is Zc - &harq_process->F, - p_decParams->BG); + // [hna] Perform nr_segmenation with input and output set to NULL to calculate only (B, C, K, Z, F) + nr_segmentation(NULL, + NULL, + harq_process->B, + &harq_process->C, + &harq_process->K, + &harq_process->Z, // [hna] Z is Zc + &harq_process->F, + p_decParams->BG); #ifdef DEBUG_ULSCH_DECODING printf("ulsch decoding nr segmentation Z %d\n", harq_process->Z); if (!frame%100) - printf("K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, harq_process->Z, harq_process->Nl); + printf("K %d C %d Z %d\n", harq_process->K, harq_process->C, harq_process->Z); #endif } p_decParams->Z = harq_process->Z; @@ -445,7 +438,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, if (nb_rb != 273) { a_segments = a_segments*nb_rb; a_segments = a_segments/273; - } + } if (harq_process->C > a_segments) { LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments); @@ -463,7 +456,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, K_bytes_F = Kr_bytes-(harq_process->F>>3); for (r=0; rC; r++) { - E = nr_get_E(G, harq_process->C, nfapi_ulsch_pdu_rel15->Qm, nfapi_ulsch_pdu_rel15->n_layers, r); + E = nr_get_E(G, harq_process->C, Qm, n_layers, r); #if gNB_TIMING_TRACE start_meas(ulsch_deinterleaving_stats); @@ -476,7 +469,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, //////////////////////////// ulsch_llr =====> harq_process->e ////////////////////////////// nr_deinterleaving_ldpc(E, - nfapi_ulsch_pdu_rel15->Qm, + Qm, harq_process->e[r], ulsch_llr+r_offset); @@ -496,10 +489,10 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, harq_pid,r, G, Kr*3, harq_process->TBS, - nfapi_ulsch_pdu_rel15->Qm, - nfapi_ulsch_pdu_rel15->number_rbs, - nfapi_ulsch_pdu_rel15->n_layers, - nfapi_ulsch_pdu_rel15->rv, + Qm, + nb_rb, + n_layers, + pusch_pdu->pusch_data.rv_index, harq_process->round); #endif ////////////////////////////////////////////////////////////////////////////////////////// @@ -511,7 +504,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, ///////////////////////// harq_process->e =====> harq_process->d ///////////////////////// - Tbslbrm = nr_compute_tbslbrm(0,nb_rb,nfapi_ulsch_pdu_rel15->n_layers,harq_process->C); + Tbslbrm = nr_compute_tbslbrm(0,nb_rb,n_layers,harq_process->C); if (nr_rate_matching_ldpc_rx(Ilbrm, Tbslbrm, @@ -520,7 +513,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, harq_process->d[r], harq_process->e[r], harq_process->C, - nfapi_ulsch_pdu_rel15->rv, + pusch_pdu->pusch_data.rv_index, (harq_process->round==0)?1:0, E, harq_process->F, @@ -557,7 +550,11 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, // printf("done\n"); if (harq_process->C == 1) { - crc_type = CRC24_A; + if (A > 3824) + crc_type = CRC24_A; + else + crc_type = CRC16; + length_dec = harq_process->B; } else { @@ -656,7 +653,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, int32_t tti_rx_prev = nr_tti_rx - 1; if (tti_rx_prev < 0) { frame_rx_prev--; - tti_rx_prev += 10*frame_parms->ttis_per_subframe; + tti_rx_prev += frame_parms->slots_per_frame; } frame_rx_prev = frame_rx_prev%1024; @@ -680,13 +677,11 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, ulsch->harq_mask &= ~(1 << harq_pid); } - if(is_crnti) { - LOG_D(PHY,"[gNB %d] ULSCH: Setting NACK for nr_tti_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", - phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->status,harq_process->round,ulsch->Mlimit,harq_process->TBS); - } + // LOG_D(PHY,"[gNB %d] ULSCH: Setting NACK for nr_tti_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", + // phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->status,harq_process->round,ulsch->Mlimit,harq_process->TBS); harq_process->handled = 1; - return (ulsch->max_ldpc_iterations + 1); + ret = ulsch->max_ldpc_iterations + 1; } else { @@ -703,32 +698,38 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, // harq_process->harq_ack.harq_id = harq_pid; // harq_process->harq_ack.send_harq_status = 1; - if(is_crnti) - { - LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d (pid %d, round %d, TBS %d)\n",phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->round,harq_process->TBS); + // LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d (pid %d, round %d, TBS %d)\n",phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->round,harq_process->TBS); + + // Reassembly of Transport block here + offset = 0; + Kr = harq_process->K; + Kr_bytes = Kr>>3; + + for (r=0; rC; r++) { + + memcpy(harq_process->b+offset, + harq_process->c[r], + Kr_bytes- - (harq_process->F>>3) -((harq_process->C>1)?3:0)); + + offset += (Kr_bytes - (harq_process->F>>3) - ((harq_process->C>1)?3:0)); + +#ifdef DEBUG_ULSCH_DECODING + printf("Segment %u : Kr = %u bytes\n", r, Kr_bytes); + printf("copied %d bytes to b sequence (harq_pid %d)\n", (Kr_bytes - (harq_process->F>>3)-((harq_process->C>1)?3:0)), harq_pid); + printf("b[0] = %x, c[%d] = %x\n", harq_process->b[offset], harq_process->F>>3, harq_process->c[r]); +#endif + } } - // Reassembly of Transport block here - offset = 0; - Kr = harq_process->K; - Kr_bytes = Kr>>3; - - for (r=0; rC; r++) { - - memcpy(harq_process->b+offset, - harq_process->c[r], - Kr_bytes- - (harq_process->F>>3) -((harq_process->C>1)?3:0)); - - offset += (Kr_bytes - (harq_process->F>>3) - ((harq_process->C>1)?3:0)); - #ifdef DEBUG_ULSCH_DECODING - printf("Segment %u : Kr = %u bytes\n", r, Kr_bytes); - printf("copied %d bytes to b sequence (harq_pid %d)\n", (Kr_bytes - (harq_process->F>>3)-((harq_process->C>1)?3:0)), harq_pid); - printf("b[0] = %x, c[%d] = %x\n", harq_process->b[offset], harq_process->F>>3, harq_process->c[r]); -#endif - + LOG_I(PHY, "Decoder output (payload): \n"); + for (i = 0; i < harq_process->TBS / 8; i++) { + //harq_process_ul_ue->a[i] = (unsigned char) rand(); + //printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]); + printf("0x%02x",harq_process->b[i]); } +#endif ulsch->last_iteration_cnt = ret; diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index aeb03213f6..bce8ddcc29 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -3,6 +3,8 @@ #include "nr_transport_proto.h" #include "PHY/impl_defs_top.h" #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" +#include "PHY/NR_REFSIG/dmrs_nr.h" +#include "PHY/NR_REFSIG/ptrs_nr.h" #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" #include "PHY/defs_nr_common.h" @@ -220,76 +222,127 @@ void nr_idft(uint32_t *z, uint32_t Msc_PUSCH) } -void nr_ulsch_extract_rbs_single(int **rxdataF, - int **ul_ch_estimates, - int **rxdataF_ext, - int **ul_ch_estimates_ext, - uint32_t rxdataF_ext_offset, - // unsigned int *rb_alloc, [hna] Resource Allocation Type 1 is assumed only for the moment + +void nr_ulsch_extract_rbs_single(int32_t **rxdataF, + NR_gNB_PUSCH *pusch_vars, unsigned char symbol, - unsigned short start_rb, - unsigned short nb_rb_pusch, - NR_DL_FRAME_PARMS *frame_parms) + uint8_t is_dmrs_symbol, + nfapi_nr_pusch_pdu_t *pusch_pdu, + NR_DL_FRAME_PARMS *frame_parms) { unsigned short start_re, re, nb_re_pusch; - unsigned char aarx, is_dmrs_symbol = 0; + unsigned char aarx; + uint8_t K_ptrs; uint32_t rxF_ext_index = 0; uint32_t ul_ch0_ext_index = 0; uint32_t ul_ch0_index = 0; - + uint32_t ul_ch0_ptrs_ext_index = 0; + uint32_t ul_ch0_ptrs_index = 0; + uint8_t is_ptrs_symbol_flag,k_prime; + uint16_t n=0, num_ptrs_symbols; int16_t *rxF,*rxF_ext; int *ul_ch0,*ul_ch0_ext; + int *ul_ch0_ptrs,*ul_ch0_ptrs_ext; + uint16_t n_rnti = pusch_pdu->rnti; + uint8_t delta = 0; #ifdef DEBUG_RB_EXT printf("--------------------symbol = %d-----------------------\n", symbol); - printf("--------------------ch_ext_index = %d-----------------------\n", symbol*NR_NB_SC_PER_RB * nb_rb_pusch); + printf("--------------------ch_ext_index = %d-----------------------\n", symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size); #endif + + uint8_t is_dmrs_re; + start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start * NR_NB_SC_PER_RB))%frame_parms->ofdm_symbol_size; + nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size; + is_ptrs_symbol_flag = 0; + num_ptrs_symbols = 0; - is_dmrs_symbol = (symbol == 2) ? 1 : 0; //to be updated from config - - start_re = (frame_parms->first_carrier_offset + (start_rb * NR_NB_SC_PER_RB))%frame_parms->ofdm_symbol_size; - - nb_re_pusch = NR_NB_SC_PER_RB * nb_rb_pusch; + K_ptrs = (pusch_pdu->pusch_ptrs.ptrs_freq_density)?4:2; for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { rxF = (int16_t *)&rxdataF[aarx][symbol * frame_parms->ofdm_symbol_size]; - rxF_ext = (int16_t *)&rxdataF_ext[aarx][symbol * nb_re_pusch]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 + rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 - ul_ch0 = &ul_ch_estimates[aarx][(2*(frame_parms->ofdm_symbol_size))]; // DMRS REs are only in symbol 2 (to be updated from config) - ul_ch0_ext = &ul_ch_estimates_ext[aarx][symbol*nb_re_pusch]; + ul_ch0 = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available + + ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch]; + + ul_ch0_ptrs = &pusch_vars->ul_ch_ptrs_estimates[aarx][pusch_vars->ptrs_symbol_index*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available + + ul_ch0_ptrs_ext = &pusch_vars->ul_ch_ptrs_estimates_ext[aarx][symbol*nb_re_pusch]; + + n = 0; + k_prime = 0; for (re = 0; re < nb_re_pusch; re++) { - if ( (is_dmrs_symbol && ((re&1) != 0)) || (is_dmrs_symbol == 0) ) { // [hna] (re&1) != frame_parms->nushift) assuming only dmrs type 1 and mapping type A - // frame_parms->nushift should be initialized with 0 + if (is_dmrs_symbol) + is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type)); + else + is_dmrs_re = 0; + + if ( ((pusch_pdu->pdu_bit_map)>>2)& 0x01 ) { + is_ptrs_symbol_flag = is_ptrs_symbol(symbol, + (start_re + re)%frame_parms->ofdm_symbol_size, + n_rnti, + pusch_pdu->rb_size, + pusch_pdu->nr_of_symbols, + aarx, + K_ptrs, + pusch_vars->ptrs_symbols, + start_re, + frame_parms->ofdm_symbol_size, + pusch_pdu->dmrs_config_type, + pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset); + + if (is_ptrs_symbol_flag == 1) + num_ptrs_symbols++; + + } + + #ifdef DEBUG_RB_EXT + printf("re = %d, is_dmrs_symbol_flag = %d, symbol = %d\n", re, is_dmrs_symbol_flag, symbol); + #endif + + if ( is_dmrs_re == 0 && is_ptrs_symbol_flag == 0) { + rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; + ul_ch0_ptrs_ext[ul_ch0_ptrs_ext_index] = ul_ch0_ptrs[ul_ch0_ptrs_index]; #ifdef DEBUG_RB_EXT printf("rxF_ext[%d] = %d\n", rxF_ext_index, rxF_ext[rxF_ext_index]); printf("rxF_ext[%d] = %d\n", rxF_ext_index+1, rxF_ext[rxF_ext_index+1]); - printf("ul_ch0_ext[%d] = %d\n", 2*ul_ch0_ext_index, ((int16_t *)ul_ch0_ext)[2*ul_ch0_ext_index]); - printf("ul_ch0_ext[%d] = %d\n", 2*ul_ch0_ext_index + 1, ((int16_t *)ul_ch0_ext)[2*ul_ch0_ext_index + 1]); #endif - rxF_ext_index = rxF_ext_index + 2; ul_ch0_ext_index++; - } + ul_ch0_ptrs_ext_index++; + rxF_ext_index +=2; + } else { + k_prime++; + k_prime&=1; + n+=(k_prime)?0:1; + } ul_ch0_index++; + ul_ch0_ptrs_index++; } } + + pusch_vars->ptrs_sc_per_ofdm_symbol = num_ptrs_symbols; + } void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, NR_DL_FRAME_PARMS *frame_parms, NR_gNB_ULSCH_t **ulsch_gNB, uint8_t symbol, - uint8_t pilots, - unsigned short nb_rb) + uint8_t is_dmrs_symbol, + unsigned short nb_rb, + pusch_dmrs_type_t pusch_dmrs_type) { #if defined(__x86_64__)||defined(__i386__) @@ -302,7 +355,7 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, ch_amp = 1024*8; //((pilots) ? (ulsch_gNB[0]->sqrt_rho_b) : (ulsch_gNB[0]->sqrt_rho_a)); - LOG_D(PHY,"Scaling PUSCH Chest in OFDM symbol %d by %d, pilots %d nb_rb %d NCP %d symbol %d\n", symbol, ch_amp, pilots, nb_rb, frame_parms->Ncp, symbol); + LOG_D(PHY,"Scaling PUSCH Chest in OFDM symbol %d by %d, pilots %d nb_rb %d NCP %d symbol %d\n", symbol, ch_amp, is_dmrs_symbol, nb_rb, frame_parms->Ncp, symbol); // printf("Scaling PUSCH Chest in OFDM symbol %d by %d\n",symbol_mod,ch_amp); ch_amp128 = _mm_set1_epi16(ch_amp); // Q3.13 @@ -312,8 +365,11 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*nb_rb*NR_NB_SC_PER_RB]; - if (pilots==1){ - nb_rb = nb_rb>>1; + if (is_dmrs_symbol==1){ + if (pusch_dmrs_type == pusch_dmrs_type1) + nb_rb = nb_rb>>1; + else + nb_rb = (2*nb_rb)/3; } @@ -325,7 +381,7 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, ul_ch128[1] = _mm_mulhi_epi16(ul_ch128[1], ch_amp128); ul_ch128[1] = _mm_slli_epi16(ul_ch128[1], 3); - if (pilots) { + if (is_dmrs_symbol) { ul_ch128+=2; } else { ul_ch128[2] = _mm_mulhi_epi16(ul_ch128[2], ch_amp128); @@ -364,7 +420,7 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, ul_ch128=(__m128i *)&ul_ch_estimates_ext[(aatx<<1)+aarx][symbol*nb_rb*12]; - for (rb = 0; rb < nb_rb; rb++) { + for (rb = 0; rb < len/12; rb++) { avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[0], ul_ch128[0]), x)); avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[1], ul_ch128[1]), x)); avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[2], ul_ch128[2]), x)); @@ -439,18 +495,17 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext, } void nr_ulsch_channel_compensation(int **rxdataF_ext, - int **ul_ch_estimates_ext, - int **ul_ch_mag, - int **ul_ch_magb, - int **rxdataF_comp, - int **rho, - NR_DL_FRAME_PARMS *frame_parms, - unsigned char symbol, - uint8_t pilots, - unsigned char mod_order, - unsigned short nb_rb, - unsigned char output_shift) -{ + int **ul_ch_estimates_ext, + int **ul_ch_mag, + int **ul_ch_magb, + int **rxdataF_comp, + int **rho, + NR_DL_FRAME_PARMS *frame_parms, + unsigned char symbol, + uint8_t is_dmrs_symbol, + unsigned char mod_order, + unsigned short nb_rb, + unsigned char output_shift) { #ifdef DEBUG_CH_COMP int16_t *rxF, *ul_ch; @@ -549,7 +604,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, ul_ch_mag128[1] = _mm_mulhi_epi16(ul_ch_mag128[1],QAM_amp128); ul_ch_mag128[1] = _mm_slli_epi16(ul_ch_mag128[1],1); - if (pilots==0) { + if (is_dmrs_symbol==0) { mmtmpD0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]); mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift); mmtmpD1 = _mm_packs_epi32(mmtmpD0,mmtmpD0); @@ -568,7 +623,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128b); ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],1); - if (pilots==0) { + if (is_dmrs_symbol==0) { ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128b); ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],1); } @@ -616,7 +671,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, // print_shorts("ch:",ul_ch128+1); // print_shorts("pack:",rxdataF_comp128+1); - if (pilots==0) { + if (is_dmrs_symbol==0) { // multiply by conjugated channel mmtmpD0 = _mm_madd_epi16(ul_ch128[2],rxdataF128[2]); // mmtmpD0 contains real part of 4 consecutive outputs (32-bit) @@ -738,7 +793,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, unsigned short rb; - unsigned char aatx,aarx,symbol_mod,pilots=0; + unsigned char aatx,aarx,symbol_mod,is_dmrs_symbol=0; int16x4_t *ul_ch128,*ul_ch128_2,*rxdataF128; int32x4_t mmtmpD0,mmtmpD1,mmtmpD0b,mmtmpD1b; @@ -756,7 +811,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, nb_rb=1+(5*nb_rb/6); } else { - pilots=1; + is_dmrs_symbol=1; } } @@ -793,7 +848,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, mmtmpD1 = vmull_s16(ul_ch128[3], ul_ch128[3]); mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1,vrev64q_s32(mmtmpD1)),output_shift128); mmtmpD3 = vcombine_s16(vmovn_s32(mmtmpD0),vmovn_s32(mmtmpD1)); - if (pilots==0) { + if (is_dmrs_symbol==0) { mmtmpD0 = vmull_s16(ul_ch128[4], ul_ch128[4]); mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0,vrev64q_s32(mmtmpD0)),output_shift128); mmtmpD1 = vmull_s16(ul_ch128[5], ul_ch128[5]); @@ -806,7 +861,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, ul_ch_mag128[0] = vqdmulhq_s16(mmtmpD2,QAM_amp128); ul_ch_mag128[1] = vqdmulhq_s16(mmtmpD3,QAM_amp128); - if (pilots==0) { + if (is_dmrs_symbol==0) { ul_ch_mag128b[2] = vqdmulhq_s16(mmtmpD4,QAM_amp128b); ul_ch_mag128[2] = vqdmulhq_s16(mmtmpD4,QAM_amp128); } @@ -843,7 +898,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, mmtmpD1 = vqshlq_s32(mmtmpD1,output_shift128); rxdataF_comp128[1] = vzip_s16(vmovn_s32(mmtmpD0),vmovn_s32(mmtmpD1)); - if (pilots==0) { + if (is_dmrs_symbol==0) { mmtmpD0 = vmull_s16(ul_ch128[4], rxdataF128[4]); mmtmpD1 = vmull_s16(ul_ch128[5], rxdataF128[5]); mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0),vget_high_s32(mmtmpD0)), @@ -971,74 +1026,110 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, unsigned char harq_pid) { - uint8_t first_symbol_flag, aarx, aatx, pilots; // pilots, a flag to indicate DMRS REs in current symbol - NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - nfapi_nr_ul_config_ulsch_pdu_rel15_t *rel15_ul = &gNB->ulsch[UE_id][0]->harq_processes[harq_pid]->ulsch_pdu.ulsch_pdu_rel15; + uint8_t first_symbol_flag, aarx, aatx, dmrs_symbol_flag, ptrs_symbol_flag; // dmrs_symbol_flag, a flag to indicate DMRS REs in current symbol uint32_t nb_re_pusch, bwp_start_subcarrier; + uint8_t L_ptrs = 0; // PTRS parameter int avgs; int avg[4]; + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + nfapi_nr_pusch_pdu_t *rel15_ul = &gNB->ulsch[UE_id][0]->harq_processes[harq_pid]->ulsch_pdu; - pilots = 0; + dmrs_symbol_flag = 0; + ptrs_symbol_flag = 0; first_symbol_flag = 0; - - if(symbol == rel15_ul->start_symbol){ + gNB->pusch_vars[UE_id]->ptrs_sc_per_ofdm_symbol = 0; + + if(symbol == rel15_ul->start_symbol_index){ gNB->pusch_vars[UE_id]->rxdataF_ext_offset = 0; + gNB->pusch_vars[UE_id]->dmrs_symbol = 0; + gNB->pusch_vars[UE_id]->cl_done = 0; + gNB->pusch_vars[UE_id]->ptrs_symbols = 0; first_symbol_flag = 1; + + if ( ((rel15_ul->pdu_bit_map)>>2)& 0x01 ) { // if there is ptrs pdu + L_ptrs = 1<<(rel15_ul->pusch_ptrs.ptrs_time_density); + + set_ptrs_symb_idx(&gNB->pusch_vars[UE_id]->ptrs_symbols, + rel15_ul->nr_of_symbols, + rel15_ul->start_symbol_index, + rel15_ul->dmrs_config_type, + L_ptrs, + 1, // only dmrs of length 1 is currently supported + frame_parms->ofdm_symbol_size); + } } - if (symbol == rel15_ul->start_symbol){ // [hna] here it is assumed that first carries 6 DMRS REs (dmrs-type 1) - nb_re_pusch = rel15_ul->number_rbs * 6; - pilots = 1; + bwp_start_subcarrier = (rel15_ul->rb_start*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; + + dmrs_symbol_flag = ((rel15_ul->ul_dmrs_symb_pos)>>symbol)&0x01; + + if (dmrs_symbol_flag == 1){ + nb_re_pusch = rel15_ul->rb_size * ((rel15_ul->dmrs_config_type==pusch_dmrs_type1)?6:8); + gNB->pusch_vars[UE_id]->dmrs_symbol = symbol; } else { - nb_re_pusch = rel15_ul->number_rbs * NR_NB_SC_PER_RB; - pilots = 0; + nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; + } + + if ( ((rel15_ul->pdu_bit_map)>>2)& 0x01 ) { // if there is ptrs pdu + ptrs_symbol_flag = is_ptrs_symbol(symbol, + 0, + rel15_ul->rnti, + rel15_ul->rb_size, + rel15_ul->nr_of_symbols, + 0, + (rel15_ul->pusch_ptrs.ptrs_freq_density)?4:2, + gNB->pusch_vars[UE_id]->ptrs_symbols, + 0, + frame_parms->ofdm_symbol_size, + rel15_ul->dmrs_config_type, + rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset); + } + + if (ptrs_symbol_flag == 1){ + gNB->pusch_vars[UE_id]->ptrs_symbol_index = symbol; } - bwp_start_subcarrier = (rel15_ul->start_rb*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; //---------------------------------------------------------- //--------------------- Channel estimation --------------------- //---------------------------------------------------------- - if (pilots == 1) + if (dmrs_symbol_flag == 1) nr_pusch_channel_estimation(gNB, - 0, nr_tti_rx, 0, // p symbol, bwp_start_subcarrier, - rel15_ul->number_rbs); + rel15_ul); //---------------------------------------------------------- //--------------------- RBs extraction --------------------- //---------------------------------------------------------- - + nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF, - gNB->pusch_vars[UE_id]->ul_ch_estimates, - gNB->pusch_vars[UE_id]->rxdataF_ext, - gNB->pusch_vars[UE_id]->ul_ch_estimates_ext, - gNB->pusch_vars[UE_id]->rxdataF_ext_offset, - // rb_alloc, [hna] Resource Allocation Type 1 is assumed only for the moment + gNB->pusch_vars[UE_id], symbol, - rel15_ul->start_rb, - rel15_ul->number_rbs, + dmrs_symbol_flag, + rel15_ul, frame_parms); nr_ulsch_scale_channel(gNB->pusch_vars[UE_id]->ul_ch_estimates_ext, frame_parms, gNB->ulsch[UE_id], symbol, - pilots, - rel15_ul->number_rbs); + dmrs_symbol_flag, + rel15_ul->rb_size, + rel15_ul->dmrs_config_type); + if (first_symbol_flag==1) { - nr_ulsch_channel_level(gNB->pusch_vars[UE_id]->ul_ch_estimates_ext, + nr_ulsch_channel_level(gNB->pusch_vars[UE_id]->ul_ch_estimates_ext, frame_parms, avg, symbol, nb_re_pusch, - rel15_ul->number_rbs); + rel15_ul->rb_size); avgs = 0; for (aatx=0;aatxnb_antennas_tx;aatx++) @@ -1057,28 +1148,28 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, (frame_parms->nb_antennas_tx>1) ? gNB->pusch_vars[UE_id]->rho : NULL, frame_parms, symbol, - pilots, - rel15_ul->Qm, - rel15_ul->number_rbs, + dmrs_symbol_flag, + rel15_ul->qam_mod_order, + rel15_ul->rb_size, gNB->pusch_vars[UE_id]->log2_maxh); #ifdef NR_SC_FDMA - nr_idft(&((uint32_t*)gNB->pusch_vars[UE_id]->rxdataF_ext[0])[symbol * rel15_ul->number_rbs * NR_NB_SC_PER_RB], nb_re_pusch); + nr_idft(&((uint32_t*)gNB->pusch_vars[UE_id]->rxdataF_ext[0])[symbol * rel15_ul->rb_size * NR_NB_SC_PER_RB], nb_re_pusch); #endif //---------------------------------------------------------- //-------------------- LLRs computation -------------------- //---------------------------------------------------------- - - nr_ulsch_compute_llr(&gNB->pusch_vars[UE_id]->rxdataF_comp[0][symbol * rel15_ul->number_rbs * NR_NB_SC_PER_RB], + + nr_ulsch_compute_llr(&gNB->pusch_vars[UE_id]->rxdataF_comp[0][symbol * rel15_ul->rb_size * NR_NB_SC_PER_RB], gNB->pusch_vars[UE_id]->ul_ch_mag0, gNB->pusch_vars[UE_id]->ul_ch_magb0, - &gNB->pusch_vars[UE_id]->llr[gNB->pusch_vars[UE_id]->rxdataF_ext_offset * rel15_ul->Qm], - rel15_ul->number_rbs, + &gNB->pusch_vars[UE_id]->llr[gNB->pusch_vars[UE_id]->rxdataF_ext_offset * rel15_ul->qam_mod_order], + rel15_ul->rb_size, nb_re_pusch, symbol, - rel15_ul->Qm); - - gNB->pusch_vars[UE_id]->rxdataF_ext_offset = gNB->pusch_vars[UE_id]->rxdataF_ext_offset + nb_re_pusch; + rel15_ul->qam_mod_order); + + gNB->pusch_vars[UE_id]->rxdataF_ext_offset = gNB->pusch_vars[UE_id]->rxdataF_ext_offset + nb_re_pusch - gNB->pusch_vars[UE_id]->ptrs_sc_per_ofdm_symbol; } diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 3cd5f251af..bb087aad0d 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -17,14 +17,78 @@ #include "T.h" -#define DEBUG_NR_PUCCH_RX 1 +//#define DEBUG_NR_PUCCH_RX 1 -void nr_decode_pucch0(int32_t **rxdataF, - NR_DL_FRAME_PARMS *frame_parms, +int get_pucch0_cs_lut_index(PHY_VARS_gNB *gNB,nfapi_nr_pucch_pdu_t* pucch_pdu) { + + int i=0; + +#ifdef DEBUG_NR_PUCCH_RX + printf("getting index for LUT with %d entries, Nid %d\n",gNB->pucch0_lut.nb_id, pucch_pdu->hopping_id); +#endif + + for (i=0;ipucch0_lut.nb_id;i++) { + if (gNB->pucch0_lut.Nid[i] == pucch_pdu->hopping_id) break; + } +#ifdef DEBUG_NR_PUCCH_RX + printf("found index %d\n",i); +#endif + if (ipucch0_lut.nb_id) return(i); + +#ifdef DEBUG_NR_PUCCH_RX + printf("Initializing PUCCH0 LUT index %i with Nid %d\n",i, pucch_pdu->hopping_id); +#endif + // initialize + gNB->pucch0_lut.Nid[gNB->pucch0_lut.nb_id]=pucch_pdu->hopping_id; + for (int slot=0;slot<10<subcarrier_spacing;slot++) + for (int symbol=0;symbol<14;symbol++) + gNB->pucch0_lut.lut[gNB->pucch0_lut.nb_id][slot][symbol] = (int)floor(nr_cyclic_shift_hopping(pucch_pdu->hopping_id,0,0,symbol,0,slot)/0.5235987756); + gNB->pucch0_lut.nb_id++; + return(gNB->pucch0_lut.nb_id-1); +} + + + +int16_t idft12_re[12][12] = { + {23170,23170,23170,23170,23170,23170,23170,23170,23170,23170,23170,23170}, + {23170,20066,11585,0,-11585,-20066,-23170,-20066,-11585,0,11585,20066}, + {23170,11585,-11585,-23170,-11585,11585,23170,11585,-11585,-23170,-11585,11585}, + {23170,0,-23170,0,23170,0,-23170,0,23170,0,-23170,0}, + {23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585}, + {23170,-20066,11585,0,-11585,20066,-23170,20066,-11585,0,11585,-20066}, + {23170,-23170,23170,-23170,23170,-23170,23170,-23170,23170,-23170,23170,-23170}, + {23170,-20066,11585,0,-11585,20066,-23170,20066,-11585,0,11585,-20066}, + {23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585,23170,-11585,-11585}, + {23170,0,-23170,0,23170,0,-23170,0,23170,0,-23170,0}, + {23170,11585,-11585,-23170,-11585,11585,23170,11585,-11585,-23170,-11585,11585}, + {23170,20066,11585,0,-11585,-20066,-23170,-20066,-11585,0,11585,20066} +}; + +int16_t idft12_im[12][12] = { + {0,0,0,0,0,0,0,0,0,0,0,0}, + {0,11585,20066,23170,20066,11585,0,-11585,-20066,-23170,-20066,-11585}, + {0,20066,20066,0,-20066,-20066,0,20066,20066,0,-20066,-20066}, + {0,23170,0,-23170,0,23170,0,-23170,0,23170,0,-23170}, + {0,20066,-20066,0,20066,-20066,0,20066,-20066,0,20066,-20066}, + {0,11585,-20066,23170,-20066,11585,0,-11585,20066,-23170,20066,-11585}, + {0,0,0,0,0,0,0,0,0,0,0,0}, + {0,-11585,20066,-23170,20066,-11585,0,11585,-20066,23170,-20066,11585}, + {0,-20066,20066,0,-20066,20066,0,-20066,20066,0,-20066,20066}, + {0,-23170,0,23170,0,-23170,0,23170,0,-23170,0,23170}, + {0,-20066,-20066,0,20066,20066,0,-20066,-20066,0,20066,20066}, + {0,-11585,-20066,-23170,-20066,-11585,0,11585,20066,23170,20066,11585} +}; + + +void nr_decode_pucch0(PHY_VARS_gNB *gNB, int slot, nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu, nfapi_nr_pucch_pdu_t* pucch_pdu) { + + int32_t **rxdataF = gNB->common_vars.rxdataF; + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + int nr_sequences; const uint8_t *mcs; @@ -38,6 +102,8 @@ void nr_decode_pucch0(int32_t **rxdataF, mcs=table2_mcs; nr_sequences=8>>(1-pucch_pdu->sr_flag); } + + int cs_ind = get_pucch0_cs_lut_index(gNB,pucch_pdu); /* * Implement TS 38.211 Subclause 6.3.2.3.1 Sequence generation * @@ -72,17 +138,25 @@ void nr_decode_pucch0(int32_t **rxdataF, uint8_t n_hop = 0; // Frequnecy hopping not implemented FIXME!! // x_n contains the sequence r_u_v_alpha_delta(n) - int16_t x_n_re[nr_sequences][24],x_n_im[nr_sequences][24]; + int n,i,l; + nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,n_hop,slot,&u,&v); // calculating u and v value + + uint32_t re_offset=0; + uint8_t l2; + +#ifdef OLD_IMPL + int16_t x_n_re[nr_sequences][24],x_n_im[nr_sequences][24]; + for(i=0;inr_of_symbols; l++){ - - nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,n_hop,slot,&u,&v); // calculating u and v value alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id,pucch_pdu->initial_cyclic_shift,mcs[i],l,pucch_pdu->start_symbol_index,slot); #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d/%d,mcs %d)\n",u,v,alpha,l,l+pucch_pdu->start_symbol_index,mcs[i]); + printf("lut output %d\n",gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index]); #endif + alpha=0.0; for (n=0; n<12; n++){ x_n_re[i][(12*l)+n] = (int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)))); // Re part of base sequence shifted by alpha @@ -100,10 +174,7 @@ void nr_decode_pucch0(int32_t **rxdataF, /* * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources */ - uint32_t re_offset=0; - uint8_t l2; -#ifdef OLD_IMPL int16_t r_re[24],r_im[24]; for (l=0; lnr_of_symbols; l++) { @@ -151,14 +222,14 @@ void nr_decode_pucch0(int32_t **rxdataF, } #else - int16_t *x_re = x_n_re[0],*x_im = x_n_im[0]; - int16_t xr[32] __attribute__((aligned(32))); - int16_t xrt[32] __attribute__((aligned(32))); + int16_t *x_re = table_5_2_2_2_2_Re[u],*x_im = table_5_2_2_2_2_Im[u]; + int16_t xr[24] __attribute__((aligned(32))); + int16_t xrt[24] __attribute__((aligned(32))); int32_t xrtmag=0; int maxpos=0; int n2=0; uint8_t index=0; - memset((void*)xr,0,32*sizeof(int16_t)); + memset((void*)xr,0,24*sizeof(int16_t)); for (l=0; lnr_of_symbols; l++) { @@ -169,34 +240,47 @@ void nr_decode_pucch0(int32_t **rxdataF, AssertFatal(re_offset+12 < frame_parms->ofdm_symbol_size,"pucch straddles DC carrier, handle this!\n"); - n2=0; int16_t *r=(int16_t*)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size+re_offset)]; - if (l==0) for (n=0;n<12;n++,n2+=2) { - xr[n2] =((int32_t)x_re[n]*r[n2]+(int32_t)x_im[n]*r[n2+1])>>15; - xr[n2+1]=((int32_t)x_re[n]*r[n2+1]-(int32_t)x_im[n]*r[n2])>>15; - printf("x (%d,%d), r (%d,%d), xr (%d,%d)\n", - x_re[n],x_im[n],r[n2],r[n2+1],xr[n2],xr[n2+1]); - } - else for (n=0;n<12;n++,n2+=2) { - xr[n2] +=((int32_t)x_re[n]*r[n2]+(int32_t)x_im[n]*r[n2+1])>>15; - xr[n2+1]+=((int32_t)x_re[n]*r[n2+1]-(int32_t)x_im[n]*r[n2])>>15; - } - x_re+=12; - x_im+=12; - } - idft16f(xr,xrt); - n2=0; - int32_t temp; - for (n=0;n<16;n++,n2+=2) { + for (n=0;n<12;n++,n2+=2) { + xr[n2] =(int16_t)(((int32_t)x_re[n]*r[n2]+(int32_t)x_im[n]*r[n2+1])>>15); + xr[n2+1]=(int16_t)(((int32_t)x_re[n]*r[n2+1]-(int32_t)x_im[n]*r[n2])>>15); #ifdef DEBUG_NR_PUCCH_RX - printf("PUCCH IDFT[%d] = (%d,%d)\n",n,xrt[n2],xrt[n2+1]); + printf("x (%d,%d), r (%d,%d), xr (%d,%d)\n", + x_re[n],x_im[n],r[n2],r[n2+1],xr[n2],xr[n2+1]); #endif - if ((temp=(int32_t)xrt[n2]*xrt[n2]+(int32_t)xrt[n2+1]*xrt[n2+1])nr_of_symbols;l++) { + + seq_index = (pucch_pdu->initial_cyclic_shift+ + mcs[i]+ + gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index])%12; + for (n=0;n<12;n++,n2+=2) { + corr_re+=(xr[n2]*idft12_re[seq_index][n]+xr[n2+1]*idft12_im[seq_index][n])>>15; + corr_im+=(xr[n2]*idft12_im[seq_index][n]-xr[n2+1]*idft12_re[seq_index][n])>>15; + } + } + +#ifdef DEBUG_NR_PUCCH_RX + printf("PUCCH IDFT[%d/%d] = (%d,%d)=>%f\n",mcs[i],seq_index,corr_re,corr_im,10*log10(corr_re*corr_re + corr_im*corr_im)); +#endif + if ((temp=corr_re*corr_re + corr_im*corr_im)>xrtmag) { + xrtmag=temp; + maxpos=i; + } + } + +#ifdef DEBUG_NR_PUCCH_RX + printf("PUCCH 0 : maxpos %d\n",maxpos); +#endif + + index=maxpos; #endif // first bit of bitmap for sr presence and second bit for acknack presence uci_pdu->pdu_bit_map = pucch_pdu->sr_flag | ((pucch_pdu->bit_len_harq>0)<<1); diff --git a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c index eeee55ea3f..dec3d7cc2d 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c +++ b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c @@ -173,3 +173,15 @@ short filt8_dcl1_h[8]= { short filt8_dcr1_h[8]= { 0,0,4096,8192,12288,16384,0,0}; + +short filt8_ml2[8] = { +13107,9830,6554,3277,0,0,0,0}; + +short filt8_mr2[8] = { +3277,6554,9830,13107,0,0,0,0}; + +short filt8_rr1[8] = { +8192,12288,16384,20480,0,0,0,0}; + +short filt8_rr2[8] = { +-4096,-8192,-12288,-16384,0,0,0,0}; diff --git a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.h b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.h index f64aebeb52..e350985b0a 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.h +++ b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.h @@ -124,4 +124,13 @@ extern short filt8_dcr1[8]; extern short filt8_dcl1_h[8]; extern short filt8_dcr1_h[8]; -#endif + +extern short filt8_ml2[8]; + +extern short filt8_mr2[8]; + +extern short filt8_rr1[8]; + +extern short filt8_rr2[8]; + +#endif \ No newline at end of file diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index e2ae032d15..af06f9a98f 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -90,7 +90,6 @@ void phy_adjust_gain_nr(PHY_VARS_NR_UE *ue, uint32_t rx_power_fil_dB, uint8_t eNB_id); -int16_t get_nr_PL(PHY_VARS_NR_UE *ue, - uint8_t gNB_index); +int16_t get_nr_PL(PHY_VARS_NR_UE *ue,uint8_t gNB_index); #endif diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 90c221931f..aa1e2b5ade 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -20,20 +20,177 @@ */ #include "PHY/defs_nr_UE.h" +#include "PHY/phy_extern_nr_ue.h" +#include "common/utils/LOG/log.h" +#include "PHY/sse_intrin.h" + +//#define k1 1000 +#define k1 ((long long int) 1000) +#define k2 ((long long int) (1024-k1)) + +//#define DEBUG_MEAS_RRC +//#define DEBUG_MEAS_UE +//#define DEBUG_RANK_EST + +#if 0 +int16_t cond_num_threshold = 0; + +void print_shorts(char *s,short *x) +{ + + + printf("%s : %d,%d,%d,%d,%d,%d,%d,%d\n",s, + x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7] + ); + +} +void print_ints(char *s,int *x) +{ + + + printf("%s : %d,%d,%d,%d\n",s, + x[0],x[1],x[2],x[3] + ); + +} +#endif int16_t get_nr_PL(PHY_VARS_NR_UE *ue,uint8_t gNB_index) { + /* + if (ue->frame_parms.mode1_flag == 1) + RSoffset = 6; + else + RSoffset = 3; + */ + /* LOG_D(PHY,"get_nr_PL : rsrp %f dBm/RE (%f), eNB power %d dBm/RE\n", + (1.0*dB_fixed_times10(ue->measurements.rsrp[eNB_index])-(10.0*ue->rx_total_gain_dB))/10.0, + 10*log10((double)ue->measurements.rsrp[eNB_index]), + ue->frame_parms.pdsch_config_common.referenceSignalPower);*/ - LOG_D(PHY,"get_PL : rsrp %f dBm/RE (%f), eNB power %d dBm/RE\n", - (1.0*dB_fixed_times10(ue->measurements.rsrp[gNB_index])-(10.0*ue->rx_total_gain_dB))/10.0, - 10*log10((double)ue->measurements.rsrp[gNB_index]), - ue->frame_parms.ss_PBCH_BlockPower); - - return((int16_t)(((10*ue->rx_total_gain_dB) - - dB_fixed_times10(ue->measurements.rsrp[gNB_index])+ + return((int16_t)(((10*ue->rx_total_gain_dB) - dB_fixed_times10(ue->measurements.rsrp[gNB_index]))/10)); // dB_fixed_times10(RSoffset*12*ue_g[Mod_id][CC_id]->frame_parms.N_RB_DL) + - (ue->frame_parms.ss_PBCH_BlockPower*10))/10)); + //(ue->frame_parms.pdsch_config_common.referenceSignalPower*10))/10)); } + + + +void nr_ue_measurements(PHY_VARS_NR_UE *ue, + unsigned int subframe_offset, + unsigned char N0_symbol, + unsigned char abstraction_flag, + unsigned char rank_adaptation, + uint8_t subframe) +{ + int aarx,aatx,eNB_id=0; //,gain_offset=0; + //int rx_power[NUMBER_OF_CONNECTED_eNB_MAX]; + +/*#if defined(__x86_64__) || defined(__i386__) + __m128i *dl_ch0_128, *dl_ch1_128; +#elif defined(__arm__) + int16x8_t *dl_ch0_128, *dl_ch1_128get_PL; +#endif*/ + + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + //unsigned int limit, subband; + //int nb_subbands, subband_size, last_subband_size, *dl_ch0, *dl_ch1, N_RB_DL = frame_parms->N_RB_DL; + + int ch_offset, rank_tm3_tm4 = 0; + + ue->measurements.nb_antennas_rx = frame_parms->nb_antennas_rx; + + /*int16_t *dl_ch; + dl_ch = (int16_t *)&ue->pdsch_vars[ue->current_thread_id[subframe]][0]->dl_ch_estimates[eNB_id][ch_offset];*/ + + ch_offset = ue->frame_parms.ofdm_symbol_size*2; + +//printf("testing measurements\n"); + // signal measurements + + for (eNB_id=0; eNB_idn_connected_eNB; eNB_id++) { + for (aarx=0; aarxnb_antennas_rx; aarx++) { + for (aatx=0; aatxnb_antenna_ports_gNB; aatx++) { + ue->measurements.rx_spatial_power[eNB_id][aatx][aarx] = + (signal_energy_nodc(&ue->pdsch_vars[ue->current_thread_id[subframe]][0]->dl_ch_estimates[eNB_id][ch_offset], + (50*12))); + //- ue->measurements.n0_power[aarx]; + + if (ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]<0) + ue->measurements.rx_spatial_power[eNB_id][aatx][aarx] = 0; //ue->measurements.n0_power[aarx]; + + ue->measurements.rx_spatial_power_dB[eNB_id][aatx][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]); + + if (aatx==0) + ue->measurements.rx_power[eNB_id][aarx] = ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]; + else + ue->measurements.rx_power[eNB_id][aarx] += ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]; + } //aatx + + ue->measurements.rx_power_dB[eNB_id][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_power[eNB_id][aarx]); + + if (aarx==0) + ue->measurements.rx_power_tot[eNB_id] = ue->measurements.rx_power[eNB_id][aarx]; + else + ue->measurements.rx_power_tot[eNB_id] += ue->measurements.rx_power[eNB_id][aarx]; + } //aarx + + ue->measurements.rx_power_tot_dB[eNB_id] = (unsigned short) dB_fixed(ue->measurements.rx_power_tot[eNB_id]); + + } //eNB_id + + //printf("ue measurement addr dlch %p\n", dl_ch); + + eNB_id=0; + + if (ue->transmission_mode[eNB_id]!=4 && ue->transmission_mode[eNB_id]!=3) + ue->measurements.rank[eNB_id] = 0; + else + ue->measurements.rank[eNB_id] = rank_tm3_tm4; + // printf ("tx mode %d\n", ue->transmission_mode[eNB_id]); + // printf ("rank %d\n", ue->PHY_measurements.rank[eNB_id]); + + // filter to remove jitter + if (ue->init_averaging == 0) { + for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) + ue->measurements.rx_power_avg[eNB_id] = (int) + (((k1*((long long int)(ue->measurements.rx_power_avg[eNB_id]))) + + (k2*((long long int)(ue->measurements.rx_power_tot[eNB_id]))))>>10); + + //LOG_I(PHY,"Noise Power Computation: k1 %d k2 %d n0 avg %d n0 tot %d\n", k1, k2, ue->measurements.n0_power_avg, + // ue->measurements.n0_power_tot); + ue->measurements.n0_power_avg = (int) + (((k1*((long long int) (ue->measurements.n0_power_avg))) + + (k2*((long long int) (ue->measurements.n0_power_tot))))>>10); + } else { + for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) + ue->measurements.rx_power_avg[eNB_id] = ue->measurements.rx_power_tot[eNB_id]; + + ue->measurements.n0_power_avg = ue->measurements.n0_power_tot; + ue->init_averaging = 0; + } + + for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) { + ue->measurements.rx_power_avg_dB[eNB_id] = dB_fixed( ue->measurements.rx_power_avg[eNB_id]); + ue->measurements.wideband_cqi_tot[eNB_id] = dB_fixed2(ue->measurements.rx_power_tot[eNB_id],ue->measurements.n0_power_tot); + ue->measurements.wideband_cqi_avg[eNB_id] = dB_fixed2(ue->measurements.rx_power_avg[eNB_id],ue->measurements.n0_power_avg); + ue->measurements.rx_rssi_dBm[eNB_id] = ue->measurements.rx_power_avg_dB[eNB_id] - ue->rx_total_gain_dB; +//#ifdef DEBUG_MEAS_UE + LOG_D(PHY,"[eNB %d] Subframe %d, RSSI %d dBm, RSSI (digital) %d dB, WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n", + eNB_id, + subframe, + ue->measurements.rx_rssi_dBm[eNB_id], + ue->measurements.rx_power_avg_dB[eNB_id], + ue->measurements.wideband_cqi_avg[eNB_id], + ue->measurements.rx_power_avg[eNB_id], + ue->measurements.n0_power_tot); +//#endif + } + +#if defined(__x86_64__) || defined(__i386__) + _mm_empty(); + _m_empty(); +#endif +} \ No newline at end of file diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 1a1979b3df..ef22b61260 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -150,7 +150,7 @@ void nr_pdcch_demapping_deinterleaving(uint32_t *llr, for (int i=0; i<9; i++) { z[index_z + i] = llr[index_llr + i]; - LOG_DDD("[reg=%d,bundle_j=%d] z[%d]=(%d,%d) <-> \t[f_reg=%d,fbundle_j=%d] llr[%d]=(%d,%d) \n", + LOG_D(PHY,"[reg=%d,bundle_j=%d] z[%d]=(%d,%d) <-> \t[f_reg=%d,fbundle_j=%d] llr[%d]=(%d,%d) \n", reg,bundle_j,(index_z + i),*(int16_t *) &z[index_z + i],*(1 + (int16_t *) &z[index_z + i]), f_reg,f_bundle_j,(index_llr + i),*(int16_t *) &llr[index_llr + i], *(1 + (int16_t *) &llr[index_llr + i])); } @@ -195,7 +195,7 @@ int32_t nr_pdcch_llr(NR_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, #endif - +#if 0 int32_t pdcch_llr(NR_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, char *pdcch_llr, @@ -227,11 +227,12 @@ int32_t pdcch_llr(NR_DL_FRAME_PARMS *frame_parms, return(0); } +#endif //__m128i avg128P; //compute average channel_level on each (TX,RX) antenna pair -void pdcch_channel_level(int32_t **dl_ch_estimates_ext, +void nr_pdcch_channel_level(int32_t **dl_ch_estimates_ext, NR_DL_FRAME_PARMS *frame_parms, int32_t *avg, uint8_t nb_rb) { @@ -324,10 +325,8 @@ void nr_pdcch_extract_rbs_single(int32_t **rxdataF, // after removing the 3 DMRS RE, the RB contains 9 RE with PDCCH #define NBR_RE_PER_RB_WITHOUT_DMRS 9 uint16_t c_rb, nb_rb = 0; - // this variable will be incremented by 1 each time a bit set to '0' is found in coreset_freq_dom bitmap - uint16_t offset_discontiguous=0; //uint8_t rb_count_bit; - uint8_t i, j, aarx, bitcnt_coreset_freq_dom=0; + uint8_t i, j, aarx; int32_t *dl_ch0, *dl_ch0_ext, *rxF, *rxF_ext; #ifdef DEBUG_DCI_DECODING @@ -608,7 +607,7 @@ void nr_pdcch_channel_compensation(int32_t **rxdataF_ext, } -void pdcch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, +void nr_pdcch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, uint8_t symbol) { #if defined(__x86_64__) || defined(__i386__) @@ -643,6 +642,7 @@ void pdcch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, #endif } +#if 0 void pdcch_siso(NR_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, uint8_t l) { @@ -657,11 +657,7 @@ void pdcch_siso(NR_DL_FRAME_PARMS *frame_parms, } } } - - - - - +#endif #ifdef NR_PDCCH_DCI_RUN int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, @@ -681,10 +677,9 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, rel15 = &pdcch_vars->pdcch_config[i]; int n_rb,rb_offset; get_coreset_rballoc(rel15->coreset.frequency_domain_resource,&n_rb,&rb_offset); - for (int s=rel15->coreset.StartSymbolIndex; - s<(rel15->coreset.StartSymbolIndex+rel15->coreset.duration); - s++) { - + for (int s=rel15->coreset.StartSymbolIndex; s<(rel15->coreset.StartSymbolIndex+rel15->coreset.duration); s++) { + LOG_D(PHY,"in nr_pdcch_extract_rbs_single(rxdataF -> rxdataF_ext || dl_ch_estimates -> dl_ch_estimates_ext)\n"); + nr_pdcch_extract_rbs_single(common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[slot]].rxdataF, pdcch_vars->dl_ch_estimates, pdcch_vars->rxdataF_ext, @@ -695,17 +690,17 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, n_rb, rel15->BWPStart); - LOG_DD("we enter pdcch_channel_level(avgP=%d) => compute channel level based on ofdm symbol 0, pdcch_vars[eNB_id]->dl_ch_estimates_ext\n",*avgP); - LOG_DD("in pdcch_channel_level(dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); + LOG_D(PHY,"we enter nr_pdcch_channel_level(avgP=%d) => compute channel level based on ofdm symbol 0, pdcch_vars[eNB_id]->dl_ch_estimates_ext\n",*avgP); + LOG_D(PHY,"in nr_pdcch_channel_level(dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); // compute channel level based on ofdm symbol 0 - pdcch_channel_level(pdcch_vars->dl_ch_estimates_ext, - frame_parms, - avgP, - n_rb); + nr_pdcch_channel_level(pdcch_vars->dl_ch_estimates_ext, + frame_parms, + avgP, + n_rb); avgs = 0; - + for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) - avgs = cmax(avgs, avgP[aarx]); + avgs = cmax(avgs, avgP[aarx]); log2_maxh = (log2_approx(avgs) / 2) + 5; //+frame_parms->nb_antennas_rx; #ifdef UE_DEBUG_TRACE @@ -713,27 +708,26 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, #endif #if T_TRACER T(T_UE_PHY_PDCCH_ENERGY, T_INT(0), T_INT(0), T_INT(frame%1024), T_INT(slot), - T_INT(avgP[0]), T_INT(avgP[1]), T_INT(avgP[2]), T_INT(avgP[3])); + T_INT(avgP[0]), T_INT(avgP[1]), T_INT(avgP[2]), T_INT(avgP[3])); #endif - LOG_DD("we enter nr_pdcch_channel_compensation(log2_maxh=%d)\n",log2_maxh); - LOG_DD("in nr_pdcch_channel_compensation(rxdataF_ext x dl_ch_estimates_ext -> rxdataF_comp)\n"); + LOG_D(PHY,"we enter nr_pdcch_channel_compensation(log2_maxh=%d)\n",log2_maxh); + LOG_D(PHY,"in nr_pdcch_channel_compensation(rxdataF_ext x dl_ch_estimates_ext -> rxdataF_comp)\n"); // compute LLRs for ofdm symbol 0 only nr_pdcch_channel_compensation(pdcch_vars->rxdataF_ext, - pdcch_vars->dl_ch_estimates_ext, - pdcch_vars->rxdataF_comp, - NULL, - frame_parms, - s, - log2_maxh, - n_rb); // log2_maxh+I0_shift + pdcch_vars->dl_ch_estimates_ext, + pdcch_vars->rxdataF_comp, + NULL, + frame_parms, + s, + log2_maxh, + n_rb); // log2_maxh+I0_shift if (frame_parms->nb_antennas_rx > 1) { - LOG_DD("we enter pdcch_detection_mrc(frame_parms->nb_antennas_rx=%d)\n", - frame_parms->nb_antennas_rx); - pdcch_detection_mrc(frame_parms, pdcch_vars->rxdataF_comp,s); + LOG_D(PHY,"we enter nr_pdcch_detection_mrc(frame_parms->nb_antennas_rx=%d)\n", frame_parms->nb_antennas_rx); + nr_pdcch_detection_mrc(frame_parms, pdcch_vars->rxdataF_comp,s); } - LOG_DD("we enter nr_pdcch_llr(for symbol %d), pdcch_vars[eNB_id]->rxdataF_comp ---> pdcch_vars[eNB_id]->llr \n",s); - LOG_DD("in nr_pdcch_llr(rxdataF_comp -> llr)\n"); + LOG_D(PHY,"we enter nr_pdcch_llr(for symbol %d), pdcch_vars[eNB_id]->rxdataF_comp ---> pdcch_vars[eNB_id]->llr \n",s); + LOG_D(PHY,"in nr_pdcch_llr(rxdataF_comp -> llr)\n"); nr_pdcch_llr(frame_parms, pdcch_vars->rxdataF_comp, pdcch_vars->llr, @@ -751,7 +745,7 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, #endif } - LOG_DD("we enter nr_pdcch_demapping_deinterleaving()\n"); + LOG_D(PHY,"we enter nr_pdcch_demapping_deinterleaving()\n"); nr_pdcch_demapping_deinterleaving((uint32_t *) pdcch_vars->llr, (uint32_t *) pdcch_vars->e_rx, frame_parms, @@ -760,6 +754,7 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, rel15->coreset.RegBundleSize, rel15->coreset.InterleaverSize, rel15->coreset.ShiftIndex); + /* nr_pdcch_unscrambling(rel15->rnti, frame_parms, slot, @@ -767,207 +762,16 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, rel15->coreset.duration*n_rb*9*2, // get_nCCE(n_pdcch_symbols, frame_parms, mi) * 72, rel15->coreset.pdcch_dmrs_scrambling_id); - LOG_DD("we end nr_pdcch_unscrambling()\n"); - LOG_DD("Ending nr_rx_pdcch() function\n"); + */ + LOG_D(PHY,"we end nr_pdcch_unscrambling()\n"); + LOG_D(PHY,"Ending nr_rx_pdcch() function\n"); } return (0); } - /* -int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, - uint32_t frame, - uint8_t nr_tti_rx, - uint8_t eNB_id, - MIMO_mode_t mimo_mode, - uint32_t high_speed_flag, - uint8_t is_secondary_ue, - int nb_coreset_active, - uint16_t symbol_mon, - NR_SEARCHSPACE_TYPE_t searchSpaceType) { - NR_UE_COMMON *common_vars = &ue->common_vars; - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - NR_UE_PDCCH **pdcch_vars = ue->pdcch_vars[ue->current_thread_id[nr_tti_rx]]; - NR_UE_PDCCH *pdcch_vars2 = ue->pdcch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id]; - int do_common; - - if (searchSpaceType == common) do_common=1; - - if (searchSpaceType == ue_specific) do_common=0; - - uint8_t log2_maxh, aarx; - int32_t avgs; - int32_t avgP[4]; - // number of RB (1 symbol) or REG (12 RE) in one CORESET: higher-layer parameter CORESET-freq-dom - // (bit map 45 bits: each bit indicates 6 RB in CORESET -> 1 bit MSB indicates PRB 0..6 are part of CORESET) - uint64_t coreset_freq_dom = pdcch_vars2->coreset[nb_coreset_active].frequencyDomainResources; - // number of symbols in CORESET: higher-layer parameter CORESET-time-dur {1,2,3} - int coreset_time_dur = pdcch_vars2->coreset[nb_coreset_active].duration; - // depends on higher-layer parameter CORESET-shift-index {0,1,...,274} - int n_shift = pdcch_vars2->coreset[nb_coreset_active].cce_reg_mappingType.shiftIndex; - // higher-layer parameter CORESET-REG-bundle-size (for non-interleaved L = 6 / for interleaved L {2,6}) - NR_UE_CORESET_REG_bundlesize_t reg_bundle_size_L = pdcch_vars2->coreset[nb_coreset_active].cce_reg_mappingType.reg_bundlesize; - // higher-layer parameter CORESET-interleaver-size {2,3,6} - NR_UE_CORESET_interleaversize_t coreset_interleaver_size_R= pdcch_vars2->coreset[nb_coreset_active].cce_reg_mappingType.interleaversize; - //NR_UE_CORESET_precoder_granularity_t precoder_granularity = pdcch_vars2->coreset[nb_coreset_active].precoderGranularity; - //int tci_statesPDCCH = pdcch_vars2->coreset[nb_coreset_active].tciStatesPDCCH; - //int tci_present = pdcch_vars2->coreset[nb_coreset_active].tciPresentInDCI; - uint16_t pdcch_DMRS_scrambling_id = pdcch_vars2->coreset[nb_coreset_active].pdcchDMRSScramblingID; - // The UE can be assigned 4 different BWP but only one active at a time. - // For each BWP the number of CORESETs is limited to 3 (including initial CORESET Id=0 -> ControlResourceSetId (0..maxNrofControlReourceSets-1) (0..12-1) - //uint32_t n_BWP_start = 0; - //uint32_t n_rb_offset = 0; - uint32_t n_rb_offset = pdcch_vars2->coreset[nb_coreset_active].rb_offset;//+(int)floor(frame_parms->ssb_start_subcarrier/NR_NB_SC_PER_RB); - // start time position for CORESET - // parameter symbol_mon is a 14 bits bitmap indicating monitoring symbols within a slot - uint8_t start_symbol = 0; - - // at the moment we are considering that the PDCCH is always starting at symbol 0 of current slot - // the following code to initialize start_symbol must be activated once we implement PDCCH demapping on symbol not equal to 0 (considering symbol_mon) - for (int i=0; i < 14; i++) { - if (((symbol_mon >> (i+1))&0x1) != 0) { - start_symbol = i; - i=14; - } - } - - LOG_DD("symbol_mon=(%u) and start_symbol=(%u)\n",symbol_mon,start_symbol); - LOG_DD("coreset_freq_dom=(%lu) n_rb_offset=(%u) coreset_time_dur=(%d) n_shift=(%d) reg_bundle_size_L=(%d) coreset_interleaver_size_R=(%d) scrambling_ID=(%d) \n", - coreset_freq_dom,n_rb_offset,coreset_time_dur,n_shift,reg_bundle_size_L,coreset_interleaver_size_R,pdcch_DMRS_scrambling_id); - // - // according to 38.213 v15.1.0: a PDCCH monitoring pattern within a slot, - // indicating first symbol(s) of the control resource set within a slot - // for PDCCH monitoring, by higher layer parameter monitoringSymbolsWithinSlot - // - // at the moment we do not implement this and start_symbol is always 0 - // note that the bitmap symbol_mon may indicate several monitoring times within a same slot (symbols 0..13) - // this may lead to a modification in ue scheduler - // indicates the number of active CORESETs for the current BWP to decode PDCCH: max is 3 (this variable is not useful here, to be removed) - //uint8_t coreset_nbr_act; - // indicates the number of REG contained in the PDCCH (number of RBs * number of symbols, in CORESET) - uint32_t coreset_nbr_rb = 0; - // for (int j=0; j < coreset_nbr_act; j++) { - // for each active CORESET (max number of active CORESETs in a BWP is 3), - // we calculate the number of RB for each CORESET bitmap - LOG_DD("coreset_freq_dom=(%lu)\n",coreset_freq_dom); - int i; //for each bit in the coreset_freq_dom bitmap - - for (i = 0; i < 45; i++) { - // this loop counts each bit of the bit map coreset_freq_dom, and increments nbr_RB_coreset for each bit set to '1' - if (((coreset_freq_dom & 0x1FFFFFFFFFFF) >> i) & 0x1) coreset_nbr_rb++; - } - - coreset_nbr_rb = 6 * coreset_nbr_rb; // coreset_nbr_rb has to be multiplied by 6 to indicate the number of PRB or REG(=12 RE) within the CORESET - LOG_DD("coreset_freq_dom=(%lu,%lx), coreset_nbr_rb=%u\n", coreset_freq_dom,coreset_freq_dom,coreset_nbr_rb); - LOG_DD("coreset_nbr_rb=%u, coreset_nbr_reg=%u, coreset_C=(%u/(%d*%d))=%u\n", - coreset_nbr_rb, - coreset_time_dur * coreset_nbr_rb, - coreset_time_dur * coreset_nbr_rb, - reg_bundle_size_L,coreset_interleaver_size_R, - (uint32_t)((coreset_time_dur * coreset_nbr_rb) / (reg_bundle_size_L * coreset_interleaver_size_R)) ); - - for (int s = start_symbol; s < (start_symbol + coreset_time_dur); s++) { - LOG_DD("we enter nr_pdcch_extract_rbs_single(is_secondary_ue=%d) to remove DM-RS PDCCH\n", - is_secondary_ue); - LOG_DD("in nr_pdcch_extract_rbs_single(rxdataF -> rxdataF_ext || dl_ch_estimates -> dl_ch_estimates_ext)\n"); - nr_pdcch_extract_rbs_single(common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[nr_tti_rx]].rxdataF, - pdcch_vars[eNB_id]->dl_ch_estimates, - pdcch_vars[eNB_id]->rxdataF_ext, - pdcch_vars[eNB_id]->dl_ch_estimates_ext, - s, - high_speed_flag, - frame_parms, - coreset_freq_dom, - coreset_nbr_rb, - n_rb_offset); - LOG_DD("we enter pdcch_channel_level(avgP=%d) => compute channel level based on ofdm symbol 0, pdcch_vars[eNB_id]->dl_ch_estimates_ext\n",*avgP); - LOG_DD("in pdcch_channel_level(dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); - // compute channel level based on ofdm symbol 0 - pdcch_channel_level(pdcch_vars[eNB_id]->dl_ch_estimates_ext, - frame_parms, - avgP, - coreset_nbr_rb); - avgs = 0; - - for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) - avgs = cmax(avgs, avgP[aarx]); - - log2_maxh = (log2_approx(avgs) / 2) + 5; //+frame_parms->nb_antennas_rx; -#ifdef UE_DEBUG_TRACE - LOG_D(PHY,"nr_tti_rx %d: pdcch log2_maxh = %d (%d,%d)\n",nr_tti_rx,log2_maxh,avgP[0],avgs); -#endif -#if T_TRACER - T(T_UE_PHY_PDCCH_ENERGY, T_INT(eNB_id), T_INT(0), T_INT(frame%1024), T_INT(nr_tti_rx), - T_INT(avgP[0]), T_INT(avgP[1]), T_INT(avgP[2]), T_INT(avgP[3])); -#endif - LOG_DD("we enter nr_pdcch_channel_compensation(log2_maxh=%d)\n",log2_maxh); - LOG_DD("in nr_pdcch_channel_compensation(rxdataF_ext x dl_ch_estimates_ext -> rxdataF_comp)\n"); - // compute LLRs for ofdm symbol 0 only - nr_pdcch_channel_compensation(pdcch_vars[eNB_id]->rxdataF_ext, - pdcch_vars[eNB_id]->dl_ch_estimates_ext, - pdcch_vars[eNB_id]->rxdataF_comp, - NULL, - frame_parms, - s, - log2_maxh, - coreset_nbr_rb); // log2_maxh+I0_shift -#ifdef DEBUG_PHY - - if (nr_tti_rx==5) - write_output("rxF_comp_d.m","rxF_c_d",&pdcch_vars[eNB_id]->rxdataF_comp[0][s*frame_parms->N_RB_DL*12],frame_parms->N_RB_DL*12,1,1); #endif - if (frame_parms->nb_antennas_rx > 1) { - LOG_DD("we enter pdcch_detection_mrc(frame_parms->nb_antennas_rx=%d)\n", - frame_parms->nb_antennas_rx); - pdcch_detection_mrc(frame_parms, pdcch_vars[eNB_id]->rxdataF_comp,s); - } - - LOG_DD("we enter nr_pdcch_llr(for symbol %d), pdcch_vars[eNB_id]->rxdataF_comp ---> pdcch_vars[eNB_id]->llr \n",s); - LOG_DD("in nr_pdcch_llr(rxdataF_comp -> llr)\n"); - nr_pdcch_llr(frame_parms, - pdcch_vars[eNB_id]->rxdataF_comp, - pdcch_vars[eNB_id]->llr, - s, - coreset_nbr_rb); -#if T_TRACER - - // T(T_UE_PHY_PDCCH_IQ, T_INT(frame_parms->N_RB_DL), T_INT(frame_parms->N_RB_DL), - // T_INT(n_pdcch_symbols), - // T_BUFFER(pdcch_vars[eNB_id]->rxdataF_comp, frame_parms->N_RB_DL*12*n_pdcch_symbols* 4)); - -#endif -#ifdef DEBUG_DCI_DECODING - printf("demapping: nr_tti_rx %d, mi %d\n",nr_tti_rx,get_mi(frame_parms,nr_tti_rx)); -#endif - } - - LOG_DD("we enter nr_pdcch_demapping_deinterleaving()\n"); - nr_pdcch_demapping_deinterleaving((uint32_t *) pdcch_vars[eNB_id]->llr, - (uint32_t *) pdcch_vars[eNB_id]->e_rx, - frame_parms, - coreset_time_dur, - coreset_nbr_rb, - reg_bundle_size_L, - coreset_interleaver_size_R, - n_shift); - nr_pdcch_unscrambling(pdcch_vars[eNB_id]->crnti, - frame_parms, - nr_tti_rx, - pdcch_vars[eNB_id]->e_rx, - coreset_time_dur*coreset_nbr_rb*9*2, - // get_nCCE(n_pdcch_symbols, frame_parms, mi) * 72, - pdcch_DMRS_scrambling_id, - do_common); - LOG_DD("we end nr_pdcch_unscrambling()\n"); - LOG_DD("Ending nr_rx_pdcch() function\n"); - return (0); -} - */ -#endif - - - void pdcch_scrambling(NR_DL_FRAME_PARMS *frame_parms, uint8_t nr_tti_rx, uint8_t *e, @@ -996,7 +800,7 @@ void pdcch_scrambling(NR_DL_FRAME_PARMS *frame_parms, #ifdef NR_PDCCH_DCI_RUN void nr_pdcch_unscrambling(uint16_t crnti, NR_DL_FRAME_PARMS *frame_parms, uint8_t slot, - int16_t *z, uint32_t length, uint16_t pdcch_DMRS_scrambling_id) { + int16_t *z, int16_t *z2,uint32_t length, uint16_t pdcch_DMRS_scrambling_id) { int i; uint8_t reset; uint32_t x1, x2, s = 0; @@ -1016,7 +820,8 @@ void nr_pdcch_unscrambling(uint16_t crnti, NR_DL_FRAME_PARMS *frame_parms, uint8 reset = 0; } - if (((s >> (i % 32)) & 1) == 1) z[i] = -z[i]; + if (((s >> (i % 32)) & 1) == 1) z2[i] = -z[i]; + else z2[i]=z[i]; } } @@ -1035,15 +840,29 @@ uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, rel15 = &pdcch_vars->pdcch_config[i]; int dci_length = rel15->dci_length; + int16_t tmp_e[16*108]; + for (int j=0;jnumber_of_candidates;j++) { + LOG_D(PHY,"Trying DCI candidate %d, CCE %d (%d), L %d\n",j,rel15->CCE[j],rel15->CCE[j]*9*6*2,rel15->L[j]); int CCEind = rel15->CCE[j]; int L = rel15->L[j]; uint64_t dci_estimation[2]= {0}; const t_nrPolar_params *currentPtrDCI=nr_polar_params(1, dci_length, L,1,&ue->polarList); - uint16_t crc = polar_decoder_int16(&pdcch_vars->e_rx[CCEind*9*6*2], + + nr_pdcch_unscrambling(rel15->rnti, + &ue->frame_parms, + slot, + &pdcch_vars->e_rx[CCEind*108], + tmp_e, + L*108, + // get_nCCE(n_pdcch_symbols, frame_parms, mi) * 72, + rel15->coreset.pdcch_dmrs_scrambling_id); + + uint16_t crc = polar_decoder_int16(tmp_e, dci_estimation, 1, currentPtrDCI); + LOG_D(PHY,"Decoded crc %x\n",crc); if (crc == rel15->rnti) { dci_ind->SFN = frame; dci_ind->slot = slot; diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c index 17ecce714a..347c9c2ab9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c @@ -88,17 +88,13 @@ uint8_t nr_subframe2harq_pid(NR_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8 } uint8_t nr_pdcch_alloc2ul_subframe(NR_DL_FRAME_PARMS *frame_parms,uint8_t n) { - uint8_t ul_subframe = 255; AssertFatal(1==0,"Not ready for this\n"); } uint32_t nr_pdcch_alloc2ul_frame(NR_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t n) { - uint32_t ul_frame = 255; - AssertFatal(1==0,"Not ready for this\n"); - } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index f7a1b0cb30..00167507ce 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -41,9 +41,8 @@ #include "SCHED_NR_UE/defs.h" #include "SIMULATION/TOOLS/sim.h" #include "executables/nr-uesoftmodem.h" -#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h" -#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" -//#define DEBUG_DLSCH_DECODING 1 +#include "PHY/CODING/nrLDPC_extern.h" +//#define DEBUG_DLSCH_DECODING //#define ENABLE_PHY_PAYLOAD_DEBUG 1 //#define OAI_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX @@ -51,8 +50,9 @@ static uint64_t nb_total_decod =0; static uint64_t nb_error_decod =0; -notifiedFIFO_t freeBlocks; -notifiedFIFO_elt_t *msgToPush; +notifiedFIFO_t freeBlocks_dl; +notifiedFIFO_elt_t *msgToPush_dl; +int nbDlProcessing =0; //extern double cpuf; @@ -112,7 +112,7 @@ void free_nr_ue_dlsch(NR_UE_DLSCH_t **dlschptr,uint8_t N_RB_DL) } } -NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_ldpc_iterations,uint8_t N_RB_DL, uint8_t abstraction_flag) +NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_ldpc_iterations,uint16_t N_RB_DL, uint8_t abstraction_flag) { NR_UE_DLSCH_t *dlsch; @@ -272,6 +272,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, __m128i *pv = (__m128i*)&z; __m128i *pl = (__m128i*)&l; + + vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN); //NR_DL_UE_HARQ_t *harq_process = dlsch->harq_processes[0]; @@ -327,8 +329,6 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, LOG_D(PHY,"DLSCH Decoding, harq_pid %d TBS %d G %d nb_re_dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, nb_re_dmrs,harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN); - if ((harq_process->R)<1024) Coderate = (float) (harq_process->R) /(float) 1024; else @@ -389,7 +389,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, #endif } - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT); p_decParams->Z = harq_process->Z; //printf("dlsch decoding nr segmentation Z %d\n", p_decParams->Z); @@ -434,7 +434,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, start_meas(dlsch_deinterleaving_stats); #endif - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN); nr_deinterleaving_ldpc(E, @@ -442,8 +442,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, harq_process->w[r], // [hna] w is e dlsch_llr+r_offset); - - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_OUT); //for (int i =0; i<16; i++) // printf("rx output deinterleaving w[%d]= %d r_offset %d\n", i,harq_process->w[r][i], r_offset); @@ -456,9 +455,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, start_meas(dlsch_rate_unmatching_stats); #endif -#ifdef DEBUG_DLSCH_DECODING - LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", - harq_pid,r, G, + LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,E %d, F %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", + harq_pid,r, G,E,harq_process->F, Kr*3, harq_process->TBS, harq_process->Qm, @@ -466,9 +464,9 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, harq_process->Nl, harq_process->rvidx, harq_process->round); -#endif - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN); if ((harq_process->Nl)<4) Tbslbrm = nr_compute_tbslbrm(harq_process->mcs_table,nb_rb,harq_process->Nl,harq_process->C); @@ -486,9 +484,9 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, harq_process->rvidx, (harq_process->round==0)?1:0, E, - harq_process->F, - Kr-harq_process->F-2*(p_decParams->Z))==-1) { - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT); + harq_process->F, + Kr-harq_process->F-2*(p_decParams->Z))==-1) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE stop_meas(dlsch_rate_unmatching_stats); #endif @@ -496,7 +494,6 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, return(dlsch->max_ldpc_iterations + 1); } else { - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE stop_meas(dlsch_rate_unmatching_stats); #endif @@ -571,13 +568,15 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, pl[j] = _mm_packs_epi16(pv[i],pv[i+1]); } - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_IN); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_IN); + no_iteration_ldpc = nrLDPC_decoder(p_decParams, (int8_t*)&pl[0], llrProcBuf, p_nrLDPC_procBuf[r], p_procTime); - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_OUT); // Fixme: correct type is unsigned, but nrLDPC_decoder and all called behind use signed int if (check_crc((uint8_t*)llrProcBuf,length_dec,harq_process->F,crc_type)) { @@ -672,7 +671,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, return((1 + dlsch->max_ldpc_iterations)); } else { //#if UE_DEBUG_TRACE - LOG_I(PHY,"[UE %d] DLSCH: Setting ACK for nr_tti_rx %d TBS %d mcs %d nb_rb %d harq_process->round %d\n", + LOG_D(PHY,"[UE %d] DLSCH: Setting ACK for nr_tti_rx %d TBS %d mcs %d nb_rb %d harq_process->round %d\n", phy_vars_ue->Mod_id,nr_tti_rx,harq_process->TBS,harq_process->mcs,harq_process->nb_rb, harq_process->round); //#endif @@ -704,7 +703,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, printf("C %d\n",harq_process->C); */ - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_COMBINE_SEG, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_COMBINE_SEG, VCD_FUNCTION_IN); for (r=0; rC; r++) { @@ -739,7 +738,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, } - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_COMBINE_SEG, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_COMBINE_SEG, VCD_FUNCTION_OUT); dlsch->last_iteration_cnt = ret; @@ -792,25 +791,29 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, int16_t z [68*384]; int8_t l [68*384]; //__m128i l; - int16_t inv_d [68*384]; + //int16_t inv_d [68*384]; //int16_t *p_invd =&inv_d; uint8_t kb, kc; uint8_t Ilbrm = 1; uint32_t Tbslbrm = 950984; uint16_t nb_rb = 30; double Coderate = 0.0; - nfapi_nr_dl_config_dlsch_pdu_rel15_t *dl_config_pdu = &harq_processes[harq_pid]->dl_config_pdu - uint8_t dmrs_type = dl_config_pdu->dmrsConfigType; + uint8_t dmrs_type = harq_process->dmrsConfigType; + //nfapi_nr_config_request_t *cfg = &phy_vars_ue->nrUE_config; + //uint8_t dmrs_type = cfg->pdsch_config.dmrs_type.value; + uint8_t nb_re_dmrs = (dmrs_type==1)?6:4; - uint16_t length_dmrs = get_num_dmrs(dl_config_pdu->dlDmrsSymbPos); + uint16_t length_dmrs = get_num_dmrs(harq_process->dlDmrsSymbPos); uint32_t i,j; +// int nbDlProcessing =0; __m128i *pv = (__m128i*)&z; __m128i *pl = (__m128i*)&l; notifiedFIFO_t nf; initNotifiedFIFO(&nf); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN); if (!dlsch_llr) { printf("dlsch_decoding.c: NULL dlsch_llr pointer\n"); @@ -856,7 +859,8 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, A = harq_process->TBS; - ret = dlsch->max_ldpc_iterations; + ret = dlsch->max_ldpc_iterations + 1; + dlsch->last_iteration_cnt = ret; harq_process->G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, harq_process->Qm,harq_process->Nl); @@ -864,7 +868,6 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, LOG_D(PHY,"DLSCH Decoding main, harq_pid %d TBS %d G %d, nb_re_dmrs %d, length_dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, nb_re_dmrs, length_dmrs, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); - proc->decoder_main_available = 1; proc->decoder_thread_available = 0; proc->decoder_thread_available1 = 0; @@ -925,9 +928,10 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, &harq_process->F, p_decParams->BG); - p_decParams->Z = harq_process->Z; } + + p_decParams->Z = harq_process->Z; //printf("coderate %f kc %d \n", Coderate, kc); p_decParams->numMaxIter = dlsch->max_ldpc_iterations; @@ -951,17 +955,20 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, printf("Segmentation: C %d, K %d\n",harq_process->C,harq_process->K); #endif - notifiedFIFO_elt_t *res; + notifiedFIFO_elt_t *res_dl; opp_enabled=1; if (harq_process->C>1) { for (int nb_seg =1 ; nb_segC; nb_seg++){ - if ( (res=tryPullTpool(&nf, Tpool)) != NULL ) { - pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); + if ( (res_dl=tryPullTpool(&nf, Tpool_dl)) != NULL ) { + pushNotifiedFIFO_nothreadSafe(&freeBlocks_dl,res_dl); } - AssertFatal((msgToPush=pullNotifiedFIFO_nothreadSafe(&freeBlocks)) != NULL,"chained list failure"); - nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(msgToPush); + AssertFatal((msgToPush_dl=pullNotifiedFIFO_nothreadSafe(&freeBlocks_dl)) != NULL,"chained list failure"); + nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(msgToPush_dl); curMsg->UE=phy_vars_ue; + + nbDlProcessing++; + memset(&curMsg->proc, 0, sizeof(curMsg->proc)); curMsg->proc.frame_rx = proc->frame_rx; @@ -972,8 +979,8 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, curMsg->proc.harq_pid=harq_pid; curMsg->proc.llr8_flag = llr8_flag; - msgToPush->key=nb_seg; - pushTpool(Tpool, msgToPush); + msgToPush_dl->key= (nr_tti_rx%2) ? (nb_seg+30): nb_seg; + pushTpool(Tpool_dl, msgToPush_dl); /*Qm= harq_process->Qm; Nl=harq_process->Nl; @@ -1046,7 +1053,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, if (harq_process->Nl < Nl) Nl = harq_process->Nl; - Tbslbrm = nr_compute_tbslbrm(rel15.mcs_table,nb_rb,Nl,dlsch->harq_processes[harq_pid]->C); + Tbslbrm = nr_compute_tbslbrm(harq_process->mcs_table,nb_rb,harq_process->Nl,harq_process->C); if (nr_rate_matching_ldpc_rx(Ilbrm, Tbslbrm, @@ -1142,11 +1149,13 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j])); } - for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++) + j+=(harq_process->F>>3); + // for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++) + for (i=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++,j++) { pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j])); } - + for (i=0, j=0; j < ((kc*p_decParams->Z)>>4); i+=2, j++) { pl[j] = _mm_packs_epi16(pv[i],pv[i+1]); @@ -1176,9 +1185,9 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, ret = 1+dlsch->max_ldpc_iterations; } - //if (!nb_total_decod%10000){ - printf("Error number of iteration LPDC %d %lu/%lu \n", no_iteration_ldpc, nb_error_decod,nb_total_decod);fflush(stdout); - //} + if (!nb_total_decod%10000){ + printf("Error number of iteration LPDC %d %ld/%ld \n", no_iteration_ldpc, nb_error_decod,nb_total_decod);fflush(stdout); + } //else //printf("OK number of iteration LPDC %d\n", no_iteration_ldpc); @@ -1283,21 +1292,13 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, printf("F %d, Fbytes %d\n",harq_process->F,harq_process->F>>3); printf("C %d\n",harq_process->C); */ - uint32_t wait = 0; - /*if (harq_process->C==2){ - while((proc->decoder_thread_available == 0) ) + //uint32_t wait = 0; + + /* while((proc->decoder_thread_available == 0) ) { usleep(1); - wait++; } - } - else if ((harq_process->C==3) ){ - while((proc->decoder_thread_available == 0) || (proc->decoder_thread_available1 == 0)) - { - usleep(1); - wait++; - } - }*/ + proc->decoder_thread_available == 0;*/ /*notifiedFIFO_elt_t *res1=tryPullTpool(&nf, Tpool); if (!res1) { @@ -1305,6 +1306,8 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, usleep(1); wait++; }*/ + + //usleep(50); proc->decoder_main_available = 0; Kr = harq_process->K; //to check if same K in all segments @@ -1327,6 +1330,8 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, harq_process->c[r]); #endif } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT); dlsch->last_iteration_cnt = ret; //proc->decoder_thread_available = 0; @@ -1337,7 +1342,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, #endif #ifdef UE_DLSCH_PARALLELISATION -void *nr_dlsch_decoding_process(void *arg) +void nr_dlsch_decoding_process(void *arg) { nr_rxtx_thread_data_t *rxtxD= (nr_rxtx_thread_data_t *)arg; UE_nr_rxtx_proc_t *proc = &rxtxD->proc; @@ -1354,8 +1359,8 @@ void *nr_dlsch_decoding_process(void *arg) int16_t z [68*384]; int8_t l [68*384]; //__m128i l; - int16_t inv_d [68*384]; - int16_t *p_invd =&inv_d; + //int16_t inv_d [68*384]; + //int16_t *p_invd =&inv_d; uint8_t kb, kc; uint8_t Ilbrm = 1; uint32_t Tbslbrm = 950984; @@ -1476,7 +1481,8 @@ void *nr_dlsch_decoding_process(void *arg) } } - if (harq_process->round == 0) { + harq_process->round =0; + // if (harq_process->round == 0) { // This is a new packet, so compute quantities regarding segmentation if (A > 3824) harq_process->B = A+24; @@ -1494,9 +1500,10 @@ void *nr_dlsch_decoding_process(void *arg) p_decParams->Z = harq_process->Z; - } + // } + + //printf("round %d Z %d K %d BG %d\n", harq_process->round, p_decParams->Z, harq_process->K, p_decParams->BG); - p_decParams->numMaxIter = dlsch->max_ldpc_iterations; p_decParams->outMode= 0; @@ -1668,6 +1675,7 @@ void *nr_dlsch_decoding_process(void *arg) inv_d[cnt] = (1)*harq_process->d[r][cnt]; } */ + memset(pv,0,2*p_decParams->Z*sizeof(int16_t)); //memset(pl,0,2*p_decParams->Z*sizeof(int8_t)); memset((pv+K_bytes_F),127,harq_process->F*sizeof(int16_t)); @@ -1677,9 +1685,11 @@ void *nr_dlsch_decoding_process(void *arg) pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j])); } - for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++) + j+=(harq_process->F>>3); + // for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++) + for (i=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++,j++) { - pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j])); + pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j])); } for (i=0, j=0; j < ((kc*p_decParams->Z)>>4); i+=2, j++) @@ -1753,35 +1763,38 @@ void *dlsch_thread(void *arg) { PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg; notifiedFIFO_t nf; initNotifiedFIFO(&nf); - int nbDlProcessing=0; - initNotifiedFIFO_nothreadSafe(&freeBlocks); + notifiedFIFO_elt_t *res_dl; + initNotifiedFIFO_nothreadSafe(&freeBlocks_dl); - for (int i=0; i= RX_NB_TH_DL) { - if ( (res=tryPullTpool(&nf, Tpool)) != NULL ) { + if ( (res=tryPullTpool(&nf, Tpool_dl)) != NULL ) { nr_rxtx_thread_data_t *tmp=(nr_rxtx_thread_data_t *)res->msgData; - nbDlProcessing--; - pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); + //nbDlProcessing--; + pushNotifiedFIFO_nothreadSafe(&freeBlocks_dl,res); } usleep(200); } + + res_dl=pullTpool(&nf, Tpool_dl); + nbDlProcessing--; + pushNotifiedFIFO_nothreadSafe(&freeBlocks_dl,res_dl); + - nbDlProcessing++; //msgToPush->key=0; //pushTpool(Tpool, msgToPush); } // while !oai_exit + return NULL; } #endif diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index b60843fab8..c704efdb1f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -375,24 +375,24 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } len = (pilots==1)? (nb_rb*6):(nb_rb*12); - + #if UE_TIMING_TRACE - stop_meas(&ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot]); + stop_meas(&ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot]); #if DISABLE_LOG_X - printf("[AbsSFN %u.%d] Slot%d Symbol %d Flag %d type %d: Pilot/Data extraction %5.2f \n", - frame,nr_tti_rx,slot,symbol,ue->high_speed_flag,type,ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot].p_time/(cpuf*1000.0)); + printf("[AbsSFN %u.%d] Slot%d Symbol %d Flag %d type %d: Pilot/Data extraction %5.2f \n", + frame,nr_tti_rx,slot,symbol,ue->high_speed_flag,type,ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot].p_time/(cpuf*1000.0)); #else - LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d Flag %d type %d: Pilot/Data extraction %5.2f \n", - frame,nr_tti_rx,slot,symbol,ue->high_speed_flag,type,ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot].p_time/(cpuf*1000.0)); + LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d Flag %d type %d: Pilot/Data extraction %5.2f \n", + frame,nr_tti_rx,slot,symbol,ue->high_speed_flag,type,ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot].p_time/(cpuf*1000.0)); #endif #endif - + #if UE_TIMING_TRACE - start_meas(&ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot]); + start_meas(&ue->generic_stat_bis[ue->current_thread_id[nr_tti_rx]][slot]); #endif n_tx = frame_parms->nb_antenna_ports_gNB; n_rx = frame_parms->nb_antennas_rx; - + nr_dlsch_scale_channel(pdsch_vars[eNB_id]->dl_ch_estimates_ext, frame_parms, dlsch, @@ -416,11 +416,11 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, if (beamforming_mode==0){ if (dlsch0_harq->mimo_modedl_ch_estimates_ext, - frame_parms, - avg, - symbol, - len, - nb_rb); + frame_parms, + avg, + symbol, + len, + nb_rb); avgs = 0; for (aatx=0;aatxnb_antenna_ports_gNB;aatx++) for (aarx=0;aarxnb_antennas_rx;aarx++) @@ -449,14 +449,14 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } } -#ifdef UE_DEBUG_TRACE - LOG_I(PHY,"[DLSCH] AbsSubframe %d.%d log2_maxh = %d [log2_maxh0 %d log2_maxh1 %d] (%d,%d)\n", - frame%1024,nr_tti_rx, pdsch_vars[eNB_id]->log2_maxh, - pdsch_vars[eNB_id]->log2_maxh0, - pdsch_vars[eNB_id]->log2_maxh1, - avg[0],avgs); + //#ifdef UE_DEBUG_TRACE + LOG_D(PHY,"[DLSCH] AbsSubframe %d.%d log2_maxh = %d [log2_maxh0 %d log2_maxh1 %d] (%d,%d)\n", + frame%1024,nr_tti_rx, pdsch_vars[eNB_id]->log2_maxh, + pdsch_vars[eNB_id]->log2_maxh0, + pdsch_vars[eNB_id]->log2_maxh1, + avg[0],avgs); //LOG_D(PHY,"[DLSCH] mimo_mode = %d\n", dlsch0_harq->mimo_mode); -#endif + //#endif //wait until pdcch is decoded //proc->channel_level = 1; @@ -1849,11 +1849,11 @@ void nr_dlsch_scale_channel(int **dl_ch_estimates_ext, //compute average channel_level on each (TX,RX) antenna pair void nr_dlsch_channel_level(int **dl_ch_estimates_ext, - NR_DL_FRAME_PARMS *frame_parms, - int32_t *avg, - uint8_t symbol, - uint32_t len, - unsigned short nb_rb) + NR_DL_FRAME_PARMS *frame_parms, + int32_t *avg, + uint8_t symbol, + uint32_t len, + unsigned short nb_rb) { #if defined(__x86_64__)||defined(__i386__) @@ -1864,8 +1864,9 @@ void nr_dlsch_channel_level(int **dl_ch_estimates_ext, //nb_rb*nre = y * 2^x int16_t x = factor2(len); + //x = (x>4) ? 4 : x; int16_t y = (len)>>x; - //printf("nb_rb*nre = %d = %d * 2^(%d)\n",nb_rb*nre,y,x); + //printf("len = %d = %d * 2^(%d)\n",len,y,x); for (aatx=0; aatxnb_antenna_ports_gNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { @@ -1876,29 +1877,10 @@ void nr_dlsch_channel_level(int **dl_ch_estimates_ext, dl_ch128=(__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*nb_rb*12]; for (rb=0;rbNcp-1)))&&(frame_parms->nb_antenna_ports_gNB!=1)) { - dl_ch128+=2; - } - else {*/ - avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[2],dl_ch128[2]),x)); - //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[2],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[2], coeff128),15))); - dl_ch128+=3; - // } - /* - if (rb==0) { - print_shorts("dl_ch128",&dl_ch128[0]); - print_shorts("dl_ch128",&dl_ch128[1]); - print_shorts("dl_ch128",&dl_ch128[2]); - } - */ + avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[2],dl_ch128[2]),x)); + dl_ch128+=3; } avg[(aatx<<1)+aarx] =(((int32_t*)&avg128D)[0] + diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c index e7b2921368..ce1c0df156 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c @@ -39,8 +39,8 @@ //#define DEBUG_LLR_SIC -int16_t zeros[8] __attribute__ ((aligned(16))) = {0,0,0,0,0,0,0,0}; -int16_t ones[8] __attribute__ ((aligned(16))) = {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; +int16_t nr_zeros[8] __attribute__ ((aligned(16))) = {0,0,0,0,0,0,0,0}; +int16_t nr_ones[8] __attribute__ ((aligned(16))) = {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; #if defined(__x86_64__) || defined(__i386__) __m128i rho_rpi __attribute__ ((aligned(16))); __m128i rho_rmi __attribute__ ((aligned(16))); @@ -604,11 +604,11 @@ __m128i tmp_result4 __attribute__ ((aligned(16))); #define prodsum_psi_a_epi16(psi_r,a_r,psi_i,a_i,psi_a) tmp_result = _mm_mulhi_epi16(psi_r,a_r); tmp_result = _mm_slli_epi16(tmp_result,1); tmp_result2 = _mm_mulhi_epi16(psi_i,a_i); tmp_result2 = _mm_slli_epi16(tmp_result2,1); psi_a = _mm_adds_epi16(tmp_result,tmp_result2); // calculate interference magnitude -#define interference_abs_epi16(psi,int_ch_mag,int_mag,c1,c2) tmp_result = _mm_cmplt_epi16(psi,int_ch_mag); tmp_result2 = _mm_xor_si128(tmp_result,(*(__m128i*)&ones[0])); tmp_result = _mm_and_si128(tmp_result,c1); tmp_result2 = _mm_and_si128(tmp_result2,c2); int_mag = _mm_or_si128(tmp_result,tmp_result2); +#define interference_abs_epi16(psi,int_ch_mag,int_mag,c1,c2) tmp_result = _mm_cmplt_epi16(psi,int_ch_mag); tmp_result2 = _mm_xor_si128(tmp_result,(*(__m128i*)&nr_ones[0])); tmp_result = _mm_and_si128(tmp_result,c1); tmp_result2 = _mm_and_si128(tmp_result2,c2); int_mag = _mm_or_si128(tmp_result,tmp_result2); // calculate interference magnitude -// tmp_result = ones in shorts corr. to interval 2<=x<=4, tmp_result2 interval < 2, tmp_result3 interval 46 -#define interference_abs_64qam_epi16(psi,int_ch_mag,int_two_ch_mag,int_three_ch_mag,a,c1,c3,c5,c7) tmp_result = _mm_cmplt_epi16(psi,int_two_ch_mag); tmp_result3 = _mm_xor_si128(tmp_result,(*(__m128i*)&ones[0])); tmp_result2 = _mm_cmplt_epi16(psi,int_ch_mag); tmp_result = _mm_xor_si128(tmp_result,tmp_result2); tmp_result4 = _mm_cmpgt_epi16(psi,int_three_ch_mag); tmp_result3 = _mm_xor_si128(tmp_result3,tmp_result4); tmp_result = _mm_and_si128(tmp_result,c3); tmp_result2 = _mm_and_si128(tmp_result2,c1); tmp_result3 = _mm_and_si128(tmp_result3,c5); tmp_result4 = _mm_and_si128(tmp_result4,c7); tmp_result = _mm_or_si128(tmp_result,tmp_result2); tmp_result3 = _mm_or_si128(tmp_result3,tmp_result4); a = _mm_or_si128(tmp_result,tmp_result3); +// tmp_result = nr_ones in shorts corr. to interval 2<=x<=4, tmp_result2 interval < 2, tmp_result3 interval 46 +#define interference_abs_64qam_epi16(psi,int_ch_mag,int_two_ch_mag,int_three_ch_mag,a,c1,c3,c5,c7) tmp_result = _mm_cmplt_epi16(psi,int_two_ch_mag); tmp_result3 = _mm_xor_si128(tmp_result,(*(__m128i*)&nr_ones[0])); tmp_result2 = _mm_cmplt_epi16(psi,int_ch_mag); tmp_result = _mm_xor_si128(tmp_result,tmp_result2); tmp_result4 = _mm_cmpgt_epi16(psi,int_three_ch_mag); tmp_result3 = _mm_xor_si128(tmp_result3,tmp_result4); tmp_result = _mm_and_si128(tmp_result,c3); tmp_result2 = _mm_and_si128(tmp_result2,c1); tmp_result3 = _mm_and_si128(tmp_result3,c5); tmp_result4 = _mm_and_si128(tmp_result4,c7); tmp_result = _mm_or_si128(tmp_result,tmp_result2); tmp_result3 = _mm_or_si128(tmp_result3,tmp_result4); a = _mm_or_si128(tmp_result,tmp_result3); // calculates a_sq = int_ch_mag*(a_r^2 + a_i^2)*scale_factor #define square_a_epi16(a_r,a_i,int_ch_mag,scale_factor,a_sq) tmp_result = _mm_mulhi_epi16(a_r,a_r); tmp_result = _mm_slli_epi16(tmp_result,1); tmp_result = _mm_mulhi_epi16(tmp_result,scale_factor); tmp_result = _mm_slli_epi16(tmp_result,1); tmp_result = _mm_mulhi_epi16(tmp_result,int_ch_mag); tmp_result = _mm_slli_epi16(tmp_result,1); tmp_result2 = _mm_mulhi_epi16(a_i,a_i); tmp_result2 = _mm_slli_epi16(tmp_result2,1); tmp_result2 = _mm_mulhi_epi16(tmp_result2,scale_factor); tmp_result2 = _mm_slli_epi16(tmp_result2,1); tmp_result2 = _mm_mulhi_epi16(tmp_result2,int_ch_mag); tmp_result2 = _mm_slli_epi16(tmp_result2,1); a_sq = _mm_adds_epi16(tmp_result,tmp_result2); @@ -1142,7 +1142,7 @@ int nr_dlsch_qpsk_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, // printf("nr_dlsch_qpsk_qpsk_llr: symbol %d,nb_rb %d, len %d,pbch_pss_sss_adjust %d\n",symbol,nb_rb,len,pbch_pss_sss_adjust); // printf("qpsk_qpsk: len %d, llr16 %p\n",len,llr16); - qpsk_qpsk((short *)rxF, + nr_qpsk_qpsk((short *)rxF, (short *)rxF_i, (short *)llr16, (short *)rho, @@ -1156,7 +1156,7 @@ int nr_dlsch_qpsk_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, //__m128i ONE_OVER_SQRT_8 __attribute__((aligned(16))); -void qpsk_qpsk(short *stream0_in, +void nr_qpsk_qpsk(short *stream0_in, short *stream1_in, short *stream0_out, short *rho01, @@ -1390,7 +1390,7 @@ int nr_dlsch_qpsk_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, len = (nb_rb*12) - pbch_pss_sss_adjust; } - qpsk_qam16((short *)rxF, + nr_qpsk_qam16((short *)rxF, (short *)rxF_i, (short *)ch_mag_i, (short *)llr16, @@ -1413,7 +1413,7 @@ __m128i SQRT_10_OVER_FOUR __attribute__((aligned(16))); __m128i ch_mag_int; #endif */ -void qpsk_qam16(int16_t *stream0_in, +void nr_qpsk_qam16(int16_t *stream0_in, int16_t *stream1_in, int16_t *ch_mag_i, int16_t *stream0_out, @@ -1672,7 +1672,7 @@ int nr_dlsch_qpsk_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, len = (nb_rb*12) - pbch_pss_sss_adjust; } - qpsk_qam64((short *)rxF, + nr_qpsk_qam64((short *)rxF, (short *)rxF_i, (short *)ch_mag_i, (short *)llr16, @@ -1695,7 +1695,7 @@ __m128i two_ch_mag_int_with_sigma2 __attribute__((aligned(16))); __m128i three_ch_mag_int_with_sigma2 __attribute__((aligned(16))); __m128i SQRT_42_OVER_FOUR __attribute__((aligned(16))); */ -void qpsk_qam64(short *stream0_in, +void nr_qpsk_qam64(short *stream0_in, short *stream1_in, short *ch_mag_i, short *stream0_out, @@ -1947,7 +1947,7 @@ __m128i ch_mag_over_2 __attribute__ ((aligned(16))); __m128i ch_mag_9_over_10 __attribute__ ((aligned(16))); */ -void qam16_qpsk(short *stream0_in, +void nr_qam16_qpsk(short *stream0_in, short *stream1_in, short *ch_mag, short *stream0_out, @@ -2440,7 +2440,7 @@ int nr_dlsch_16qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, // printf("symbol %d: qam16_llr, len %d (llr16 %p)\n",symbol,len,llr16); - qam16_qpsk((short *)rxF, + nr_qam16_qpsk((short *)rxF, (short *)rxF_i, (short *)ch_mag, (short *)llr16, @@ -2453,7 +2453,7 @@ int nr_dlsch_16qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, return(0); } -void qam16_qam16(short *stream0_in, +void nr_qam16_qam16(short *stream0_in, short *stream1_in, short *ch_mag, short *ch_mag_i, @@ -2981,7 +2981,7 @@ int nr_dlsch_16qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, // printf("symbol %d: qam16_llr, len %d (llr16 %p)\n",symbol,len,llr16); - qam16_qam16((short *)rxF, + nr_qam16_qam16((short *)rxF, (short *)rxF_i, (short *)ch_mag, (short *)ch_mag_i, @@ -2995,7 +2995,7 @@ int nr_dlsch_16qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, return(0); } -void qam16_qam64(int16_t *stream0_in, +void nr_qam16_qam64(int16_t *stream0_in, int16_t *stream1_in, int16_t *ch_mag, int16_t *ch_mag_i, @@ -3615,7 +3615,7 @@ int nr_dlsch_16qam_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, // printf("symbol %d: qam16_llr, len %d (llr16 %p)\n",symbol,len,llr16); - qam16_qam64((short *)rxF, + nr_qam16_qam64((short *)rxF, (short *)rxF_i, (short *)ch_mag, (short *)ch_mag_i, @@ -3670,7 +3670,7 @@ __m128i ch_mag_2_over_42_with_sigma2 __attribute__((aligned(16))); */ -void qam64_qpsk(int16_t *stream0_in, +void nr_qam64_qpsk(int16_t *stream0_in, int16_t *stream1_in, int16_t *ch_mag, int16_t *stream0_out, @@ -5175,7 +5175,7 @@ int nr_dlsch_64qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, len = (nb_rb*12) - pbch_pss_sss_adjust; } - qam64_qpsk((short *)rxF, + nr_qam64_qpsk((short *)rxF, (short *)rxF_i, (short *)ch_mag, (short *)llr16, @@ -5189,7 +5189,7 @@ int nr_dlsch_64qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, -void qam64_qam16(short *stream0_in, +void nr_qam64_qam16(short *stream0_in, short *stream1_in, short *ch_mag, short *ch_mag_i, @@ -6718,7 +6718,7 @@ int nr_dlsch_64qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, len = (nb_rb*12) - pbch_pss_sss_adjust; } - qam64_qam16((short *)rxF, + nr_qam64_qam16((short *)rxF, (short *)rxF_i, (short *)ch_mag, (short *)ch_mag_i, @@ -6731,6 +6731,7 @@ int nr_dlsch_64qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, return(0); } +#if 0 void qam64_qam64(short *stream0_in, short *stream1_in, short *ch_mag, @@ -8481,6 +8482,7 @@ void qam64_qam64(short *stream0_in, _m_empty(); #endif } +#endif int nr_dlsch_64qam_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index d2dc8a95fd..61748a8e56 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -255,7 +255,7 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, runmode_t mode, double s_time = 1/(1.0e3*fp->samples_per_subframe); // sampling time double off_angle = -2*M_PI*s_time*(ue->common_vars.freq_offset); // offset rotation angle compensation per sample - int start = ue->ssb_offset; // start for offset correction is at ssb_offset (pss time position) + int start = is*fp->samples_per_frame+ue->ssb_offset; // start for offset correction is at ssb_offset (pss time position) int end = start + 4*(fp->ofdm_symbol_size + fp->nb_prefix_samples); // loop over samples in 4 symbols (ssb size), including prefix for(int n=start; nssb_offset, + is*fp->samples_per_frame+ue->ssb_offset, 0); #ifdef DEBUG_INITIAL_SYNCH @@ -303,7 +303,13 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, runmode_t mode, // sync at symbol ue->symbol_offset // computing the offset wrt the beginning of the frame sync_pos_frame = (fp->ofdm_symbol_size + fp->nb_prefix_samples0)+((ue->symbol_offset)-1)*(fp->ofdm_symbol_size + fp->nb_prefix_samples); - ue->rx_offset = ue->ssb_offset - sync_pos_frame; + + if (ue->ssb_offset < sync_pos_frame) + ue->rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset; + else + ue->rx_offset = ue->ssb_offset - sync_pos_frame; + + ue->init_sync_frame = is; } nr_gold_pdcch(ue,0, 2); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index 95ca3ddfa7..60306d8e53 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -621,7 +621,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue, rx_ind.number_pdus = 1; //rx_ind.number_pdus++; if (ue->if_inst && ue->if_inst->dl_indication) - ue->if_inst->dl_indication(&dl_indication); + ue->if_inst->dl_indication(&dl_indication, NULL); return 0; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c index 9af68a9bc5..f407119024 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c @@ -104,7 +104,7 @@ int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t first_nonzero_root_idx=0; #if defined(OAI_USRP) - prach_start = (ue->rx_offset+subframe*(fp->samples_per_slot<<1)-ue->hw_timing_advance-ue->N_TA_offset); + prach_start = (ue->rx_offset+subframe*fp->samples_per_subframe-ue->hw_timing_advance-ue->N_TA_offset); #ifdef NR_PRACH_DEBUG LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, prach_start, @@ -114,13 +114,13 @@ int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, #endif if (prach_start<0) - prach_start+=((fp->samples_per_slot<<1)*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME); + prach_start+=(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME); - if (prach_start>=((fp->samples_per_slot<<1)*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME)) - prach_start-=((fp->samples_per_slot<<1)*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME); + if (prach_start>=(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME)) + prach_start-=(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME); #else //normal case (simulation) - prach_start = subframe*(fp->samples_per_slot<<1)-ue->N_TA_offset; + prach_start = subframe*fp->samples_per_subframe-ue->N_TA_offset; LOG_D(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, prach_start, ue->rx_offset, @@ -793,10 +793,10 @@ int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, #if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) int j; - int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*(fp->samples_per_slot<<1); + int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_subframe; LOG_D( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow ); - for (i=prach_start,j=0; isamples_per_slot<<1)*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,prach_start+prach_len); i++,j++) { + for (i=prach_start,j=0; isamples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,prach_start+prach_len); i++,j++) { ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j]; ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1]; } @@ -820,7 +820,7 @@ int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, #if defined(PRACH_WRITE_OUTPUT_DEBUG) LOG_M("prach_txF0.m","prachtxF0",prachF,prach_len-Ncp,1,1); LOG_M("prach_tx0.m","prachtx0",prach+(Ncp<<1),prach_len-Ncp,1,1); - LOG_M("txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][prach_start]),4*fp->samples_per_slot,1,1); + LOG_M("txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][prach_start]),fp->samples_per_subframe,1,1); exit(-1); #endif 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 d40a1fbee0..35fe8bc899 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -59,12 +59,12 @@ void free_nr_ue_dlsch(NR_UE_DLSCH_t **dlsch,uint8_t N_RB_DL); @params N_RB_DL total number of resource blocks (determine the operating BW) @param abstraction_flag Flag to indicate abstracted interface */ -NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_turbo_iterations,uint8_t N_RB_DL, uint8_t abstraction_flag); +NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_turbo_iterations,uint16_t N_RB_DL, uint8_t abstraction_flag); void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulsch,unsigned char N_RB_UL); -NR_UE_ULSCH_t *new_nr_ue_ulsch(unsigned char N_RB_UL, int number_of_harq_pids, uint8_t abstraction_flag); +NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids, uint8_t abstraction_flag); void fill_UE_dlsch_MCH(PHY_VARS_NR_UE *ue,int mcs,int ndi,int rvidx,int eNB_id); @@ -90,7 +90,7 @@ void dump_mch(PHY_VARS_NR_UE *phy_vars_ue,uint8_t eNB_id,uint16_t coded_bits_per @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qpsk_qpsk(int16_t *stream0_in, +void nr_qpsk_qpsk(int16_t *stream0_in, int16_t *stream1_in, int16_t *stream0_out, int16_t *rho01, @@ -126,7 +126,7 @@ int32_t nr_dlsch_qpsk_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qpsk_qam16(int16_t *stream0_in, +void nr_qpsk_qam16(int16_t *stream0_in, int16_t *stream1_in, short *ch_mag_i, int16_t *stream0_out, @@ -164,7 +164,7 @@ int32_t nr_dlsch_qpsk_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qpsk_qam64(int16_t *stream0_in, +void nr_qpsk_qam64(int16_t *stream0_in, int16_t *stream1_in, short *ch_mag_i, int16_t *stream0_out, @@ -202,7 +202,7 @@ int32_t nr_dlsch_qpsk_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qam16_qpsk(short *stream0_in, +void nr_qam16_qpsk(short *stream0_in, short *stream1_in, short *ch_mag, short *stream0_out, @@ -240,7 +240,7 @@ int nr_dlsch_16qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qam16_qam16(short *stream0_in, +void nr_qam16_qam16(short *stream0_in, short *stream1_in, short *ch_mag, short *ch_mag_i, @@ -283,7 +283,7 @@ int nr_dlsch_16qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qam16_qam64(short *stream0_in, +void nr_qam16_qam64(short *stream0_in, short *stream1_in, short *ch_mag, short *ch_mag_i, @@ -324,7 +324,7 @@ int nr_dlsch_16qam_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qam64_qpsk(short *stream0_in, +void nr_qam64_qpsk(short *stream0_in, short *stream1_in, short *ch_mag, short *stream0_out, @@ -363,7 +363,7 @@ int nr_dlsch_64qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, @param stream0_out Output from LLR unit for stream0 @param rho01 Cross-correlation between channels (MR combined) @param length in complex channel outputs*/ -void qam64_qam16(short *stream0_in, +void nr_qam64_qam16(short *stream0_in, short *stream1_in, short *ch_mag, short *ch_mag_i, @@ -1078,6 +1078,7 @@ void nr_pusch_codeword_scrambling(uint8_t *in, void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, unsigned char harq_pid, + uint8_t frame, uint8_t slot, uint8_t thread_id, int gNB_id); @@ -1539,7 +1540,7 @@ uint8_t get_num_pdcch_symbols(uint8_t num_dci,DCI_ALLOC_t *dci_alloc,NR_DL_FRAME void pdcch_interleaving(NR_DL_FRAME_PARMS *frame_parms,int32_t **z, int32_t **wbar,uint8_t n_symbols_pdcch,uint8_t mi); void nr_pdcch_unscrambling(uint16_t crnti, NR_DL_FRAME_PARMS *frame_parms, uint8_t slot, - int16_t *z, uint32_t length, uint16_t pdcch_DMRS_scrambling_id); + int16_t *z, int16_t *z2,uint32_t length, uint16_t pdcch_DMRS_scrambling_id); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index ca87ed1fae..fb560f229d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -242,6 +242,8 @@ typedef struct { int16_t Po_SRS; /// num active cba group uint8_t num_active_cba_groups; + /// bit mask of PT-RS ofdm symbol indicies + uint16_t ptrs_symbols; /// num dci found for cba //uint8_t num_cba_dci[10]; /// allocated CBA RNTI diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 20357aeb4e..55bac90520 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -36,7 +36,7 @@ #include "PHY/CODING/coding_defs.h" #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/lte_interleaver_inline.h" -#include "PHY/CODING/nrLDPC_encoder/defs.h" +#include "PHY/CODING/nrLDPC_extern.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "LAYER2/NR_MAC_gNB/mac_proto.h" @@ -105,7 +105,7 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr,unsigned char N_RB_UL) } -NR_UE_ULSCH_t *new_nr_ue_ulsch(unsigned char N_RB_UL, +NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids, uint8_t abstraction_flag) { @@ -229,7 +229,8 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch, uint32_t A, Z, F; uint32_t *pz; uint8_t mod_order; - uint16_t Kr,r,r_offset; + uint16_t Kr,r; + uint32_t r_offset; uint8_t BG; uint32_t E,Kb; uint8_t Ilbrm; @@ -261,7 +262,7 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch, Ilbrm = 0; Tbslbrm = 950984; //max tbs nb_re_dmrs = ulsch->nb_re_dmrs; - length_dmrs = 1; + length_dmrs = ulsch->length_dmrs; Coderate = 0.0; /////////// @@ -270,7 +271,7 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN); - LOG_D(PHY,"ulsch coding nb_rb %d nb_symb_sch %d nb_re_dmrs %d, length_dmrs %d\n", nb_rb,nb_symb_sch, nb_re_dmrs,length_dmrs); + LOG_D(PHY,"ulsch coding nb_rb %d nb_symb_sch %d nb_re_dmrs %d, length_dmrs %d, harq_process->Nl = %d\n", nb_rb,nb_symb_sch, nb_re_dmrs,length_dmrs, harq_process->Nl); G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs,mod_order,harq_process->Nl); @@ -291,17 +292,35 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch, printf("%02x.",a[i]); printf("\n"); */ - // Add 24-bit crc (polynomial A) to payload - crc = crc24a(harq_process->a,A)>>8; - harq_process->a[A>>3] = ((uint8_t*)&crc)[2]; - harq_process->a[1+(A>>3)] = ((uint8_t*)&crc)[1]; - harq_process->a[2+(A>>3)] = ((uint8_t*)&crc)[0]; - //printf("CRC %x (A %d)\n",crc,A); - //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); + if (A > 3824) { + // Add 24-bit crc (polynomial A) to payload + crc = crc24a(harq_process->a,A)>>8; + harq_process->a[A>>3] = ((uint8_t*)&crc)[2]; + harq_process->a[1+(A>>3)] = ((uint8_t*)&crc)[1]; + harq_process->a[2+(A>>3)] = ((uint8_t*)&crc)[0]; + //printf("CRC %x (A %d)\n",crc,A); + //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); - harq_process->B = A+24; + harq_process->B = A+24; - memcpy(harq_process->b,harq_process->a,(A/8)+4); + AssertFatal((A/8)+4 <= MAX_NR_ULSCH_PAYLOAD_BYTES,"A %d is too big (A/8+4 = %d > %d)\n",A,(A/8)+4,MAX_NR_ULSCH_PAYLOAD_BYTES); + + memcpy(harq_process->b,harq_process->a,(A/8)+4); + } + else { + // Add 16-bit crc (polynomial A) to payload + crc = crc16(harq_process->a,A)>>16; + harq_process->a[A>>3] = ((uint8_t*)&crc)[1]; + harq_process->a[1+(A>>3)] = ((uint8_t*)&crc)[0]; + //printf("CRC %x (A %d)\n",crc,A); + //printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); + + harq_process->B = A+16; + + AssertFatal((A/8)+3 <= MAX_NR_ULSCH_PAYLOAD_BYTES,"A %d is too big (A/8+3 = %d > %d)\n",A,(A/8)+3,MAX_NR_ULSCH_PAYLOAD_BYTES); + + memcpy(harq_process->b,harq_process->a,(A/8)+3); // using 3 bytes to mimic the case of 24 bit crc + } /////////// /////////////////////////////////////////////////////////////////////////// @@ -374,8 +393,11 @@ opp_enabled=0; printf("%d \n", harq_process->d[0][cnt]); } printf("\n");*/ + encoder_implemparams_t impp; + impp.n_segments=harq_process->C; + impp.macro_num=0; - ldpc_encoder_optim_8seg(harq_process->c,harq_process->d,*pz,Kb,Kr,BG,harq_process->C,NULL,NULL,NULL,NULL); + nrLDPC_encoder(harq_process->c,harq_process->d,*pz,Kb,Kr,BG,&impp); //stop_meas(te_stats); //printf("end ldpc encoder -- output\n"); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index d2dbd6fef2..f1d4a304f9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -31,6 +31,7 @@ */ #include #include "PHY/NR_REFSIG/dmrs_nr.h" +#include "PHY/NR_REFSIG/ptrs_nr.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "PHY/MODULATION/nr_modulation.h" @@ -41,9 +42,15 @@ #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" #include "PHY/defs_nr_common.h" #include "PHY/TOOLS/tools_defs.h" +#include "executables/nr-softmodem.h" +#include "executables/softmodem-common.h" +#include "LAYER2/NR_MAC_UE/mac_proto.h" //#define DEBUG_SCFDMA //#define DEBUG_PUSCH_MAPPING +//#define DEBUG_MAC_PDU + +//extern int32_t uplink_counter; void nr_pusch_codeword_scrambling(uint8_t *in, uint32_t size, @@ -86,47 +93,67 @@ void nr_pusch_codeword_scrambling(uint8_t *in, void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, unsigned char harq_pid, + uint8_t frame, uint8_t slot, uint8_t thread_id, int gNB_id) { uint32_t available_bits; - uint8_t mod_order, cwd_index, num_of_codewords; + uint8_t mod_order, cwd_index, num_of_codewords, l; uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5]; uint32_t ***pusch_dmrs; int16_t **tx_layers; int32_t **txdataF; uint16_t start_sc, start_rb; - int8_t Wf[2], Wt[2], l0, l_prime[2], delta; - uint16_t n_dmrs,code_rate; - uint8_t dmrs_type, length_dmrs; - uint8_t mapping_type; + int8_t Wf[2], Wt[2], l_prime[2], delta; + uint16_t n_dmrs, code_rate, number_dmrs_symbols, k; + uint8_t dmrs_type; int ap, start_symbol, Nid_cell, i; int sample_offsetF, N_RE_prime, N_PRB_oh; uint16_t n_rnti; + uint8_t data_existing =0; + uint8_t L_ptrs, K_ptrs; // PTRS parameters + uint16_t beta_ptrs; // PTRS parameter related to power control NR_UE_ULSCH_t *ulsch_ue; NR_UL_UE_HARQ_t *harq_process_ul_ue; NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; NR_UE_PUSCH *pusch_ue = UE->pusch_vars[thread_id][gNB_id]; + uint8_t ulsch_input_buffer[MAX_ULSCH_PAYLOAD_BYTES]; + ptrs_UplinkConfig_t *ptrs_Uplink_Config = &UE->pusch_config.dmrs_UplinkConfig.ptrs_UplinkConfig; num_of_codewords = 1; // tmp assumption - length_dmrs = 1; n_rnti = 0x1234; Nid_cell = 0; N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig + number_dmrs_symbols = 0; + uint8_t mapping_type = UE->pusch_config.pusch_TimeDomainResourceAllocation[0]->mappingType; for (cwd_index = 0;cwd_index < num_of_codewords; cwd_index++) { ulsch_ue = UE->ulsch[thread_id][gNB_id][cwd_index]; harq_process_ul_ue = ulsch_ue->harq_processes[harq_pid]; - ulsch_ue->length_dmrs = length_dmrs; + start_symbol = harq_process_ul_ue->start_symbol; + + for (i = start_symbol; i < start_symbol + harq_process_ul_ue->number_of_symbols; i++) + number_dmrs_symbols += is_dmrs_symbol((mapping_type)?i-start_symbol:i, + 0, + 0, + 0, + 0, + 0, + harq_process_ul_ue->number_of_symbols, + UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type, + frame_parms->ofdm_symbol_size); + + ulsch_ue->length_dmrs = number_dmrs_symbols; // pusch.MaxLenght is redundant here as number_dmrs_symbols + // contains all dmrs symbols even for double symbol dmrs ulsch_ue->rnti = n_rnti; ulsch_ue->Nid_cell = Nid_cell; - ulsch_ue->nb_re_dmrs = UE->dmrs_UplinkConfig.pusch_maxLength*(UE->dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1?6:4); + ulsch_ue->nb_re_dmrs = ((UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1)?6:4); - N_RE_prime = NR_NB_SC_PER_RB*harq_process_ul_ue->number_of_symbols - ulsch_ue->nb_re_dmrs - N_PRB_oh; + N_RE_prime = NR_NB_SC_PER_RB*harq_process_ul_ue->number_of_symbols - ulsch_ue->nb_re_dmrs*number_dmrs_symbols - N_PRB_oh; harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*harq_process_ul_ue->nb_rb*num_of_codewords; @@ -141,13 +168,45 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, 0, harq_process_ul_ue->Nl); + uint8_t access_mode = SCHEDULED_ACCESS; + //-----------------------------------------------------// // to be removed later when MAC is ready if (harq_process_ul_ue != NULL){ - for (i = 0; i < harq_process_ul_ue->TBS / 8; i++) { - harq_process_ul_ue->a[i] = (unsigned char) rand(); - //printf("input encoder a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]); + data_existing = 0; + + if (IS_SOFTMODEM_NOS1){ + data_existing = nr_ue_get_sdu(UE->Mod_id, UE->CC_id, frame, + slot, 0, ulsch_input_buffer, harq_process_ul_ue->TBS/8, &access_mode); + //IP traffic to be transmitted + if(data_existing){ + //harq_process_ul_ue->a = (unsigned char*)calloc(harq_process_ul_ue->TBS/8, sizeof(unsigned char)); + memcpy(harq_process_ul_ue->a, ulsch_input_buffer, harq_process_ul_ue->TBS/8); + + #ifdef DEBUG_MAC_PDU + LOG_I(PHY, "Printing MAC PDU to be encoded, TBS is: %d \n", harq_process_ul_ue->TBS/8); + for (i = 0; i < harq_process_ul_ue->TBS / 8; i++) { + printf("0x%02x",harq_process_ul_ue->a[i]); + } + printf("\n"); + #endif + } + } + //Random traffic to be transmitted if there is no IP traffic available for this Tx opportunity + if (!IS_SOFTMODEM_NOS1 || !data_existing) { + //Use zeros for the header bytes in noS1 mode, in order to make sure that the LCID is not valid + //and block this traffic from being forwarded to the upper layers at the gNB + uint16_t payload_offset = 5; + LOG_D(PHY, "Random data to be tranmsitted: \n"); + //Give the header bytes some dummy value in order to block the random packet at the MAC layer of the receiver + for (i = 0; ia[i] = 0; + + for (i = payload_offset; i < harq_process_ul_ue->TBS / 8; i++) { + harq_process_ul_ue->a[i] = (unsigned char) rand(); + //printf(" input encoder a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]); + } } } else { LOG_E(PHY, "[phy_procedures_nrUE_TX] harq_process_ul_ue is NULL !!\n"); @@ -159,6 +218,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH coding///////////////////////// /////////// + nr_ulsch_encoding(ulsch_ue, frame_parms, harq_pid); /////////// @@ -203,24 +263,47 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, //////////////////////////////////////////////////////////////////////// + //} } - start_symbol = 14 - harq_process_ul_ue->number_of_symbols; - /////////////////////////DMRS Modulation///////////////////////// /////////// pusch_dmrs = UE->nr_gold_pusch_dmrs[slot]; - n_dmrs = (harq_process_ul_ue->nb_rb*ulsch_ue->nb_re_dmrs); + n_dmrs = (harq_process_ul_ue->nb_rb*ulsch_ue->nb_re_dmrs*ulsch_ue->length_dmrs); int16_t mod_dmrs[n_dmrs<<1]; - dmrs_type = UE->dmrs_UplinkConfig.pusch_dmrs_type; - mapping_type = UE->pusch_config.pusch_TimeDomainResourceAllocation[0]->mappingType; - - l0 = get_l0_ul(mapping_type, 2); - nr_modulation(pusch_dmrs[l0][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated - + dmrs_type = UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type; /////////// //////////////////////////////////////////////////////////////////////// + + /////////////////////////PTRS parameters' initialization///////////////////////// + /////////// + + int16_t mod_ptrs[(harq_process_ul_ue->nb_rb/2)*(NR_SYMBOLS_PER_SLOT-1)*2]; // assume maximum number of PTRS per pusch allocation + K_ptrs = 0; // just to avoid a warning + + if (UE->ptrs_configured == 1) { + + K_ptrs = get_K_ptrs(ptrs_Uplink_Config, harq_process_ul_ue->nb_rb); + + L_ptrs = get_L_ptrs(ptrs_Uplink_Config, harq_process_ul_ue->mcs); + + beta_ptrs = 1; // temp value until power control is implemented + + ulsch_ue->ptrs_symbols = 0; + + set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols, + harq_process_ul_ue->number_of_symbols, + start_symbol, + dmrs_type, + L_ptrs, + ulsch_ue->length_dmrs, + frame_parms->ofdm_symbol_size); + } + + /////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////ULSCH layer mapping///////////////////////// /////////// @@ -239,7 +322,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////// l_prime[0] = 0; // single symbol ap 0 - uint8_t dmrs_symbol = l0+l_prime[0], l; // Assuming dmrs-AdditionalPosition = 0 #ifdef NR_SC_FDMA uint32_t nb_re_pusch, nb_re_dmrs_per_rb; @@ -247,8 +329,18 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, for (l = start_symbol; l < start_symbol + harq_process_ul_ue->number_of_symbols; l++) { - if(l == dmrs_symbol) - nb_re_dmrs_per_rb = ulsch_ue->nb_re_dmrs; // [hna] ulsch_ue->nb_re_dmrs = 6 in this configuration + is_dmrs = is_dmrs_symbol((mapping_type)?l-start_symbol:l, + 0, + 0, + 0, + 0, + 0, + harq_process_ul_ue->number_of_symbols, + dmrs_type, + frame_parms->ofdm_symbol_size); + + if (is_dmrs == 1) + nb_re_dmrs_per_rb = ulsch_ue->nb_re_dmrs; else nb_re_dmrs_per_rb = 0; @@ -287,17 +379,54 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint8_t k_prime=0; - uint16_t m=0, n=0, dmrs_idx=0, k=0; + uint8_t is_dmrs, is_ptrs; + uint8_t l_ref; + uint16_t m=0, n=0, dmrs_idx=0, ptrs_idx = 0; for (l=start_symbol; lnumber_of_symbols; l++) { k = start_sc; + n = 0; + dmrs_idx = 0; + l_ref = (mapping_type) ? l-start_symbol : l; for (i=0; inb_rb*NR_NB_SC_PER_RB; i++) { sample_offsetF = l*frame_parms->ofdm_symbol_size + k; - if ((l == dmrs_symbol) && (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%(frame_parms->ofdm_symbol_size)))) { + is_dmrs = 0; + is_ptrs = 0; + + is_dmrs = is_dmrs_symbol(l_ref, + k, + start_sc, + k_prime, + n, + delta, + harq_process_ul_ue->number_of_symbols, + dmrs_type, + frame_parms->ofdm_symbol_size); + + if (UE->ptrs_configured == 1){ + is_ptrs = is_ptrs_symbol(l, + k, + ulsch_ue->rnti, + harq_process_ul_ue->nb_rb, + harq_process_ul_ue->number_of_symbols, + ap, + K_ptrs, + ulsch_ue->ptrs_symbols, + start_sc, + frame_parms->ofdm_symbol_size, + UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type, + ptrs_Uplink_Config->resourceElementOffset); + } + + if (is_dmrs == 1) { + + if (k == start_sc){ + nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated + } ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; @@ -313,9 +442,19 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, k_prime++; k_prime&=1; n+=(k_prime)?0:1; - } - else { + } else if (is_ptrs == 1) { + + if (k == start_sc){ + nr_modulation(pusch_dmrs[l][0], harq_process_ul_ue->nb_rb/2, DMRS_MOD_ORDER, mod_ptrs); + } + + ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15; + ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15; + + ptrs_idx++; + + } else { ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = ((int16_t *) ulsch_ue->y)[m<<1]; ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1]; @@ -335,10 +474,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, } } + //} + /////////// //////////////////////////////////////////////////////////////////////// - return; + LOG_D(PHY, "Is data existing ?: %d \n", data_existing); } @@ -364,11 +505,18 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, timing_advance = 0; #endif - tx_offset = slot*frame_parms->samples_per_slot - timing_advance; + tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0) - timing_advance; if (tx_offset < 0) tx_offset += frame_parms->samples_per_frame; + // clear the transmit data array for the current subframe + /*for (int aa=0; aaframe_parms.nb_antennas_tx; aa++) { + memset(&UE->common_vars.txdata[aa][tx_offset],0,UE->frame_parms.samples_per_slot*sizeof(int32_t)); + //memset(&UE->common_vars.txdataF[aa][tx_offset],0,UE->frame_parms.samples_per_slot*sizeof(int32_t)); + }*/ + + txdata = UE->common_vars.txdata; txdataF = UE->common_vars.txdataF; @@ -387,6 +535,7 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, frame_parms); } } + /////////// //////////////////////////////////////////////////// return 0; diff --git a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c index b13cd008b5..e8eceb77a6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c @@ -880,7 +880,7 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain /* perform correlation of rx data and pss sequence ie it is a dot product */ result = dot_product64((short*)primary_synchro_time_nr[pss_index], - (short*) &(rxdata[ar][n])+(is*frame_parms->samples_per_frame), + (short*) &(rxdata[ar][n+is*frame_parms->samples_per_frame]), frame_parms->ofdm_symbol_size, shift); pss_corr_ue[pss_index][n] += abs64(result); @@ -914,13 +914,13 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain int64_t result1,result2; // Computing cross-correlation at peak on half the symbol size for first half of data result1 = dot_product64((short*)primary_synchro_time_nr[pss_source], - (short*) &(rxdata[0][peak_position])+(is*frame_parms->samples_per_frame), + (short*) &(rxdata[0][peak_position+is*frame_parms->samples_per_frame]), frame_parms->ofdm_symbol_size>>1, shift); // Computing cross-correlation at peak on half the symbol size for data shifted by half symbol size // as it is real and complex it is necessary to shift by a value equal to symbol size to obtain such shift result2 = dot_product64((short*)primary_synchro_time_nr[pss_source]+(frame_parms->ofdm_symbol_size), - (short*) &(rxdata[0][peak_position])+(frame_parms->ofdm_symbol_size+(is*frame_parms->samples_per_frame)), + (short*) &(rxdata[0][peak_position+is*frame_parms->samples_per_frame])+frame_parms->ofdm_symbol_size, frame_parms->ofdm_symbol_size>>1, shift); diff --git a/openair1/PHY/TOOLS/Makefile b/openair1/PHY/TOOLS/Makefile index db20bc834e..c71717dc87 100644 --- a/openair1/PHY/TOOLS/Makefile +++ b/openair1/PHY/TOOLS/Makefile @@ -1,9 +1,5 @@ lte_dfts_sse4: lte_dfts.c -<<<<<<< HEAD - gcc -O2 -std=gnu99 -msse4.1 -g -ggdb -o lte_dfts_sse4 lte_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c $$OPENAIR_HOME/common/utils/backtrace.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS -======= gcc-7 -O3 -std=gnu99 -msse4.1 -o lte_dfts_sse4 lte_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS ->>>>>>> origin/develop-nr lte_dfts_avx2: lte_dfts.c gcc -O2 -std=gnu99 -mavx2 -g -ggdb -o lte_dfts_avx2 lte_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c $$OPENAIR_HOME/common/utils/backtrace.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS diff --git a/openair1/PHY/TOOLS/cmult_sv.c b/openair1/PHY/TOOLS/cmult_sv.c index 013fedc6e9..dc57964ca5 100644 --- a/openair1/PHY/TOOLS/cmult_sv.c +++ b/openair1/PHY/TOOLS/cmult_sv.c @@ -119,6 +119,32 @@ void multadd_real_vector_complex_scalar(int16_t *x, } +void multadd_real_four_symbols_vector_complex_scalar(int16_t *x, + int16_t *alpha, + int16_t *y) +{ + + // do 8 multiplications at a time + simd_q15_t alpha_r_128,alpha_i_128,yr,yi,*x_128=(simd_q15_t*)x; + simd_q15_t y_128; + y_128 = _mm_loadu_si128((simd_q15_t*)y); + + alpha_r_128 = set1_int16(alpha[0]); + alpha_i_128 = set1_int16(alpha[1]); + + + yr = mulhi_s1_int16(alpha_r_128,x_128[0]); + yi = mulhi_s1_int16(alpha_i_128,x_128[0]); + y_128 = _mm_adds_epi16(y_128,_mm_unpacklo_epi16(yr,yi)); + y_128 = _mm_adds_epi16(y_128,_mm_unpackhi_epi16(yr,yi)); + + _mm_storeu_si128((simd_q15_t*)y, y_128); + + _mm_empty(); + _m_empty(); + +} + /* int rotate_cpx_vector(int16_t *x, int16_t *alpha, diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c index cc89fb3f9b..40803c30f4 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.c +++ b/openair1/PHY/TOOLS/nr_phy_scope.c @@ -155,30 +155,30 @@ void phy_scope_gNB(FD_phy_scope_gnb *form, RU_t *phy_vars_ru, int UE_id) { - int i,i2,arx,atx,ind,k; + int i, arx; //int i,i2,arx,atx,ind,k; NR_DL_FRAME_PARMS *frame_parms = &phy_vars_gnb->frame_parms; int nsymb_ce = 12*frame_parms->N_RB_UL*frame_parms->symbols_per_tti; uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; uint8_t nb_antennas_tx = 1; // frame_parms->nb_antennas_tx; // in LTE Rel. 8 and 9 only a single transmit antenna is assumed at the UE int16_t **rxsig_t, **rxsig_f; - int16_t **chest_t=NULL; - int16_t **chest_f=NULL; - int16_t *pusch_llr=NULL; - int32_t *pusch_comp=NULL; - int32_t *pucch1_comp=NULL; - int32_t *pucch1_thres=NULL; - int32_t *pucch1ab_comp=NULL; - float Re,Im,ymax; + // int16_t **chest_t=NULL; + // int16_t **chest_f=NULL; + // int16_t *pusch_llr=NULL; + // int32_t *pusch_comp=NULL; + // int32_t *pucch1_comp=NULL; + // int32_t *pucch1_thres=NULL; + // int32_t *pucch1ab_comp=NULL; + // float Re,Im,ymax; float *llr, *bit; - float I[nsymb_ce*2], Q[nsymb_ce*2]; - float I_pucch[10240],Q_pucch[10240],A_pucch[10240],B_pucch[10240],C_pucch[10240]; + // float I[nsymb_ce*2], Q[nsymb_ce*2]; + // float I_pucch[10240],Q_pucch[10240],A_pucch[10240],B_pucch[10240],C_pucch[10240]; float *rxsig_t_dB[nb_antennas_rx]; float *rxsig_f_dB[nb_antennas_rx]; float time[frame_parms->samples_per_frame]; - float freq[nsymb_ce*nb_antennas_rx*nb_antennas_tx]; -// uint32_t total_dlsch_bitrate = phy_vars_gnb->total_dlsch_bitrate; + // float freq[nsymb_ce*nb_antennas_rx*nb_antennas_tx]; + // uint32_t total_dlsch_bitrate = phy_vars_gnb->total_dlsch_bitrate; int coded_bits_per_codeword = 0; - uint8_t harq_pid; // in TDD config 3 it is sf-2, i.e., can be 0,1,2 + // uint8_t harq_pid; // in TDD config 3 it is sf-2, i.e., can be 0,1,2 int Qm = 2; /* diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 8a2310378e..8e0406d07d 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -29,6 +29,10 @@ */ +#ifdef __cplusplus +extern "C" { +#endif + #include #include "PHY/sse_intrin.h" @@ -69,6 +73,10 @@ void multadd_real_vector_complex_scalar(int16_t *x, int16_t *y, uint32_t N); +void multadd_real_four_symbols_vector_complex_scalar(int16_t *x, + int16_t *alpha, + int16_t *y); + /*!\fn void multadd_complex_vector_real_scalar(int16_t *x,int16_t alpha,int16_t *y,uint8_t zero_flag,uint32_t N) This function performs componentwise multiplication and accumulation of a real scalar and a complex vector. @param x Vector input (Q1.15) in the format |Re0 Im0|Re1 Im 1| ... @@ -439,4 +447,8 @@ double interp(double x, double *xs, double *ys, int count); int write_output(const char *fname,const char *vname,void *data,int length,int dec,char format); +#ifdef __cplusplus +} +#endif + #endif //__PHY_TOOLS_DEFS__H__ diff --git a/openair1/PHY/TOOLS/twiddle3072.h b/openair1/PHY/TOOLS/twiddle3072.h deleted file mode 100644 index 099ef57455..0000000000 --- a/openair1/PHY/TOOLS/twiddle3072.h +++ /dev/null @@ -1,42 +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 - */ - -/* Twiddles generated with -twa = floor(32767*exp(-sqrt(-1)*2*pi*(0:1023)/3072)); -twb = floor(32767*exp(-sqrt(-1)*2*pi*(0:2:2046)/3072)); -twa2 = zeros(1,2048); -twb2 = zeros(1,2048); -twa2(1:2:end) = real(twa); -twa2(2:2:end) = imag(twa); -twb2(1:2:end) = real(twb); -twb2(2:2:end) = imag(twb); -fd=fopen("twiddle_tmp.txt","w"); -fprintf(fd,"static int16_t twa3072[2048] = {"); -fprintf(fd,"%d,",twa2); -fprintf(fd,"};\n"); -fprintf(fd,"static int16_t twb3072[2048] = {"); -fprintf(fd,"%d,",twb2); -fprintf(fd,"};\n"); -fclose(fd); - */ - -static int16_t twa3072[2048] = {32767,0,32766,-68,32766,-135,32766,-202,32765,-269,32765,-336,32764,-403,32763,-470,32762,-537,32761,-604,32760,-671,32758,-738,32757,-805,32755,-872,32753,-939,32751,-1006,32749,-1073,32747,-1140,32744,-1207,32742,-1274,32739,-1340,32736,-1407,32733,-1474,32730,-1541,32727,-1608,32724,-1675,32720,-1742,32717,-1809,32713,-1876,32709,-1943,32705,-2010,32701,-2077,32696,-2144,32692,-2210,32687,-2277,32683,-2344,32678,-2411,32673,-2478,32668,-2545,32662,-2611,32657,-2678,32651,-2745,32646,-2812,32640,-2879,32634,-2945,32628,-3012,32622,-3079,32615,-3146,32609,-3212,32602,-3279,32595,-3346,32588,-3412,32581,-3479,32574,-3546,32567,-3612,32559,-3679,32552,-3745,32544,-3812,32536,-3878,32528,-3945,32520,-4012,32512,-4078,32503,-4145,32495,-4211,32486,-4277,32477,-4344,32468,-4410,32459,-4477,32450,-4543,32441,-4609,32431,-4676,32422,-4742,32412,-4808,32402,-4875,32392,-4941,32382,-5007,32371,-5073,32361,-5140,32350,-5206,32340,-5272,32329,-5338,32318,-5404,32307,-5470,32295,-5536,32284,-5602,32273,-5668,32261,-5734,32249,-5800,32237,-5866,32225,-5932,32213,-5998,32201,-6064,32188,-6130,32176,-6196,32163,-6262,32150,-6327,32137,-6393,32124,-6459,32110,-6524,32097,-6590,32084,-6656,32070,-6721,32056,-6787,32042,-6852,32028,-6918,32014,-6983,31999,-7049,31985,-7114,31970,-7180,31956,-7245,31941,-7311,31926,-7376,31911,-7441,31895,-7506,31880,-7572,31864,-7637,31849,-7702,31833,-7767,31817,-7832,31801,-7897,31785,-7962,31768,-8027,31752,-8092,31735,-8157,31718,-8222,31701,-8287,31684,-8352,31667,-8416,31650,-8481,31633,-8546,31615,-8611,31597,-8675,31580,-8740,31562,-8804,31544,-8869,31525,-8933,31507,-8998,31489,-9062,31470,-9127,31451,-9191,31432,-9255,31413,-9320,31394,-9384,31375,-9448,31356,-9512,31336,-9576,31316,-9640,31297,-9704,31277,-9768,31257,-9832,31236,-9896,31216,-9960,31196,-10024,31175,-10088,31154,-10152,31134,-10215,31113,-10279,31092,-10343,31070,-10406,31049,-10470,31028,-10533,31006,-10597,30984,-10660,30962,-10723,30940,-10787,30918,-10850,30896,-10913,30874,-10976,30851,-11039,30828,-11102,30806,-11165,30783,-11228,30760,-11291,30737,-11354,30713,-11417,30690,-11480,30666,-11543,30643,-11605,30619,-11668,30595,-11731,30571,-11793,30547,-11856,30522,-11918,30498,-11981,30473,-12043,30449,-12105,30424,-12167,30399,-12230,30374,-12292,30349,-12354,30323,-12416,30298,-12478,30272,-12540,30247,-12602,30221,-12664,30195,-12725,30169,-12787,30142,-12849,30116,-12910,30090,-12972,30063,-13034,30036,-13095,30009,-13156,29983,-13218,29955,-13279,29928,-13340,29901,-13401,29873,-13463,29846,-13524,29818,-13585,29790,-13646,29762,-13707,29734,-13767,29706,-13828,29678,-13889,29649,-13950,29621,-14010,29592,-14071,29563,-14131,29534,-14192,29505,-14252,29476,-14312,29446,-14373,29417,-14433,29387,-14493,29358,-14553,29328,-14613,29298,-14673,29268,-14733,29238,-14793,29207,-14853,29177,-14912,29146,-14972,29116,-15031,29085,-15091,29054,-15150,29023,-15210,28992,-15269,28960,-15328,28929,-15388,28897,-15447,28866,-15506,28834,-15565,28802,-15624,28770,-15683,28738,-15741,28706,-15800,28673,-15859,28641,-15918,28608,-15976,28575,-16035,28543,-16093,28510,-16151,28477,-16210,28443,-16268,28410,-16326,28377,-16384,28343,-16442,28309,-16500,28275,-16558,28242,-16616,28208,-16673,28173,-16731,28139,-16789,28105,-16846,28070,-16904,28036,-16961,28001,-17018,27966,-17075,27931,-17133,27896,-17190,27861,-17247,27825,-17304,27790,-17361,27754,-17417,27719,-17474,27683,-17531,27647,-17587,27611,-17644,27575,-17700,27538,-17757,27502,-17813,27466,-17869,27429,-17925,27392,-17981,27355,-18037,27319,-18093,27281,-18149,27244,-18205,27207,-18261,27170,-18316,27132,-18372,27094,-18427,27057,-18483,27019,-18538,26981,-18593,26943,-18648,26905,-18703,26866,-18758,26828,-18813,26789,-18868,26751,-18923,26712,-18977,26673,-19032,26634,-19087,26595,-19141,26556,-19195,26516,-19250,26477,-19304,26437,-19358,26398,-19412,26358,-19466,26318,-19520,26278,-19574,26238,-19627,26198,-19681,26158,-19734,26117,-19788,26077,-19841,26036,-19895,25995,-19948,25954,-20001,25913,-20054,25872,-20107,25831,-20160,25790,-20213,25749,-20265,25707,-20318,25665,-20370,25624,-20423,25582,-20475,25540,-20528,25498,-20580,25456,-20632,25414,-20684,25371,-20736,25329,-20788,25286,-20839,25243,-20891,25201,-20943,25158,-20994,25115,-21046,25072,-21097,25029,-21148,24985,-21199,24942,-21250,24898,-21301,24855,-21352,24811,-21403,24767,-21454,24723,-21504,24679,-21555,24635,-21605,24591,-21656,24546,-21706,24502,-21756,24457,-21806,24413,-21856,24368,-21906,24323,-21956,24278,-22005,24233,-22055,24188,-22105,24143,-22154,24097,-22203,24052,-22253,24006,-22302,23961,-22351,23915,-22400,23869,-22449,23823,-22497,23777,-22546,23731,-22595,23685,-22643,23638,-22692,23592,-22740,23545,-22788,23499,-22836,23452,-22884,23405,-22932,23358,-22980,23311,-23028,23264,-23075,23217,-23123,23169,-23170,23122,-23218,23074,-23265,23027,-23312,22979,-23359,22931,-23406,22883,-23453,22835,-23500,22787,-23546,22739,-23593,22691,-23639,22642,-23686,22594,-23732,22545,-23778,22496,-23824,22448,-23870,22399,-23916,22350,-23962,22301,-24007,22252,-24053,22202,-24098,22153,-24144,22104,-24189,22054,-24234,22004,-24279,21955,-24324,21905,-24369,21855,-24414,21805,-24458,21755,-24503,21705,-24547,21655,-24592,21604,-24636,21554,-24680,21503,-24724,21453,-24768,21402,-24812,21351,-24856,21300,-24899,21249,-24943,21198,-24986,21147,-25030,21096,-25073,21045,-25116,20993,-25159,20942,-25202,20890,-25244,20838,-25287,20787,-25330,20735,-25372,20683,-25415,20631,-25457,20579,-25499,20527,-25541,20474,-25583,20422,-25625,20369,-25666,20317,-25708,20264,-25750,20212,-25791,20159,-25832,20106,-25873,20053,-25914,20000,-25955,19947,-25996,19894,-26037,19840,-26078,19787,-26118,19733,-26159,19680,-26199,19626,-26239,19573,-26279,19519,-26319,19465,-26359,19411,-26399,19357,-26438,19303,-26478,19249,-26517,19194,-26557,19140,-26596,19086,-26635,19031,-26674,18976,-26713,18922,-26752,18867,-26790,18812,-26829,18757,-26867,18702,-26906,18647,-26944,18592,-26982,18537,-27020,18482,-27058,18426,-27095,18371,-27133,18315,-27171,18260,-27208,18204,-27245,18148,-27282,18092,-27320,18036,-27356,17980,-27393,17924,-27430,17868,-27467,17812,-27503,17756,-27539,17699,-27576,17643,-27612,17586,-27648,17530,-27684,17473,-27720,17416,-27755,17360,-27791,17303,-27826,17246,-27862,17189,-27897,17132,-27932,17074,-27967,17017,-28002,16960,-28037,16903,-28071,16845,-28106,16788,-28140,16730,-28174,16672,-28209,16615,-28243,16557,-28276,16499,-28310,16441,-28344,16383,-28378,16325,-28411,16267,-28444,16209,-28478,16150,-28511,16092,-28544,16034,-28576,15975,-28609,15917,-28642,15858,-28674,15799,-28707,15740,-28739,15682,-28771,15623,-28803,15564,-28835,15505,-28867,15446,-28898,15387,-28930,15327,-28961,15268,-28993,15209,-29024,15149,-29055,15090,-29086,15030,-29117,14971,-29147,14911,-29178,14852,-29208,14792,-29239,14732,-29269,14672,-29299,14612,-29329,14552,-29359,14492,-29388,14432,-29418,14372,-29447,14311,-29477,14251,-29506,14191,-29535,14130,-29564,14070,-29593,14009,-29622,13949,-29650,13888,-29679,13827,-29707,13766,-29735,13706,-29763,13645,-29791,13584,-29819,13523,-29847,13462,-29874,13400,-29902,13339,-29929,13278,-29956,13217,-29984,13155,-30010,13094,-30037,13033,-30064,12971,-30091,12909,-30117,12848,-30143,12786,-30170,12724,-30196,12663,-30222,12601,-30248,12539,-30273,12477,-30299,12415,-30324,12353,-30350,12291,-30375,12229,-30400,12166,-30425,12104,-30450,12042,-30474,11980,-30499,11917,-30523,11855,-30548,11792,-30572,11730,-30596,11667,-30620,11604,-30644,11542,-30667,11479,-30691,11416,-30714,11353,-30738,11290,-30761,11227,-30784,11164,-30807,11101,-30829,11038,-30852,10975,-30875,10912,-30897,10849,-30919,10786,-30941,10722,-30963,10659,-30985,10596,-31007,10532,-31029,10469,-31050,10405,-31071,10342,-31093,10278,-31114,10214,-31135,10151,-31155,10087,-31176,10023,-31197,9959,-31217,9895,-31237,9831,-31258,9767,-31278,9703,-31298,9639,-31317,9575,-31337,9511,-31357,9447,-31376,9383,-31395,9319,-31414,9254,-31433,9190,-31452,9126,-31471,9061,-31490,8997,-31508,8932,-31526,8868,-31545,8803,-31563,8739,-31581,8674,-31598,8610,-31616,8545,-31634,8480,-31651,8415,-31668,8351,-31685,8286,-31702,8221,-31719,8156,-31736,8091,-31753,8026,-31769,7961,-31786,7896,-31802,7831,-31818,7766,-31834,7701,-31850,7636,-31865,7571,-31881,7505,-31896,7440,-31912,7375,-31927,7310,-31942,7244,-31957,7179,-31971,7113,-31986,7048,-32000,6982,-32015,6917,-32029,6851,-32043,6786,-32057,6720,-32071,6655,-32085,6589,-32098,6523,-32111,6458,-32125,6392,-32138,6326,-32151,6261,-32164,6195,-32177,6129,-32189,6063,-32202,5997,-32214,5931,-32226,5865,-32238,5799,-32250,5733,-32262,5667,-32274,5601,-32285,5535,-32296,5469,-32308,5403,-32319,5337,-32330,5271,-32341,5205,-32351,5139,-32362,5072,-32372,5006,-32383,4940,-32393,4874,-32403,4807,-32413,4741,-32423,4675,-32432,4608,-32442,4542,-32451,4476,-32460,4409,-32469,4343,-32478,4276,-32487,4210,-32496,4144,-32504,4077,-32513,4011,-32521,3944,-32529,3877,-32537,3811,-32545,3744,-32553,3678,-32560,3611,-32568,3545,-32575,3478,-32582,3411,-32589,3345,-32596,3278,-32603,3211,-32610,3145,-32616,3078,-32623,3011,-32629,2944,-32635,2878,-32641,2811,-32647,2744,-32652,2677,-32658,2610,-32663,2544,-32669,2477,-32674,2410,-32679,2343,-32684,2276,-32688,2209,-32693,2143,-32697,2076,-32702,2009,-32706,1942,-32710,1875,-32714,1808,-32718,1741,-32721,1674,-32725,1607,-32728,1540,-32731,1473,-32734,1406,-32737,1339,-32740,1273,-32743,1206,-32745,1139,-32748,1072,-32750,1005,-32752,938,-32754,871,-32756,804,-32758,737,-32759,670,-32761,603,-32762,536,-32763,469,-32764,402,-32765,335,-32766,268,-32766,201,-32767,134,-32767,67,-32767,0,-32767,-68,-32767,-135,-32767,-202,-32767,-269,-32766,-336,-32766,-403,-32765,-470,-32764,-537,-32763,-604,-32762,-671,-32761,-738,-32759,-805,-32758,-872,-32756,-939,-32754,-1006,-32752,-1073,-32750,-1140,-32748,-1207,-32745,-1274,-32743,-1340,-32740,-1407,-32737,-1474,-32734,-1541,-32731,-1608,-32728,-1675,-32725,-1742,-32721,-1809,-32718,-1876,-32714,-1943,-32710,-2010,-32706,-2077,-32702,-2144,-32697,-2210,-32693,-2277,-32688,-2344,-32684,-2411,-32679,-2478,-32674,-2545,-32669,-2611,-32663,-2678,-32658,-2745,-32652,-2812,-32647,-2879,-32641,-2945,-32635,-3012,-32629,-3079,-32623,-3146,-32616,-3212,-32610,-3279,-32603,-3346,-32596,-3412,-32589,-3479,-32582,-3546,-32575,-3612,-32568,-3679,-32560,-3745,-32553,-3812,-32545,-3878,-32537,-3945,-32529,-4012,-32521,-4078,-32513,-4145,-32504,-4211,-32496,-4277,-32487,-4344,-32478,-4410,-32469,-4477,-32460,-4543,-32451,-4609,-32442,-4676,-32432,-4742,-32423,-4808,-32413,-4875,-32403,-4941,-32393,-5007,-32383,-5073,-32372,-5140,-32362,-5206,-32351,-5272,-32341,-5338,-32330,-5404,-32319,-5470,-32308,-5536,-32296,-5602,-32285,-5668,-32274,-5734,-32262,-5800,-32250,-5866,-32238,-5932,-32226,-5998,-32214,-6064,-32202,-6130,-32189,-6196,-32177,-6262,-32164,-6327,-32151,-6393,-32138,-6459,-32125,-6524,-32111,-6590,-32098,-6656,-32085,-6721,-32071,-6787,-32057,-6852,-32043,-6918,-32029,-6983,-32015,-7049,-32000,-7114,-31986,-7180,-31971,-7245,-31957,-7311,-31942,-7376,-31927,-7441,-31912,-7506,-31896,-7572,-31881,-7637,-31865,-7702,-31850,-7767,-31834,-7832,-31818,-7897,-31802,-7962,-31786,-8027,-31769,-8092,-31753,-8157,-31736,-8222,-31719,-8287,-31702,-8352,-31685,-8416,-31668,-8481,-31651,-8546,-31634,-8611,-31616,-8675,-31598,-8740,-31581,-8804,-31563,-8869,-31545,-8933,-31526,-8998,-31508,-9062,-31490,-9127,-31471,-9191,-31452,-9255,-31433,-9320,-31414,-9384,-31395,-9448,-31376,-9512,-31357,-9576,-31337,-9640,-31317,-9704,-31298,-9768,-31278,-9832,-31258,-9896,-31237,-9960,-31217,-10024,-31197,-10088,-31176,-10152,-31155,-10215,-31135,-10279,-31114,-10343,-31093,-10406,-31071,-10470,-31050,-10533,-31029,-10597,-31007,-10660,-30985,-10723,-30963,-10787,-30941,-10850,-30919,-10913,-30897,-10976,-30875,-11039,-30852,-11102,-30829,-11165,-30807,-11228,-30784,-11291,-30761,-11354,-30738,-11417,-30714,-11480,-30691,-11543,-30667,-11605,-30644,-11668,-30620,-11731,-30596,-11793,-30572,-11856,-30548,-11918,-30523,-11981,-30499,-12043,-30474,-12105,-30450,-12167,-30425,-12230,-30400,-12292,-30375,-12354,-30350,-12416,-30324,-12478,-30299,-12540,-30273,-12602,-30248,-12664,-30222,-12725,-30196,-12787,-30170,-12849,-30143,-12910,-30117,-12972,-30091,-13034,-30064,-13095,-30037,-13156,-30010,-13218,-29984,-13279,-29956,-13340,-29929,-13401,-29902,-13463,-29874,-13524,-29847,-13585,-29819,-13646,-29791,-13707,-29763,-13767,-29735,-13828,-29707,-13889,-29679,-13950,-29650,-14010,-29622,-14071,-29593,-14131,-29564,-14192,-29535,-14252,-29506,-14312,-29477,-14373,-29447,-14433,-29418,-14493,-29388,-14553,-29359,-14613,-29329,-14673,-29299,-14733,-29269,-14793,-29239,-14853,-29208,-14912,-29178,-14972,-29147,-15031,-29117,-15091,-29086,-15150,-29055,-15210,-29024,-15269,-28993,-15328,-28961,-15388,-28930,-15447,-28898,-15506,-28867,-15565,-28835,-15624,-28803,-15683,-28771,-15741,-28739,-15800,-28707,-15859,-28674,-15918,-28642,-15976,-28609,-16035,-28576,-16093,-28544,-16151,-28511,-16210,-28478,-16268,-28444,-16326,-28411,}; -static int16_t twb3072[2048] = {32767,0,32766,-135,32765,-269,32764,-403,32762,-537,32760,-671,32757,-805,32753,-939,32749,-1073,32744,-1207,32739,-1340,32733,-1474,32727,-1608,32720,-1742,32713,-1876,32705,-2010,32696,-2144,32687,-2277,32678,-2411,32668,-2545,32657,-2678,32646,-2812,32634,-2945,32622,-3079,32609,-3212,32595,-3346,32581,-3479,32567,-3612,32552,-3745,32536,-3878,32520,-4012,32503,-4145,32486,-4277,32468,-4410,32450,-4543,32431,-4676,32412,-4808,32392,-4941,32371,-5073,32350,-5206,32329,-5338,32307,-5470,32284,-5602,32261,-5734,32237,-5866,32213,-5998,32188,-6130,32163,-6262,32137,-6393,32110,-6524,32084,-6656,32056,-6787,32028,-6918,31999,-7049,31970,-7180,31941,-7311,31911,-7441,31880,-7572,31849,-7702,31817,-7832,31785,-7962,31752,-8092,31718,-8222,31684,-8352,31650,-8481,31615,-8611,31580,-8740,31544,-8869,31507,-8998,31470,-9127,31432,-9255,31394,-9384,31356,-9512,31316,-9640,31277,-9768,31236,-9896,31196,-10024,31154,-10152,31113,-10279,31070,-10406,31028,-10533,30984,-10660,30940,-10787,30896,-10913,30851,-11039,30806,-11165,30760,-11291,30713,-11417,30666,-11543,30619,-11668,30571,-11793,30522,-11918,30473,-12043,30424,-12167,30374,-12292,30323,-12416,30272,-12540,30221,-12664,30169,-12787,30116,-12910,30063,-13034,30009,-13156,29955,-13279,29901,-13401,29846,-13524,29790,-13646,29734,-13767,29678,-13889,29621,-14010,29563,-14131,29505,-14252,29446,-14373,29387,-14493,29328,-14613,29268,-14733,29207,-14853,29146,-14972,29085,-15091,29023,-15210,28960,-15328,28897,-15447,28834,-15565,28770,-15683,28706,-15800,28641,-15918,28575,-16035,28510,-16151,28443,-16268,28377,-16384,28309,-16500,28242,-16616,28173,-16731,28105,-16846,28036,-16961,27966,-17075,27896,-17190,27825,-17304,27754,-17417,27683,-17531,27611,-17644,27538,-17757,27466,-17869,27392,-17981,27319,-18093,27244,-18205,27170,-18316,27094,-18427,27019,-18538,26943,-18648,26866,-18758,26789,-18868,26712,-18977,26634,-19087,26556,-19195,26477,-19304,26398,-19412,26318,-19520,26238,-19627,26158,-19734,26077,-19841,25995,-19948,25913,-20054,25831,-20160,25749,-20265,25665,-20370,25582,-20475,25498,-20580,25414,-20684,25329,-20788,25243,-20891,25158,-20994,25072,-21097,24985,-21199,24898,-21301,24811,-21403,24723,-21504,24635,-21605,24546,-21706,24457,-21806,24368,-21906,24278,-22005,24188,-22105,24097,-22203,24006,-22302,23915,-22400,23823,-22497,23731,-22595,23638,-22692,23545,-22788,23452,-22884,23358,-22980,23264,-23075,23169,-23170,23074,-23265,22979,-23359,22883,-23453,22787,-23546,22691,-23639,22594,-23732,22496,-23824,22399,-23916,22301,-24007,22202,-24098,22104,-24189,22004,-24279,21905,-24369,21805,-24458,21705,-24547,21604,-24636,21503,-24724,21402,-24812,21300,-24899,21198,-24986,21096,-25073,20993,-25159,20890,-25244,20787,-25330,20683,-25415,20579,-25499,20474,-25583,20369,-25666,20264,-25750,20159,-25832,20053,-25914,19947,-25996,19840,-26078,19733,-26159,19626,-26239,19519,-26319,19411,-26399,19303,-26478,19194,-26557,19086,-26635,18976,-26713,18867,-26790,18757,-26867,18647,-26944,18537,-27020,18426,-27095,18315,-27171,18204,-27245,18092,-27320,17980,-27393,17868,-27467,17756,-27539,17643,-27612,17530,-27684,17416,-27755,17303,-27826,17189,-27897,17074,-27967,16960,-28037,16845,-28106,16730,-28174,16615,-28243,16499,-28310,16383,-28378,16267,-28444,16150,-28511,16034,-28576,15917,-28642,15799,-28707,15682,-28771,15564,-28835,15446,-28898,15327,-28961,15209,-29024,15090,-29086,14971,-29147,14852,-29208,14732,-29269,14612,-29329,14492,-29388,14372,-29447,14251,-29506,14130,-29564,14009,-29622,13888,-29679,13766,-29735,13645,-29791,13523,-29847,13400,-29902,13278,-29956,13155,-30010,13033,-30064,12909,-30117,12786,-30170,12663,-30222,12539,-30273,12415,-30324,12291,-30375,12166,-30425,12042,-30474,11917,-30523,11792,-30572,11667,-30620,11542,-30667,11416,-30714,11290,-30761,11164,-30807,11038,-30852,10912,-30897,10786,-30941,10659,-30985,10532,-31029,10405,-31071,10278,-31114,10151,-31155,10023,-31197,9895,-31237,9767,-31278,9639,-31317,9511,-31357,9383,-31395,9254,-31433,9126,-31471,8997,-31508,8868,-31545,8739,-31581,8610,-31616,8480,-31651,8351,-31685,8221,-31719,8091,-31753,7961,-31786,7831,-31818,7701,-31850,7571,-31881,7440,-31912,7310,-31942,7179,-31971,7048,-32000,6917,-32029,6786,-32057,6655,-32085,6523,-32111,6392,-32138,6261,-32164,6129,-32189,5997,-32214,5865,-32238,5733,-32262,5601,-32285,5469,-32308,5337,-32330,5205,-32351,5072,-32372,4940,-32393,4807,-32413,4675,-32432,4542,-32451,4409,-32469,4276,-32487,4144,-32504,4011,-32521,3877,-32537,3744,-32553,3611,-32568,3478,-32582,3345,-32596,3211,-32610,3078,-32623,2944,-32635,2811,-32647,2677,-32658,2544,-32669,2410,-32679,2276,-32688,2143,-32697,2009,-32706,1875,-32714,1741,-32721,1607,-32728,1473,-32734,1339,-32740,1206,-32745,1072,-32750,938,-32754,804,-32758,670,-32761,536,-32763,402,-32765,268,-32766,134,-32767,0,-32767,-135,-32767,-269,-32766,-403,-32765,-537,-32763,-671,-32761,-805,-32758,-939,-32754,-1073,-32750,-1207,-32745,-1340,-32740,-1474,-32734,-1608,-32728,-1742,-32721,-1876,-32714,-2010,-32706,-2144,-32697,-2277,-32688,-2411,-32679,-2545,-32669,-2678,-32658,-2812,-32647,-2945,-32635,-3079,-32623,-3212,-32610,-3346,-32596,-3479,-32582,-3612,-32568,-3745,-32553,-3878,-32537,-4012,-32521,-4145,-32504,-4277,-32487,-4410,-32469,-4543,-32451,-4676,-32432,-4808,-32413,-4941,-32393,-5073,-32372,-5206,-32351,-5338,-32330,-5470,-32308,-5602,-32285,-5734,-32262,-5866,-32238,-5998,-32214,-6130,-32189,-6262,-32164,-6393,-32138,-6524,-32111,-6656,-32085,-6787,-32057,-6918,-32029,-7049,-32000,-7180,-31971,-7311,-31942,-7441,-31912,-7572,-31881,-7702,-31850,-7832,-31818,-7962,-31786,-8092,-31753,-8222,-31719,-8352,-31685,-8481,-31651,-8611,-31616,-8740,-31581,-8869,-31545,-8998,-31508,-9127,-31471,-9255,-31433,-9384,-31395,-9512,-31357,-9640,-31317,-9768,-31278,-9896,-31237,-10024,-31197,-10152,-31155,-10279,-31114,-10406,-31071,-10533,-31029,-10660,-30985,-10787,-30941,-10913,-30897,-11039,-30852,-11165,-30807,-11291,-30761,-11417,-30714,-11543,-30667,-11668,-30620,-11793,-30572,-11918,-30523,-12043,-30474,-12167,-30425,-12292,-30375,-12416,-30324,-12540,-30273,-12664,-30222,-12787,-30170,-12910,-30117,-13034,-30064,-13156,-30010,-13279,-29956,-13401,-29902,-13524,-29847,-13646,-29791,-13767,-29735,-13889,-29679,-14010,-29622,-14131,-29564,-14252,-29506,-14373,-29447,-14493,-29388,-14613,-29329,-14733,-29269,-14853,-29208,-14972,-29147,-15091,-29086,-15210,-29024,-15328,-28961,-15447,-28898,-15565,-28835,-15683,-28771,-15800,-28707,-15918,-28642,-16035,-28576,-16151,-28511,-16268,-28444,-16384,-28378,-16500,-28310,-16616,-28243,-16731,-28174,-16846,-28106,-16961,-28037,-17075,-27967,-17190,-27897,-17304,-27826,-17417,-27755,-17531,-27684,-17644,-27612,-17757,-27539,-17869,-27467,-17981,-27393,-18093,-27320,-18205,-27245,-18316,-27171,-18427,-27095,-18538,-27020,-18648,-26944,-18758,-26867,-18868,-26790,-18977,-26713,-19087,-26635,-19195,-26557,-19304,-26478,-19412,-26399,-19520,-26319,-19627,-26239,-19734,-26159,-19841,-26078,-19948,-25996,-20054,-25914,-20160,-25832,-20265,-25750,-20370,-25666,-20475,-25583,-20580,-25499,-20684,-25415,-20788,-25330,-20891,-25244,-20994,-25159,-21097,-25073,-21199,-24986,-21301,-24899,-21403,-24812,-21504,-24724,-21605,-24636,-21706,-24547,-21806,-24458,-21906,-24369,-22005,-24279,-22105,-24189,-22203,-24098,-22302,-24007,-22400,-23916,-22497,-23824,-22595,-23732,-22692,-23639,-22788,-23546,-22884,-23453,-22980,-23359,-23075,-23265,-23170,-23170,-23265,-23075,-23359,-22980,-23453,-22884,-23546,-22788,-23639,-22692,-23732,-22595,-23824,-22497,-23916,-22400,-24007,-22302,-24098,-22203,-24189,-22105,-24279,-22005,-24369,-21906,-24458,-21806,-24547,-21706,-24636,-21605,-24724,-21504,-24812,-21403,-24899,-21301,-24986,-21199,-25073,-21097,-25159,-20994,-25244,-20891,-25330,-20788,-25415,-20684,-25499,-20580,-25583,-20475,-25666,-20370,-25750,-20265,-25832,-20160,-25914,-20054,-25996,-19948,-26078,-19841,-26159,-19734,-26239,-19627,-26319,-19520,-26399,-19412,-26478,-19304,-26557,-19195,-26635,-19087,-26713,-18977,-26790,-18868,-26867,-18758,-26944,-18648,-27020,-18538,-27095,-18427,-27171,-18316,-27245,-18205,-27320,-18093,-27393,-17981,-27467,-17869,-27539,-17757,-27612,-17644,-27684,-17531,-27755,-17417,-27826,-17304,-27897,-17190,-27967,-17075,-28037,-16961,-28106,-16846,-28174,-16731,-28243,-16616,-28310,-16500,-28378,-16384,-28444,-16268,-28511,-16151,-28576,-16035,-28642,-15918,-28707,-15800,-28771,-15683,-28835,-15565,-28898,-15447,-28961,-15328,-29024,-15210,-29086,-15091,-29147,-14972,-29208,-14853,-29269,-14733,-29329,-14613,-29388,-14493,-29447,-14373,-29506,-14252,-29564,-14131,-29622,-14010,-29679,-13889,-29735,-13767,-29791,-13646,-29847,-13524,-29902,-13401,-29956,-13279,-30010,-13156,-30064,-13034,-30117,-12910,-30170,-12787,-30222,-12664,-30273,-12540,-30324,-12416,-30375,-12292,-30425,-12167,-30474,-12043,-30523,-11918,-30572,-11793,-30620,-11668,-30667,-11543,-30714,-11417,-30761,-11291,-30807,-11165,-30852,-11039,-30897,-10913,-30941,-10787,-30985,-10660,-31029,-10533,-31071,-10406,-31114,-10279,-31155,-10152,-31197,-10024,-31237,-9896,-31278,-9768,-31317,-9640,-31357,-9512,-31395,-9384,-31433,-9255,-31471,-9127,-31508,-8998,-31545,-8869,-31581,-8740,-31616,-8611,-31651,-8481,-31685,-8352,-31719,-8222,-31753,-8092,-31786,-7962,-31818,-7832,-31850,-7702,-31881,-7572,-31912,-7441,-31942,-7311,-31971,-7180,-32000,-7049,-32029,-6918,-32057,-6787,-32085,-6656,-32111,-6524,-32138,-6393,-32164,-6262,-32189,-6130,-32214,-5998,-32238,-5866,-32262,-5734,-32285,-5602,-32308,-5470,-32330,-5338,-32351,-5206,-32372,-5073,-32393,-4941,-32413,-4808,-32432,-4676,-32451,-4543,-32469,-4410,-32487,-4277,-32504,-4145,-32521,-4012,-32537,-3878,-32553,-3745,-32568,-3612,-32582,-3479,-32596,-3346,-32610,-3212,-32623,-3079,-32635,-2945,-32647,-2812,-32658,-2678,-32669,-2545,-32679,-2411,-32688,-2277,-32697,-2144,-32706,-2010,-32714,-1876,-32721,-1742,-32728,-1608,-32734,-1474,-32740,-1340,-32745,-1207,-32750,-1073,-32754,-939,-32758,-805,-32761,-671,-32763,-537,-32765,-403,-32766,-269,-32767,-135,-32767,-1,-32767,134,-32766,268,-32765,402,-32763,536,-32761,670,-32758,804,-32754,938,-32750,1072,-32745,1206,-32740,1339,-32734,1473,-32728,1607,-32721,1741,-32714,1875,-32706,2009,-32697,2143,-32688,2276,-32679,2410,-32669,2544,-32658,2677,-32647,2811,-32635,2944,-32623,3078,-32610,3211,-32596,3345,-32582,3478,-32568,3611,-32553,3744,-32537,3877,-32521,4011,-32504,4144,-32487,4276,-32469,4409,-32451,4542,-32432,4675,-32413,4807,-32393,4940,-32372,5072,-32351,5205,-32330,5337,-32308,5469,-32285,5601,-32262,5733,-32238,5865,-32214,5997,-32189,6129,-32164,6261,-32138,6392,-32111,6523,-32085,6655,-32057,6786,-32029,6917,-32000,7048,-31971,7179,-31942,7310,-31912,7440,-31881,7571,-31850,7701,-31818,7831,-31786,7961,-31753,8091,-31719,8221,-31685,8351,-31651,8480,-31616,8610,-31581,8739,-31545,8868,-31508,8997,-31471,9126,-31433,9254,-31395,9383,-31357,9511,-31317,9639,-31278,9767,-31237,9895,-31197,10023,-31155,10151,-31114,10278,-31071,10405,-31029,10532,-30985,10659,-30941,10786,-30897,10912,-30852,11038,-30807,11164,-30761,11290,-30714,11416,-30667,11542,-30620,11667,-30572,11792,-30523,11917,-30474,12042,-30425,12166,-30375,12291,-30324,12415,-30273,12539,-30222,12663,-30170,12786,-30117,12909,-30064,13033,-30010,13155,-29956,13278,-29902,13400,-29847,13523,-29791,13645,-29735,13766,-29679,13888,-29622,14009,-29564,14130,-29506,14251,-29447,14372,-29388,14492,-29329,14612,-29269,14732,-29208,14852,-29147,14971,-29086,15090,-29024,15209,-28961,15327,-28898,15446,-28835,15564,-28771,15682,-28707,15799,-28642,15917,-28576,16034,-28511,16150,-28444,16267,-28378,16383,-28310,16499,-28243,16615,-28174,16730,-28106,16845,-28037,16960,-27967,17074,-27897,17189,-27826,17303,-27755,17416,-27684,17530,-27612,17643,-27539,17756,-27467,17868,-27393,17980,-27320,18092,-27245,18204,-27171,18315,-27095,18426,-27020,18537,-26944,18647,-26867,18757,-26790,18867,-26713,18976,-26635,19086,-26557,19194,-26478,19303,-26399,19411,-26319,19519,-26239,19626,-26159,19733,-26078,19840,-25996,19947,-25914,20053,-25832,20159,-25750,20264,-25666,20369,-25583,20474,-25499,20579,-25415,20683,-25330,20787,-25244,20890,-25159,20993,-25073,21096,-24986,21198,-24899,21300,-24812,21402,-24724,21503,-24636,21604,-24547,21705,-24458,21805,-24369,21905,-24279,22004,-24189,22104,-24098,22202,-24007,22301,-23916,22399,-23824,22496,-23732,22594,-23639,22691,-23546,22787,-23453,22883,-23359,22979,-23265,23074,-23170,23169,-23075,23264,-22980,23358,-22884,23452,-22788,23545,-22692,23638,-22595,23731,-22497,23823,-22400,23915,-22302,24006,-22203,24097,-22105,24188,-22005,24278,-21906,24368,-21806,24457,-21706,24546,-21605,24635,-21504,24723,-21403,24811,-21301,24898,-21199,24985,-21097,25072,-20994,25158,-20891,25243,-20788,25329,-20684,25414,-20580,25498,-20475,25582,-20370,25665,-20265,25749,-20160,25831,-20054,25913,-19948,25995,-19841,26077,-19734,26158,-19627,26238,-19520,26318,-19412,26398,-19304,26477,-19195,26556,-19087,26634,-18977,26712,-18868,26789,-18758,26866,-18648,26943,-18538,27019,-18427,27094,-18316,27170,-18205,27244,-18093,27319,-17981,27392,-17869,27466,-17757,27538,-17644,27611,-17531,27683,-17417,27754,-17304,27825,-17190,27896,-17075,27966,-16961,28036,-16846,28105,-16731,28173,-16616,28242,-16500,28309,}; diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 3521ba56bc..10496ced20 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -37,7 +37,7 @@ #include "common_lib.h" #include "openairinterface5g_limits.h" #include "PHY/TOOLS/time_meas.h" -#include "openair1/PHY/defs_common.h" +#include "defs_common.h" #define MAX_BANDS_PER_RRU 4 @@ -412,7 +412,7 @@ typedef enum { } rru_state_t; -/// Some commamds to RRU. Not sure we should do it like this ! +/// Some commands to RRU. Not sure we should do it like this ! typedef enum { EMPTY = 0, STOP_RU = 1, @@ -434,7 +434,7 @@ typedef struct RU_t_s { node_function_t function; /// Ethernet parameters for fronthaul interface eth_params_t eth_params; - /// flag to indicate the RU is in synch with a master reference + /// flag to indicate the RU is in sync with a master reference int in_synch; /// timing offset int rx_offset; @@ -567,7 +567,7 @@ typedef struct RU_t_s { time_stats_t rx_fhaul; /// Timing statistics (TX Fronthaul + Compression) time_stats_t tx_fhaul; - /// Timong statistics (Compression) + /// Timing statistics (Compression) time_stats_t compression; /// Timing statistics (Fronthaul transport) time_stats_t transport; @@ -621,7 +621,9 @@ typedef enum { RRU_sync_ok=6, RRU_frame_resynch=7, RRU_MSG_max_num=8, - RRU_check_sync = 9 + RRU_check_sync = 9, + RRU_config_update=10, + RRU_config_update_ok=11 } rru_config_msg_type_t; @@ -680,7 +682,7 @@ typedef struct RRU_config_s { uint32_t tx_freq[MAX_BANDS_PER_RRU]; /// RX frequency uint32_t rx_freq[MAX_BANDS_PER_RRU]; - /// TX attenation w.r.t. max + /// TX attenuation w.r.t. max uint8_t att_tx[MAX_BANDS_PER_RRU]; /// RX attenuation w.r.t. max uint8_t att_rx[MAX_BANDS_PER_RRU]; @@ -699,7 +701,7 @@ typedef struct RRU_config_s { int emtc_prach_FreqOffset[MAX_BANDS_PER_RRU][4]; /// emtc_prach_ConfigIndex for IF4p5 per CE Level int emtc_prach_ConfigIndex[MAX_BANDS_PER_RRU][4]; - /// mutex for asynch RX/TX thread + /// mutex for async RX/TX thread pthread_mutex_t mutex_asynch_rxtx; /// mutex for RU access to eNB processing (PDSCH/PUSCH) pthread_mutex_t mutex_RU; @@ -715,6 +717,10 @@ typedef struct RRU_config_s { time_stats_t ru_arrival_time; /// mask for RUs serving eNB (PRACH) int RU_mask_prach; + /// embms mbsfn sf config + int num_MBSFN_config; + /// embms mbsfn sf config + MBSFN_config_t MBSFN_config[8]; } RRU_config_t; #endif //__PHY_DEFS_RU__H__ diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h index 2dffd09131..9163fc13b6 100644 --- a/openair1/PHY/defs_UE.h +++ b/openair1/PHY/defs_UE.h @@ -671,7 +671,7 @@ typedef struct { LTE_UE_PDSCH *pdsch_vars_SI[NUMBER_OF_CONNECTED_eNB_MAX+1]; LTE_UE_PDSCH *pdsch_vars_ra[NUMBER_OF_CONNECTED_eNB_MAX+1]; LTE_UE_PDSCH *pdsch_vars_p[NUMBER_OF_CONNECTED_eNB_MAX+1]; - LTE_UE_PDSCH *pdsch_vars_MCH[NUMBER_OF_CONNECTED_eNB_MAX]; + LTE_UE_PDSCH *pdsch_vars_MCH[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX]; LTE_UE_PBCH *pbch_vars[NUMBER_OF_CONNECTED_eNB_MAX]; LTE_UE_PDCCH *pdcch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX]; LTE_UE_PRACH *prach_vars[NUMBER_OF_CONNECTED_eNB_MAX]; diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index e5cbe4b756..f52558b632 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -72,13 +72,10 @@ #include "types.h" #include "nfapi_interface.h" -//#include "defs.h" - -#include "defs_RU.h" #define RX_NB_TH_MAX 2 #define RX_NB_TH 2 -#define RX_NB_TH_DL 2 +#define RX_NB_TH_DL 14 #define LTE_SLOTS_PER_SUBFRAME 2 diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index 943dd672e2..7b06f6c8c7 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -57,6 +57,7 @@ #include "common_lib.h" #include "msc.h" #include "defs_common.h" +#include "defs_RU.h" #include "impl_defs_top.h" #include "PHY/TOOLS/time_meas.h" //#include "PHY/CODING/coding_defs.h" @@ -72,7 +73,6 @@ #define MAX_NUM_RU_PER_eNB 64 #define MAX_NUM_RX_PRACH_PREAMBLES 4 - typedef struct { /// \brief Pointers (dynamic) to the received data in the time domain. /// - first index: rx antenna [0..nb_antennas_rx[ diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index f5e41e00e8..d64153414f 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -40,10 +40,17 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/impl_defs_top.h" #include "PHY/defs_common.h" -#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h" +#include "PHY/CODING/nrLDPC_extern.h" #include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" #define MAX_NUM_RU_PER_gNB MAX_NUM_RU_PER_eNB +#define MAX_PUCCH0_NID 8 + +typedef struct { + int nb_id; + int Nid[MAX_PUCCH0_NID]; + int lut[MAX_PUCCH0_NID][160][14]; +} NR_gNB_PUCCH0_LUT_t; typedef struct { uint32_t pbch_a; @@ -162,7 +169,7 @@ typedef struct { typedef struct { /// Nfapi ULSCH PDU - nfapi_nr_ul_config_ulsch_pdu ulsch_pdu; + nfapi_nr_pusch_pdu_t ulsch_pdu; /// Frame where current HARQ round was sent uint32_t frame; /// Subframe where current HARQ round was sent @@ -363,6 +370,14 @@ typedef struct { /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ int32_t **ul_ch_estimates_ext; + /// \brief Hold the PTRS phase estimates in frequency domain. + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_ptrs_estimates; + /// \brief Uplink phase estimates extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_ptrs_estimates_ext; /// \brief Holds the compensated signal. /// - first index: rx antenna id [0..nb_antennas_rx[ /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ @@ -402,6 +417,16 @@ typedef struct { /// \brief llr values. /// - first index: ? [0..1179743] (hard coded) int16_t *llr; + /// DMRS symbol index, to be updated every DMRS symbol within a slot. + uint8_t dmrs_symbol; + // PTRS symbol index, to be updated every PTRS symbol within a slot. + uint8_t ptrs_symbol_index; + /// bit mask of PT-RS ofdm symbol indicies + uint16_t ptrs_symbols; + // PTRS subcarriers per OFDM symbol + uint16_t ptrs_sc_per_ofdm_symbol; + /// flag to verify if channel level computation is done + uint8_t cl_done; } NR_gNB_PUSCH; @@ -629,6 +654,8 @@ typedef struct PHY_VARS_gNB_s { uint8_t pbch_configured; char gNB_generate_rar; + // PUCCH0 Look-up table for cyclic-shifts + NR_gNB_PUCCH0_LUT_t pucch0_lut; /// NR synchronization sequences int16_t d_pss[NR_PSS_LENGTH]; int16_t d_sss[NR_SSS_LENGTH]; @@ -644,9 +671,9 @@ typedef struct PHY_VARS_gNB_s { /// PDSCH DMRS sequence uint32_t ****nr_gold_pdsch_dmrs; - + /// PUSCH DMRS - uint32_t nr_gold_pusch[2][20][2][NR_MAX_PUSCH_DMRS_INIT_LENGTH_DWORD]; + uint32_t ****nr_gold_pusch_dmrs; /// Indicator set to 0 after first SR uint8_t first_sr[NUMBER_OF_NR_SR_MAX]; diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index dcf9642d09..6f6c5ac8e9 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -811,6 +811,16 @@ typedef struct UE_NR_SCAN_INFO_s { int32_t freq_offset_Hz[3][10]; } UE_NR_SCAN_INFO_t; +typedef struct NR_UL_TIME_ALIGNMENT { + /// flag used by MAC to inform PHY about a TA to be applied + unsigned char apply_ta; + /// frame and slot when to apply the TA as stated in TS 38.213 setion 4.2 + int16_t ta_frame; + char ta_slot; + /// TA command and TAGID received from the gNB + uint8_t ta_command; + uint8_t tag_id; +} NR_UL_TIME_ALIGNMENT_t; #include "NR_IF_Module.h" @@ -888,7 +898,7 @@ typedef struct { //fapi_nr_dci_indication_t dci_ind; // point to the current rxTx thread index - uint8_t current_thread_id[40]; + uint8_t current_thread_id[NR_MAX_SLOTS_PER_FRAME]; t_nrPolar_params *polarList; NR_UE_PDSCH *pdsch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX+1]; // two RxTx Threads @@ -944,6 +954,9 @@ typedef struct { /// PUSCH DMRS sequence uint32_t ****nr_gold_pusch_dmrs; + /// flag to indicate if PTRS is configured + uint8_t ptrs_configured; + uint32_t X_u[64][839]; uint32_t high_speed_flag; @@ -1002,15 +1015,21 @@ typedef struct { // uint8_t prach_timer; uint8_t decode_SIB; uint8_t decode_MIB; + uint8_t init_sync_frame; /// temporary offset during cell search prior to MIB decoding int ssb_offset; uint16_t symbol_offset; // offset in terms of symbols for detected ssb in sync int rx_offset; /// Timing offset int rx_offset_diff; /// Timing adjustment for ofdm symbol0 on HW USRP int time_sync_cell; - int timing_advance; ///timing advance signalled from eNB - int hw_timing_advance; - int N_TA_offset; ///timing offset used in TDD + + /// Timing Advance updates variables + /// Timing advance update computed from the TA command signalled from gNB + int timing_advance; + int hw_timing_advance; + int N_TA_offset; ///timing offset used in TDD + NR_UL_TIME_ALIGNMENT_t ul_time_alignment[NUMBER_OF_CONNECTED_gNB_MAX]; + /// Flag to tell if UE is secondary user (cognitive mode) unsigned char is_secondary_ue; /// Flag to tell if secondary eNB has channel estimates to create NULL-beams from. @@ -1070,7 +1089,6 @@ typedef struct { crossCarrierSchedulingConfig_t crossCarrierSchedulingConfig; supplementaryUplink_t supplementaryUplink; - dmrs_UplinkConfig_t dmrs_UplinkConfig; dmrs_DownlinkConfig_t dmrs_DownlinkConfig; csi_MeasConfig_t csi_MeasConfig; PUSCH_ServingCellConfig_t PUSCH_ServingCellConfig; diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 487b28473f..ccc79b7d47 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -223,7 +223,13 @@ typedef struct { NR_PRACH_CONFIG_INFO prach_ConfigInfo; } NR_PRACH_CONFIG_COMMON; -typedef struct NR_DL_FRAME_PARMS { +typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; + +typedef uint32_t (*get_samples_per_slot_t)(int slot, NR_DL_FRAME_PARMS* fp); + +typedef uint32_t (*get_samples_slot_timestamp_t)(int slot, NR_DL_FRAME_PARMS* fp, uint8_t sl_ahead); + +struct NR_DL_FRAME_PARMS { /// frequency range nr_frequency_range_e freq_range; // /// Placeholder to replace overlapping fields below @@ -270,12 +276,18 @@ typedef struct NR_DL_FRAME_PARMS { uint16_t symbols_per_slot; /// Number of slots per subframe uint16_t slots_per_subframe; - /// Number of slots per frame + /// Number of slots per frame uint16_t slots_per_frame; /// Number of samples in a subframe uint32_t samples_per_subframe; - /// Number of samples in a slot - uint32_t samples_per_slot; + /// Number of samples in current slot + get_samples_per_slot_t get_samples_per_slot; + /// Number of samples before slot + get_samples_slot_timestamp_t get_samples_slot_timestamp; + /// Number of samples in 0th and center slot of a subframe + uint32_t samples_per_slot0; + /// Number of samples in other slots of the subframe + uint32_t samples_per_slotN0; /// Number of OFDM/SC-FDMA symbols in one subframe (to be modified to account for potential different in UL/DL) uint16_t symbols_per_tti; /// Number of samples in a radio frame @@ -339,7 +351,7 @@ typedef struct NR_DL_FRAME_PARMS { /// PBCH polar encoder params t_nrPolar_params pbch_polar_params; -} NR_DL_FRAME_PARMS; +}; #define KHz (1000UL) #define MHz (1000*KHz) diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h index 6a5cf76f98..44f2e314ea 100644 --- a/openair1/PHY/impl_defs_nr.h +++ b/openair1/PHY/impl_defs_nr.h @@ -36,6 +36,7 @@ #include #include "types.h" +#include "NR_PDSCH-TimeDomainResourceAllocation.h" #ifdef DEFINE_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H #define EXTERN @@ -350,8 +351,10 @@ typedef enum { ////////////////////////////////////////////////////////////////////////////////################################ -#define MAX_NR_RATE_MATCH_PATTERNS 4 -#define MAX_NR_ZP_CSI_RS_RESOURCES 32 +#define MAX_NR_RATE_MATCH_PATTERNS 4 +#define MAX_NR_ZP_CSI_RS_RESOURCES 32 +#define MAX_NR_OF_DL_ALLOCATIONS 16 +#define MAX_NR_OF_UL_ALLOCATIONS (16) typedef enum{ dl_resourceAllocationType0 = 1, @@ -446,6 +449,8 @@ typedef struct { */ maxNrofCodeWordsScheduledByDCI_t maxNrofCodeWordsScheduledByDCI; + NR_PDSCH_TimeDomainResourceAllocation_t *pdsch_TimeDomainResourceAllocation[MAX_NR_OF_DL_ALLOCATIONS]; + } PDSCH_Config_t; /*********************************************************************** @@ -456,7 +461,6 @@ typedef struct { * ************************************************************************/ -#define MAX_NR_OF_UL_ALLOCATIONS (16) typedef enum { enable_tpc_accumulation = 0, /* by default it is enable */ @@ -479,9 +483,6 @@ typedef struct { uint8_t startSymbolAndLength; } PUSCH_TimeDomainResourceAllocation_t; ////////////////////////////////////////////////////////////////////////////////################################ -typedef struct { // The IE PTRS-UplinkConfig is used to configure uplink Phase-Tracking-Reference-Signals (PTRS) - -} ptrs_UplinkConfig_t; typedef enum{ maxCodeBlockGroupsPerTransportBlock_n2 = 2, maxCodeBlockGroupsPerTransportBlock_n4 = 4, @@ -499,8 +500,8 @@ typedef enum { pdsch_dmrs_type2 = 2 } pdsch_dmrs_type_t; typedef enum { - pusch_dmrs_type1 = 1, - pusch_dmrs_type2 = 2 + pusch_dmrs_type1 = 0, + pusch_dmrs_type2 = 1 } pusch_dmrs_type_t; typedef enum { pdsch_dmrs_pos0 = 0, @@ -510,8 +511,15 @@ typedef enum { typedef enum { pusch_dmrs_pos0 = 0, pusch_dmrs_pos1 = 1, + pusch_dmrs_pos2 = 2, pusch_dmrs_pos3 = 3, } pusch_dmrs_AdditionalPosition_t; +typedef enum { + offset00 = 0, + offset01 = 1, + offset10 = 2, + offset11 = 3, +} ptrs_resource_elementoffset_t; typedef enum { pdsch_len1 = 1, pdsch_len2 = 2 @@ -520,6 +528,22 @@ typedef enum { pusch_len1 = 1, pusch_len2 = 2 } pusch_maxLength_t; +typedef struct { + uint8_t ptrs_mcs1; + uint8_t ptrs_mcs2; + uint8_t ptrs_mcs3; +} ptrs_time_density_t; +typedef struct { + uint16_t n_rb0; + uint16_t n_rb1; +} ptrs_frequency_density_t; +typedef struct { // The IE PTRS-UplinkConfig is used to configure uplink Phase-Tracking-Reference-Signals (PTRS) + uint8_t num_ptrs_ports; + ptrs_resource_elementoffset_t resourceElementOffset; + ptrs_time_density_t timeDensity; + ptrs_frequency_density_t frequencyDensity; + uint32_t ul_ptrs_power; +} ptrs_UplinkConfig_t; typedef struct { // The IE DMRS-DownlinkConfig is used to configure downlink demodulation reference signals for PDSCH pdsch_dmrs_type_t pdsch_dmrs_type; pdsch_dmrs_AdditionalPosition_t pdsch_dmrs_AdditionalPosition; @@ -531,6 +555,7 @@ typedef struct { // The IE DMRS-UplinkConfig is used to configure uplink demodul pusch_dmrs_type_t pusch_dmrs_type; pusch_dmrs_AdditionalPosition_t pusch_dmrs_AdditionalPosition; pusch_maxLength_t pusch_maxLength; + ptrs_UplinkConfig_t ptrs_UplinkConfig; uint16_t scramblingID0; uint16_t scramblingID1; } dmrs_UplinkConfig_t; @@ -615,6 +640,10 @@ typedef struct { * resourceAllocation */ ul_resourceAllocation_t ul_resourceAllocation; +/* + * DMRS-Uplinkconfig + */ + dmrs_UplinkConfig_t dmrs_UplinkConfig; /* * rgb_Size */ diff --git a/openair1/PHY/phy_extern.h b/openair1/PHY/phy_extern.h index 4280b684f9..deb7087c8c 100644 --- a/openair1/PHY/phy_extern.h +++ b/openair1/PHY/phy_extern.h @@ -69,7 +69,6 @@ extern uint16_t NB_UE_INST; extern unsigned char NB_RN_INST; #endif -extern unsigned int ULSCH_max_consecutive_errors; extern int flag_LA; extern double sinr_bler_map[MCS_COUNT][2][MCS_TABLE_LENGTH_MAX]; extern double sinr_bler_map_up[MCS_COUNT][2][16]; diff --git a/openair1/PHY/phy_extern_nr_ue.h b/openair1/PHY/phy_extern_nr_ue.h index 2a4292a779..569bec6851 100644 --- a/openair1/PHY/phy_extern_nr_ue.h +++ b/openair1/PHY/phy_extern_nr_ue.h @@ -66,7 +66,6 @@ extern uint16_t NB_UE_INST; extern unsigned char NB_RN_INST; #endif -extern unsigned int ULSCH_max_consecutive_errors; extern int flag_LA; extern double sinr_bler_map[MCS_COUNT][2][MCS_TABLE_LENGTH_MAX]; extern double sinr_bler_map_up[MCS_COUNT][2][16]; diff --git a/openair1/PHY/phy_extern_ue.h b/openair1/PHY/phy_extern_ue.h index 490d7b578f..4f9ed0f26b 100644 --- a/openair1/PHY/phy_extern_ue.h +++ b/openair1/PHY/phy_extern_ue.h @@ -66,7 +66,6 @@ extern uint16_t NB_UE_INST; extern unsigned char NB_RN_INST; #endif -extern unsigned int ULSCH_max_consecutive_errors; extern int flag_LA; extern double sinr_bler_map[MCS_COUNT][2][MCS_TABLE_LENGTH_MAX]; extern double sinr_bler_map_up[MCS_COUNT][2][16]; diff --git a/openair1/PHY/phy_vars.h b/openair1/PHY/phy_vars.h index 492abe7e8d..26540f6fc8 100644 --- a/openair1/PHY/phy_vars.h +++ b/openair1/PHY/phy_vars.h @@ -65,8 +65,6 @@ unsigned char NB_RN_INST=0; unsigned char NB_INST=0; #endif -unsigned int ULSCH_max_consecutive_errors = 20; - int number_of_cards; diff --git a/openair1/PHY/phy_vars_nr_ue.h b/openair1/PHY/phy_vars_nr_ue.h index c3eecb9008..bd077b5b0c 100644 --- a/openair1/PHY/phy_vars_nr_ue.h +++ b/openair1/PHY/phy_vars_nr_ue.h @@ -64,7 +64,6 @@ unsigned char NB_RN_INST=0; unsigned char NB_INST=0; #endif -unsigned int ULSCH_max_consecutive_errors = 20; int number_of_cards; @@ -141,4 +140,6 @@ int16_t unscrambling_lut[65536*16] __attribute__((aligned(32))); uint8_t scrambling_lut[65536*16] __attribute__((aligned(32))); uint8_t max_ldpc_iterations=4; +uint8_t max_turbo_iterations=4; + #endif /*__PHY_VARS_H__ */ diff --git a/openair1/PHY/phy_vars_ue.h b/openair1/PHY/phy_vars_ue.h index ccce93c41f..05f2e1b8f1 100644 --- a/openair1/PHY/phy_vars_ue.h +++ b/openair1/PHY/phy_vars_ue.h @@ -57,7 +57,6 @@ short conjugate2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1}; unsigned char NB_INST=0; #endif -unsigned int ULSCH_max_consecutive_errors = 20; int number_of_cards; diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index e8b422a157..8105877bc3 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -137,7 +137,6 @@ void handle_nfapi_bch_pdu(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, // adjust transmit amplitude here based on NFAPI info } - extern uint32_t localRIV2alloc_LUT6[32]; extern uint32_t localRIV2alloc_LUT25[512]; extern uint32_t localRIV2alloc_LUT50_0[1600]; @@ -147,6 +146,52 @@ extern uint32_t localRIV2alloc_LUT100_1[6000]; extern uint32_t localRIV2alloc_LUT100_2[6000]; extern uint32_t localRIV2alloc_LUT100_3[6000]; +void handle_nfapi_mch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t *proc, + nfapi_dl_config_request_pdu_t *dl_config_pdu, + uint8_t *sdu){ + + nfapi_dl_config_mch_pdu_rel8_t *rel8 = &dl_config_pdu->mch_pdu.mch_pdu_rel8; + + LTE_eNB_DLSCH_t *dlsch = eNB->dlsch_MCH; + LTE_DL_FRAME_PARMS *frame_parms=&eNB->frame_parms; + + // dlsch->rnti = M_RNTI; + dlsch->harq_processes[0]->mcs = rel8->modulation; + // dlsch->harq_processes[0]->Ndi = ndi; + dlsch->harq_processes[0]->rvidx = 0;//rvidx; + dlsch->harq_processes[0]->Nl = 1; + dlsch->harq_processes[0]->TBS = TBStable[get_I_TBS(dlsch->harq_processes[0]->mcs)][frame_parms->N_RB_DL-1]; + // dlsch->harq_ids[subframe] = 0; + dlsch->harq_processes[0]->nb_rb = frame_parms->N_RB_DL; + + switch(frame_parms->N_RB_DL) { + case 6: + dlsch->harq_processes[0]->rb_alloc[0] = 0x3f; + break; + + case 25: + dlsch->harq_processes[0]->rb_alloc[0] = 0x1ffffff; + break; + + case 50: + dlsch->harq_processes[0]->rb_alloc[0] = 0xffffffff; + dlsch->harq_processes[0]->rb_alloc[1] = 0x3ffff; + break; + + case 100: + dlsch->harq_processes[0]->rb_alloc[0] = 0xffffffff; + dlsch->harq_processes[0]->rb_alloc[1] = 0xffffffff; + dlsch->harq_processes[0]->rb_alloc[2] = 0xffffffff; + dlsch->harq_processes[0]->rb_alloc[3] = 0xf; + break; + } + + dlsch->harq_ids[proc->frame_tx%2][proc->subframe_tx] = 0; + + dlsch->harq_processes[0]->pdu = sdu; + + dlsch->active = 1; +} void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, @@ -807,8 +852,30 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) { break; - case NFAPI_DL_CONFIG_MCH_PDU_TYPE: + case NFAPI_DL_CONFIG_MCH_PDU_TYPE:{ // handle_nfapi_mch_dl_pdu(eNB,dl_config_pdu); + //AssertFatal(1==0,"OK\n"); + nfapi_dl_config_mch_pdu_rel8_t *mch_pdu_rel8 = &dl_config_pdu->mch_pdu.mch_pdu_rel8; + uint16_t pdu_index = mch_pdu_rel8->pdu_index; + uint16_t tx_pdus = TX_req->tx_request_body.number_of_pdus; + uint16_t invalid_pdu = pdu_index == -1; + uint8_t *sdu = invalid_pdu ? NULL : pdu_index >= tx_pdus ? NULL : TX_req->tx_request_body.tx_pdu_list[pdu_index].segments[0].segment_data; + LOG_D(PHY,"%s() [PDU:%d] NFAPI_DL_CONFIG_MCH_PDU_TYPE SFN/SF:%04d%d TX:%d/%d RX:%d/%d pdu_index:%d sdu:%p\n", + __FUNCTION__, i, + NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf), + proc->frame_tx, proc->subframe_tx, + proc->frame_rx, proc->subframe_rx, + pdu_index, sdu); + if (sdu) { //sdu != NULL) + if (NFAPI_MODE!=NFAPI_MODE_VNF) + handle_nfapi_mch_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu, sdu); + } else { + dont_send=1; + LOG_E(MAC,"%s() NFAPI_DL_CONFIG_MCH_PDU_TYPE sdu is NULL DL_CFG:SFN/SF:%d:pdu_index:%d TX_REQ:SFN/SF:%d:pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(DL_req->sfn_sf), pdu_index, + NFAPI_SFNSF2DEC(TX_req->sfn_sf), tx_pdus); + } + do_oai=1; + } break; case NFAPI_DL_CONFIG_DLSCH_PDU_TYPE: { diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index 3bd469b685..05ec813917 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -53,6 +53,11 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu); + +void handle_nfapi_mch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t *proc, + nfapi_dl_config_request_pdu_t *dl_config_pdu, + uint8_t *sdu); + void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, nfapi_ul_config_request_pdu_t *ul_config_pdu, uint16_t frame,uint8_t subframe,uint8_t srs_present); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c0afdf25d1..34d5a01590 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -48,6 +48,8 @@ #include "intertask_interface.h" +#define MBMS_NFAPI_SCHEDULER + nfapi_ue_release_request_body_t release_rntis; int16_t get_hundred_times_delta_IF_eNB(PHY_VARS_eNB *eNB,uint16_t UE_id,uint8_t harq_pid, uint8_t bw_factor) { @@ -118,11 +120,21 @@ lte_subframe_t get_subframe_direction(uint8_t Mod_id,uint8_t CC_id,uint8_t subfr return(subframe_select(&RC.eNB[Mod_id][CC_id]->frame_parms,subframe)); } +#ifdef MBMS_NFAPI_SCHEDULER +void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { + int subframe = proc->subframe_tx; + // This is DL-Cell spec pilots in Control region + generate_pilots_slot (eNB, eNB->common_vars.txdataF, AMP, subframe << 1, 1); + if(eNB->dlsch_MCH->active==1) + generate_mch (eNB, proc,NULL/*, eNB->dlsch_MCH->harq_processes[0]->pdu*/); + eNB->dlsch_MCH->active = 0; +} +#else void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { MCH_PDU *mch_pduP=NULL; // uint8_t sync_area=255; int subframe = proc->subframe_tx; - AssertFatal (1 == 0, "pmch not tested for the moment, exiting\n"); + AssertFatal (1 == 1, "pmch not tested for the moment, exiting\n"); // This is DL-Cell spec pilots in Control region generate_pilots_slot (eNB, eNB->common_vars.txdataF, AMP, subframe << 1, 1); @@ -134,6 +146,7 @@ void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { proc->frame_tx, subframe); */ + mch_pduP= &RC.mac[eNB->Mod_id]->common_channels[eNB->CC_id].MCH_pdu; if ((mch_pduP->Pdu_size > 0) && (mch_pduP->sync_area == 0)) // TEST: only transmit mcch for sync area 0 LOG_D(PHY,"[eNB%"PRIu8"] Frame %d subframe %d : Got MCH pdu for MBSFN (MCS %"PRIu8", TBS %d) \n", eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->mcs, @@ -147,12 +160,15 @@ void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { if (mch_pduP) { fill_eNB_dlsch_MCH (eNB, mch_pduP->mcs, 1, 0); + eNB->dlsch_MCH->harq_ids[proc->frame_tx%2][subframe] = 0; + eNB->dlsch_MCH->harq_processes[0]->pdu=(uint8_t *) mch_pduP->payload; // Generate PMCH - generate_mch (eNB, proc, (uint8_t *) mch_pduP->payload); + generate_mch (eNB, proc, NULL/*(uint8_t *) mch_pduP->payload*/); } else { LOG_D (PHY, "[eNB/RN] Frame %d subframe %d: MCH not generated \n", proc->frame_tx, subframe); } } +#endif void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index 3583e222d5..eb9a2922c5 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -46,9 +46,7 @@ #include -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" extern int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); @@ -150,7 +148,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, } else { if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) { - LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", + LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, frame, diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index 78475e986b..6d392b0437 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -80,45 +80,69 @@ void feptx0(RU_t *ru, slot_offset = slot*(fp->samples_per_tti>>1); //slot_offset = subframe*fp->samples_per_tti + (slot*(fp->samples_per_tti>>1)); - //LOG_D(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d\n",ru->proc.frame_tx, ru->proc.subframe_tx,slot); + //LOG_D(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d\n",ru->proc.frame_tx, ru->proc.tti_tx,slot); for (aa=0; aanb_tx; aa++) { - if (fp->Ncp == EXTENDED) PHY_ofdm_mod(&ru->common.txdataF_BF[aa][(slot&1)*slot_sizeF], - (int*)&ru->common.txdata[aa][slot_offset], - fp->ofdm_symbol_size, - 6, - fp->nb_prefix_samples, - CYCLIC_PREFIX); - else { - /* AssertFatal(ru->generate_dmrs_sync==1 && (fp->frame_type != TDD || ru->is_slave == 1), - "ru->generate_dmrs_sync should not be set, frame_type %d, is_slave %d\n", - fp->frame_type,ru->is_slave); - */ - int num_symb = 7; + if (fp->Ncp == EXTENDED) { + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][(slot&1)*slot_sizeF], + (int*)&ru->common.txdata[aa][slot_offset], + fp->ofdm_symbol_size, + 6, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + } else { + if(is_pmch_subframe(ru->proc.frame_tx,subframe,fp)){ + if ((slot&1) == 0) {//just use one slot chance + normal_prefix_mod(&ru->common.txdataF_BF[aa][(slot&1)*slot_sizeF], + (int*)&ru->common.txdata[aa][slot_offset], + 2, + fp); + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][(slot&1)*slot_sizeF+fp->ofdm_symbol_size*2], + (int*)&ru->common.txdata[aa][slot_offset+((fp->ofdm_symbol_size>>2)*2+fp->ofdm_symbol_size*2)], + fp->ofdm_symbol_size, + 10, + fp->ofdm_symbol_size>>2, + CYCLIC_PREFIX); + LOG_D(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d F(%d) t(%d) IS PMCH(%d)\n", + ru->proc.frame_tx, + ru->proc.tti_tx, + slot, + slot*slot_sizeF+fp->ofdm_symbol_size*2, + slot_offset+((fp->ofdm_symbol_size>>2)*2+fp->ofdm_symbol_size*2), + is_pmch_subframe(ru->proc.frame_tx,subframe,fp)); + } + } else { + /* AssertFatal(ru->generate_dmrs_sync==1 && (fp->frame_type != TDD || ru->is_slave == 1), + "ru->generate_dmrs_sync should not be set, frame_type %d, is_slave %d\n", + fp->frame_type,ru->is_slave); + */ + int num_symb = 7; - if (subframe_select(fp,subframe) == SF_S) num_symb=fp->dl_symbols_in_S_subframe+1; - - if (ru->generate_dmrs_sync == 1 && slot == 0 && subframe == 1 && aa==0) { - //int32_t dmrs[ru->frame_parms.ofdm_symbol_size*14] __attribute__((aligned(32))); - //int32_t *dmrsp[2] ={dmrs,NULL}; //{&dmrs[(3-ru->frame_parms.Ncp)*ru->frame_parms.ofdm_symbol_size],NULL}; - generate_drs_pusch((PHY_VARS_UE *)NULL, - (UE_rxtx_proc_t*)NULL, - fp, - ru->common.txdataF_BF, - 0, - AMP, - 0, - 0, - fp->N_RB_DL, - aa); - } - normal_prefix_mod(&ru->common.txdataF_BF[aa][(slot&1)*slot_sizeF], - (int*)&ru->common.txdata[aa][slot_offset], - num_symb, - fp); + if (subframe_select(fp,subframe) == SF_S) + num_symb = fp->dl_symbols_in_S_subframe+1; + + if (ru->generate_dmrs_sync == 1 && slot == 0 && subframe == 1 && aa==0) { + //int32_t dmrs[ru->frame_parms.ofdm_symbol_size*14] __attribute__((aligned(32))); + //int32_t *dmrsp[2] ={dmrs,NULL}; //{&dmrs[(3-ru->frame_parms.Ncp)*ru->frame_parms.ofdm_symbol_size],NULL}; + + generate_drs_pusch((PHY_VARS_UE *)NULL, + (UE_rxtx_proc_t*)NULL, + fp, + ru->common.txdataF_BF, + 0, + AMP, + 0, + 0, + fp->N_RB_DL, + aa); + } + normal_prefix_mod(&ru->common.txdataF_BF[aa][(slot&1)*slot_sizeF], + (int*)&ru->common.txdata[aa][slot_offset], + num_symb, + fp); + } } - /* len = fp->samples_per_tti>>1; @@ -152,10 +176,10 @@ void feptx0(RU_t *ru, tx_offset = (int)slot_offset+i-ru->N_TA_offset/2; if (tx_offset<0) tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti; - + if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti)) tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti; - + ru->common.txdata[aa][tx_offset] = 0x00000000; } }*/ @@ -190,7 +214,7 @@ static void *feptx_thread(void *param) } /*if(opp_enabled == 1 && ru->ofdm_mod_wakeup_stats.p_time>30*3000){ print_meas_now(&ru->ofdm_mod_wakeup_stats,"fep wakeup",stderr); - printf("delay in fep wakeup in frame_tx: %d subframe_rx: %d \n",proc->frame_tx,proc->subframe_tx); + printf("delay in fep wakeup in frame_tx: %d subframe_rx: %d \n",proc->frame_tx,proc->tti_tx); }*/ } return(NULL); @@ -237,7 +261,7 @@ void feptx_ofdm_2thread(RU_t *ru, exit_fun( "ERROR pthread_cond_signal" ); return; } - //start_meas(&ru->ofdm_mod_wakeup_stats); + //start_meas(&ru->ofdm_mod_wakeup_stats); pthread_mutex_unlock( &proc->mutex_feptx ); } @@ -249,7 +273,7 @@ void feptx_ofdm_2thread(RU_t *ru, stop_meas(&ru->ofdm_mod_wait_stats); /*if(opp_enabled == 1 && ru->ofdm_mod_wait_stats.p_time>30*3000){ print_meas_now(&ru->ofdm_mod_wait_stats,"fep wakeup",stderr); - printf("delay in feptx wait on condition in frame_rx: %d subframe_rx: %d \n", proc->frame_tx, proc->subframe_tx); + printf("delay in feptx wait on condition in frame_rx: %d subframe_rx: %d \n", proc->frame_tx, proc->tti_tx); }*/ stop_meas(&ru->ofdm_mod_stats); @@ -297,16 +321,29 @@ void feptx_ofdm(RU_t *ru, fp->nb_prefix_samples, CYCLIC_PREFIX); } else { + if(is_pmch_subframe(ru->proc.frame_tx,subframe,fp)/*subframe==1*/){ + normal_prefix_mod(&ru->common.txdataF_BF[aa][0], + dummy_tx_b, + 2, + fp); + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][fp->ofdm_symbol_size*2], + dummy_tx_b+((fp->ofdm_symbol_size>>2)*2+fp->ofdm_symbol_size*2), + fp->ofdm_symbol_size, + 10, + fp->ofdm_symbol_size>>2, + CYCLIC_PREFIX); + }else{ normal_prefix_mod(&ru->common.txdataF_BF[aa][slot_offset_F], dummy_tx_b, 7, fp); - // if S-subframe generate first slot only + // if S-subframe generate first slot only if (subframe_select(fp,subframe) == SF_DL) normal_prefix_mod(&ru->common.txdataF_BF[aa][slot_offset_F+slot_sizeF], dummy_tx_b+(fp->samples_per_tti>>1), 7, fp); + } } // if S-subframe generate first slot only diff --git a/openair1/SCHED_NR/fapi_nr_l1.h b/openair1/SCHED_NR/fapi_nr_l1.h index c35ae82c0b..07509b3bb7 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.h +++ b/openair1/SCHED_NR/fapi_nr_l1.h @@ -47,3 +47,5 @@ void handle_nr_nfapi_pdsch_pdu(PHY_VARS_gNB *gNB,int frame,int slot, uint8_t *sdu); void nr_fill_rx_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int UE_id, uint8_t harq_pid); + +void nr_fill_crc_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int UE_id, uint8_t crc_flag); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 559244643d..aefeec43e2 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -38,7 +38,7 @@ #include "PHY/LTE_TRANSPORT/if4_tools.h" #include "PHY/LTE_TRANSPORT/if5_tools.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/MAC/mac.h" #include "common/utils/LOG/log.h" #include "common/utils/system.h" @@ -66,46 +66,77 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) { //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+(first_symbol!=0?1:0) , 1 ); - slot_offset = slot*fp->samples_per_slot; + slot_offset = fp->get_samples_slot_timestamp(slot,fp,0); slot_offsetF = first_symbol*fp->ofdm_symbol_size; + int abs_first_symbol = slot*fp->symbols_per_slot; - if (first_symbol>0) slot_offset += (fp->ofdm_symbol_size*first_symbol) + (fp->nb_prefix_samples0) + (fp->nb_prefix_samples*(first_symbol-1)); + for (uint16_t idx_sym=abs_first_symbol; idx_symnumerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; + + slot_offset += fp->ofdm_symbol_size*first_symbol; LOG_D(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d (first_symbol %d num_symbols %d)\n",ru->proc.frame_tx, ru->proc.tti_tx,slot,first_symbol,num_symbols); - - if (fp->Ncp == 1) { + + if (fp->Ncp == 1) PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], (int*)&ru->common.txdata[aa][slot_offset], fp->ofdm_symbol_size, num_symbols, fp->nb_prefix_samples, CYCLIC_PREFIX); - } else { - if (first_symbol==0) { - PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], - (int*)&ru->common.txdata[aa][slot_offset], - fp->ofdm_symbol_size, - 1, - fp->nb_prefix_samples0, - CYCLIC_PREFIX); - PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF+fp->ofdm_symbol_size], - (int*)&ru->common.txdata[aa][slot_offset+fp->nb_prefix_samples0+fp->ofdm_symbol_size], - fp->ofdm_symbol_size, - num_symbols-1, - fp->nb_prefix_samples, - CYCLIC_PREFIX); + if (fp->numerology_index != 0) { + + if (!(slot%(fp->slots_per_subframe/2))&&(first_symbol==0)) { + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], + (int*)&ru->common.txdata[aa][slot_offset], + fp->ofdm_symbol_size, + 1, + fp->nb_prefix_samples0, + CYCLIC_PREFIX); + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF+fp->ofdm_symbol_size], + (int*)&ru->common.txdata[aa][slot_offset+fp->nb_prefix_samples0+fp->ofdm_symbol_size], + fp->ofdm_symbol_size, + num_symbols-1, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + } + else { + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], + (int*)&ru->common.txdata[aa][slot_offset], + fp->ofdm_symbol_size, + num_symbols, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + } } + else { - PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], - (int*)&ru->common.txdata[aa][slot_offset], - fp->ofdm_symbol_size, - num_symbols, - fp->nb_prefix_samples, - CYCLIC_PREFIX); + for (uint16_t idx_sym=abs_first_symbol; idx_symcommon.txdataF_BF[aa][slot_offsetF], + (int*)&ru->common.txdata[aa][slot_offset], + fp->ofdm_symbol_size, + 1, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + slot_offset += fp->nb_prefix_samples+fp->ofdm_symbol_size; + } + else { + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], + (int*)&ru->common.txdata[aa][slot_offset], + fp->ofdm_symbol_size, + 1, + fp->nb_prefix_samples0, + CYCLIC_PREFIX); + slot_offset += fp->nb_prefix_samples0+fp->ofdm_symbol_size; + } + } } } + + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+(first_symbol!=0?1:0), 0); } @@ -370,7 +401,7 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) { int slot_sizeF = (fp->ofdm_symbol_size)* ((cyclic_prefix_type == 1) ? 12 : 14); int slot = tti_tx; - int *txdata = &ru->common.txdata[aa][slot*fp->samples_per_slot]; + int *txdata = &ru->common.txdata[aa][fp->get_samples_slot_timestamp(slot,fp,0)]; if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return; @@ -386,8 +417,8 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) { stop_meas(&ru->ofdm_mod_stats); LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, slot %d: txp (time %p) %d dB, txp (freq) %d dB\n", - frame_tx,slot,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->samples_per_slot)), - dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF))); + frame_tx,slot,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->get_samples_per_slot( + slot,fp))),dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF))); } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 461da165f7..46f9a79460 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -22,6 +22,7 @@ #include "PHY/phy_extern.h" #include "PHY/defs_gNB.h" #include "sched_nr.h" +#include "PHY/NR_REFSIG/dmrs_nr.h" #include "PHY/NR_TRANSPORT/nr_transport.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" @@ -39,23 +40,29 @@ #include "PHY/INIT/phy_init.h" #include "PHY/MODULATION/nr_modulation.h" #include "T.h" +#include "executables/nr-softmodem.h" +#include "executables/softmodem-common.h" #include "assertions.h" #include "msc.h" #include -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" uint8_t SSB_Table[38]={0,2,4,6,8,10,12,14,254,254,16,18,20,22,24,26,28,30,254,254,32,34,36,38,40,42,44,46,254,254,48,50,52,54,56,58,60,62}; extern uint8_t nfapi_mode; void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME_PARMS *fp) { - fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + cfg->ssb_table.ssb_subcarrier_offset.value); - LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,cfg->ssb_table.ssb_subcarrier_offset.value); + + uint8_t sco = 0; + if (((fp->freq_range == nr_FR1) && (cfg->ssb_table.ssb_subcarrier_offset.value<24)) || + ((fp->freq_range == nr_FR2) && (cfg->ssb_table.ssb_subcarrier_offset.value<12)) ) + sco = cfg->ssb_table.ssb_subcarrier_offset.value; + + fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + sco); + LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,sco); } void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame, int slot) { @@ -89,8 +96,7 @@ void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame, int slot) { ssb_index = i + SSB_Table[rel_slot]; // computing the ssb_index - if ((ssb_index<64) && ((fp->L_ssb >> ssb_index) & 0x01)) { // generating the ssb only if the bit of L_ssb at current ssb index is 1 - + if ((ssb_index<64) && ((fp->L_ssb >> (63-ssb_index)) & 0x01)) { // generating the ssb only if the bit of L_ssb at current ssb index is 1 fp->ssb_index = ssb_index; int ssb_start_symbol_abs = nr_get_ssb_start_symbol(fp); // computing the starting symbol for current ssb ssb_start_symbol = ssb_start_symbol_abs % fp->symbols_per_slot; // start symbol wrt slot @@ -209,20 +215,29 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH_id, uint8_t harq_pid) { - NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - nfapi_nr_ul_config_ulsch_pdu *rel15_ul = &gNB->ulsch[ULSCH_id][0]->harq_processes[harq_pid]->ulsch_pdu; - nfapi_nr_ul_config_ulsch_pdu_rel15_t *nfapi_ulsch_pdu_rel15 = &rel15_ul->ulsch_pdu_rel15; + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id][0]->harq_processes[harq_pid]->ulsch_pdu; uint8_t ret; + uint8_t l, number_dmrs_symbols = 0; uint32_t G; - int Nid_cell = 0; // [hna] shouldn't be a local variable (should be signaled) + uint16_t start_symbol, number_symbols, nb_re_dmrs; + + start_symbol = pusch_pdu->start_symbol_index; + number_symbols = pusch_pdu->nr_of_symbols; + + for (l = start_symbol; l < start_symbol + number_symbols; l++) + number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos)>>l)&0x01; + + nb_re_dmrs = ((pusch_pdu->dmrs_config_type == pusch_dmrs_type1)?6:4); + + G = nr_get_G(pusch_pdu->rb_size, + number_symbols, + nb_re_dmrs, + number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs + pusch_pdu->qam_mod_order, + pusch_pdu->nrOfLayers); - G = nr_get_G(nfapi_ulsch_pdu_rel15->number_rbs, - nfapi_ulsch_pdu_rel15->number_symbols, - nfapi_ulsch_pdu_rel15->nb_re_dmrs, - nfapi_ulsch_pdu_rel15->length_dmrs, - nfapi_ulsch_pdu_rel15->Qm, - nfapi_ulsch_pdu_rel15->n_layers); //---------------------------------------------------------- //------------------- ULSCH unscrambling ------------------- @@ -231,27 +246,34 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH nr_ulsch_unscrambling(gNB->pusch_vars[ULSCH_id]->llr, G, 0, - Nid_cell, - rel15_ul->rnti); + pusch_pdu->data_scrambling_id, + pusch_pdu->rnti); //---------------------------------------------------------- //--------------------- ULSCH decoding --------------------- //---------------------------------------------------------- ret = nr_ulsch_decoding(gNB, - ULSCH_id, - gNB->pusch_vars[ULSCH_id]->llr, - frame_parms, - frame_rx, - nfapi_ulsch_pdu_rel15->number_symbols, - slot_rx, - harq_pid, - 0); + ULSCH_id, + gNB->pusch_vars[ULSCH_id]->llr, + frame_parms, + pusch_pdu, + frame_rx, + slot_rx, + harq_pid, + G); + if (ret > gNB->ulsch[ULSCH_id][0]->max_ldpc_iterations) - LOG_I(PHY, "ULSCH in error\n"); - else - LOG_I(PHY, "ULSCH received ok\n"); + LOG_I(PHY, "ULSCH %d in error\n",ULSCH_id); + //gNB->ulsch[ULSCH_id+1][0]->harq_processes[harq_pid]->b + else if(gNB->ulsch[ULSCH_id][0]->harq_processes[harq_pid]->b!=NULL){ + LOG_I(PHY, "ULSCH received ok \n"); + if(IS_SOFTMODEM_NOS1){ //&& gNB->ulsch[ULSCH_id][0]->rnti == 0x1234 + nr_fill_crc_indication(gNB,frame_rx, slot_rx, ULSCH_id, 0); + nr_fill_rx_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); + } + } } @@ -261,41 +283,47 @@ void nr_fill_rx_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_ // -------------------- // [hna] TO BE CLEANED // -------------------- - // [FM] This structure is not SCF fapi structure and shouldn't be used - // nfapi_rx_indication_pdu_t *pdu; + nfapi_rx_indication_pdu_t *pdu; int timing_advance_update; int sync_pos; + uint16_t mu = gNB->frame_parms.numerology_index; // pthread_mutex_lock(&gNB->UL_INFO_mutex); + NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id][0]; + NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_processes[harq_pid]; - // gNB->UL_INFO.rx_ind.sfn_sf = frame<<4| slot_rx; - // gNB->UL_INFO.rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + pthread_mutex_lock(&gNB->UL_INFO_mutex); - // pdu = &gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list[gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus]; + gNB->UL_INFO.rx_ind.sfn_sf = frame<<4| slot_rx; + gNB->UL_INFO.rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list->rx_indication_rel8.length = gNB->ulsch[ULSCH_id][0]->harq_processes[harq_pid]->TBS; - // pdu->rx_ue_information.handle = gNB->ulsch[UE_id+1][0]->handle; - // pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - // pdu->rx_ue_information.rnti = gNB->ulsch[UE_id+1][0]->rnti; - // pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; - // pdu->rx_indication_rel8.length = gNB->ulsch[UE_id+1][0]->harq_processes[harq_pid]->TBS>>3; - // pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation - // pdu->data = gNB->ulsch[UE_id+1][0]->harq_processes[harq_pid]->b; + pdu = &gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list[gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus]; + + //pdu->rx_ue_information.handle = gNB->ulsch[ULSCH_id+1][0]->handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = gNB->ulsch[ULSCH_id][0]->rnti; + pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; + pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation + pdu->data = harq_process->b;//gNB->ulsch[ULSCH_id+1][0]->harq_processes[harq_pid]->b; // estimate timing advance for MAC sync_pos = nr_est_timing_advance_pusch(gNB, ULSCH_id); timing_advance_update = sync_pos; // - gNB->frame_parms.nb_prefix_samples/4; //to check // printf("\x1B[33m" "timing_advance_update = %d\n" "\x1B[0m", timing_advance_update); + + // pdu->data = gNB->ulsch[ULSCH_id+1][0]->harq_processes[harq_pid]->b; + sync_pos = nr_est_timing_advance_pusch(gNB, ULSCH_id); // estimate timing advance for MAC + timing_advance_update = sync_pos * (1 << mu); // scale by the used scs numerology + + // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size switch (gNB->frame_parms.N_RB_DL) { - // case 6: /* nothing to do */ break; - // case 15: timing_advance_update /= 2; break; - // case 25: timing_advance_update /= 4; break; - // case 50: timing_advance_update /= 8; break; - // case 75: timing_advance_update /= 12; break; case 106: timing_advance_update /= 16; break; case 217: timing_advance_update /= 32; break; + case 245: timing_advance_update /= 32; break; case 273: timing_advance_update /= 32; break; - case 66: timing_advance_update /= 12; break; + case 66: timing_advance_update /= 12; break; default: abort(); } @@ -305,25 +333,43 @@ void nr_fill_rx_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_ if (timing_advance_update < 0) timing_advance_update = 0; if (timing_advance_update > 63) timing_advance_update = 63; - // pdu->rx_indication_rel8.timing_advance = timing_advance_update; + LOG_D(PHY, "Estimated timing advance PUSCH is = %d, timing_advance_update is %d \n", sync_pos,timing_advance_update); + + pdu->rx_indication_rel8.timing_advance = timing_advance_update; // estimate UL_CQI for MAC (from antenna port 0 only) - // int SNRtimes10 = dB_fixed_times10(gNB->pusch_vars[UE_id]->ulsch_power[0]) - 300;//(10*gNB->measurements.n0_power_dB[0]); + int SNRtimes10 = dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0]) - 300;//(10*gNB->measurements.n0_power_dB[0]); - // if (SNRtimes10 < -640) pdu->rx_indication_rel8.ul_cqi=0; - // else if (SNRtimes10 > 635) pdu->rx_indication_rel8.ul_cqi=255; - // else pdu->rx_indication_rel8.ul_cqi=(640+SNRtimes10)/5; + if (SNRtimes10 < -640) pdu->rx_indication_rel8.ul_cqi=0; + else if (SNRtimes10 > 635) pdu->rx_indication_rel8.ul_cqi=255; + else pdu->rx_indication_rel8.ul_cqi=(640+SNRtimes10)/5; // LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n", // harq_pid,frame,slot_rx,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance, // timing_advance_update); - // gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++; - // gNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | slot_rx; + gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++; + gNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | slot_rx; - // pthread_mutex_unlock(&gNB->UL_INFO_mutex); + pthread_mutex_unlock(&gNB->UL_INFO_mutex); } +void nr_fill_crc_indication (PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, uint8_t crc_flag) { + pthread_mutex_lock(&gNB->UL_INFO_mutex); + nfapi_crc_indication_pdu_t *pdu = &gNB->UL_INFO. crc_ind.crc_indication_body.crc_pdu_list[gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs]; + gNB->UL_INFO.crc_ind.sfn_sf = frame<<4 | slot_rx; + gNB->UL_INFO.crc_ind.header.message_id = NFAPI_CRC_INDICATION; + gNB->UL_INFO.crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG; + pdu->instance_length = 0; // don't know what to do with this + // pdu->rx_ue_information.handle = handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = gNB->ulsch[ULSCH_id][0]->rnti; + pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; + pdu->crc_indication_rel8.crc_flag = crc_flag; + gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs++; + //LOG_D(PHY, "%s() rnti:%04x crcs:%d crc_flag:%d\n", __FUNCTION__, pdu->rx_ue_information.rnti, eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, crc_flag); + pthread_mutex_unlock(&gNB->UL_INFO_mutex); +} void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { @@ -355,53 +401,57 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) uci_indication->slot = slot_rx; uci_indication->num_ucis = 0; + LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d, num_pdus %d\n",frame_rx,slot_rx,num_pdus); - + + gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0; + for (int i = 0; i < num_pdus; i++) { switch (UL_tti_req->pdus_list[i].pdu_type) { - case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: - LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE\n",frame_rx,slot_rx); + case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE:{ + LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE\n",frame_rx,slot_rx); - nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[i].pusch_pdu; - nr_fill_ulsch(gNB,frame_rx,slot_rx,pusch_pdu); + nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu; + nr_fill_ulsch(gNB,frame_rx,slot_rx,pusch_pdu); + + uint8_t ULSCH_id = find_nr_ulsch(pusch_pdu->rnti,gNB,SEARCH_EXIST); + uint8_t harq_pid = pusch_pdu->pusch_data.harq_process_id; + uint8_t symbol_start = pusch_pdu->start_symbol_index; + uint8_t symbol_end = symbol_start + pusch_pdu->nr_of_symbols; + + for(uint8_t symbol = symbol_start; symbol < symbol_end; symbol++) { + nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, symbol, harq_pid); + } + //LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1); + //LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); + nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); + nr_fill_rx_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); // indicate SDU to MAC + nr_fill_crc_indication(gNB, frame_rx, slot_rx, ULSCH_id, 0); + } + case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE:{ + LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE\n",frame_rx,slot_rx); + + nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[i].pucch_pdu; + switch (pucch_pdu->format_type) { + case 0: + uci_indication->uci_list[uci_indication->num_ucis].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; + uci_indication->uci_list[uci_indication->num_ucis].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); + nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci_indication->uci_list[uci_indication->num_ucis].pucch_pdu_format_0_1; - uint8_t ULSCH_id = find_nr_ulsch(pusch_pdu->rnti,gNB,SEARCH_EXIST); - uint8_t harq_pid = pusch_pdu->pusch_data.harq_process_id; - uint8_t symbol_start = pusch_pdu->start_symbol_index; - uint8_t symbol_end = symbol_start + pusch_pdu->nr_of_symbols; + nr_decode_pucch0(gNB, + slot_rx, + uci_pdu_format0, + pucch_pdu); - for(uint8_t symbol = symbol_start; symbol < symbol_end; symbol++) { - nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, symbol, harq_pid); - } - //LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1); - //LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); - nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); - nr_fill_rx_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); // indicate SDU to MAC - break; - case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: - LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE\n",frame_rx,slot_rx); - - nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[i].pucch_pdu; - switch (pucch_pdu->format_type) { - case 0: - uci_indication->uci_list[uci_indication->num_ucis].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; - uci_indication->uci_list[uci_indication->num_ucis].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); - nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci_indication->uci_list[uci_indication->num_ucis].pucch_pdu_format_0_1; - - nr_decode_pucch0(gNB->common_vars.rxdataF, - &gNB->frame_parms, - slot_rx, - uci_pdu_format0, - pucch_pdu); - - uci_indication->num_ucis += 1; - break; - case 1: - break; - default: - AssertFatal(1==0,"Only PUCCH format 0 and 1 are currently supported\n"); - } - break; + uci_indication->num_ucis += 1; + break; + case 1: + break; + default: + AssertFatal(1==0,"Only PUCCH format 0 and 1 are currently supported\n"); + } + break; + } } } } diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index c205468a63..e34ce2b6de 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -289,10 +289,16 @@ uint16_t nr_get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1); int8_t nr_find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB); -void nr_process_timing_advance(module_id_t Mod_id,uint8_t CC_id,int16_t timing_advance); +/*! \brief Compute the timing adjustment at UE side from the old TA offset and the new received TA command + @param Mod_id Local UE index on which to act + @param CC_id Component Carrier Index + @param ta_command TA command received from the network + @param mu numerology index (0,1,2..) +*/ +void nr_process_timing_advance(module_id_t Mod_id,uint8_t CC_id,uint8_t ta_command, uint8_t mu, uint16_t bwp_ul_NB_RB); void nr_process_timing_advance_rar(PHY_VARS_NR_UE *phy_vars_ue,UE_nr_rxtx_proc_t *proc,uint16_t timing_advance); -unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb); +unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb); void phy_reset_ue(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index); diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index c6a830a8da..69876159d6 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -51,7 +51,6 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response) uint8_t cc_id = scheduled_response->CC_id; uint32_t i; int slot = scheduled_response->slot; - // Note: we have to handle the thread IDs for this. To be revisited completely. uint8_t thread_id = PHY_vars_UE_g[module_id][cc_id]->current_thread_id[slot]; NR_UE_PDCCH *pdcch_vars = PHY_vars_UE_g[module_id][cc_id]->pdcch_vars[thread_id][0]; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index aa8fa0e638..509f4b6021 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -21,11 +21,11 @@ /*! \file phy_procedures_nr_ue.c * \brief Implementation of UE procedures from 36.213 LTE specifications - * \author R. Knopp, F. Kaltenberger, N. Nikaein, A. Mico Pereperez + * \author R. Knopp, F. Kaltenberger, N. Nikaein, A. Mico Pereperez, G. Casati * \date 2018 * \version 0.1 * \company Eurecom - * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr, guido.casati@iis.fraunhofer.de * \note * \warning */ @@ -45,6 +45,7 @@ //#include "PHY/extern.h" #include "SCHED_NR_UE/defs.h" #include "SCHED_NR/extern.h" +#include "SCHED_NR_UE/phy_sch_processing_time.h" //#include //#include "targets/RT/USER/nr-softmodem.h" #include "PHY/NR_UE_ESTIMATION/nr_estimation.h" @@ -73,15 +74,7 @@ fifo_dump_emos_UE emos_dump_UE; #include "common/utils/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" - -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#endif - -//#include "PHY/defs.h" - -//#include "PHY/CODING/extern.h" - +#include "intertask_interface.h" #include "T.h" #define DLSCH_RB_ALLOC 0x1fbf // skip DC RB (total 23/25 RBs) @@ -89,7 +82,7 @@ fifo_dump_emos_UE emos_dump_UE; #define NS_PER_SLOT 500000 -char mode_string[4][20] = {"NOT SYNCHED","PRACH","RAR","PUSCH"}; +char nr_mode_string[4][20] = {"NOT SYNCHED","PRACH","RAR","PUSCH"}; extern double cpuf; @@ -406,22 +399,6 @@ void nr_process_timing_advance_rar(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,ui LOG_I(PHY,"[UE %d] AbsoluteSubFrame %d.%d, received (rar) timing_advance %d\n",ue->Mod_id,proc->frame_rx, proc->nr_tti_rx, ue->timing_advance); #endif -} - -void nr_process_timing_advance(uint8_t Mod_id,uint8_t CC_id,int16_t timing_advance) -{ - - // uint32_t frame = PHY_vars_UE_g[Mod_id]->frame; - - // timing advance has Q1.5 format - timing_advance = timing_advance - 31; - - PHY_vars_UE_g[Mod_id][CC_id]->timing_advance = PHY_vars_UE_g[Mod_id][CC_id]->timing_advance+timing_advance*4; //this is for 25RB only!!! - - - LOG_D(PHY,"[UE %d] Got timing advance %d from MAC, new value %d\n",Mod_id, timing_advance, PHY_vars_UE_g[Mod_id][CC_id]->timing_advance); - - } uint8_t nr_is_SR_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id) @@ -550,8 +527,8 @@ void ue_compute_srs_occasion(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t // Simultaneous-AN-and-SRS is FALSE // check PUCCH format 2/2a/2b transmissions - is_pucch2_subframe = is_cqi_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0); - is_pucch2_subframe = (is_ri_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0)) || is_pucch2_subframe; + is_pucch2_subframe = nr_is_cqi_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0); + is_pucch2_subframe = (nr_is_ri_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0)) || is_pucch2_subframe; // check ACK/SR transmission if(frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission == FALSE) @@ -1414,6 +1391,31 @@ void ulsch_common_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_ #endif + +void nr_process_timing_advance(module_id_t Mod_id, uint8_t CC_id, uint8_t ta_command, uint8_t mu, uint16_t bwp_ul_NB_RB){ + + // 3GPP TS 38.213 p4.2 + // scale by the scs numerology + int factor_mu = 1 << mu; + uint16_t bw_scaling; + + // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size + switch (bwp_ul_NB_RB) { + case 32: bw_scaling = 4; break; + case 66: bw_scaling = 8; break; + case 106: bw_scaling = 16; break; + case 217: bw_scaling = 32; break; + case 245: bw_scaling = 32; break; + case 273: bw_scaling = 32; break; + default: abort(); + } + + PHY_vars_UE_g[Mod_id][CC_id]->timing_advance += (ta_command - 31) * bw_scaling / factor_mu; + + LOG_D(PHY, "[UE %d] Got timing advance command %u from MAC, new value is %u\n", Mod_id, ta_command, PHY_vars_UE_g[Mod_id][CC_id]->timing_advance); +} + +#if 0 void ue_ulsch_uespec_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t eNB_id, @@ -1569,10 +1571,10 @@ void ue_ulsch_uespec_procedures(PHY_VARS_NR_UE *ue, // check Periodic CQI/RI reporting cqi_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0)&& - (is_cqi_TXOp(ue,proc,eNB_id)==1)); + (nr_is_cqi_TXOp(ue,proc,eNB_id)==1)); ri_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) && - (is_ri_TXOp(ue,proc,eNB_id)==1)); + (nr_is_ri_TXOp(ue,proc,eNB_id)==1)); // compute CQI/RI resources compute_cqi_ri_resources(ue, ue->ulsch[eNB_id], eNB_id, ue->ulsch[eNB_id]->rnti, P_RNTI, CBA_RNTI, cqi_status, ri_status); @@ -1777,7 +1779,7 @@ if (abstraction_flag == 0) { ue->tx_total_RE[nr_tti_tx] = nb_rb*12; #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) - tx_amp = get_tx_amp(ue->tx_power_dBm[nr_tti_tx], + tx_amp = nr_get_tx_amp(ue->tx_power_dBm[nr_tti_tx], ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, nb_rb); @@ -1786,7 +1788,7 @@ if (abstraction_flag == 0) { #endif #if T_TRACER T(T_UE_PHY_PUSCH_TX_POWER, T_INT(eNB_id),T_INT(Mod_id), T_INT(frame_tx%1024), T_INT(nr_tti_tx),T_INT(ue->tx_power_dBm[nr_tti_tx]), - T_INT(tx_amp),T_INT(ue->ulsch[eNB_id]->f_pusch),T_INT(get_PL(Mod_id,0,eNB_id)),T_INT(nb_rb)); + T_INT(tx_amp),T_INT(ue->ulsch[eNB_id]->f_pusch),T_INT(get_nr_PL(Mod_id,0,eNB_id)),T_INT(nb_rb)); #endif #ifdef UE_DEBUG_TRACE @@ -1836,6 +1838,7 @@ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDUR #endif } +#endif #if 0 @@ -1868,7 +1871,7 @@ void ue_srs_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) if (ue->mac_enabled==1) { - tx_amp = get_tx_amp(Po_SRS, + tx_amp = nr_get_tx_amp(Po_SRS, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, nb_rb_srs); @@ -2093,10 +2096,10 @@ void ue_pucch_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_ nb_cw = ( (ack_status_cw0 != 0) ? 1:0) + ( (ack_status_cw1 != 0) ? 1:0); cqi_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0)&& - (is_cqi_TXOp(ue,proc,eNB_id)==1)); + (nr_is_cqi_TXOp(ue,proc,eNB_id)==1)); ri_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) && - (is_ri_TXOp(ue,proc,eNB_id)==1)); + (nr_is_ri_TXOp(ue,proc,eNB_id)==1)); // Part - II // if nothing to report ==> exit function @@ -2151,7 +2154,7 @@ void ue_pucch_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_ ue->tx_total_RE[nr_tti_tx] = 12; #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) - tx_amp = get_tx_amp(Po_PUCCH, + tx_amp = nr_get_tx_amp(Po_PUCCH, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, 1); @@ -2160,7 +2163,7 @@ void ue_pucch_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_ #endif #if T_TRACER T(T_UE_PHY_PUCCH_TX_POWER, T_INT(eNB_id),T_INT(Mod_id), T_INT(frame_tx%1024), T_INT(nr_tti_tx),T_INT(ue->tx_power_dBm[nr_tti_tx]), - T_INT(tx_amp),T_INT(ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][eNB_id][0]->g_pucch),T_INT(get_PL(ue->Mod_id,ue->CC_id,eNB_id))); + T_INT(tx_amp),T_INT(ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][eNB_id][0]->g_pucch),T_INT(get_nr_PL(ue->Mod_id,ue->CC_id,eNB_id))); #endif #ifdef UE_DEBUG_TRACE @@ -2259,7 +2262,7 @@ void ue_pucch_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_ ue->tx_total_RE[nr_tti_tx] = 12; #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) - tx_amp = get_tx_amp(Po_PUCCH, + tx_amp = nr_get_tx_amp(Po_PUCCH, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, 1); @@ -2268,7 +2271,7 @@ void ue_pucch_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_ #endif #if T_TRACER T(T_UE_PHY_PUCCH_TX_POWER, T_INT(eNB_id),T_INT(Mod_id), T_INT(frame_tx%1024), T_INT(nr_tti_tx),T_INT(ue->tx_power_dBm[nr_tti_tx]), - T_INT(tx_amp),T_INT(ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][eNB_id][0]->g_pucch),T_INT(get_PL(ue->Mod_id,ue->CC_id,eNB_id))); + T_INT(tx_amp),T_INT(ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][eNB_id][0]->g_pucch),T_INT(get_nr_PL(ue->Mod_id,ue->CC_id,eNB_id))); #endif #ifdef UE_DEBUG_TRACE LOG_I(PHY,"[UE %d][RNTI %x] AbsSubFrame %d.%d Generating PUCCH 2 (RI or CQI), Po_PUCCH %d, isShortenPucch %d, amp %d\n", @@ -2338,6 +2341,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, nr_ue_ulsch_procedures(ue, harq_pid, + frame_tx, slot_tx, thread_id, gNB_id); @@ -2352,8 +2356,8 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, } // UE_mode==PUSCH */ - - nr_ue_pusch_common_procedures(ue, + LOG_D(PHY, "Sending data \n"); + nr_ue_pusch_common_procedures(ue, harq_pid, slot_tx, thread_id, @@ -2362,6 +2366,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, //LOG_M("txdata.m","txs",ue->common_vars.txdata[0],1228800,1,1); + /* if ((ue->UE_mode[eNB_id] == PRACH) && (ue->frame_parms.prach_config_common.prach_Config_enabled==1)) { @@ -2608,6 +2613,8 @@ void nr_ue_measurement_procedures(uint16_t l, // symbol index of each slot [0 //printf("start adjust gain power avg db %d\n", ue->measurements.rx_power_avg_dB[eNB_id]); phy_adjust_gain_nr (ue,ue->measurements.rx_power_avg_dB[eNB_id],eNB_id); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT); } @@ -2769,7 +2776,7 @@ void nr_ue_pbch_procedures(uint8_t eNB_id, -unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb) +unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb) { int gain_dB = power_dBm - power_max_dBm; @@ -2818,14 +2825,14 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, int nb_searchspace_active=0; NR_UE_PDCCH **pdcch_vars = ue->pdcch_vars[ue->current_thread_id[nr_tti_rx]]; - NR_UE_PDCCH *pdcch_vars2 = ue->pdcch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id]; + NR_UE_PDCCH *pdcch_vars2 = ue->pdcch_vars[ue->current_thread_id[nr_tti_rx]][gNB_id]; // s in TS 38.212 Subclause 10.1, for each active BWP the UE can deal with 10 different search spaces // Higher layers have updated the number of searchSpaces with are active in the current slot and this value is stored in variable nb_searchspace_total int nb_searchspace_total = pdcch_vars2->nb_search_space; - pdcch_vars[eNB_id]->crnti = 0x1234; //to be check how to set when using loop memory + pdcch_vars[gNB_id]->crnti = 0x1234; //to be check how to set when using loop memory - uint16_t c_rnti=pdcch_vars[eNB_id]->crnti; + uint16_t c_rnti=pdcch_vars[gNB_id]->crnti; uint16_t cs_rnti=0,new_rnti=0,tc_rnti=0; uint16_t p_rnti=P_RNTI; uint16_t si_rnti=SI_RNTI; @@ -2956,14 +2963,14 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_FUNCTION_IN); #ifdef NR_PDCCH_SCHED_DEBUG - printf("<-NR_PDCCH_PHY_PROCEDURES_LTE_UE (nr_ue_pdcch_procedures)-> Entering function nr_rx_pdcch with eNB_id=%d (nb_coreset_active=%d, (symbol_within_slot_mon&0x3FFF)=%d, searchSpaceType=%d)\n", - eNB_id,nb_coreset_active,(symbol_within_slot_mon&0x3FFF), + printf("<-NR_PDCCH_PHY_PROCEDURES_LTE_UE (nr_ue_pdcch_procedures)-> Entering function nr_rx_pdcch with gNB_id=%d (nb_coreset_active=%d, (symbol_within_slot_mon&0x3FFF)=%d, searchSpaceType=%d)\n", + gNB_id,nb_coreset_active,(symbol_within_slot_mon&0x3FFF), searchSpaceType); #endif nr_rx_pdcch(ue, proc->frame_rx, nr_tti_rx, - eNB_id, + gNB_id, //(ue->frame_parms.mode1_flag == 1) ? SISO : ALAMOUTI, SISO, ue->high_speed_flag, @@ -2992,7 +2999,6 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, printf("<-NR_PDCCH_PHY_PROCEDURES_LTE_UE (nr_ue_pdcch_procedures)-> Entering function nr_dci_decoding_procedure with (nb_searchspace_active=%d)\n", pdcch_vars->nb_search_space); #endif - fapi_nr_dci_indication_t dci_ind; nr_downlink_indication_t dl_indication; @@ -3012,15 +3018,14 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, for (int i=0; i rnti %x : format %d\n", - ue->Mod_id,frame_rx%1024,nr_tti_rx,mode_string[ue->UE_mode[0]], + ue->Mod_id,frame_rx%1024,nr_tti_rx,nr_mode_string[ue->UE_mode[gNB_id]], i, dci_ind.dci_list[i].rnti, dci_ind.dci_list[i].dci_format); } ue->pdcch_vars[ue->current_thread_id[nr_tti_rx]][gNB_id]->dci_received += dci_cnt; - - dci_ind.number_of_dcis = dci_cnt; + dci_ind.number_of_dcis = dci_cnt; /* for (int i=0; iframe_parms.frame_type, dci_alloc_rx[i].dci_length, dci_alloc_rx[i].rnti, @@ -3067,14 +3072,11 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, dl_indication.dci_ind = &dci_ind; // send to mac - ue->if_inst->dl_indication(&dl_indication); + ue->if_inst->dl_indication(&dl_indication, NULL); #if UE_TIMING_TRACE stop_meas(&ue->dlsch_rx_pdcch_stats); #endif - - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_OUT); return(dci_cnt); @@ -3216,6 +3218,7 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, #endif +#if 0 void copy_harq_proc_struct(NR_DL_UE_HARQ_t *harq_processes_dest, NR_DL_UE_HARQ_t *current_harq_processes) { @@ -3252,6 +3255,7 @@ void copy_harq_proc_struct(NR_DL_UE_HARQ_t *harq_processes_dest, NR_DL_UE_HARQ_t harq_processes_dest->vrb_type = current_harq_processes->vrb_type ; } +#endif /*void copy_ack_struct(nr_harq_status_t *harq_ack_dest, nr_harq_status_t *current_harq_ack) { @@ -3450,7 +3454,6 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, int frame_rx = proc->frame_rx; int nr_tti_rx = proc->nr_tti_rx; int ret=0, ret1=0; - //int CC_id = ue->CC_id; NR_UE_PDSCH *pdsch_vars; uint8_t is_cw0_active = 0; uint8_t is_cw1_active = 0; @@ -3461,6 +3464,20 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, uint16_t nb_symb_sch = 9; nr_downlink_indication_t dl_indication; fapi_nr_rx_indication_t rx_ind; + // params for UL time alignment procedure + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &ue->ul_time_alignment[eNB_id]; + uint16_t slots_per_frame = ue->frame_parms.slots_per_frame; + uint16_t slots_per_subframe = ue->frame_parms.slots_per_subframe; + uint8_t numerology = ue->frame_parms.numerology_index, mapping_type_ul, mapping_type_dl; + int ul_tx_timing_adjustment, N_TA_max, factor_mu, N_t_1, N_t_2, N_1, N_2, d_1_1 = 0, d_2_1, d; + uint8_t d_2_2 = 0;// set to 0 because there is only 1 BWP + // TODO this should corresponds to the switching time as defined in + // TS 38.133 + uint16_t ofdm_symbol_size = ue->frame_parms.ofdm_symbol_size; + uint16_t nb_prefix_samples = ue->frame_parms.nb_prefix_samples; + uint32_t t_subframe = 1; // subframe duration of 1 msec + uint16_t bw_scaling, start_symbol; + float tc_factor; if (dlsch0==NULL) AssertFatal(0,"dlsch0 should be defined at this level \n"); @@ -3469,6 +3486,7 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, harq_pid = dlsch0->current_harq_pid; is_cw0_active = dlsch0->harq_processes[harq_pid]->status; nb_symb_sch = dlsch0->harq_processes[harq_pid]->nb_symbols; + start_symbol = dlsch0->harq_processes[harq_pid]->start_symbol; @@ -3720,13 +3738,130 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, dl_indication.dci_ind = NULL; //&ue->dci_ind; // send to mac if (ue->if_inst && ue->if_inst->dl_indication) - ue->if_inst->dl_indication(&dl_indication); + ue->if_inst->dl_indication(&dl_indication, ul_time_alignment); } - } + // TODO CRC check for CW0 + // Check CRC for CW 0 + /*if (ret == (1+dlsch0->max_turbo_iterations)) { + *dlsch_errors=*dlsch_errors+1; + if(dlsch0->rnti != 0xffff){ + LOG_D(PHY,"[UE %d][PDSCH %x/%d] AbsSubframe %d.%d : DLSCH CW0 in error (rv %d,round %d, mcs %d,TBS %d)\n", + ue->Mod_id,dlsch0->rnti, + harq_pid,frame_rx,subframe_rx, + dlsch0->harq_processes[harq_pid]->rvidx, + dlsch0->harq_processes[harq_pid]->round, + dlsch0->harq_processes[harq_pid]->mcs, + dlsch0->harq_processes[harq_pid]->TBS); + } + } else { + if(dlsch0->rnti != 0xffff){ + LOG_D(PHY,"[UE %d][PDSCH %x/%d] AbsSubframe %d.%d : Received DLSCH CW0 (rv %d,round %d, mcs %d,TBS %d)\n", + ue->Mod_id,dlsch0->rnti, + harq_pid,frame_rx,subframe_rx, + dlsch0->harq_processes[harq_pid]->rvidx, + dlsch0->harq_processes[harq_pid]->round, + dlsch0->harq_processes[harq_pid]->mcs, + dlsch0->harq_processes[harq_pid]->TBS); + } + if ( LOG_DEBUGFLAG(DEBUG_UE_PHYPROC)){ + int j; + LOG_D(PHY,"dlsch harq_pid %d (rx): \n",dlsch0->current_harq_pid); + for (j=0; jharq_processes[dlsch0->current_harq_pid]->TBS>>3; j++) + LOG_T(PHY,"%x.",dlsch0->harq_processes[dlsch0->current_harq_pid]->b[j]); + LOG_T(PHY,"\n"); + }*/ + if (ue->mac_enabled == 1) { + + // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size + switch (ue->frame_parms.N_RB_DL) { + case 32: bw_scaling = 4; break; + case 66: bw_scaling = 8; break; + case 106: bw_scaling = 16; break; + case 217: bw_scaling = 32; break; + case 245: bw_scaling = 32; break; + case 273: bw_scaling = 32; break; + default: abort(); + } + + /* Time Alignment procedure + // - UE processing capability 1 + // - Setting the TA update to be applied after the reception of the TA command + // - Timing adjustment computed according to TS 38.213 section 4.2 + // - Durations of N1 and N2 symbols corresponding to PDSCH and PUSCH are + // computed according to sections 5.3 and 6.4 of TS 38.214 */ + factor_mu = 1 << numerology; + N_TA_max = 3846 * bw_scaling / factor_mu; + + /* PDSCH decoding time N_1 for processing capability 1 */ + if (ue->dmrs_DownlinkConfig.pdsch_dmrs_AdditionalPosition == pdsch_dmrs_pos0) + N_1 = pdsch_N_1_capability_1[numerology][1]; + else if (ue->dmrs_DownlinkConfig.pdsch_dmrs_AdditionalPosition == pdsch_dmrs_pos1 || ue->dmrs_DownlinkConfig.pdsch_dmrs_AdditionalPosition == 2) // TODO set to pdsch_dmrs_pos2 when available + N_1 = pdsch_N_1_capability_1[numerology][2]; + else + N_1 = pdsch_N_1_capability_1[numerology][3]; + + /* PUSCH preapration time N_2 for processing capability 1 */ + N_2 = pusch_N_2_timing_capability_1[numerology][1]; + mapping_type_dl = ue->PDSCH_Config.pdsch_TimeDomainResourceAllocation[0]->mappingType; + mapping_type_ul = ue->pusch_config.pusch_TimeDomainResourceAllocation[0]->mappingType; + + /* d_1_1 depending on the number of PDSCH symbols allocated */ + d = 0; // TODO number of overlapping symbols of the scheduling PDCCH and the scheduled PDSCH + if (mapping_type_dl == typeA) + if (nb_symb_sch + start_symbol < 7) + d_1_1 = 7 - (nb_symb_sch + start_symbol); + else + d_1_1 = 0; + else // mapping type B + switch (nb_symb_sch){ + case 7: d_1_1 = 0; break; + case 4: d_1_1 = 3; break; + case 2: d_1_1 = 3 + d; break; + default: break; + } + + /* d_2_1 */ + if (mapping_type_ul == typeB && start_symbol != 0) + d_2_1 = 0; + else + d_2_1 = 1; + + /* N_t_1 time duration in msec of N_1 symbols corresponding to a PDSCH reception time + // N_t_2 time duration in msec of N_2 symbols corresponding to a PUSCH preparation time */ + N_t_1 = (N_1 + d_1_1) * (ofdm_symbol_size + nb_prefix_samples) / factor_mu; + N_t_2 = (N_2 + d_2_1) * (ofdm_symbol_size + nb_prefix_samples) / factor_mu; + if (N_t_2 < d_2_2) N_t_2 = d_2_2; + + /* Time alignment procedure */ + // N_t_1 + N_t_2 + N_TA_max is in unit of Ts, therefore must be converted to Tc + // N_t_1 + N_t_2 + N_TA_max must be in msec + tc_factor = 64 * 0.509 * 10e-7; + ul_tx_timing_adjustment = 1 + ceil(slots_per_subframe*((N_t_1 + N_t_2 + N_TA_max)*tc_factor + 0.5)/t_subframe); + + if (ul_time_alignment->apply_ta == 1){ + ul_time_alignment->ta_slot = (nr_tti_rx + ul_tx_timing_adjustment) % slots_per_frame; + if (nr_tti_rx + ul_tx_timing_adjustment > slots_per_frame){ + ul_time_alignment->ta_frame = (frame_rx + 1) % 1024; + } else { + ul_time_alignment->ta_frame = frame_rx; + } + // reset TA flag + ul_time_alignment->apply_ta = 0; + LOG_D(PHY,"Frame %d slot %d -- Starting UL time alignment procedures. TA update will be applied at frame %d slot %d\n", frame_rx, nr_tti_rx, ul_time_alignment->ta_frame, ul_time_alignment->ta_slot); + } + } + + /*ue->total_TBS[eNB_id] = ue->total_TBS[eNB_id] + dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS; + ue->total_received_bits[eNB_id] = ue->total_TBS[eNB_id] + dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS; + }*/ + + // TODO CRC check for CW1 + + } } @@ -4068,6 +4203,8 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, uint8_t dci_cnt = 0; NR_DL_FRAME_PARMS *fp = &ue->frame_parms; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN); + LOG_D(PHY," ****** start RX-Chain for Frame.Slot %d.%d ****** \n", frame_rx%1024, nr_tti_rx); /* @@ -4199,7 +4336,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, #endif // do procedures for C-RNTI if (ue->dlsch[ue->current_thread_id[nr_tti_rx]][eNB_id][0]->active == 1) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); nr_ue_pdsch_procedures(ue, proc, eNB_id, @@ -4219,7 +4356,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, write_output("rxF_llr.m","rxFllr",ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id]->llr[0],(nb_symb_sch-1)*50*12+50*6,1,0); */ - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT); + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT); } // do procedures for SI-RNTI @@ -4454,7 +4591,7 @@ return (0); } -uint8_t is_cqi_TXOp(PHY_VARS_NR_UE *ue, +uint8_t nr_is_cqi_TXOp(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { @@ -4476,7 +4613,7 @@ uint8_t is_cqi_TXOp(PHY_VARS_NR_UE *ue, } -uint8_t is_ri_TXOp(PHY_VARS_NR_UE *ue, +uint8_t nr_is_ri_TXOp(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { diff --git a/openair1/SCHED_NR_UE/phy_sch_processing_time.h b/openair1/SCHED_NR_UE/phy_sch_processing_time.h new file mode 100644 index 0000000000..1962df22ee --- /dev/null +++ b/openair1/SCHED_NR_UE/phy_sch_processing_time.h @@ -0,0 +1,109 @@ +/* + * 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 phy_sch_processing_time.h + \brief tables for UE PDSCH processing and UE PUSCH preparation procedure time + from TS 38.214 Physical procedures for data v15.6.0 + \author Guido Casati + \date 2019 + \version 0.1 + \company Fraunhofer IIS + \email: guido.casati@iis.fraunhofer.de + \note + \warning +*/ + +/* TS 38.214 Table 5.3-1: PDSCH processing time for PDSCH processing capability 1 +// corresponding to the PDSCH decoding time N_1 [symbols] +// where mu corresponds to the one of {mu_PDCCH, mu_PDSCH, mu_UL} +// resulting with the largest T_proc_1 +// where mu_PDCCH is the SCS of PDCCH scheduling PDSCH +// mu_PDSCH is the SCS of the scheduled PDSCH +// mu_UL is the SCS of the UL channel with which the HARQ-ACK is to be transmitted +// column A is N_1 corresponding to dmrs-AdditionalPosition pos0 in DMRS-DownlinkConfig +// in both dmrs-DownlinkForPDSCH-MappingTypeA and dmrs-DownlinkForPDSCH-MappingTypeB +// column B is N_1 corresponding to corresponds to dmrs-AdditionalPosition !0 +// in DMRS-DownlinkConfig in both dmrs-DownlinkForPDSCH-MappingTypeA, +// dmrs-DownlinkForPDSCH-MappingTypeB or if the higher layer param is not configured +// when PDSCH DM-RS position l1 for the additional DM-RS is l1 = 1,2 +// column C is N_1 corresponding to corresponds to dmrs-AdditionalPosition !0 +// in DMRS-DownlinkConfig in both dmrs-DownlinkForPDSCH-MappingTypeA, +// dmrs-DownlinkForPDSCH-MappingTypeB or if the higher layer param is not configured +// when PDSCH DM-RS position l1 for the additional DM-RS is != 1,2 + +*/ +int8_t pdsch_N_1_capability_1[4][4] = { +/* mu A B C */ +{ 0, 8, 14, 13 }, +{ 1, 10, 13, 13 }, +{ 2, 17, 20, 20 }, +{ 3, 20, 24, 24 }, +}; + +/* TS 38.214 Table 5.3-2: PDSCH processing time for PDSCH processing capability 2 +// corresponding to the PDSCH decoding time N_1 [symbols] +// where mu corresponds to the one of {mu_PDCCH, mu_PDSCH, mu_UL} +// resulting with the largest T_proc_1 +// where mu_PDCCH is the SCS of PDCCH scheduling PDSCH +// mu_PDSCH is the SCS of the scheduled PDSCH +// mu_UL is the SCS of the UL channel with which the HARQ-ACK is to be transmitted +// column A is N_1 corresponding to dmrs-AdditionalPosition pos0 in DMRS-DownlinkConfig in both +// dmrs-DownlinkForPDSCH-MappingTypeA and dmrs-DownlinkForPDSCH-MappingTypeB +// mu == 2 is for FR1 only +*/ +float pdsch_N_1_capability_2[3][2] = { +/* mu A */ +{ 0, 3 }, +{ 1, 4.5 }, +{ 2, 9 }, +}; + +/* TS 38.214 Table 6.4-1: PUSCH preparation time for PUSCH timing capability 1 +// corresponding to the PUSCH preparation time N_2 [symbols] +// where mu corresponds to the one of {mu_DL, mu_UL} +// resulting with the largest T_proc_2 +// where mu_DL is the SCS with which the PDCCH +// carrying the DCI scheduling the PUSCH was transmitted +// mu_UL is the SCS of the UL channel with which PUSCH to be transmitted +*/ +int8_t pusch_N_2_timing_capability_1[4][2] = { +/* mu N_2 */ +{ 0, 10 }, +{ 1, 12 }, +{ 2, 23 }, +{ 3, 36 }, +}; + +/* TS 38.214 Table 6.4-2: PUSCH preparation time for PUSCH timing capability 2 +// corresponding to the PUSCH preparation time N_2 [symbols] +// where mu corresponds to the one of {mu_DL, mu_UL} +// resulting with the largest T_proc_2 +// where mu_DL is the SCS with which the PDCCH +// carrying the DCI scheduling the PUSCH was transmitted +// mu_UL is the SCS of the UL channel with which PUSCH to be transmitted +// mu == 2 is for FR1 only +*/ +float pusch_N_2_timing_capability_2[3][2] = { +/* mu N_2 */ +{ 0, 5 }, +{ 1, 5.5 }, +{ 2, 11 }, +}; \ No newline at end of file diff --git a/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c b/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c index d955cbb242..9632291e67 100644 --- a/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c +++ b/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c @@ -33,6 +33,7 @@ #include "SCHED_NR_UE/pucch_uci_ue_nr.h" #include "SCHED_NR_UE/pucch_power_control_ue_nr.h" #include +#include /**************** defines **************************************/ @@ -69,17 +70,17 @@ int16_t get_pucch_tx_power_ue(PHY_VARS_NR_UE *ue, uint8_t gNB_id, - UE_nr_rxtx_proc_t *proc, - pucch_format_nr_t pucch_format, - int nb_of_prbs, - int N_sc_ctrl_RB, - int N_symb_PUCCH, - int O_UCI, - int O_SR, - int O_CSI, - int O_ACK, + UE_nr_rxtx_proc_t *proc, + pucch_format_nr_t pucch_format, + int nb_of_prbs, + int N_sc_ctrl_RB, + int N_symb_PUCCH, + int O_UCI, + int O_SR, + int O_CSI, + int O_ACK, int O_CRC, - int n_HARQ_ACK) { + int n_HARQ_ACK) { int16_t P_O_NOMINAL_PUCCH = ue->pucch_config_common_nr[gNB_id].p0_nominal; PUCCH_PowerControl_t *power_config = &ue->pucch_config_dedicated_nr[gNB_id].pucch_PowerControl; @@ -103,7 +104,7 @@ int16_t get_pucch_tx_power_ue(PHY_VARS_NR_UE *ue, int P_O_PUCCH = P_O_NOMINAL_PUCCH + P_O_UE_PUCCH; - int16_t PL = 100;//get_PL(ue->Mod_id, ue->CC_id, gNB_id); /* LTE function because NR path loss not yet implemented FFS TODO NR */ + int16_t PL = get_nr_PL(ue, gNB_id); /* LTE function because NR path loss not yet implemented FFS TODO NR */ int16_t delta_F_PUCCH = power_config->deltaF_PUCCH_f[pucch_format]; diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c index 74a2ea5cbc..326c617dfb 100644 --- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c +++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c @@ -41,6 +41,7 @@ #ifndef NO_RAT_NR +#include "SCHED_NR_UE/defs.h" #include "SCHED_NR_UE/harq_nr.h" #include "SCHED_NR_UE/pucch_power_control_ue_nr.h" @@ -52,8 +53,8 @@ -uint8_t is_cqi_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); -uint8_t is_ri_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); +uint8_t nr_is_cqi_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); +uint8_t nr_is_ri_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); /* void nr_generate_pucch0(int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, @@ -226,10 +227,10 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_ &n_HARQ_ACK, reset_harq); // 1 to reset ACK/NACK status : 0 otherwise cqi_status = ((ue->cqi_report_config[gNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0) && - (is_cqi_TXOp(ue,proc,gNB_id) == 1)); + (nr_is_cqi_TXOp(ue,proc,gNB_id) == 1)); ri_status = ((ue->cqi_report_config[gNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) && - (is_ri_TXOp(ue,proc,gNB_id) == 1)); + (nr_is_ri_TXOp(ue,proc,gNB_id) == 1)); csi_status = get_csi_nr(ue, gNB_id, &csi_payload); @@ -547,7 +548,7 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_ #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) - tx_amp = get_tx_amp(pucch_tx_power, + tx_amp = nr_get_tx_amp(pucch_tx_power, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, nb_of_prbs); diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index 921a1b8a38..e0ea4ef2b2 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -36,7 +36,7 @@ #include "assertions.h" #include "PHY/defs_UE.h" #include "PHY/phy_extern_ue.h" -#include "executables/nr-uesoftmodem.h" +//#include "executables/nr-uesoftmodem.h" #include "targets/RT/USER/lte-softmodem.h" #include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h" @@ -53,11 +53,7 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" - -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif - +#include "intertask_interface.h" #include "PHY/defs_UE.h" #include "PHY/CODING/coding_extern.h" @@ -2957,7 +2953,7 @@ void ue_pmch_procedures(PHY_VARS_UE *ue, dlsch_unscrambling(&ue->frame_parms,1,ue->dlsch_MCH[0], ue->dlsch_MCH[0]->harq_processes[0]->G, - ue->pdsch_vars_MCH[0]->llr[0],0,subframe_rx<<1); + ue->pdsch_vars_MCH[ue->current_thread_id[subframe_rx]][0]->llr[0],0,subframe_rx<<1); LOG_D(PHY,"start turbo decode for MCH %d.%d --> nb_rb %d \n", frame_rx, subframe_rx, ue->dlsch_MCH[0]->harq_processes[0]->nb_rb); LOG_D(PHY,"start turbo decode for MCH %d.%d --> rb_alloc_even %x \n", frame_rx, subframe_rx, (unsigned int)((intptr_t)ue->dlsch_MCH[0]->harq_processes[0]->rb_alloc_even)); LOG_D(PHY,"start turbo decode for MCH %d.%d --> Qm %d \n", frame_rx, subframe_rx, ue->dlsch_MCH[0]->harq_processes[0]->Qm); @@ -2965,7 +2961,7 @@ void ue_pmch_procedures(PHY_VARS_UE *ue, LOG_D(PHY,"start turbo decode for MCH %d.%d --> G %d \n", frame_rx, subframe_rx, ue->dlsch_MCH[0]->harq_processes[0]->G); LOG_D(PHY,"start turbo decode for MCH %d.%d --> Kmimo %d \n", frame_rx, subframe_rx, ue->dlsch_MCH[0]->Kmimo); ret = dlsch_decoding(ue, - ue->pdsch_vars_MCH[0]->llr[0], + ue->pdsch_vars_MCH[ue->current_thread_id[subframe_rx]][0]->llr[0], &ue->frame_parms, ue->dlsch_MCH[0], ue->dlsch_MCH[0]->harq_processes[0], @@ -4885,10 +4881,8 @@ void phy_procedures_UE_lte(PHY_VARS_UE *ue, uint8_t abstraction_flag, uint8_t do_pdcch_flag, runmode_t mode) { -#if defined(ENABLE_ITTI) MessageDef *msg_p; int result; -#endif int frame_rx = proc->frame_rx; int frame_tx = proc->frame_tx; int subframe_rx = proc->subframe_rx; @@ -4905,9 +4899,6 @@ void phy_procedures_UE_lte(PHY_VARS_UE *ue, if ( LOG_DEBUGFLAG(UE_TIMING)) { start_meas(&ue->phy_proc[ue->current_thread_id[subframe_rx]]); } - -#if defined(ENABLE_ITTI) - do { // Checks if a message has been sent to PHY sub-task itti_poll_msg (TASK_PHY_UE, &msg_p); @@ -4929,8 +4920,6 @@ void phy_procedures_UE_lte(PHY_VARS_UE *ue, } } while(msg_p != NULL); -#endif - for (slot=0; slot<2; slot++) { if ((subframe_select(&ue->frame_parms,subframe_tx)==SF_UL)|| (ue->frame_parms.frame_type == FDD)) { diff --git a/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c b/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c index 396c76f8e6..9b4aba46c3 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c @@ -58,6 +58,8 @@ struct iovec nas_iov_rx = {nl_rx_buf, sizeof(nl_rx_buf)}; int nas_sock_fd[MAX_MOBILES_PER_ENB]; +int nas_sock_mbms_fd; + struct msghdr nas_msg_tx; struct msghdr nas_msg_rx; @@ -92,6 +94,63 @@ static int tun_alloc(char *dev) { return fd; } + +int netlink_init_mbms_tun(char *ifprefix) { + int ret; + char ifname[64]; + + sprintf(ifname, "oaitun_%.3s1",ifprefix); // added "1": for historical reasons + nas_sock_mbms_fd = tun_alloc(ifname); + + if (nas_sock_mbms_fd == -1) { + printf("[NETLINK] Error opening socket %s (%d:%s)\n",ifname,errno, strerror(errno)); + exit(1); + } + + printf("[NETLINK]Opened socket %s with fd %d\n",ifname,nas_sock_mbms_fd); + ret = fcntl(nas_sock_mbms_fd,F_SETFL,O_NONBLOCK); + + if (ret == -1) { + printf("[NETLINK] Error fcntl (%d:%s)\n",errno, strerror(errno)); + + if (LINK_ENB_PDCP_TO_IP_DRIVER) { + exit(1); + } + } + + memset(&nas_src_addr, 0, sizeof(nas_src_addr)); + nas_src_addr.nl_family = AF_NETLINK; + nas_src_addr.nl_pid = 1;//getpid(); /* self pid */ + nas_src_addr.nl_groups = 0; /* not in mcast groups */ + ret = bind(nas_sock_mbms_fd, (struct sockaddr *)&nas_src_addr, sizeof(nas_src_addr)); + memset(&nas_dest_addr, 0, sizeof(nas_dest_addr)); + nas_dest_addr.nl_family = AF_NETLINK; + nas_dest_addr.nl_pid = 0; /* For Linux Kernel */ + nas_dest_addr.nl_groups = 0; /* unicast */ + // TX PART + nas_nlh_tx=(struct nlmsghdr *)malloc(NLMSG_SPACE(NL_MAX_PAYLOAD)); + memset(nas_nlh_tx, 0, NLMSG_SPACE(NL_MAX_PAYLOAD)); + /* Fill the netlink message header */ + nas_nlh_tx->nlmsg_len = NLMSG_SPACE(NL_MAX_PAYLOAD); + nas_nlh_tx->nlmsg_pid = 1;//getpid(); /* self pid */ + nas_nlh_tx->nlmsg_flags = 0; + nas_iov_tx.iov_base = (void *)nas_nlh_tx; + nas_iov_tx.iov_len = nas_nlh_tx->nlmsg_len; + memset(&nas_msg_tx,0,sizeof(nas_msg_tx)); + nas_msg_tx.msg_name = (void *)&nas_dest_addr; + nas_msg_tx.msg_namelen = sizeof(nas_dest_addr); + nas_msg_tx.msg_iov = &nas_iov_tx; + nas_msg_tx.msg_iovlen = 1; + // RX PART + memset(&nas_msg_rx,0,sizeof(nas_msg_rx)); + nas_msg_rx.msg_name = (void *)&nas_src_addr; + nas_msg_rx.msg_namelen = sizeof(nas_src_addr); + nas_msg_rx.msg_iov = &nas_iov_rx; + nas_msg_rx.msg_iovlen = 1; + + return 1; +} + int netlink_init_tun(char *ifprefix, int num_if) { int ret; char ifname[64]; @@ -105,7 +164,8 @@ int netlink_init_tun(char *ifprefix, int num_if) { exit(1); } - printf("[NETLINK]Opened socket %s with fd %d\n",ifname,nas_sock_fd[i]); + printf("[NETLINK]Opened socket %s with fd nas_sock_fd[%d]=%d\n", + ifname, i, nas_sock_fd[i]); ret = fcntl(nas_sock_fd[i],F_SETFL,O_NONBLOCK); if (ret == -1) { @@ -163,7 +223,7 @@ int netlink_init(void) { } } - printf("[NETLINK]Opened socket with fd %d\n",nas_sock_fd[0]); + printf("[NETLINK] Opened socket with fd %d\n",nas_sock_fd[0]); ret = fcntl(nas_sock_fd[0],F_SETFL,O_NONBLOCK); if (ret == -1) { diff --git a/openair1/SIMULATION/ETH_TRANSPORT/proto.h b/openair1/SIMULATION/ETH_TRANSPORT/proto.h index ff677d1580..e6159199d4 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/proto.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/proto.h @@ -63,5 +63,6 @@ void clear_eNB_transport_info(uint8_t); void clear_UE_transport_info(uint8_t); int netlink_init(void); int netlink_init_tun(char *ifsuffix, int num_if); +int netlink_init_mbms_tun(char *ifsuffix); #endif /* EMU_PROTO_H_ */ diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index eeee9bb6a5..80b26c0bbd 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -56,7 +56,7 @@ RAN_CONTEXT_t RC; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; double cpuf; -int nfapi_mode = 0; +uint8_t nfapi_mode = 0; uint16_t NB_UE_INST = 1; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 6ce7755451..ebcedbaeb0 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -76,16 +76,17 @@ int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; double cpuf; -int sf_ahead=4; +int sf_ahead=4 ; +int sl_ahead=0; +uint8_t nfapi_mode = 0; +uint16_t NB_UE_INST = 1; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; // dummy functions int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } void pdcp_run (const protocol_ctxt_t *const ctxt_pP) { return;} -int nfapi_mode=0; - - int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, const int CC_id, const uint8_t gNB_index, @@ -97,14 +98,17 @@ int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, } -uint16_t NB_UE_INST = 1; - -//Dummy Functions -//lte_subframe_t subframe_select(LTE_DL_FRAME_PARMS *frame_parms, unsigned char subframe) {return(SF_DL);} -int rlc_module_init (int eNB_id) {return(0);} - - void pdcp_layer_init(void) {} +boolean_t +pdcp_data_ind( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const sdu_size_t sdu_buffer_sizeP, + mem_block_t *const sdu_buffer_pP +) { return(false);} + int rrc_init_nr_global_param(void){return(0);} void config_common(int Mod_idP, @@ -112,29 +116,6 @@ void config_common(int Mod_idP, NR_ServingCellConfigCommon_t *scc ); -uint64_t get_softmodem_optmask(void) {return 0;} -mac_rlc_status_resp_t mac_rlc_status_ind(const module_id_t module_idP, - const rnti_t rntiP, - const eNB_index_t eNB_index, - const frame_t frameP, - const sub_frame_t subframeP, - const eNB_flag_t enb_flagP, - const MBMS_flag_t MBMS_flagP, - const logical_chan_id_t channel_idP, - const tb_size_t tb_sizeP, - const uint32_t sourceL2Id, - const uint32_t destinationL2Id) {mac_rlc_status_resp_t mac_rlc_status_resp = {0}; return mac_rlc_status_resp;} -tbs_size_t mac_rlc_data_req(const module_id_t module_idP, - const rnti_t rntiP, - const eNB_index_t eNB_index, - const frame_t frameP, - const eNB_flag_t enb_flagP, - const MBMS_flag_t MBMS_flagP, - const logical_chan_id_t channel_idP, - const tb_size_t tb_sizeP, - char *buffer_pP, - const uint32_t sourceL2Id, - const uint32_t destinationL2Id) {return 0;} int generate_dlsch_header(unsigned char *mac_header, unsigned char num_sdus, unsigned short *sdu_lengths, @@ -145,24 +126,13 @@ int generate_dlsch_header(unsigned char *mac_header, unsigned char short_padding, unsigned short post_padding){return 0;} void nr_ip_over_LTE_DRB_preconfiguration(void){} -void mac_rlc_data_ind ( - const module_id_t module_idP, - const rnti_t rntiP, - const eNB_index_t eNB_index, - const frame_t frameP, - const eNB_flag_t enb_flagP, - const MBMS_flag_t MBMS_flagP, - const logical_chan_id_t channel_idP, - char *buffer_pP, - const tb_size_t tb_sizeP, - num_tb_t num_tbP, - crc_t *crcs_pP) -{} // needed for some functions openair0_config_t openair0_cfg[MAX_CARDS]; + + int main(int argc, char **argv) { char c; @@ -232,17 +202,18 @@ int main(int argc, char **argv) int mcsIndex_set=0,rbStart_set=0,rbSize_set=0; int print_perf = 0; + FILE *scg_fd=NULL; + while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:e:m:")) != -1) { switch (c) { - /*case 'f': - write_output_file=1; - output_fd = fopen(optarg,"w"); + case 'f': + scg_fd = fopen(optarg,"r"); - if (output_fd==NULL) { + if (scg_fd==NULL) { printf("Error opening %s\n",optarg); exit(-1); } - break;*/ + break; /*case 'd': frame_type = 1; @@ -432,7 +403,7 @@ int main(int argc, char **argv) printf("-O oversampling factor (1,2,4,8,16)\n"); printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); - //printf("-f Output filename (.txt format) for Pe/SNR results\n"); + printf("-f raw file containing RRC configuration (generated by gNB)\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); printf("-E used CSS scheduler\n"); printf("-o CORESET offset\n"); @@ -450,6 +421,8 @@ int main(int argc, char **argv) set_glog(loglvl); T_stdout = 1; + get_softmodem_params()->phy_test = 1; + if (snr1set==0) snr1 = snr0+10; @@ -466,12 +439,16 @@ int main(int argc, char **argv) frame_parms->N_RB_UL = N_RB_DL; RC.nb_nr_macrlc_inst = 1; + RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); + for (i = 0; i < RC.nb_nr_macrlc_inst; i++) + RC.nb_nr_mac_CC[i] = 1; mac_top_init_gNB(); gNB_mac = RC.nrmac[0]; gNB_RRC_INST rrc; memset((void*)&rrc,0,sizeof(rrc)); + + /* // read in SCGroupConfig - FILE *scg_fd = fopen("reconfig.raw","r"); AssertFatal(scg_fd != NULL,"no reconfig.raw file\n"); char buffer[1024]; int msg_len=fread(buffer,1,1024,scg_fd); @@ -508,15 +485,28 @@ int main(int argc, char **argv) SEQUENCE_free( &asn_DEF_NR_CellGroupConfig, secondaryCellGroup, 1 ); exit(-1); } - - NR_ServingCellConfigCommon_t *scc = secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon; - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); + NR_ServingCellConfigCommon_t *scc = secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon; + */ - rrc.carrier.servingcellconfigcommon = secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon; - printf("%p,%p\n", - secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon, - rrc.carrier.servingcellconfigcommon); + + rrc.carrier.servingcellconfigcommon = calloc(1,sizeof(*rrc.carrier.servingcellconfigcommon)); + + NR_ServingCellConfigCommon_t *scc = rrc.carrier.servingcellconfigcommon; + NR_CellGroupConfig_t *secondaryCellGroup=calloc(1,sizeof(*secondaryCellGroup)); + prepare_scc(rrc.carrier.servingcellconfigcommon); + uint64_t ssb_bitmap; + fill_scc(rrc.carrier.servingcellconfigcommon,&ssb_bitmap,N_RB_DL,N_RB_DL,mu,mu); + + fill_default_secondaryCellGroup(scc, + secondaryCellGroup, + 0, + 1, + n_tx, + 0); + fix_scc(scc,ssb_bitmap); + + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); AssertFatal((gNB->if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; @@ -630,7 +620,6 @@ int main(int argc, char **argv) nr_gold_pbch(UE); nr_gold_pdcch(UE,0,2); - nr_l2_init_ue(NULL); UE_mac = get_mac_inst(0); @@ -659,9 +648,9 @@ int main(int argc, char **argv) gNB->ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234; if (mcsIndex_set==0) dlsch_config.mcsIndex[0]=9; - if (rbSize_set==0) dlsch_config.rbSize=N_RB_DL; + if (rbStart_set==0) dlsch_config.rbStart=0; - + if (rbSize_set==0) dlsch_config.rbSize=N_RB_DL-dlsch_config.rbStart; //Configure UE rrc.carrier.MIB = (uint8_t*) malloc(4); @@ -731,9 +720,11 @@ int main(int argc, char **argv) Sched_INFO.TX_req = &gNB_mac->TX_req[0]; nr_schedule_response(&Sched_INFO); - phy_procedures_gNB_TX(gNB,frame,slot,0); + if (run_initial_sync) + nr_common_signal_procedures(gNB,frame,slot); + else + phy_procedures_gNB_TX(gNB,frame,slot,0); - //nr_common_signal_procedures (gNB,frame,subframe); int txdataF_offset = (slot%2) * frame_parms->samples_per_slot_wCP; if (n_trials==1) { @@ -741,7 +732,7 @@ int main(int argc, char **argv) if (gNB->frame_parms.nb_antennas_tx>1) LOG_M("txsigF1.m","txsF1", gNB->common_vars.txdataF[1],frame_length_complex_samples_no_prefix,1,1); } - int tx_offset = slot*frame_parms->samples_per_slot; + int tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); if (n_trials==1) printf("samples_per_slot_wCP = %d\n", frame_parms->samples_per_slot_wCP); //TODO: loop over slots @@ -770,13 +761,13 @@ int main(int argc, char **argv) if (output_fd) fwrite(txdata[0],sizeof(int32_t),frame_length_complex_samples,output_fd); - int txlev = signal_energy(&txdata[0][(slot*frame_parms->samples_per_slot)+5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], + int txlev = signal_energy(&txdata[0][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)+5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); // if (n_trials==1) printf("txlev %d (%f)\n",txlev,10*log10((double)txlev)); - for (i=(slot * frame_parms->samples_per_slot); - i<((slot+1) * frame_parms->samples_per_slot); + for (i=(frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)); + i<(frame_parms->get_samples_slot_timestamp(slot+1,frame_parms,0)); i++) { for (aa=0; aanb_antennas_tx; aa++) { r_re[aa][i] = ((double)(((short *)txdata[aa]))[(i<<1)]); @@ -792,8 +783,8 @@ int main(int argc, char **argv) sigma2 = pow(10, sigma2_dB/10); if (n_trials==1) printf("sigma2 %f (%f dB), txlev %f (factor %f)\n",sigma2,sigma2_dB,10*log10((double)txlev),(double)(double)UE->frame_parms.ofdm_symbol_size/(12*rel15.rbSize)); - for (i=(slot * frame_parms->samples_per_slot); - i<((slot+1) * frame_parms->samples_per_slot); + for (i=frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); + iget_samples_slot_timestamp(slot+1,frame_parms,0); i++) { for (aa=0; aanb_antennas_rx; aa++) { ((short*) UE->common_vars.rxdata[aa])[2*i] = (short) ((r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0))); diff --git a/openair1/SIMULATION/NR_PHY/nr_unitary_defs.h b/openair1/SIMULATION/NR_PHY/nr_unitary_defs.h index 78596cc792..c7a30f826e 100644 --- a/openair1/SIMULATION/NR_PHY/nr_unitary_defs.h +++ b/openair1/SIMULATION/NR_PHY/nr_unitary_defs.h @@ -55,4 +55,172 @@ signed char quantize(double D, double x, unsigned char B) { return ((char) qxd); } +void fill_scc(NR_ServingCellConfigCommon_t *scc,uint64_t *ssb_bitmap,int N_RB_DL,int N_RB_UL,int mu_dl,int mu_ul) { + + *scc->physCellId=0; \ + // *scc->n_TimingAdvanceOffset=NR_ServingCellConfigCommon__n_TimingAdvanceOffset_n0; + *scc->ssb_periodicityServingCell=NR_ServingCellConfigCommon__ssb_periodicityServingCell_ms20; + scc->dmrs_TypeA_Position=NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos2; + *scc->ssbSubcarrierSpacing=NR_SubcarrierSpacing_kHz30; + *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB=641032; + *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]=78; + scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA=640000; + scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier=0; + scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing=NR_SubcarrierSpacing_kHz30; + + scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth=N_RB_DL; + scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth=13036; + scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing=mu_dl;//NR_SubcarrierSpacing_kHz30; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero=12; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero=0; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[0]->k0=0; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[0]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[0]->startSymbolAndLength=40; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[1]->k0=0; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[1]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[1]->startSymbolAndLength=53; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[2]->k0=0; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[2]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[2]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[3]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[3]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[3]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[4]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[4]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[4]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[5]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[5]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[5]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[6]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[6]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[6]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[7]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[7]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[7]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[8]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[8]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[8]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[9]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[9]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[9]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[10]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[10]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[10]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[11]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[11]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[11]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[12]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[12]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[12]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[13]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[13]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[13]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[14]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[14]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[14]->startSymbolAndLength=54; + *scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[15]->k0=-1; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[15]->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA; + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[15]->startSymbolAndLength=54; + *scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list.array[0]=78; + *scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA=-1; + scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier=0; + scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing=NR_SubcarrierSpacing_kHz30; + scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth=N_RB_UL; + *scc->uplinkConfigCommon->frequencyInfoUL->p_Max=20; + scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth=13036; + scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing=mu_ul;//NR_SubcarrierSpacing_kHz30; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex=98; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM=NR_RACH_ConfigGeneric__msg1_FDM_one; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart=0; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig=13; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower=-118; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax=NR_RACH_ConfigGeneric__preambleTransMax_n10; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep=NR_RACH_ConfigGeneric__powerRampingStep_dB2; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow=NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB__one_n64; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer=NR_RACH_ConfigCommon__ra_ContentionResolutionTimer_sf64; + *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB=19; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present=NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.choice.l139=0; + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[0]->k2=2; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[0]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[0]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[1]->k2=2; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[1]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[1]->startSymbolAndLength=69; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[2]->k2=2; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[2]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[2]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[3]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[3]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[3]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[4]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[4]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[4]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[5]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[5]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[5]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[6]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[6]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[6]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[7]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[7]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[7]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[8]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[8]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[8]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[9]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[9]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[9]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[10]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[10]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[10]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[11]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[11]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[11]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[12]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[12]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[12]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[13]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[13]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[13]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[14]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[14]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[14]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[15]->k2=33; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[15]->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[15]->startSymbolAndLength=55; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble=1; + *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant=-90; + scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping=NR_PUCCH_ConfigCommon__pucch_GroupHopping_neither; + *scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId=40; + *scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal=-90; + scc->ssb_PositionsInBurst->present=NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap; + *ssb_bitmap=0xff; + scc->tdd_UL_DL_ConfigurationCommon->referenceSubcarrierSpacing=NR_SubcarrierSpacing_kHz30; + scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5; + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots=7; + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSymbols=6; + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots=2; + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols=4; + scc->tdd_UL_DL_ConfigurationCommon->pattern2->dl_UL_TransmissionPeriodicity=321; + + scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSlots=-1; + scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSymbols=-1; + scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofUplinkSlots=-1; + scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofUplinkSymbols=-1; + scc->ss_PBCH_BlockPower=20; + *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing=-1; +} + +void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap); +void prepare_scc(NR_ServingCellConfigCommon_t *scc); +s1ap_eNB_config_t s1ap_config; +uint32_t s1ap_generate_eNB_id(void) {return 0;} +void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) { return;} +void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port) { return;} + + #endif diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index a1f35b07d9..99ca466fee 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -55,14 +55,57 @@ RAN_CONTEXT_t RC; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; double cpuf; -int nfapi_mode=0; - - +uint8_t nfapi_mode = 0; uint16_t NB_UE_INST = 1; // needed for some functions openair0_config_t openair0_cfg[MAX_CARDS]; +uint64_t get_softmodem_optmask(void) {return 0;} +void nr_phy_config_request_sim_pbchsim(PHY_VARS_gNB *gNB, + int N_RB_DL, + int N_RB_UL, + int mu, + int Nid_cell, + uint64_t position_in_burst) +{ + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + nfapi_nr_config_request_scf_t *gNB_config = &gNB->gNB_config; + //overwrite for new NR parameters + + uint64_t rev_burst=0; + for (int i=0; i<64; i++) + rev_burst |= (((position_in_burst>>(63-i))&0x01)<cell_config.phy_cell_id.value = Nid_cell; + gNB_config->ssb_config.scs_common.value = mu; + gNB_config->ssb_table.ssb_subcarrier_offset.value = 0; + gNB_config->ssb_table.ssb_offset_point_a.value = (N_RB_DL-20)>>1; + gNB_config->ssb_table.ssb_mask_list[1].ssb_mask.value = (rev_burst)&(0xFFFFFFFF); + gNB_config->ssb_table.ssb_mask_list[0].ssb_mask.value = (rev_burst>>32)&(0xFFFFFFFF); + gNB_config->cell_config.frame_duplex_type.value = TDD; + gNB_config->ssb_table.ssb_period.value = 1; //10ms + gNB_config->carrier_config.dl_grid_size[mu].value = N_RB_DL; + gNB_config->carrier_config.ul_grid_size[mu].value = N_RB_UL; + gNB_config->carrier_config.num_tx_ant.value = fp->nb_antennas_tx; + gNB_config->carrier_config.num_rx_ant.value = fp->nb_antennas_rx; + + gNB_config->tdd_table.tdd_period.value = 0; + //gNB_config->subframe_config.dl_cyclic_prefix_type.value = (fp->Ncp == NORMAL) ? NFAPI_CP_NORMAL : NFAPI_CP_EXTENDED; + + gNB->mac_enabled = 1; + fp->dl_CarrierFreq = 3500000000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value); + fp->ul_CarrierFreq = 3500000000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000); + if (mu>2) fp->nr_band = 257; + else fp->nr_band = 78; + fp->threequarter_fs= 0; + + gNB_config->carrier_config.dl_bandwidth.value = config_bandwidth(mu, N_RB_DL, fp->nr_band); + + nr_init_frame_parms(gNB_config, fp); + gNB->configured = 1; + LOG_I(PHY,"gNB configured\n"); +} int main(int argc, char **argv) { char c; @@ -129,7 +172,7 @@ int main(int argc, char **argv) randominit(0); - while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:o:s:S:t:x:y:z:M:N:F:GR:dP:IL:")) != -1) { + while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:o:s:S:t:x:y:z:M:N:F:GR:dP:IL:m:")) != -1) { switch (c) { /*case 'f': write_output_file=1; @@ -304,6 +347,10 @@ int main(int argc, char **argv) loglvl = atoi(optarg); break; + case 'm': + mu = atoi(optarg); + break; + default: case 'h': printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", @@ -312,6 +359,7 @@ int main(int argc, char **argv) //printf("-p Use extended prefix mode\n"); //printf("-d Use TDD\n"); printf("-n Number of frames to simulate\n"); + printf("-m Numerology index\n"); printf("-s Starting SNR, runs from SNR0 to SNR0 + 5 dB. If n_frames is 1 then just SNR is simulated\n"); printf("-S Ending SNR, runs from SNR0 to SNR1\n"); printf("-t Delay spread for multipath channel\n"); @@ -351,18 +399,20 @@ int main(int argc, char **argv) frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; frame_parms->N_RB_DL = N_RB_DL; - frame_parms->N_RB_UL = N_RB_DL; frame_parms->Nid_cell = Nid_cell; frame_parms->nushift = Nid_cell%4; frame_parms->ssb_type = nr_ssb_type_C; - nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); + nr_phy_config_request_sim_pbchsim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,0); + nr_set_ssb_first_subcarrier(&gNB->gNB_config,frame_parms); uint8_t n_hf = 0; int cyclic_prefix_type = NFAPI_CP_NORMAL; - double fs,bw,scs,eps; + double fs, eps; + double scs = 30000; + double bw = 100e6; switch (mu) { case 1: @@ -386,8 +436,17 @@ int main(int argc, char **argv) } else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL); break; - } + + case 3: + scs = 120000; + if (N_RB_DL == 66) { + fs = 122.88e6; + bw = 100e6; + } + else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL); + break; + } // cfo with respect to sub-carrier spacing eps = cfo/scs; @@ -477,18 +536,18 @@ int main(int argc, char **argv) memset(gNB->common_vars.txdataF[aa],0,frame_parms->samples_per_slot_wCP*sizeof(int32_t)); nr_common_signal_procedures (gNB,frame,slot); - + for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { if (cyclic_prefix_type == 1) { PHY_ofdm_mod(gNB->common_vars.txdataF[aa], - &txdata[aa][slot*frame_parms->samples_per_slot], + &txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)], frame_parms->ofdm_symbol_size, 12, frame_parms->nb_prefix_samples, CYCLIC_PREFIX); } else { nr_normal_prefix_mod(gNB->common_vars.txdataF[aa], - &txdata[aa][slot*frame_parms->samples_per_slot], + &txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)], 14, frame_parms); } @@ -578,7 +637,6 @@ int main(int argc, char **argv) if (gNB->frame_parms.nb_antennas_tx>1) LOG_M("rxsig1.m","rxs1", UE->common_vars.rxdata[1],frame_parms->samples_per_frame,1,1); } - if (UE->is_synchronized == 0) { UE_nr_rxtx_proc_t proc={0}; ret = nr_initial_sync(&proc, UE, normal_txrx,1); @@ -591,7 +649,8 @@ int main(int argc, char **argv) while (!((SSB_positions >> ssb_index) & 0x01)) ssb_index++; // to select the first transmitted ssb frame_parms->ssb_index = ssb_index; UE->symbol_offset = nr_get_ssb_start_symbol(frame_parms); - int ssb_slot = (ssb_index/2)+(n_hf*frame_parms->slots_per_frame); + + int ssb_slot = (ssb_index>>1)+(n_hf*frame_parms->slots_per_frame); for (int i=UE->symbol_offset+1; isymbol_offset+4; i++) { nr_slot_fep(UE, i%frame_parms->symbols_per_slot, @@ -619,7 +678,7 @@ int main(int argc, char **argv) uint8_t gNB_xtra_byte=0; for (int i=0; i<8; i++) gNB_xtra_byte |= ((gNB->pbch.pbch_a>>(31-i))&1)<<(7-i); - + payload_ret = (UE->pbch_vars[0]->xtra_byte == gNB_xtra_byte); for (i=0;i<3;i++){ payload_ret += (UE->pbch_vars[0]->decoded_output[i] == (gNB->ssb_pdu.ssb_pdu_rel15.bchPayload>>(8*i))); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index fb247e89c1..5c00352515 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -73,13 +73,20 @@ int8_t nr_ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t e return 0; } +uint8_t nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t *ulsch_buffer, uint16_t buflen, uint8_t *access_mode) {return(0);} + int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind) {return(0);} openair0_config_t openair0_cfg[MAX_CARDS]; -int nfapi_mode=0; +uint8_t nfapi_mode=0; NR_IF_Module_t *NR_IF_Module_init(int Mod_id){return(NULL);} int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) { return(0); } +uint64_t get_softmodem_optmask(void) { + return 0; +} int main(int argc, char **argv) { @@ -393,7 +400,7 @@ int main(int argc, char **argv) nsymb = (frame_parms->Ncp == 0) ? 14 : 12; printf("FFT Size %d, Extended Prefix %d, Samples per subframe %d,Frame type %s, Frequency Range %s\n",NUMBER_OF_OFDM_CARRIERS, - frame_parms->Ncp,frame_parms->samples_per_slot<<1,frame_parms->frame_type == FDD ? "FDD" : "TDD", frame_parms->freq_range == nr_FR1 ? "FR1" : "FR2"); + frame_parms->Ncp,frame_parms->samples_per_subframe,frame_parms->frame_type == FDD ? "FDD" : "TDD", frame_parms->freq_range == nr_FR1 ? "FR1" : "FR2"); ru->nr_frame_parms=frame_parms; ru->if_south = LOCAL_RF; @@ -421,7 +428,7 @@ int main(int argc, char **argv) } txdata = UE->common_vars.txdata; - printf("txdata %p\n",&txdata[0][subframe*frame_parms->samples_per_slot<<1]); + printf("txdata %p\n",&txdata[0][subframe*frame_parms->samples_per_subframe]); double fs,bw; @@ -524,25 +531,25 @@ int main(int argc, char **argv) /* tx_lev_dB not used later, no need to set */ //tx_lev_dB = (unsigned int) dB_fixed(tx_lev); - LOG_M("txsig0.m","txs0", &txdata[0][subframe*frame_parms->samples_per_slot<<1],frame_parms->samples_per_slot<<1,1,1); + LOG_M("txsig0.m","txs0", &txdata[0][subframe*frame_parms->samples_per_subframe],frame_parms->samples_per_subframe,1,1); //LOG_M("txsig1.m","txs1", txdata[1],FRAME_LENGTH_COMPLEX_SAMPLES,1,1); // multipath channel dump_nr_prach_config(&gNB->frame_parms,subframe); - for (i=0; i<2*frame_parms->samples_per_slot<<1; i++) { + for (i=0; i<2*frame_parms->samples_per_subframe; i++) { for (aa=0; aa<1; aa++) { if (awgn_flag == 0) { - s_re[aa][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_slot<<1]))[(i<<1)]); - s_im[aa][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_slot<<1]))[(i<<1)+1]); + s_re[aa][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)]); + s_im[aa][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)+1]); } else { for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { if (aa==0) { - r_re[aarx][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_slot<<1]))[(i<<1)]); - r_im[aarx][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_slot<<1]))[(i<<1)+1]); + r_re[aarx][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)]); + r_im[aarx][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)+1]); } else { - r_re[aarx][i] += ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_slot<<1]))[(i<<1)]); - r_im[aarx][i] += ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_slot<<1]))[(i<<1)+1]); + r_re[aarx][i] += ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)]); + r_im[aarx][i] += ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)+1]); } } } @@ -573,7 +580,7 @@ int main(int argc, char **argv) if (awgn_flag == 0) { multipath_tv_channel(UE2gNB,s_re,s_im,r_re,r_im, - 2*frame_parms->samples_per_slot<<1,0); + 2*frame_parms->samples_per_subframe,0); } if (n_frames==1) { @@ -582,11 +589,11 @@ int main(int argc, char **argv) 10*log10(tx_lev)); } - for (i=0; isamples_per_slot<<1; i++) { + for (i=0; isamples_per_subframe; i++) { for (aa=0; aaframe_parms.nb_antennas_rx; aa++) { - ((short*) &gNB->common_vars.rxdata[aa][subframe*(frame_parms->samples_per_slot<<1)])[2*i] = (short) (.167*(r_re[aa][i] +sqrt(sigma2/2)*gaussdouble(0.0,1.0))); - ((short*) &gNB->common_vars.rxdata[aa][subframe*(frame_parms->samples_per_slot<<1)])[2*i+1] = (short) (.167*(r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0))); + ((short*) &gNB->common_vars.rxdata[aa][subframe*(frame_parms->samples_per_subframe)])[2*i] = (short) (.167*(r_re[aa][i] +sqrt(sigma2/2)*gaussdouble(0.0,1.0))); + ((short*) &gNB->common_vars.rxdata[aa][subframe*(frame_parms->samples_per_subframe)])[2*i+1] = (short) (.167*(r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0))); } } uint16_t preamble_rx; @@ -612,11 +619,11 @@ int main(int argc, char **argv) printf("preamble %d (tx %d) : energy %d, delay %d\n",preamble_rx,preamble_tx,preamble_energy_list[0],preamble_delay_list[0]); - LOG_M("prach0.m","prach0", &txdata[0][subframe*frame_parms->samples_per_slot<<1],frame_parms->samples_per_slot<<1,1,1); + LOG_M("prach0.m","prach0", &txdata[0][subframe*frame_parms->samples_per_subframe],frame_parms->samples_per_subframe,1,1); LOG_M("prachF0.m","prachF0", &gNB->prach_vars.prachF[0],24576,1,1); LOG_M("rxsig0.m","rxs0", - &gNB->common_vars.rxdata[0][subframe*frame_parms->samples_per_slot<<1], - frame_parms->samples_per_slot<<1,1,1); + &gNB->common_vars.rxdata[0][subframe*frame_parms->samples_per_subframe], + frame_parms->samples_per_subframe,1,1); LOG_M("rxsigF0.m","rxsF0", gNB->prach_vars.rxsigF[0],839*4,1,1); LOG_M("prach_preamble.m","prachp",&gNB->X_u[0],839,1,1); } diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 33023eaeeb..3b7305bf9b 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -53,7 +53,7 @@ openair0_config_t openair0_cfg[MAX_CARDS]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; double cpuf; -int nfapi_mode=0; +uint8_t nfapi_mode = 0; uint16_t NB_UE_INST = 1; // needed for some functions @@ -66,7 +66,7 @@ int main(int argc, char **argv) double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0; double cfo=0; uint8_t snr1set=0; - int **txdata; + int **txdataF,**rxdataF; double **s_re,**s_im,**r_re,**r_im; //int sync_pos, sync_pos_slot; //FILE *rx_frame_file; @@ -93,7 +93,6 @@ int main(int argc, char **argv) uint8_t nrofSymbols=1; //number of OFDM symbols can be 1-2 for format 1 uint8_t startingSymbolIndex=0; // resource allocated see 9.2.1, 38.213 for more info.should be actually present in the resource set provided uint16_t startingPRB=0,startingPRB_intraSlotHopping=0; //PRB number not sure see 9.2.1, 38.213 for more info. Should be actually present in the resource set provided - uint32_t hoppingId=40; uint8_t timeDomainOCC=0; SCM_t channel_model=AWGN;//Rayleigh1_anticorr; @@ -335,7 +334,7 @@ int main(int argc, char **argv) RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *)); RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB)); gNB = RC.gNB[0]; - + memset((void*)gNB,0,sizeof(*gNB)); frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; @@ -401,8 +400,10 @@ int main(int argc, char **argv) s_im = malloc(2*sizeof(double*)); r_re = malloc(2*sizeof(double*)); r_im = malloc(2*sizeof(double*)); - txdata = malloc(2*sizeof(int*)); - + txdataF = malloc(2*sizeof(int*)); + rxdataF = malloc(2*sizeof(int*)); + gNB->common_vars.rxdataF=rxdataF; + memcpy((void*)&gNB->frame_parms,(void*)frame_parms,sizeof(frame_parms)); for (i=0; i<2; i++) { s_re[i] = malloc(frame_length_complex_samples*sizeof(double)); @@ -415,17 +416,18 @@ int main(int argc, char **argv) r_im[i] = malloc(frame_length_complex_samples*sizeof(double)); bzero(r_im[i],frame_length_complex_samples*sizeof(double)); - printf("Allocating %d samples for txdata\n",frame_length_complex_samples); - txdata[i] = malloc(frame_length_complex_samples*sizeof(int)); - bzero(r_re[i],frame_length_complex_samples*sizeof(int)); - + printf("Allocating %d samples for txdataF/rxdataF\n",14*frame_parms->ofdm_symbol_size); + txdataF[i] = malloc(14*frame_parms->ofdm_symbol_size*sizeof(int)); + bzero(txdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int)); + rxdataF[i] = malloc(14*frame_parms->ofdm_symbol_size*sizeof(int)); + bzero(rxdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int)); } //configure UE UE = malloc(sizeof(PHY_VARS_NR_UE)); memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS)); - UE->pucch_config_common_nr->hoppingId = hoppingId; + UE->pucch_config_common_nr->hoppingId = Nid_cell; //phy_init_nr_top(UE); //called from init_nr_ue_signal UE->perfect_ce = 0; @@ -455,36 +457,33 @@ int main(int argc, char **argv) ack_nack_errors=0; n_errors = 0; for (trial=0; trialofdm_symbol_size*sizeof(int)); if(format==0){ - nr_generate_pucch0(UE,txdata,frame_parms,UE->pucch_config_dedicated,amp,nr_tti_tx,m0,mcs,nrofSymbols,startingSymbolIndex,startingPRB); + nr_generate_pucch0(UE,txdataF,frame_parms,UE->pucch_config_dedicated,amp,nr_tti_tx,m0,mcs,nrofSymbols,startingSymbolIndex,startingPRB); } else{ - nr_generate_pucch1(UE,txdata,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,0,nr_bit); + nr_generate_pucch1(UE,txdataF,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,0,nr_bit); } - int tx_lev=signal_energy( - sigma2_dB = 20*log10((double)amp/32767)-SNR; + + int txlev = signal_energy(&txdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size], + frame_parms->ofdm_symbol_size); + // printf("txlev %d (%d dB), offset %d\n",txlev,dB_fixed(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size); + + // note : this scaling is for 1 PRB, to be updated for PUCCH 2 + sigma2_dB = 10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12)-SNR; sigma2 = pow(10,sigma2_dB/10); - for(i=(nr_tti_tx*frame_parms->samples_per_slot; i<(nr_tti_tx+1)*frame_parms->samples_per_slot; i++) { - r_re[aa][i]=((double)(((int16_t *)txdata[0])[(i<<1)])/32767 + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - r_im[aa][i]=((double)(((int16_t *)txdata[0])[(i<<1)+1])/32767+ sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - r_re[aa][i]=r_re[0][i]/(sqrt(sigma2/2)+1); - r_im[aa][i]=r_im[0][i]/(sqrt(sigma2/2)+1); - if(r_re[aa][i]<-1) - r_re[aa][i]=-1; - else if(r_re[aa][i]>1) - r_re[aa][i]=1; - if(r_im[aa][i]<-1) - r_im[aa][i]=-1; - else if(r_im[aa][i]>1) - r_im[aa][i]=1; - ((int16_t *)txdata[aa])[(i<<1)] = (int16_t)round(r_re[aa][i]*32767); - ((int16_t *)txdata[aa])[(i<<1)+1] =(int16_t)round(r_im[aa][i]*32767); + for(i=startingSymbolIndex*frame_parms->ofdm_symbol_size; i<(startingSymbolIndex+1)*frame_parms->ofdm_symbol_size; i++) { + ((int16_t*)rxdataF[aa])[i<<1] = (int16_t)(100.0*((double)(((int16_t *)txdataF[aa])[(i<<1)]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0))/sqrt((double)txlev)); + ((int16_t*)rxdataF[aa])[1+(i<<1)]=(int16_t)(100.0*((double)(((int16_t *)txdataF[aa])[(i<<1)+1])+ sqrt(sigma2/2)*gaussdouble(0.0,1.0))/sqrt((double)txlev)); } + int rxlev = signal_energy(&rxdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size], + frame_parms->ofdm_symbol_size); + // printf("rxlev %d (%d dB), sigma2 %f dB, SNR %f, TX %f\n",rxlev,dB_fixed(rxlev),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12)); if(format==0){ nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu; nfapi_nr_pucch_pdu_t pucch_pdu; + pucch_pdu.subcarrier_spacing = 1; pucch_pdu.group_hop_flag = PUCCH_GroupHopping&1; pucch_pdu.sequence_hop_flag = (PUCCH_GroupHopping>>1)&1; pucch_pdu.bit_len_harq = nr_bit; @@ -494,7 +493,7 @@ int main(int argc, char **argv) pucch_pdu.initial_cyclic_shift = 0; pucch_pdu.start_symbol_index = startingSymbolIndex; pucch_pdu.prb_start = startingPRB; - nr_decode_pucch0(txdata,frame_parms,nr_tti_tx,&uci_pdu,&pucch_pdu); + nr_decode_pucch0(gNB,nr_tti_tx,&uci_pdu,&pucch_pdu); if(nr_bit==1) ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value); else @@ -503,7 +502,7 @@ int main(int argc, char **argv) } else{ - nr_decode_pucch1(txdata,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit); + nr_decode_pucch1(rxdataF,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit); if(nr_bit==1) ack_nack_errors+=((actual_payload^payload_received)&1); else @@ -523,13 +522,15 @@ int main(int argc, char **argv) free(s_im[i]); free(r_re[i]); free(r_im[i]); - free(txdata[i]); + free(txdataF[i]); + free(rxdataF[i]); } free(s_re); free(s_im); free(r_re); free(r_im); - free(txdata); + free(txdataF); + free(rxdataF); if (output_fd) fclose(output_fd); if (input_fd) fclose(input_fd); diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index 41a93ada66..48ea26da8f 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -55,7 +55,7 @@ RAN_CONTEXT_t RC; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; double cpuf; -int nfapi_mode = 0; +uint8_t nfapi_mode = 0; uint16_t NB_UE_INST = 1; // needed for some functions @@ -232,9 +232,9 @@ int main(int argc, char **argv) break; case 'R': - N_RB_DL = atoi(optarg); + N_RB_UL = atoi(optarg); #ifdef DEBUG_NR_ULSCHSIM - printf("N_RB_DL (-R) = %d\n", N_RB_DL); + printf("N_RB_UL (-R) = %d\n", N_RB_UL); #endif break; @@ -292,7 +292,7 @@ int main(int argc, char **argv) //printf("-j Relative strength of second intefering eNB (in dB) - cell_id mod 3 = 2\n"); printf("-M Multiple SSB positions in burst\n"); printf("-N Nid_cell\n"); - printf("-R N_RB_DL\n"); + printf("-R N_RB_UL\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); printf("-m\n"); printf("-l\n"); @@ -339,10 +339,11 @@ int main(int argc, char **argv) frame_parms->N_RB_DL = N_RB_DL; frame_parms->N_RB_UL = N_RB_UL; frame_parms->Ncp = extended_prefix_flag ? EXTENDED : NORMAL; - crcTableInit(); - nr_phy_config_request_sim(gNB, N_RB_DL, N_RB_DL, mu, Nid_cell, SSB_positions); + memcpy(&gNB->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS)); + + nr_phy_config_request_sim(gNB, N_RB_UL, N_RB_UL, mu, Nid_cell, SSB_positions); phy_init_nr_gNB(gNB, 0, 0); @@ -370,7 +371,6 @@ int main(int argc, char **argv) } unsigned char harq_pid = 0; - uint8_t is_crnti = 0; unsigned int TBS = 8424; unsigned int available_bits; uint8_t nb_re_dmrs = 6; @@ -383,7 +383,8 @@ int main(int argc, char **argv) uint8_t UE_id = 0; NR_gNB_ULSCH_t *ulsch_gNB = gNB->ulsch[UE_id][0]; - nfapi_nr_ul_config_ulsch_pdu_rel15_t *rel15_ul = &ulsch_gNB->harq_processes[harq_pid]->ulsch_pdu.ulsch_pdu_rel15; + NR_UL_gNB_HARQ_t *harq_process_gNB = ulsch_gNB->harq_processes[harq_pid]; + nfapi_nr_pusch_pdu_t *rel15_ul = &harq_process_gNB->ulsch_pdu; NR_UE_ULSCH_t *ulsch_ue = UE->ulsch[0][0][0]; @@ -395,15 +396,15 @@ int main(int argc, char **argv) printf("\nAvailable bits %u TBS %u mod_order %d\n", available_bits, TBS, mod_order); /////////// setting rel15_ul parameters /////////// - rel15_ul->number_rbs = nb_rb; - rel15_ul->number_symbols = nb_symb_sch; - rel15_ul->Qm = mod_order; - rel15_ul->mcs = Imcs; - rel15_ul->rv = rvidx; - rel15_ul->n_layers = Nl; - rel15_ul->nb_re_dmrs = nb_re_dmrs; - rel15_ul->length_dmrs = length_dmrs; - rel15_ul->R = code_rate; + rel15_ul->rb_size = nb_rb; + rel15_ul->nr_of_symbols = nb_symb_sch; + rel15_ul->qam_mod_order = mod_order; + rel15_ul->mcs_index = Imcs; + rel15_ul->pusch_data.rv_index = rvidx; + rel15_ul->nrOfLayers = Nl; + //rel15_ul->length_dmrs = length_dmrs; + rel15_ul->target_code_rate = code_rate; + rel15_ul->pusch_data.tb_size = TBS>>3; /////////////////////////////////////////////////// double *modulated_input = malloc16(sizeof(double) * 16 * 68 * 384); // [hna] 16 segments, 68*Zc @@ -526,8 +527,15 @@ int main(int argc, char **argv) exit(-1); #endif - ret = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, - frame, nb_symb_sch, subframe, harq_pid, is_crnti); + uint32_t G = nr_get_G(rel15_ul->rb_size, + rel15_ul->nr_of_symbols, + nb_re_dmrs, + 1, // FIXME only single dmrs is implemented + rel15_ul->qam_mod_order, + rel15_ul->nrOfLayers); + + ret = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, + frame, subframe, harq_pid, G); if (ret > ulsch_gNB->max_ldpc_iterations) n_errors++; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 0df719848c..2adc67501a 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -52,7 +52,7 @@ #include "openair1/SIMULATION/TOOLS/sim.h" #include "openair1/SIMULATION/RF/rf.h" #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h" -#include "openair1/SIMULATION/NR_PHY/nr_dummy_functions.c" +#include "openair2/RRC/NR/MESSAGES/asn1_msg.h" #include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" @@ -63,47 +63,16 @@ PHY_VARS_NR_UE *UE; RAN_CONTEXT_t RC; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; +int sf_ahead=4 ; +int sl_ahead=0; double cpuf; -int nfapi_mode = 0; +uint8_t nfapi_mode = 0; uint16_t NB_UE_INST = 1; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; + int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, const int CC_id, const uint8_t gNB_index, const int8_t channel, const uint8_t* pduP, const sdu_size_t pdu_len) { return 0; } -void mac_rlc_data_ind ( const module_id_t module_idP, - const rnti_t rntiP, - const eNB_index_t eNB_index, - const frame_t frameP, - const eNB_flag_t enb_flagP, - const MBMS_flag_t MBMS_flagP, - const logical_chan_id_t channel_idP, - char *buffer_pP, - const tb_size_t tb_sizeP, - num_tb_t num_tbP, - crc_t *crcs_pP){} -mac_rlc_status_resp_t mac_rlc_status_ind( const module_id_t module_idP, - const rnti_t rntiP, - const eNB_index_t eNB_index, - const frame_t frameP, - const sub_frame_t subframeP, - const eNB_flag_t enb_flagP, - const MBMS_flag_t MBMS_flagP, - const logical_chan_id_t channel_idP, - const tb_size_t tb_sizeP, - const uint32_t sourceL2Id, - const uint32_t destinationL2Id) -{mac_rlc_status_resp_t mac_rlc_status_resp; return mac_rlc_status_resp;} -tbs_size_t mac_rlc_data_req( const module_id_t module_idP, - const rnti_t rntiP, - const eNB_index_t eNB_index, - const frame_t frameP, - const eNB_flag_t enb_flagP, - const MBMS_flag_t MBMS_flagP, - const logical_chan_id_t channel_idP, - const tb_size_t tb_sizeP, - char *buffer_pP, - const uint32_t sourceL2Id, - const uint32_t destinationL2Id ) -{return 0;} int generate_dlsch_header(unsigned char *mac_header, unsigned char num_sdus, unsigned short *sdu_lengths, @@ -113,10 +82,20 @@ int generate_dlsch_header(unsigned char *mac_header, unsigned char *ue_cont_res_id, unsigned char short_padding, unsigned short post_padding){return 0;} -uint64_t get_softmodem_optmask(void) {return 0;} -int rlc_module_init (int enb) {return(0);} void pdcp_layer_init (void) {} +boolean_t pdcp_data_ind( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const sdu_size_t sdu_buffer_sizeP, + mem_block_t *const sdu_buffer_pP +) { return(false);} + +void pdcp_run (const protocol_ctxt_t *const ctxt_pP) { return;} void nr_ip_over_LTE_DRB_preconfiguration(void){} +int rrc_init_nr_global_param(void){return(0);} + // needed for some functions uint16_t n_rnti = 0x1234; @@ -128,9 +107,9 @@ int main(int argc, char **argv) int i,sf; double SNR, snr0 = -2.0, snr1 = 2.0; double sigma, sigma_dB; - double snr_step = 0.1; + double snr_step = 1; uint8_t snr1set = 0; - int slot = 0; + int slot = 0, frame = 0; FILE *output_fd = NULL; //uint8_t write_output_file = 0; int trial, n_trials = 1, n_errors = 0, n_false_positive = 0, delay = 0; @@ -144,13 +123,12 @@ int main(int argc, char **argv) SCM_t channel_model = AWGN; //Rayleigh1_anticorr; uint16_t N_RB_DL = 106, N_RB_UL = 106, mu = 1; //unsigned char frame_type = 0; - int number_of_frames = 1; int frame_length_complex_samples,frame_length_complex_samples_no_prefix; NR_DL_FRAME_PARMS *frame_parms; int loglvl = OAILOG_WARNING; uint64_t SSB_positions=0x01; uint16_t nb_symb_sch = 12; - int start_symbol = NR_SYMBOLS_PER_SLOT - nb_symb_sch; + int start_symbol = 0; uint16_t nb_rb = 50; uint8_t Imcs = 9; uint8_t precod_nbr_layers = 1; @@ -161,11 +139,13 @@ int main(int argc, char **argv) int32_t txlev; int start_rb = 0; int UE_id =0; // [hna] only works for UE_id = 0 because NUMBER_OF_NR_UE_MAX is set to 1 (phy_init_nr_gNB causes segmentation fault) - + float target_error_rate = 0.01; + cpuf = get_cpu_freq_GHz(); UE_nr_rxtx_proc_t UE_proc; + FILE *scg_fd=NULL; if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0 ) { @@ -187,19 +167,14 @@ int main(int argc, char **argv) break; case 'f': - number_of_frames = atoi(optarg); - break; + scg_fd = fopen(optarg, "r"); - /*case 'f': - write_output_file = 1; - output_fd = fopen(optarg, "w"); - - if (output_fd == NULL) { + if (scg_fd == NULL) { printf("Error opening %s\n", optarg); exit(-1); } - break;*/ + break; case 'g': switch ((char) *optarg) { @@ -356,10 +331,10 @@ int main(int argc, char **argv) //printf("-x Transmission mode (1,2,6 for the moment)\n"); printf("-y Number of TX antennas used in eNB\n"); printf("-z Number of RX antennas used in UE\n"); - printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); + printf("-G raw file containing RRC configuration (generated by gNB)\n"); printf("-M Multiple SSB positions in burst\n"); printf("-N Nid_cell\n"); printf("-O oversampling factor (1,2,4,8,16)\n"); @@ -374,6 +349,8 @@ int main(int argc, char **argv) set_glog(loglvl); T_stdout = 1; + get_softmodem_params()->phy_test = 1; + if (snr1set == 0) snr1 = snr0 + 10; @@ -392,6 +369,11 @@ int main(int argc, char **argv) gNB = RC.gNB[0]; //gNB_config = &gNB->gNB_config; + //memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO)); + gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = (nfapi_rx_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_rx_indication_pdu_t)); + gNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = (nfapi_crc_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_crc_indication_pdu_t)); + gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0; + gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs = 0; frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; @@ -399,12 +381,45 @@ int main(int argc, char **argv) frame_parms->N_RB_UL = N_RB_UL; frame_parms->Ncp = extended_prefix_flag ? EXTENDED : NORMAL; - crcTableInit(); + RC.nb_nr_macrlc_inst = 1; + RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); + for (i = 0; i < RC.nb_nr_macrlc_inst; i++) + RC.nb_nr_mac_CC[i] = 1; + mac_top_init_gNB(); + gNB_MAC_INST* gNB_mac = RC.nrmac[0]; + gNB_RRC_INST rrc; + memset((void*)&rrc,0,sizeof(rrc)); - nr_phy_config_request_sim(gNB, N_RB_DL, N_RB_UL, mu, Nid_cell, SSB_positions); + rrc.carrier.servingcellconfigcommon = calloc(1,sizeof(*rrc.carrier.servingcellconfigcommon)); - phy_init_nr_gNB(gNB, 0, 0); - //init_eNB_afterRU(); + NR_ServingCellConfigCommon_t *scc = rrc.carrier.servingcellconfigcommon; + NR_CellGroupConfig_t *secondaryCellGroup=calloc(1,sizeof(*secondaryCellGroup)); + prepare_scc(rrc.carrier.servingcellconfigcommon); + uint64_t ssb_bitmap; + fill_scc(rrc.carrier.servingcellconfigcommon,&ssb_bitmap,N_RB_DL,N_RB_DL,mu,mu); + + fill_default_secondaryCellGroup(scc, + secondaryCellGroup, + 0, + 1, + n_tx, + 0); + fix_scc(scc,ssb_bitmap); + + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); + + AssertFatal((gNB->if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); + gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; + // common configuration + rrc_mac_config_req_gNB(0,0,1,scc,0,0,NULL); + // UE dedicated configuration + rrc_mac_config_req_gNB(0,0,1,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + phy_init_nr_gNB(gNB,0,0); + N_RB_DL = gNB->frame_parms.N_RB_DL; + + //crcTableInit(); + + //nr_phy_config_request_sim(gNB, N_RB_DL, N_RB_UL, mu, Nid_cell, SSB_positions); frame_length_complex_samples = frame_parms->samples_per_subframe; frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP; @@ -424,7 +439,9 @@ int main(int argc, char **argv) } //nr_init_frame_parms_ue(&UE->frame_parms); - //init_nr_ue_transport(UE, 0); + init_nr_ue_transport(UE, 0); + + /* for (sf = 0; sf < 2; sf++) { for (i = 0; i < 2; i++) { @@ -434,22 +451,31 @@ int main(int argc, char **argv) printf("Can't get ue ulsch structures\n"); exit(-1); } - } } + */ + + nr_l2_init_ue(NULL); + NR_UE_MAC_INST_t* UE_mac = get_mac_inst(0); + + UE->if_inst = nr_ue_if_module_init(0); + UE->if_inst->scheduled_response = nr_ue_scheduled_response; + UE->if_inst->phy_config_request = nr_ue_phy_config_request; + UE->if_inst->dl_indication = nr_ue_dl_indication; + UE->if_inst->ul_indication = nr_ue_ul_indication; + + UE_mac->if_module = nr_ue_if_module_init(0); + + //Configure UE + rrc.carrier.MIB = (uint8_t*) malloc(4); + rrc.carrier.sizeof_MIB = do_MIB_NR(&rrc,0); + + nr_rrc_mac_config_req_ue(0,0,0,rrc.carrier.mib.message.choice.mib,secondaryCellGroup->spCellConfig); + + nr_ue_phy_config_request(&UE_mac->phy_config); + unsigned char harq_pid = 0; - unsigned int TBS; - unsigned int available_bits; - uint8_t nb_re_dmrs = UE->dmrs_UplinkConfig.pusch_maxLength*(UE->dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1?6:4); - uint8_t length_dmrs = 1; - unsigned char mod_order; - uint16_t code_rate; - - mod_order = nr_get_Qm_ul(Imcs, 0); - code_rate = nr_get_code_rate_ul(Imcs, 0); - available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, 1); - TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, precod_nbr_layers); NR_gNB_ULSCH_t *ulsch_gNB = gNB->ulsch[UE_id][0]; //nfapi_nr_ul_config_ulsch_pdu *rel15_ul = &ulsch_gNB->harq_processes[harq_pid]->ulsch_pdu; @@ -457,30 +483,47 @@ int main(int argc, char **argv) nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu; NR_UE_ULSCH_t **ulsch_ue = UE->ulsch[0][0]; - + unsigned char *estimated_output_bit; unsigned char *test_input_bit; uint32_t errors_decoding = 0; uint32_t errors_scrambling = 0; - uint32_t is_frame_in_error = 0; test_input_bit = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384); estimated_output_bit = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384); nr_scheduled_response_t scheduled_response; fapi_nr_ul_config_request_t ul_config; - + + unsigned int TBS; + uint16_t number_dmrs_symbols = 0; + unsigned int available_bits; + uint8_t nb_re_dmrs; + uint8_t length_dmrs = UE->pusch_config.dmrs_UplinkConfig.pusch_maxLength; + unsigned char mod_order; + uint16_t code_rate; + + for (i = start_symbol; i < nb_symb_sch; i++) + number_dmrs_symbols += is_dmrs_symbol(i, + 0, + 0, + 0, + 0, + 0, + nb_symb_sch, + UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type, + frame_parms->ofdm_symbol_size); + + mod_order = nr_get_Qm_ul(Imcs, 0); + nb_re_dmrs = ((UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1) ? 6 : 4) * number_dmrs_symbols; + code_rate = nr_get_code_rate_ul(Imcs, 0); + available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, 1); + TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, precod_nbr_layers); + printf("\n"); for (SNR = snr0; SNR < snr1; SNR += snr_step) { - printf("-------------------\n"); - printf("SNR %f\n", SNR); - printf("-------------------\n"); - - is_frame_in_error = 0; - for (int frame = 0; frame < number_of_frames; frame++) { - UE_proc.nr_tti_tx = slot; UE_proc.frame_tx = frame; @@ -491,7 +534,6 @@ int main(int argc, char **argv) rel15_ul->ulsch_pdu_rel15.number_rbs = nb_rb; rel15_ul->ulsch_pdu_rel15.start_symbol = start_symbol; rel15_ul->ulsch_pdu_rel15.number_symbols = nb_symb_sch; - rel15_ul->ulsch_pdu_rel15.nb_re_dmrs = nb_re_dmrs; rel15_ul->ulsch_pdu_rel15.length_dmrs = length_dmrs; rel15_ul->ulsch_pdu_rel15.Qm = mod_order; rel15_ul->ulsch_pdu_rel15.mcs = Imcs; @@ -513,8 +555,8 @@ int main(int argc, char **argv) pusch_pdu->rnti = n_rnti; pusch_pdu->mcs_index = Imcs; pusch_pdu->mcs_table = 0; - pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table); - pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table) ; + pusch_pdu->target_code_rate = code_rate; + pusch_pdu->qam_mod_order = mod_order; pusch_pdu->transform_precoding = 0; pusch_pdu->data_scrambling_id = 0; pusch_pdu->nrOfLayers = 1; @@ -533,13 +575,7 @@ int main(int argc, char **argv) pusch_pdu->pusch_data.rv_index = 0; pusch_pdu->pusch_data.harq_process_id = 0; pusch_pdu->pusch_data.new_data_indicator = 0; - pusch_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_pdu->mcs_index, - pusch_pdu->target_code_rate, - pusch_pdu->rb_size, - pusch_pdu->nr_of_symbols, - nb_re_dmrs*length_dmrs, - 0, - pusch_pdu->nrOfLayers = 1); + pusch_pdu->pusch_data.tb_size = TBS>>3; pusch_pdu->pusch_data.num_cb = 0; @@ -577,12 +613,12 @@ int main(int argc, char **argv) phy_procedures_nrUE_TX(UE, &UE_proc, gNB_id, 0); - if (number_of_frames==1) + if (n_trials==1) LOG_M("txsig0.m","txs0", UE->common_vars.txdata[0],frame_length_complex_samples,1,1); /////////// //////////////////////////////////////////////////// - tx_offset = slot*frame_parms->samples_per_slot; + tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); txlev = signal_energy_amp_shift(&UE->common_vars.txdata[0][tx_offset + 5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); @@ -615,14 +651,21 @@ int main(int argc, char **argv) //---------------------------------------------------------- //------------------- gNB phy procedures ------------------- //---------------------------------------------------------- + gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0; + gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs = 0; + phy_procedures_gNB_common_RX(gNB, frame, slot); - if (number_of_frames==1) + if (n_trials==1) LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0],frame_length_complex_samples_no_prefix,1,1); phy_procedures_gNB_uespec_RX(gNB, frame, slot); //////////////////////////////////////////////////////////// + if (gNB->ulsch[0][0]->last_iteration_cnt >= + gNB->ulsch[0][0]->max_ldpc_iterations+1) + n_errors++; + //---------------------------------------------------------- //----------------- count and print errors ----------------- //---------------------------------------------------------- @@ -632,14 +675,15 @@ int main(int argc, char **argv) if(((ulsch_ue[0]->g[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) || ((ulsch_ue[0]->g[i] == 1) && (gNB->pusch_vars[UE_id]->llr[i] >= 0))) { - if(errors_scrambling == 0) - printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i); + /*if(errors_scrambling == 0) + printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/ errors_scrambling++; } } if (errors_scrambling > 0) { - printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %d\n" "\x1B[0m", frame, trial, errors_scrambling); + if (n_trials==1) + printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %d\n" "\x1B[0m", frame, trial, errors_scrambling); } for (i = 0; i < TBS; i++) { @@ -648,38 +692,39 @@ int main(int argc, char **argv) test_input_bit[i] = (ulsch_ue[0]->harq_processes[harq_pid]->b[i/8] & (1 << (i & 7))) >> (i & 7); if (estimated_output_bit[i] != test_input_bit[i]) { - if(errors_decoding == 0) - printf("\x1B[34m""[frame %d][trial %d]\t1st bit in error in decoding = %d\n" "\x1B[0m", frame, trial, i); + /*if(errors_decoding == 0) + printf("\x1B[34m""[frame %d][trial %d]\t1st bit in error in decoding = %d\n" "\x1B[0m", frame, trial, i);*/ errors_decoding++; } } if (errors_decoding > 0) { - is_frame_in_error = 1; n_false_positive++; - printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in decoding = %d\n" "\x1B[0m", frame, trial, errors_decoding); - } else { - is_frame_in_error = 0; - break; - } - //////////////////////////////////////////////////////////// + if (n_trials==1) + printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in decoding = %d\n" "\x1B[0m", frame, trial, errors_decoding); + } + } // trial loop - if (is_frame_in_error == 1) - break; - } // frame loop + printf("*****************************************\n"); + printf("SNR %f: n_errors (negative CRC) = %d/%d, false_positive %d/%d, errors_scrambling %d/%d\n", SNR, n_errors, n_trials, n_false_positive, n_trials, errors_scrambling, n_trials); + printf("\n"); + printf("SNR %f: Channel BLER %e, Channel BER %e\n", SNR,(double)n_errors/n_trials,(double)errors_scrambling/available_bits/n_trials); + printf("*****************************************\n"); + printf("\n"); - if(is_frame_in_error == 0 || number_of_frames==1) - break; + if(n_trials==1) + break; + + if ((float)n_errors/(float)n_trials <= target_error_rate) { + printf("*************\n"); + printf("PUSCH test OK\n"); + printf("*************\n"); + break; + } + } // SNR loop - if(is_frame_in_error == 0) { - printf("\n"); - printf("*************\n"); - printf("PUSCH test OK\n"); - printf("*************\n"); - } - printf("\n"); free(test_input_bit); diff --git a/openair2/COMMON/m2ap_messages_def.h b/openair2/COMMON/m2ap_messages_def.h new file mode 100644 index 0000000000..adad70c9cc --- /dev/null +++ b/openair2/COMMON/m2ap_messages_def.h @@ -0,0 +1,94 @@ +/* + * 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 + */ + + +/* eNB application layer -> M2AP messages */ +/* ITTI LOG messages */ +/* ENCODER */ +MESSAGE_DEF(M2AP_RESET_REQUST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m2ap_reset_request_log) +MESSAGE_DEF(M2AP_RESOURCE_STATUS_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m2ap_resource_status_response_log) +MESSAGE_DEF(M2AP_RESOURCE_STATUS_FAILURE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m2ap_resource_status_failure_log) + +/* Messages for M2AP logging */ +MESSAGE_DEF(M2AP_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m2ap_setup_request_log) + + +/* eNB application layer -> M2AP messages */ +MESSAGE_DEF(M2AP_REGISTER_ENB_REQ , MESSAGE_PRIORITY_MED, m2ap_register_enb_req_t , m2ap_register_enb_req) +MESSAGE_DEF(M2AP_SUBFRAME_PROCESS , MESSAGE_PRIORITY_MED, m2ap_subframe_process_t , m2ap_subframe_process) + +/* M2AP -> eNB application layer messages */ +MESSAGE_DEF(M2AP_REGISTER_ENB_CNF , MESSAGE_PRIORITY_MED, m2ap_register_enb_cnf_t , m2ap_register_enb_cnf) +MESSAGE_DEF(M2AP_DEREGISTERED_ENB_IND , MESSAGE_PRIORITY_MED, m2ap_deregistered_enb_ind_t , m2ap_deregistered_enb_ind) + +/* handover messages M2AP <-> RRC */ +//MESSAGE_DEF(M2AP_HANDOVER_REQ , MESSAGE_PRIORITY_MED, m2ap_handover_req_t , m2ap_handover_req) +//MESSAGE_DEF(M2AP_HANDOVER_REQ_ACK , MESSAGE_PRIORITY_MED, m2ap_handover_req_ack_t , m2ap_handover_req_ack) +//MESSAGE_DEF(M2AP_HANDOVER_CANCEL , MESSAGE_PRIORITY_MED, m2ap_handover_cancel_t , m2ap_handover_cancel) + +/* handover messages M2AP <-> S1AP */ +//MESSAGE_DEF(M2AP_UE_CONTEXT_RELEASE , MESSAGE_PRIORITY_MED, m2ap_ue_context_release_t , m2ap_ue_context_release) + +/* M2AP -> SCTP */ + +MESSAGE_DEF(M2AP_MCE_SCTP_REQ , MESSAGE_PRIORITY_MED, m2ap_mce_sctp_req_t , m2ap_mce_sctp_req) +//MESSAGE_DEF(M2AP_ENB_SCTP_REQ , MESSAGE_PRIORITY_MED, m2ap_enb_setup_req_t , f1ap_enb_setup_req) + +/* eNB_DU application layer -> M2AP messages or CU M2AP -> RRC*/ +MESSAGE_DEF(M2AP_SETUP_REQ , MESSAGE_PRIORITY_MED, m2ap_setup_req_t , m2ap_setup_req) + +MESSAGE_DEF(M2AP_SETUP_RESP , MESSAGE_PRIORITY_MED, m2ap_setup_resp_t , m2ap_setup_resp) +MESSAGE_DEF(M2AP_SETUP_FAILURE , MESSAGE_PRIORITY_MED, m2ap_setup_failure_t , m2ap_setup_failure) + +MESSAGE_DEF(M2AP_RESET , MESSAGE_PRIORITY_MED, m2ap_reset_t , m2ap_reset) + +MESSAGE_DEF(M2AP_REGISTER_MCE_REQ , MESSAGE_PRIORITY_MED, m2ap_register_mce_req_t , m2ap_register_mce_req) + +MESSAGE_DEF(M2AP_MBMS_SCHEDULING_INFORMATION , MESSAGE_PRIORITY_MED, m2ap_mbms_scheduling_information_t , m2ap_mbms_scheduling_information) +MESSAGE_DEF(M2AP_MBMS_SCHEDULING_INFORMATION_RESP , MESSAGE_PRIORITY_MED, m2ap_mbms_scheduling_information_resp_t , m2ap_mbms_scheduling_information_resp) + +MESSAGE_DEF(M2AP_MBMS_SESSION_START_REQ , MESSAGE_PRIORITY_MED, m2ap_session_start_req_t ,m2ap_session_start_req ) +MESSAGE_DEF(M2AP_MBMS_SESSION_START_RESP , MESSAGE_PRIORITY_MED, m2ap_session_start_resp_t ,m2ap_session_start_resp ) +MESSAGE_DEF(M2AP_MBMS_SESSION_START_FAILURE , MESSAGE_PRIORITY_MED, m2ap_session_start_failure_t ,m2ap_session_start_failure ) + +MESSAGE_DEF(M2AP_MBMS_SESSION_STOP_REQ , MESSAGE_PRIORITY_MED, m2ap_session_stop_req_t ,m2ap_session_stop_req ) +MESSAGE_DEF(M2AP_MBMS_SESSION_STOP_RESP , MESSAGE_PRIORITY_MED, m2ap_session_stop_resp_t ,m2ap_session_stop_resp ) + + +MESSAGE_DEF(M2AP_ENB_CONFIGURATION_UPDATE , MESSAGE_PRIORITY_MED, m2ap_enb_configuration_update_t, m2ap_enb_configuration_update ) +MESSAGE_DEF(M2AP_ENB_CONFIGURATION_UPDATE_ACK , MESSAGE_PRIORITY_MED, m2ap_enb_configuration_update_ack_t, m2ap_enb_configuration_update_ack ) +MESSAGE_DEF(M2AP_ENB_CONFIGURATION_UPDATE_FAILURE , MESSAGE_PRIORITY_MED, m2ap_enb_configuration_update_failure_t, m2ap_enb_configuration_update_failure ) + +MESSAGE_DEF(M2AP_MCE_CONFIGURATION_UPDATE , MESSAGE_PRIORITY_MED, m2ap_mce_configuration_update_t, m2ap_mce_configuration_update ) +MESSAGE_DEF(M2AP_MCE_CONFIGURATION_UPDATE_ACK , MESSAGE_PRIORITY_MED, m2ap_mce_configuration_update_ack_t, m2ap_mce_configuration_update_ack ) +MESSAGE_DEF(M2AP_MCE_CONFIGURATION_UPDATE_FAILURE , MESSAGE_PRIORITY_MED, m2ap_mce_configuration_update_failure_t, m2ap_mce_configuration_update_failure ) + + +MESSAGE_DEF(M2AP_ERROR_INDICATION , MESSAGE_PRIORITY_MED, m2ap_error_indication_t, m2ap_error_indication ) +MESSAGE_DEF(M2AP_MBMS_SESSION_UPDATE_REQ , MESSAGE_PRIORITY_MED, m2ap_mbms_session_update_req_t, m2ap_mbms_session_update_req ) +MESSAGE_DEF(M2AP_MBMS_SESSION_UPDATE_RESP , MESSAGE_PRIORITY_MED, m2ap_mbms_session_update_resp_t, m2ap_mbms_session_update_resp ) +MESSAGE_DEF(M2AP_MBMS_SESSION_UPDATE_FAILURE , MESSAGE_PRIORITY_MED, m2ap_mbms_session_update_failure_t, m2ap_mbms_session_update_failure ) +MESSAGE_DEF(M2AP_MBMS_SERVICE_COUNTING_REPORT , MESSAGE_PRIORITY_MED, m2ap_mbms_service_counting_report_t, m2ap_mbms_service_counting_report ) +MESSAGE_DEF(M2AP_MBMS_OVERLOAD_NOTIFICATION , MESSAGE_PRIORITY_MED, m2ap_mbms_overload_notification_t, m2ap_mbms_overload_notification ) +MESSAGE_DEF(M2AP_MBMS_SERVICE_COUNTING_REQ , MESSAGE_PRIORITY_MED, m2ap_mbms_service_counting_req_t, m2ap_mbms_service_counting_req ) +MESSAGE_DEF(M2AP_MBMS_SERVICE_COUNTING_RESP , MESSAGE_PRIORITY_MED, m2ap_mbms_service_counting_resp_t, m2ap_mbms_service_counting_resp ) +MESSAGE_DEF(M2AP_MBMS_SERVICE_COUNTING_FAILURE , MESSAGE_PRIORITY_MED, m2ap_mbms_service_counting_failure_t, m2ap_mbms_service_counting_failure ) + diff --git a/openair2/COMMON/m2ap_messages_types.h b/openair2/COMMON/m2ap_messages_types.h new file mode 100644 index 0000000000..501414f296 --- /dev/null +++ b/openair2/COMMON/m2ap_messages_types.h @@ -0,0 +1,666 @@ +/* + * 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 + */ + + +#ifndef M2AP_MESSAGES_TYPES_H_ +#define M2AP_MESSAGES_TYPES_H_ + +#include "s1ap_messages_types.h" +#include "LTE_PhysCellId.h" + +//-------------------------------------------------------------------------------------------// +// Defines to access message fields. + +#define M2AP_MCE_SCTP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mce_sctp_req + +#define M2AP_REGISTER_ENB_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_register_enb_req +//#define M2AP_HANDOVER_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_handover_req +//#define M2AP_HANDOVER_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.m2ap_handover_req_ack +#define M2AP_REGISTER_ENB_CNF(mSGpTR) (mSGpTR)->ittiMsg.m2ap_register_enb_cnf +#define M2AP_DEREGISTERED_ENB_IND(mSGpTR) (mSGpTR)->ittiMsg.m2ap_deregistered_enb_ind +//#define M2AP_UE_CONTEXT_RELEASE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_ue_context_release +//#define M2AP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.m2ap_handover_cancel + +#define M2AP_ENB_SCTP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_enb_sctp_req +#define M2AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_setup_req +#define M2AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.m2ap_setup_resp +#define M2AP_SETUP_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_setup_failure + + +#define M2AP_REGISTER_MCE_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_register_mce_req + + + +#define M2AP_MBMS_SCHEDULING_INFORMATION(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_scheduling_information +#define M2AP_MBMS_SCHEDULING_INFORMATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_scheduling_information_resp +#define M2AP_MBMS_SESSION_START_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_session_start_req +#define M2AP_MBMS_SESSION_START_RESP(mSGpTR) (mSGpTR)->ittiMsg.m2ap_session_start_resp +#define M2AP_MBMS_SESSION_START_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_session_start_failure +#define M2AP_MBMS_SESSION_STOP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_session_stop_req +#define M2AP_MBMS_SESSION_STOP_RESP(mSGpTR) (mSGpTR)->ittiMsg.m2ap_session_stop_resp + +#define M2AP_RESET(mSGpTR) (mSGpTR)->ittiMsg.m2ap_reset +#define M2AP_ENB_CONFIGURATION_UPDATE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_enb_configuration_update +#define M2AP_ENB_CONFIGURATION_UPDATE_ACK(mSGpTR) (mSGpTR)->ittiMsg.m2ap_enb_configuration_update_ack +#define M2AP_ENB_CONFIGURATION_UPDATE_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_enb_configuration_update_failure +#define M2AP_MCE_CONFIGURATION_UPDATE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mce_configuration_update +#define M2AP_MCE_CONFIGURATION_UPDATE_ACK(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mce_configuration_update_ack +#define M2AP_MCE_CONFIGURATION_UPDATE_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mce_configuration_update_failure + +#define M2AP_ERROR_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.m2ap_error_indication +#define M2AP_MBMS_SESSION_UPDATE_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_session_update_req +#define M2AP_MBMS_SESSION_UPDATE_RESP(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_session_update_resp +#define M2AP_MBMS_SESSION_UPDATE_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_session_update_failure +#define M2AP_MBMS_SERVICE_COUNTING_REPORT(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_service_counting_report +#define M2AP_MBMS_OVERLOAD_NOTIFICATION(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_overload_notification +#define M2AP_MBMS_SERVICE_COUNTING_REQ(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_service_counting_req +#define M2AP_MBMS_SERVICE_COUNTING_RESP(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_service_counting_resp +#define M2AP_MBMS_SERVICE_COUNTING_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m2ap_mbms_service_counting_failure + +#define M2AP_MAX_NB_ENB_IP_ADDRESS 2 +#define M2AP_MAX_NB_MCE_IP_ADDRESS 2 + +#define M2AP_MAX_NB_CELLS 2 + + + +typedef struct m2ap_net_ip_address_s { + unsigned ipv4:1; + unsigned ipv6:1; + char ipv4_address[16]; + char ipv6_address[46]; +} m2ap_net_ip_address_t; + +typedef struct m2ap_enb_setup_req_s { + // +} m2ap_enb_setup_req_t; + + +typedef struct m2ap_setup_req_s { + + // Midhaul networking parameters + + /* Connexion id used between SCTP/M2AP */ + uint16_t cnx_id; + + /* SCTP association id */ + int32_t assoc_id; + + /* The eNB IP address to bind */ + m2ap_net_ip_address_t MCE_M2_ip_address; + m2ap_net_ip_address_t ENB_M2_ip_address; + + /* Number of SCTP streams used for a mme association */ + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + + uint16_t default_sctp_stream_id; + + // M2_Setup_Req payload + uint64_t eNB_id; + char *eNB_name; + + uint64_t GlobalENB_ID; + char * ENBname; + + uint16_t num_mbms_available; + + /* M2AP_MBSFN_SynchronisationArea_ID_t */ + long mbsfn_synchronization_area[M2AP_MAX_NB_CELLS]; + + /* eCGI->eCGI.pLMN_Identity */ + uint16_t plmn_identity[M2AP_MAX_NB_CELLS]; + /* eCGI->eCGI.eUTRANcellIdentifier */ + uint16_t eutran_cell_identifier[M2AP_MAX_NB_CELLS]; + + struct{ + uint16_t mbsfn_sync_area; + uint16_t mbms_service_area_list[8]; + uint16_t num_mbms_service_area_list; + }mbms_configuration_data_list[8]; + uint16_t num_mbms_configuration_data_list; + + +// +// /* The type of the cell */ +// enum cell_type_e cell_type; +// +// /// number of DU cells available +// uint16_t num_cells_available; //0< num_cells_available <= 512; +// +// // +// uint16_t num_mbms_available; +// +// // Served Cell Information +// /* Tracking area code */ +// uint16_t tac[M2AP_MAX_NB_CELLS]; +// +// /* Mobile Country Codes +// * Mobile Network Codes +// */ +// uint16_t mcc[M2AP_MAX_NB_CELLS];//[6]; +// uint16_t mnc[M2AP_MAX_NB_CELLS];//[6]; +// uint8_t mnc_digit_length[M2AP_MAX_NB_CELLS];//[6]; +// +// // NR Global Cell Id +// uint64_t nr_cellid[M2AP_MAX_NB_CELLS]; +// // NR Physical Cell Ids +// uint16_t nr_pci[M2AP_MAX_NB_CELLS]; +// // Number of slide support items (max 16, could be increased to as much as 1024) +// uint16_t num_ssi[M2AP_MAX_NB_CELLS];//[6]; +// uint8_t sst[M2AP_MAX_NB_CELLS];//[16][6]; +// uint8_t sd[M2AP_MAX_NB_CELLS];//[16][6]; +// // fdd_flag = 1 means FDD, 0 means TDD +// int fdd_flag; +// +// /* eCGI->eCGI.pLMN_Identity */ +// uint16_t plmn_identity[M2AP_MAX_NB_CELLS]; +// /* eCGI->eCGI.eUTRANcellIdentifier */ +// uint16_t eutran_cell_identifier[M2AP_MAX_NB_CELLS]; +// +// /* M2AP_MBSFN_SynchronisationArea_ID_t */ +// long mbsfn_synchronization_area[M2AP_MAX_NB_CELLS]; +// +// uint16_t service_area_id[M2AP_MAX_NB_CELLS][4]; +// +// union { +// struct { +// uint32_t ul_nr_arfcn; +// uint8_t ul_scs; +// uint8_t ul_nrb; +// +// uint32_t dl_nr_arfcn; +// uint8_t dl_scs; +// uint8_t dl_nrb; +// +// uint32_t sul_active; +// uint32_t sul_nr_arfcn; +// uint8_t sul_scs; +// uint8_t sul_nrb; +// +// uint8_t ul_num_frequency_bands; +// uint16_t ul_nr_band[32]; +// uint8_t ul_num_sul_frequency_bands; +// uint16_t ul_nr_sul_band[32]; +// +// uint8_t dl_num_frequency_bands; +// uint16_t dl_nr_band[32]; +// uint8_t dl_num_sul_frequency_bands; +// uint16_t dl_nr_sul_band[32]; +// } fdd; +// struct { +// +// uint32_t nr_arfcn; +// uint8_t scs; +// uint8_t nrb; +// +// uint32_t sul_active; +// uint32_t sul_nr_arfcn; +// uint8_t sul_scs; +// uint8_t sul_nrb; +// +// uint8_t num_frequency_bands; +// uint16_t nr_band[32]; +// uint8_t num_sul_frequency_bands; +// uint16_t nr_sul_band[32]; +// +// } tdd; +// } nr_mode_info[M2AP_MAX_NB_CELLS]; +// +// char *measurement_timing_information[M2AP_MAX_NB_CELLS]; +// uint8_t ranac[M2AP_MAX_NB_CELLS]; +// +// // System Information +// uint8_t *mib[M2AP_MAX_NB_CELLS]; +// int mib_length[M2AP_MAX_NB_CELLS]; +// uint8_t *sib1[M2AP_MAX_NB_CELLS]; +// int sib1_length[M2AP_MAX_NB_CELLS]; + + +} m2ap_setup_req_t; + + +typedef struct m2ap_setup_resp_s { + + + + struct { + uint8_t mbsfn_area; + uint8_t pdcch_length; + uint8_t repetition_period; + uint8_t offset; + uint8_t modification_period; + uint8_t subframe_allocation_info; + uint8_t mcs; + } mcch_config_per_mbsfn[8]; + + /* Connexion id used between SCTP/M2AP */ + uint16_t cnx_id; + + /* SCTP association id */ + int32_t assoc_id; + + /* Number of SCTP streams used for a mme association */ + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + + + uint64_t MCE_id; + char *MCE_name; + + uint8_t num_mcch_config_per_mbsfn; + + +// /// string holding gNB_CU_name +// char *gNB_CU_name; +// /// number of DU cells to activate +// uint16_t num_cells_to_activate; //0< num_cells_to_activate <= 512; +// /// mcc of DU cells +// //uint16_t mcc[M2AP_MAX_NB_CELLS]; + uint16_t mcc;//[M2AP_MAX_NB_CELLS]; + /// mnc of DU cells + //uint16_t mnc[M2AP_MAX_NB_CELLS]; + uint16_t mnc;//[M2AP_MAX_NB_CELLS]; + /// mnc digit length of DU cells + //uint8_t mnc_digit_length[M2AP_MAX_NB_CELLS]; + uint8_t mnc_digit_length;//[M2AP_MAX_NB_CELLS]; + // NR Global Cell Id +// uint64_t nr_cellid[M2AP_MAX_NB_CELLS]; +// /// NRPCI +// uint16_t nrpci[M2AP_MAX_NB_CELLS]; +// /// num SI messages per DU cell +// uint8_t num_SI[M2AP_MAX_NB_CELLS]; +// /// SI message containers (up to 21 messages per cell) +// uint8_t *SI_container[M2AP_MAX_NB_CELLS][21]; +// int SI_container_length[M2AP_MAX_NB_CELLS][21]; + +} m2ap_setup_resp_t; + +typedef struct m2ap_setup_failure_s { + uint16_t cause; + uint16_t time_to_wait; + uint16_t criticality_diagnostics; +} m2ap_setup_failure_t; + + + +// eNB application layer -> M2AP messages + +/* M2AP UE CONTEXT RELEASE */ +//typedef struct m2ap_ue_context_release_s { +// /* used for M2AP->RRC in source and RRC->M2AP in target */ +// int rnti; +// +// int source_assoc_id; +//} m2ap_ue_context_release_t; + +//typedef enum { +// M2AP_T_RELOC_PREP_TIMEOUT, +// M2AP_TX2_RELOC_OVERALL_TIMEOUT +//} m2ap_handover_cancel_cause_t; + +//typedef struct m2ap_handover_cancel_s { +// int rnti; +// m2ap_handover_cancel_cause_t cause; +//} m2ap_handover_cancel_t; +typedef struct m2ap_register_mce_req_s { + /* Unique eNB_id to identify the eNB within EPC. + * For macro eNB ids this field should be 20 bits long. + * For home eNB ids this field should be 28 bits long. + */ + uint32_t MCE_id; + /* The type of the cell */ + enum cell_type_e cell_type; + + /* Optional name for the cell + * NOTE: the name can be NULL (i.e no name) and will be cropped to 150 + * characters. + */ + char *MCE_name; + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + /* + * CC Params + */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + /* To be considered for TDD */ + //uint16_t tdd_EARFCN; + //uint16_t tdd_Transmission_Bandwidth; + + /* The local eNB IP address to bind */ + net_ip_address_t mce_m2_ip_address; + + /* Nb of MME to connect to */ + uint8_t nb_m2; + + /* List of target eNB to connect to for M2*/ + net_ip_address_t target_mce_m2_ip_address[M2AP_MAX_NB_ENB_IP_ADDRESS]; + + /* Number of SCTP streams used for associations */ + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + + /* eNB port for M2C*/ + uint32_t mce_port_for_M2C; + + /* timers (unit: millisecond) */ + int t_reloc_prep; + int tm2_reloc_overall; +} m2ap_register_mce_req_t; + + +typedef struct m2ap_register_enb_req_s { + /* Unique eNB_id to identify the eNB within EPC. + * For macro eNB ids this field should be 20 bits long. + * For home eNB ids this field should be 28 bits long. + */ + uint32_t eNB_id; + /* The type of the cell */ + enum cell_type_e cell_type; + + /* Optional name for the cell + * NOTE: the name can be NULL (i.e no name) and will be cropped to 150 + * characters. + */ + char *eNB_name; + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + struct{ + uint16_t mbsfn_sync_area; + uint16_t mbms_service_area_list[8]; + uint16_t num_mbms_service_area_list; + }mbms_configuration_data_list[8]; + uint16_t num_mbms_configuration_data_list; + + + + /* + * CC Params + */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + /* To be considered for TDD */ + //uint16_t tdd_EARFCN; + //uint16_t tdd_Transmission_Bandwidth; + + /* The local eNB IP address to bind */ + net_ip_address_t enb_m2_ip_address; + + /* Nb of MME to connect to */ + uint8_t nb_m2; + + /* List of target eNB to connect to for M2*/ + net_ip_address_t target_mce_m2_ip_address[M2AP_MAX_NB_ENB_IP_ADDRESS]; + + /* Number of SCTP streams used for associations */ + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + + /* eNB port for M2C*/ + uint32_t enb_port_for_M2C; + + /* timers (unit: millisecond) */ + int t_reloc_prep; + int tm2_reloc_overall; +} m2ap_register_enb_req_t; + +typedef struct m2ap_subframe_process_s { + /* nothing, we simply use the module ID in the header */ +} m2ap_subframe_process_t; + +//-------------------------------------------------------------------------------------------// +// M2AP -> eNB application layer messages +typedef struct m2ap_register_enb_cnf_s { + /* Nb of connected eNBs*/ + uint8_t nb_m2; +} m2ap_register_enb_cnf_t; + +typedef struct m2ap_deregistered_enb_ind_s { + /* Nb of connected eNBs */ + uint8_t nb_m2; +} m2ap_deregistered_enb_ind_t; + + +typedef struct m2ap_mbms_scheduling_information_s { + uint16_t mcch_update_time; + struct{ + uint8_t common_sf_allocation_period; + uint8_t mbms_area_id; + struct{ + uint8_t allocated_sf_end; + uint8_t data_mcs; + uint8_t mch_scheduling_period; + struct{ + //struct{ + uint32_t service_id; + uint16_t lcid; + uint8_t mcc; + uint8_t mnc; + uint8_t mnc_length; + //}mbms_session_per_pmch[8]; + //int num_mbms_session_per_pmch; + }mbms_session_list[8]; + int num_mbms_session_list; + }pmch_config_list[8]; + int num_pmch_config_list; + + struct{ + uint8_t radioframe_allocation_period; + uint8_t radioframe_allocation_offset; + uint8_t is_four_sf; + uint32_t subframe_allocation; + }mbms_sf_config_list[8]; + int num_mbms_sf_config_list; + + }mbms_area_config_list[8]; + uint8_t num_mbms_area_config_list; + + + + + + uint16_t mcc[M2AP_MAX_NB_CELLS];//[6]; + uint16_t mnc[M2AP_MAX_NB_CELLS];//[6]; + uint8_t mnc_digit_length[M2AP_MAX_NB_CELLS];//[6]; + uint8_t TMGI[5]; // {4,3,2,1,0}; + uint8_t is_one_frame; + uint8_t buf1; //i.e 0x38<<2 + uint8_t buf2; //i.e 0x38<<2 + uint8_t buf3; //i.e 0x38<<2 + uint16_t common_subframe_allocation_period; + +} m2ap_mbms_scheduling_information_t; + + +typedef struct m2ap_mce_sctp_req_s { + /* The local MCE IP address to bind */ + net_ip_address_t mce_m2_ip_address; + + /* eNB port for M2C*/ + uint32_t mce_port_for_M2C; +}m2ap_mce_sctp_req_t; + +typedef struct m2ap_mbms_scheduling_information_resp_s { +} m2ap_mbms_scheduling_information_resp_t; +typedef struct m2ap_session_start_req_s { +} m2ap_session_start_req_t; +typedef struct m2ap_session_start_resp_s { +} m2ap_session_start_resp_t; +typedef struct m2ap_session_start_failure_s { +} m2ap_session_start_failure_t; +typedef struct m2ap_session_stop_req_s { +} m2ap_session_stop_req_t; +typedef struct m2ap_session_stop_resp_s { +} m2ap_session_stop_resp_t; +typedef struct m2ap_reset_s { +} m2ap_reset_t; +typedef struct m2ap_enb_configuration_update_s { +} m2ap_enb_configuration_update_t; +typedef struct m2ap_enb_configuration_update_ack_s { +} m2ap_enb_configuration_update_ack_t; +typedef struct m2ap_enb_configuration_update_failure_s { +} m2ap_enb_configuration_update_failure_t; +typedef struct m2ap_mce_configuration_update_s { +} m2ap_mce_configuration_update_t; +typedef struct m2ap_mce_configuration_update_ack_s { +} m2ap_mce_configuration_update_ack_t; +typedef struct m2ap_mce_configuration_update_failure_s { +} m2ap_mce_configuration_update_failure_t; +typedef struct m2ap_error_indication_s { +}m2ap_error_indication_t; +typedef struct m2ap_mbms_session_update_req_s { +} m2ap_mbms_session_update_req_t; +typedef struct m2ap_mbms_session_update_resp_s { +} m2ap_mbms_session_update_resp_t; +typedef struct m2ap_mbms_session_update_failure_s { +} m2ap_mbms_session_update_failure_t; +typedef struct m2ap_mbms_service_counting_report_s { +} m2ap_mbms_service_counting_report_t; +typedef struct m2ap_mbms_overload_notification_s { +} m2ap_mbms_overload_notification_t; +typedef struct m2ap_mbms_service_counting_req_s { +} m2ap_mbms_service_counting_req_t; +typedef struct m2ap_mbms_service_counting_resp_s { +} m2ap_mbms_service_counting_resp_t; +typedef struct m2ap_mbms_service_counting_failure_s { +} m2ap_mbms_service_counting_failure_t; + + +//-------------------------------------------------------------------------------------------// +// M2AP <-> RRC +//typedef struct m2ap_gummei_s { +// uint16_t mcc; +// uint16_t mnc; +// uint8_t mnc_len; +// uint8_t mme_code; +// uint16_t mme_group_id; +//} m2ap_gummei_t; +// +//typedef struct m2ap_lastvisitedcell_info_s { +// uint16_t mcc; +// uint16_t mnc; +// uint8_t mnc_len; +// LTE_PhysCellId_t target_physCellId; +// cell_type_t cell_type; +// uint64_t time_UE_StayedInCell; +//}m2ap_lastvisitedcell_info_t; +// +//typedef struct m2ap_handover_req_s { +// /* used for RRC->M2AP in source eNB */ +// int rnti; +// +// /* used for M2AP->RRC in target eNB */ +// int x2_id; +// +// LTE_PhysCellId_t target_physCellId; +// +// m2ap_gummei_t ue_gummei; +// +// /*UE-ContextInformation */ +// +// /* MME UE id */ +// uint32_t mme_ue_s1ap_id; +// +// security_capabilities_t security_capabilities; +// +// uint8_t kenb[32]; // keNB or keNB* +// +// /*next_hop_chaining_coun */ +// long int kenb_ncc; +// +// /* UE aggregate maximum bitrate */ +// ambr_t ue_ambr; +// +// uint8_t nb_e_rabs_tobesetup; +// +// /* list of e_rab setup-ed by RRC layers */ +// e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB]; +// +// /* list of e_rab to be setup by RRC layers */ +// e_rab_t e_rab_param[S1AP_MAX_E_RAB]; +// +// m2ap_lastvisitedcell_info_t lastvisitedcell_info; +// +// uint8_t rrc_buffer[1024 /* arbitrary, big enough */]; +// int rrc_buffer_size; +// +// int target_assoc_id; +//} m2ap_handover_req_t; +// +//typedef struct m2ap_handover_req_ack_s { +// /* used for RRC->M2AP in target and M2AP->RRC in source */ +// int rnti; +// +// /* used for RRC->M2AP in target */ +// int x2_id_target; +// +// int source_assoc_id; +// +// uint8_t nb_e_rabs_tobesetup; +// +// /* list of e_rab setup-ed by RRC layers */ +// e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB]; +// +// /* list of e_rab to be setup by RRC layers */ +// e_rab_t e_rab_param[S1AP_MAX_E_RAB]; +// +// uint8_t rrc_buffer[1024 /* arbitrary, big enough */]; +// int rrc_buffer_size; +// +// uint32_t mme_ue_s1ap_id; +//} m2ap_handover_req_ack_t; +// +#endif /* M2AP_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/m3ap_messages_def.h b/openair2/COMMON/m3ap_messages_def.h new file mode 100644 index 0000000000..9ee725447d --- /dev/null +++ b/openair2/COMMON/m3ap_messages_def.h @@ -0,0 +1,71 @@ +/* + * 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 + */ + +/* eNB application layer -> M3AP messages */ +/* ITTI LOG messages */ +/* ENCODER */ +MESSAGE_DEF(M3AP_RESET_REQUST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m3ap_reset_request_log) +MESSAGE_DEF(M3AP_RESOURCE_STATUS_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m3ap_resource_status_response_log) +MESSAGE_DEF(M3AP_RESOURCE_STATUS_FAILURE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m3ap_resource_status_failure_log) + +/* Messages for M3AP logging */ +MESSAGE_DEF(M3AP_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , m3ap_setup_request_log) + + +/* eNB application layer -> M3AP messages */ +MESSAGE_DEF(M3AP_REGISTER_MCE_REQ , MESSAGE_PRIORITY_MED, m3ap_register_mce_req_t , m3ap_register_mce_req) +MESSAGE_DEF(M3AP_SUBFRAME_PROCESS , MESSAGE_PRIORITY_MED, m3ap_subframe_process_t , m3ap_subframe_process) + +/* M3AP -> eNB application layer messages */ +MESSAGE_DEF(M3AP_REGISTER_MCE_CNF , MESSAGE_PRIORITY_MED, m3ap_register_mce_cnf_t , m3ap_register_mce_cnf) +MESSAGE_DEF(M3AP_DEREGISTERED_MCE_IND , MESSAGE_PRIORITY_MED, m3ap_deregistered_mce_ind_t , m3ap_deregistered_mce_ind) + +/* handover messages M3AP <-> RRC */ +//MESSAGE_DEF(M3AP_HANDOVER_REQ , MESSAGE_PRIORITY_MED, m3ap_handover_req_t , m3ap_handover_req) +//MESSAGE_DEF(M3AP_HANDOVER_REQ_ACK , MESSAGE_PRIORITY_MED, m3ap_handover_req_ack_t , m3ap_handover_req_ack) +//MESSAGE_DEF(M3AP_HANDOVER_CANCEL , MESSAGE_PRIORITY_MED, m3ap_handover_cancel_t , m3ap_handover_cancel) + +/* handover messages M3AP <-> S1AP */ +//MESSAGE_DEF(M3AP_UE_CONTEXT_RELEASE , MESSAGE_PRIORITY_MED, m3ap_ue_context_release_t , m3ap_ue_context_release) + +MESSAGE_DEF(M3AP_MME_SCTP_REQ , MESSAGE_PRIORITY_MED, m3ap_mme_sctp_req_t , m3ap_mme_sctp_req) + + +MESSAGE_DEF(M3AP_MBMS_SESSION_START_REQ , MESSAGE_PRIORITY_MED ,m3ap_session_start_req_t ,m3ap_session_start_req) +MESSAGE_DEF(M3AP_MBMS_SESSION_START_RESP , MESSAGE_PRIORITY_MED ,m3ap_session_start_resp_t ,m3ap_session_start_resp) +MESSAGE_DEF(M3AP_MBMS_SESSION_START_FAILURE , MESSAGE_PRIORITY_MED ,m3ap_session_start_failure_t ,m3ap_session_start_failure) +MESSAGE_DEF(M3AP_MBMS_SESSION_STOP_REQ , MESSAGE_PRIORITY_MED ,m3ap_session_stop_req_t ,m3ap_session_stop_req) +MESSAGE_DEF(M3AP_MBMS_SESSION_STOP_RESP , MESSAGE_PRIORITY_MED ,m3ap_session_stop_resp_t ,m3ap_session_stop_resp) +MESSAGE_DEF(M3AP_MBMS_SESSION_STOP_FAILURE , MESSAGE_PRIORITY_MED ,m3ap_session_stop_failure_t ,m3ap_session_stop_failure) +MESSAGE_DEF(M3AP_ERROR_INDICATION , MESSAGE_PRIORITY_MED ,m3ap_error_indication_t ,m3ap_error_indication) +MESSAGE_DEF(M3AP_RESET , MESSAGE_PRIORITY_MED ,m3ap_reset_t ,m3ap_reset) +MESSAGE_DEF(M3AP_RESET_ACK , MESSAGE_PRIORITY_MED ,m3ap_reset_ack_t ,m3ap_reset_ack) +MESSAGE_DEF(M3AP_MBMS_SESSION_UPDATE_REQ , MESSAGE_PRIORITY_MED ,m3ap_mbms_session_update_req_t ,m3ap_mbms_session_update_req) +MESSAGE_DEF(M3AP_MBMS_SESSION_UPDATE_RESP , MESSAGE_PRIORITY_MED ,m3ap_mbms_session_update_resp_t ,m3ap_mbms_session_update_resp) +MESSAGE_DEF(M3AP_MBMS_SESSION_UPDATE_FAILURE , MESSAGE_PRIORITY_MED ,m3ap_mbms_session_update_failure_t ,m3ap_mbms_session_update_failure) +MESSAGE_DEF(M3AP_SETUP_REQ , MESSAGE_PRIORITY_MED ,m3ap_setup_req_t ,m3ap_setup_req) +MESSAGE_DEF(M3AP_SETUP_RESP , MESSAGE_PRIORITY_MED ,m3ap_setup_resp_t ,m3ap_setup_resp) +MESSAGE_DEF(M3AP_SETUP_FAILURE , MESSAGE_PRIORITY_MED ,m3ap_setup_failure_t ,m3ap_setup_failure) +MESSAGE_DEF(M3AP_MCE_CONFIGURATION_UPDATE , MESSAGE_PRIORITY_MED ,m3ap_mce_configuration_update_t ,m3ap_mce_configuration_update) +MESSAGE_DEF(M3AP_MCE_CONFIGURATION_UPDATE_ACK , MESSAGE_PRIORITY_MED ,m3ap_mce_configuration_update_ack_t ,m3ap_mce_configuration_update_ack) +MESSAGE_DEF(M3AP_MCE_CONFIGURATION_UPDATE_FAILURE, MESSAGE_PRIORITY_MED ,m3ap_mce_configuration_update_failure_t ,m3ap_mce_configuration_update_failure) + + diff --git a/openair2/COMMON/m3ap_messages_types.h b/openair2/COMMON/m3ap_messages_types.h new file mode 100644 index 0000000000..21e24dd449 --- /dev/null +++ b/openair2/COMMON/m3ap_messages_types.h @@ -0,0 +1,330 @@ +/* + * 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 + */ + +#ifndef M3AP_MESSAGES_TYPES_H_ +#define M3AP_MESSAGES_TYPES_H_ + +#include "s1ap_messages_types.h" +#include "LTE_PhysCellId.h" + +//-------------------------------------------------------------------------------------------// +// Defines to access message fields. +#define M3AP_MME_SCTP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mme_sctp_req + +#define M3AP_REGISTER_MCE_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_register_mce_req +//#define M3AP_HANDOVER_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_handover_req +//#define M3AP_HANDOVER_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.m3ap_handover_req_ack +#define M3AP_REGISTER_MCE_CNF(mSGpTR) (mSGpTR)->ittiMsg.m3ap_register_mce_cnf +#define M3AP_DEREGISTERED_MCE_IND(mSGpTR) (mSGpTR)->ittiMsg.m3ap_deregistered_mce_ind +//#define M3AP_UE_CONTEXT_RELEASE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_ue_context_release +//#define M3AP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.m3ap_handover_cancel + + +#define M3AP_MBMS_SESSION_START_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_session_start_req +#define M3AP_MBMS_SESSION_START_RESP(mSGpTR) (mSGpTR)->ittiMsg.m3ap_session_start_resp +#define M3AP_MBMS_SESSION_START_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_session_start_failure +#define M3AP_MBMS_SESSION_STOP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_session_stop_req +#define M3AP_MBMS_SESSION_STOP_RESP(mSGpTR) (mSGpTR)->ittiMsg.m3ap_session_stop_resp +#define M3AP_MBMS_SESSION_STOP_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_session_stop_failure +#define M3AP_ERROR_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.m3ap_error_indication +#define M3AP_RESET(mSGpTR) (mSGpTR)->ittiMsg.m3ap_reset +#define M3AP_RESET_ACK(mSGpTR) (mSGpTR)->ittiMsg.m3ap_reset_ack +#define M3AP_MBMS_SESSION_UPDATE_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mbms_session_update_req +#define M3AP_MBMS_SESSION_UPDATE_RESP(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mbms_session_update_resp +#define M3AP_MBMS_SESSION_UPDATE_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mbms_session_update_failure +#define M3AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.m3ap_setup_req +#define M3AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.m3ap_setup_resp +#define M3AP_SETUP_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_setup_failure +#define M3AP_MCE_CONFIGURATION_UPDATE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mce_configuration_update +#define M3AP_MCE_CONFIGURATION_UPDATE_ACK(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mce_configuration_update_ack +#define M3AP_MCE_CONFIGURATION_UPDATE_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.m3ap_mce_configuration_update_failure + + +#define M3AP_MAX_NB_MCE_IP_ADDRESS 2 + +#define M3AP_MAX_NB_MME_IP_ADDRESS 2 + + +typedef struct m3ap_net_ip_address_s { + unsigned ipv4:1; + unsigned ipv6:1; + char ipv4_address[16]; + char ipv6_address[46]; +} m3ap_net_ip_address_t; + +// eNB application layer -> M3AP messages + +/* M3AP UE CONTEXT RELEASE */ +//typedef struct m3ap_ue_context_release_s { +// /* used for M3AP->RRC in source and RRC->M3AP in target */ +// int rnti; +// +// int source_assoc_id; +//} m3ap_ue_context_release_t; + +//typedef enum { +// M3AP_T_RELOC_PREP_TIMEOUT, +// M3AP_TX2_RELOC_OVERALL_TIMEOUT +//} m3ap_handover_cancel_cause_t; + +//typedef struct m3ap_handover_cancel_s { +// int rnti; +// m3ap_handover_cancel_cause_t cause; +//} m3ap_handover_cancel_t; + +typedef struct m3ap_register_mce_req_s { + /* Unique eNB_id to identify the eNB within EPC. + * For macro eNB ids this field should be 20 bits long. + * For home eNB ids this field should be 28 bits long. + */ + uint32_t MCE_id; + /* The type of the cell */ + enum cell_type_e cell_type; + + /* Optional name for the cell + * NOTE: the name can be NULL (i.e no name) and will be cropped to 150 + * characters. + */ + char *MCE_name; + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + /* + * CC Params + */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + /* To be considered for TDD */ + //uint16_t tdd_EARFCN; + //uint16_t tdd_Transmission_Bandwidth; + + /* The local eNB IP address to bind */ + net_ip_address_t mme_m3_ip_address; + + /* Nb of MME to connect to */ + uint8_t nb_m3; + + /* List of target eNB to connect to for M3*/ + net_ip_address_t target_mme_m3_ip_address[M3AP_MAX_NB_MCE_IP_ADDRESS]; + + /* Number of SCTP streams used for associations */ + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + + /* eNB port for M3C*/ + uint32_t mme_port_for_M3C; + + /* timers (unit: millisecond) */ + int t_reloc_prep; + int tm3_reloc_overall; + + /* Nb of MME to connect to */ + uint8_t nb_mme; + /* List of MME to connect to */ + net_ip_address_t mme_ip_address[M3AP_MAX_NB_MME_IP_ADDRESS]; +} m3ap_register_mce_req_t; + +typedef struct m3ap_subframe_process_s { + /* nothing, we simply use the module ID in the header */ +} m3ap_subframe_process_t; + +//-------------------------------------------------------------------------------------------// +// M3AP -> eNB application layer messages +typedef struct m3ap_register_mce_cnf_s { + /* Nb of connected eNBs*/ + uint8_t nb_mme; +} m3ap_register_mce_cnf_t; + +typedef struct m3ap_deregistered_mce_ind_s { + /* Nb of connected eNBs */ + uint8_t nb_mme; +} m3ap_deregistered_mce_ind_t; + +//-------------------------------------------------------------------------------------------// +// M3AP <-> RRC +//typedef struct m3ap_gummei_s { +// uint16_t mcc; +// uint16_t mnc; +// uint8_t mnc_len; +// uint8_t mme_code; +// uint16_t mme_group_id; +//} m3ap_gummei_t; +// +//typedef struct m3ap_lastvisitedcell_info_s { +// uint16_t mcc; +// uint16_t mnc; +// uint8_t mnc_len; +// LTE_PhysCellId_t target_physCellId; +// cell_type_t cell_type; +// uint64_t time_UE_StayedInCell; +//}m3ap_lastvisitedcell_info_t; +// +//typedef struct m3ap_handover_req_s { +// /* used for RRC->M3AP in source eNB */ +// int rnti; +// +// /* used for M3AP->RRC in target eNB */ +// int x2_id; +// +// LTE_PhysCellId_t target_physCellId; +// +// m3ap_gummei_t ue_gummei; +// +// /*UE-ContextInformation */ +// +// /* MME UE id */ +// uint32_t mme_ue_s1ap_id; +// +// security_capabilities_t security_capabilities; +// +// uint8_t kenb[32]; // keNB or keNB* +// +// /*next_hop_chaining_coun */ +// long int kenb_ncc; +// +// /* UE aggregate maximum bitrate */ +// ambr_t ue_ambr; +// +// uint8_t nb_e_rabs_tobesetup; +// +// /* list of e_rab setup-ed by RRC layers */ +// e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB]; +// +// /* list of e_rab to be setup by RRC layers */ +// e_rab_t e_rab_param[S1AP_MAX_E_RAB]; +// +// m3ap_lastvisitedcell_info_t lastvisitedcell_info; +// +// uint8_t rrc_buffer[1024 /* arbitrary, big enough */]; +// int rrc_buffer_size; +// +// int target_assoc_id; +//} m3ap_handover_req_t; +// +//typedef struct m3ap_handover_req_ack_s { +// /* used for RRC->M3AP in target and M3AP->RRC in source */ +// int rnti; +// +// /* used for RRC->M3AP in target */ +// int x2_id_target; +// +// int source_assoc_id; +// +// uint8_t nb_e_rabs_tobesetup; +// +// /* list of e_rab setup-ed by RRC layers */ +// e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB]; +// +// /* list of e_rab to be setup by RRC layers */ +// e_rab_t e_rab_param[S1AP_MAX_E_RAB]; +// +// uint8_t rrc_buffer[1024 /* arbitrary, big enough */]; +// int rrc_buffer_size; +// +// uint32_t mme_ue_s1ap_id; +//} m3ap_handover_req_ack_t; +// + +typedef struct m3ap_mme_sctp_req_s { + /* the local mce ip address to bind */ + net_ip_address_t mme_m3_ip_address; + + /* enb port for m2c*/ + uint32_t mme_port_for_M3C; +}m3ap_mme_sctp_req_t; + + + +typedef struct m3ap_session_start_req_s{ +}m3ap_session_start_req_t; +typedef struct m3ap_session_start_resp_s{ +}m3ap_session_start_resp_t; +typedef struct m3ap_session_start_failure_s{ +}m3ap_session_start_failure_t; +typedef struct m3ap_session_stop_req_s{ +}m3ap_session_stop_req_t; +typedef struct m3ap_session_stop_resp_s{ +}m3ap_session_stop_resp_t; +typedef struct m3ap_session_stop_failure_s{ +}m3ap_session_stop_failure_t; +typedef struct m3ap_error_indication_s{ +}m3ap_error_indication_t; +typedef struct m3ap_reset_s{ +}m3ap_reset_t; +typedef struct m3ap_reset_ack_s{ +}m3ap_reset_ack_t; +typedef struct m3ap_mbms_session_update_req_s{ +}m3ap_mbms_session_update_req_t; +typedef struct m3ap_mbms_session_update_resp_s{ +}m3ap_mbms_session_update_resp_t; +typedef struct m3ap_mbms_session_update_failure_s{ +}m3ap_mbms_session_update_failure_t; +typedef struct m3ap_setup_req_s{ + /* Connexion id used between SCTP/M3AP */ + uint16_t cnx_id; + /* SCTP association id */ + int32_t assoc_id; + + /* Number of SCTP streams used for a mme association */ + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + + uint16_t default_sctp_stream_id; +}m3ap_setup_req_t; +typedef struct m3ap_setup_resp_s{ +}m3ap_setup_resp_t; +typedef struct m3ap_setup_failure_s{ +}m3ap_setup_failure_t; +typedef struct m3ap_mce_configuration_update_s{ +}m3ap_mce_configuration_update_t; +typedef struct m3ap_mce_configuration_update_ack_s{ +}m3ap_mce_configuration_update_ack_t; +typedef struct m3ap_mce_configuration_update_failure_s{ +}m3ap_mce_configuration_update_failure_t; + + + + + + + + + + + + +#endif /* M3AP_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index f69186e4b8..09b3f2aab4 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -45,3 +45,6 @@ MESSAGE_DEF(RRC_MAC_MCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcMacMcchDat MESSAGE_DEF(RRC_MAC_MCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, RrcMacMcchDataInd, rrc_mac_mcch_data_ind) MESSAGE_DEF(RRC_MAC_PCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcMacPcchDataReq, rrc_mac_pcch_data_req) + +/* RRC configures DRX context (MAC timers) of a UE */ +MESSAGE_DEF(RRC_MAC_DRX_CONFIG_REQ, MESSAGE_PRIORITY_MED, rrc_mac_drx_config_req_t, rrc_mac_drx_config_req) \ No newline at end of file diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index 3bbea66d0d..e227296d05 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -29,6 +29,8 @@ #ifndef MAC_MESSAGES_TYPES_H_ #define MAC_MESSAGES_TYPES_H_ +#include + //-------------------------------------------------------------------------------------------// // Defines to access message fields. #define RRC_MAC_IN_SYNC_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_in_sync_ind @@ -48,6 +50,8 @@ #define RRC_MAC_MCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_mcch_data_ind #define RRC_MAC_PCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_pcch_data_req +#define RRC_MAC_DRX_CONFIG_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_drx_config_req + // Some constants from "LAYER2/MAC/defs.h" #define BCCH_SDU_SIZE (512) #define BCCH_SDU_MBMS_SIZE (512) @@ -145,4 +149,14 @@ typedef struct RrcMacPcchDataReq_s { uint8_t sdu[PCCH_SDU_SIZE]; uint8_t enb_index; } RrcMacPcchDataReq; + +/* RRC configures DRX context (MAC timers) of a UE */ +typedef struct rrc_mac_drx_config_req_s { + /* UE RNTI to configure */ + rnti_t rnti; + + /* DRX configuration from MacMainConfig to configure UE's local timers */ + LTE_DRX_Config_t * drx_Configuration; +} rrc_mac_drx_config_req_t; + #endif /* MAC_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/messages_def.h b/openair2/COMMON/messages_def.h index b0219db50a..0d302cfea0 100644 --- a/openair2/COMMON/messages_def.h +++ b/openair2/COMMON/messages_def.h @@ -36,6 +36,8 @@ #include "s1ap_messages_def.h" #include "f1ap_messages_def.h" #include "x2ap_messages_def.h" +#include "m2ap_messages_def.h" +#include "m3ap_messages_def.h" #include "sctp_messages_def.h" #include "udp_messages_def.h" #include "gtpv1_u_messages_def.h" diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h index 3dd05d6575..7a7e984aca 100644 --- a/openair2/COMMON/platform_constants.h +++ b/openair2/COMMON/platform_constants.h @@ -84,9 +84,9 @@ #else #define MAX_MOBILES_PER_ENB 4 #define MAX_MOBILES_PER_ENB_NB_IoT 4 - #define MAX_MOBILES_PER_GNB 4 - #define MAX_eNB 2 - #define MAX_gNB 2 + #define MAX_MOBILES_PER_GNB 2//16 + #define MAX_eNB 2 + #define MAX_gNB 2 #endif #endif #else @@ -118,7 +118,8 @@ #define NB_RAB_MAX LTE_maxDRB /* was 8, now 11 */ #define RAB_SHIFT1 9 #define RAB_SHIFT2 3 -#define RAB_OFFSET 0x0007 +//#define RAB_OFFSET 0x0007 +#define RAB_OFFSET 0x000F #define RAB_OFFSET1 0x7E00 #define RAB_OFFSET2 0x01F8 #define DIR_OFFSET 0x8000 diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 2948d59b02..68e1753448 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -194,6 +194,7 @@ typedef struct RrcConfigurationReq_s { int16_t N_RB_DL[MAX_NUM_CCs];// for testing, change later int nb_antenna_ports[MAX_NUM_CCs]; int eMBMS_configured; + int eMBMS_M2_configured; int eMTC_configured; int SL_configured; diff --git a/openair2/COMMON/s1ap_messages_types.h b/openair2/COMMON/s1ap_messages_types.h index 2615494d3b..aa718dbcf8 100644 --- a/openair2/COMMON/s1ap_messages_types.h +++ b/openair2/COMMON/s1ap_messages_types.h @@ -81,7 +81,8 @@ #ifndef OCP_FRAMEWORK typedef enum cell_type_e { CELL_MACRO_ENB, - CELL_HOME_ENB + CELL_HOME_ENB, + CELL_MACRO_GNB } cell_type_t; typedef enum paging_drx_e { @@ -272,6 +273,22 @@ typedef struct e_rab_setup_s { uint32_t gtp_teid; } e_rab_setup_t; +typedef struct e_rab_tobe_added_s { + /* Unique e_rab_id for the UE. */ + uint8_t e_rab_id; + + /* Unique drb_ID for the UE. */ + uint8_t drb_ID; + + /* The transport layer address for the IP packets */ + transport_layer_addr_t eNB_addr; + + /* S-GW Tunnel endpoint identifier */ + uint32_t gtp_teid; +} e_rab_tobe_added_t; + + + typedef struct e_rab_tobeswitched_s { /* Unique e_rab_id for the UE. */ uint8_t e_rab_id; diff --git a/openair2/COMMON/sctp_messages_types.h b/openair2/COMMON/sctp_messages_types.h index 9e363c0d8d..c2561c0424 100644 --- a/openair2/COMMON/sctp_messages_types.h +++ b/openair2/COMMON/sctp_messages_types.h @@ -41,7 +41,7 @@ enum sctp_state_e { }; typedef struct sctp_new_association_req_s { - /* Upper layer connexion identifier */ + /* Upper layer connection identifier */ uint16_t ulp_cnx_id; /* The port to connect to */ @@ -60,7 +60,7 @@ typedef struct sctp_new_association_req_s { } sctp_new_association_req_t; typedef struct sctp_new_association_req_multi_s { - /* Upper layer connexion identifier */ + /* Upper layer connection identifier */ uint16_t ulp_cnx_id; /* The port to connect to */ @@ -98,7 +98,7 @@ typedef struct sctp_new_association_ind_s { } sctp_new_association_ind_t; typedef struct sctp_new_association_resp_s { - /* Upper layer connexion identifier */ + /* Upper layer connection identifier */ uint16_t ulp_cnx_id; /* SCTP Association ID */ @@ -149,7 +149,7 @@ typedef struct sctp_listener_register_upper_layer_s { /* Port to listen to */ uint16_t port; /* Payload protocol identifier - * Any data receveid on PPID != will be discarded + * Any data received on PPID != will be discarded */ uint32_t ppid; } sctp_listener_register_upper_layer_t; diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h index 4703efc27e..0fb1bd6b30 100644 --- a/openair2/COMMON/tasks_def.h +++ b/openair2/COMMON/tasks_def.h @@ -50,6 +50,15 @@ TASK_DEF(TASK_GTPV1_U, TASK_PRIORITY_MED, 1000) TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED, 200) TASK_DEF(TASK_CU_F1, TASK_PRIORITY_MED, 200) TASK_DEF(TASK_DU_F1, TASK_PRIORITY_MED, 200) +/// M3ap task, acts as both source and target +TASK_DEF(TASK_M3AP, TASK_PRIORITY_MED, 200) +/// M3ap task, acts as both source and target +TASK_DEF(TASK_M3AP_MME, TASK_PRIORITY_MED, 200) +/// M3ap task, acts as both source and target +TASK_DEF(TASK_M3AP_MCE, TASK_PRIORITY_MED, 200) +/// M2ap task, acts as both source and target +TASK_DEF(TASK_M2AP_MCE, TASK_PRIORITY_MED, 200) +TASK_DEF(TASK_M2AP_ENB, TASK_PRIORITY_MED, 200) /// X2ap task, acts as both source and target TASK_DEF(TASK_X2AP, TASK_PRIORITY_MED, 200) /// Sctp task (Used by both S1AP and X2AP) diff --git a/openair2/COMMON/x2ap_messages_def.h b/openair2/COMMON/x2ap_messages_def.h index 6c2d56a942..8438fd1037 100644 --- a/openair2/COMMON/x2ap_messages_def.h +++ b/openair2/COMMON/x2ap_messages_def.h @@ -50,3 +50,8 @@ MESSAGE_DEF(X2AP_UE_CONTEXT_RELEASE , MESSAGE_PRIORITY_MED, x2ap_ue_ /*Senb bearer addition messages X2AP <-> RRC */ MESSAGE_DEF(X2AP_SENB_ADDITION_REQ , MESSAGE_PRIORITY_MED, x2ap_senb_addition_req_t , x2ap_senb_addition_req) + +/*SGnb bearer addition messages X2AP <-> RRC */ +MESSAGE_DEF(X2AP_ENDC_SGNB_ADDITION_REQ , MESSAGE_PRIORITY_MED, x2ap_ENDC_sgnb_addition_req_t , x2ap_ENDC_sgnb_addition_req) +MESSAGE_DEF(X2AP_ENDC_SGNB_ADDITION_REQ_ACK , MESSAGE_PRIORITY_MED, x2ap_ENDC_sgnb_addition_req_ACK_t , x2ap_ENDC_sgnb_addition_req_ACK) +MESSAGE_DEF(X2AP_ENDC_SGNB_RECONF_COMPLETE , MESSAGE_PRIORITY_MED, x2ap_ENDC_reconf_complete_t , x2ap_ENDC_sgnb_reconf_complete) diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h index e502191d2b..ed3470a7d6 100644 --- a/openair2/COMMON/x2ap_messages_types.h +++ b/openair2/COMMON/x2ap_messages_types.h @@ -28,16 +28,19 @@ //-------------------------------------------------------------------------------------------// // Defines to access message fields. -#define X2AP_REGISTER_ENB_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_req -#define X2AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_setup_req -#define X2AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.x2ap_setup_resp -#define X2AP_HANDOVER_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_req -#define X2AP_HANDOVER_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_req_ack -#define X2AP_REGISTER_ENB_CNF(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_cnf -#define X2AP_DEREGISTERED_ENB_IND(mSGpTR) (mSGpTR)->ittiMsg.x2ap_deregistered_enb_ind -#define X2AP_UE_CONTEXT_RELEASE(mSGpTR) (mSGpTR)->ittiMsg.x2ap_ue_context_release -#define X2AP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_cancel -#define X2AP_SENB_ADDITION_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_senb_addition_req +#define X2AP_REGISTER_ENB_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_req +#define X2AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_setup_req +#define X2AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.x2ap_setup_resp +#define X2AP_HANDOVER_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_req +#define X2AP_HANDOVER_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_req_ack +#define X2AP_REGISTER_ENB_CNF(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_cnf +#define X2AP_DEREGISTERED_ENB_IND(mSGpTR) (mSGpTR)->ittiMsg.x2ap_deregistered_enb_ind +#define X2AP_UE_CONTEXT_RELEASE(mSGpTR) (mSGpTR)->ittiMsg.x2ap_ue_context_release +#define X2AP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_cancel +#define X2AP_SENB_ADDITION_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_senb_addition_req +#define X2AP_ENDC_SGNB_ADDITION_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_ENDC_sgnb_addition_req +#define X2AP_ENDC_SGNB_ADDITION_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.x2ap_ENDC_sgnb_addition_req_ACK +#define X2AP_ENDC_SGNB_RECONF_COMPLETE(mSGpTR) (mSGpTR)->ittiMsg.x2ap_ENDC_sgnb_reconf_complete #define X2AP_MAX_NB_ENB_IP_ADDRESS 2 @@ -66,6 +69,13 @@ typedef enum { X2AP_TX2_RELOC_OVERALL_TIMEOUT } x2ap_handover_cancel_cause_t; +typedef enum { + X2AP_RECONF_RESPONSE_SUCCESS, + X2AP_RECONF_RESPONSE_REJECT + /* Extensions may appear below */ + +} x2ap_sgNB_reconf_response_information_t; + typedef struct x2ap_handover_cancel_s { int rnti; x2ap_handover_cancel_cause_t cause; @@ -286,7 +296,7 @@ typedef struct x2ap_senb_addition_req_ack_s { int MeNB_UE_X2_id; - int SeNB_UE_X2_id; + int SgNB_UE_X2_id; uint8_t nb_sCG_e_rabs_tobeadded; @@ -303,4 +313,86 @@ typedef struct x2ap_senb_addition_req_ack_s { } x2ap_senb_addition_req_ack_t; +typedef struct x2ap_ENDC_sgnb_addition_req_s { + int ue_x2_id; + + /* used for RRC->X2AP in source eNB */ + int rnti; + + security_capabilities_t security_capabilities; + + /* SgNB Security Key */ + uint8_t kgnb[32]; + + /*next_hop_chaining_coun */ + long int kgnb_ncc; + + /* UE aggregate maximum bitrate */ + ambr_t ue_ambr; + + uint8_t nb_e_rabs_tobeadded; + + /* list of e_rab to be added by RRC layers */ + e_rab_tobe_added_t e_rabs_tobeadded[S1AP_MAX_E_RAB]; + + /* list of e_rab to be setup by RRC layers */ + e_rab_t e_rab_param[S1AP_MAX_E_RAB]; + + x2ap_lastvisitedcell_info_t lastvisitedcell_info; + + uint8_t rrc_buffer[4096 /* arbitrary, big enough */]; + int rrc_buffer_size; + + int target_assoc_id; + + /*long int pDCPatSgNB = X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present; + long int mCGresources = X2AP_EN_DC_ResourceConfiguration__mCGresources_not_present; + long int sCGresources = X2AP_EN_DC_ResourceConfiguration__sCGresources_not_present;*/ + + +} x2ap_ENDC_sgnb_addition_req_t; + +typedef struct x2ap_ENDC_sgnb_addition_req_ACK_s { + int MeNB_ue_x2_id; + + int SgNB_ue_x2_id; + + /* used for X2AP->RRC in source eNB */ + int rnti; + + uint8_t nb_e_rabs_admitted_tobeadded; + + /* list of e_rab to be added by RRC layers */ + e_rab_tobe_added_t e_rabs_admitted_tobeadded[S1AP_MAX_E_RAB]; + + /* list of e_rab to be setup by RRC layers */ + e_rab_t e_rab_param[S1AP_MAX_E_RAB]; + + x2ap_lastvisitedcell_info_t lastvisitedcell_info; + + uint8_t rrc_buffer[4096 /* arbitrary, big enough */]; + int rrc_buffer_size; + + int target_assoc_id; + + /*long int pDCPatSgNB = X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present; + long int mCGresources = X2AP_EN_DC_ResourceConfiguration__mCGresources_not_present; + long int sCGresources = X2AP_EN_DC_ResourceConfiguration__sCGresources_not_present;*/ + + +} x2ap_ENDC_sgnb_addition_req_ACK_t; + +typedef struct x2ap_ENDC_reconf_complete_s { + int MeNB_ue_x2_id; + + int SgNB_ue_x2_id; + + x2ap_sgNB_reconf_response_information_t reconf_response; + + uint8_t rrc_buffer[4096 /* arbitrary, big enough */]; + int rrc_buffer_size; + +} x2ap_ENDC_reconf_complete_t; + + #endif /* X2AP_MESSAGES_TYPES_H_ */ diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 51ec781de3..c489f10dae 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -62,675 +62,528 @@ int n_ue_slice_assoc_updates = 0; pthread_mutex_t sc_update_mtx = PTHREAD_MUTEX_INITIALIZER; -int flexran_agent_mac_stats_reply(mid_t mod_id, - const report_config_t *report_config, - Protocol__FlexUeStatsReport **ue_report, - Protocol__FlexCellStatsReport **cell_report) { - - - // Protocol__FlexHeader *header; - int i, j, k; - int UE_id; - int cc_id = 0; - int enb_id = mod_id; - - /* Allocate memory for list of UE reports */ - if (report_config->nr_ue > 0) { - - - for (i = 0; i < report_config->nr_ue; i++) { - - UE_id = flexran_get_mac_ue_id(mod_id, i); - - ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; - ue_report[i]->has_rnti = 1; - - /* Check flag for creation of buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { - //TODO should be automated - ue_report[i]->n_bsr = 4; - uint32_t *elem; - elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); - if (elem == NULL) - goto error; - for (j = 0; j < ue_report[i]->n_bsr; j++) { - // NN: we need to know the cc_id here, consider the first one - elem[j] = flexran_get_ue_bsr_ul_buffer_info (enb_id, i, j); - } - - ue_report[i]->bsr = elem; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR; - } - - /* Check flag for creation of PHR report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { - ue_report[i]->phr = flexran_get_ue_phr (enb_id, UE_id); // eNB_UE_list->UE_template[UE_PCCID(enb_id,UE_id)][UE_id].phr_info; - ue_report[i]->has_phr = 1; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR; - - } - - /* Check flag for creation of RLC buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { - ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs - Protocol__FlexRlcBsr ** rlc_reports; - rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); - if (rlc_reports == NULL) - goto error; - - // NN: see LAYER2/openair2_proc.c for rlc status - for (j = 0; j < ue_report[i]->n_rlc_report; j++) { - - rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); - if (rlc_reports[j] == NULL){ - for (k = 0; k < j; k++){ - free(rlc_reports[k]); - } - free(rlc_reports); - goto error; - } - protocol__flex_rlc_bsr__init(rlc_reports[j]); - rlc_reports[j]->lc_id = j+1; - rlc_reports[j]->has_lc_id = 1; - rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id, UE_id, j + 1); - rlc_reports[j]->has_tx_queue_size = 1; - - //TODO:Set tx queue head of line delay in ms - rlc_reports[j]->tx_queue_hol_delay = flexran_get_hol_delay(enb_id, UE_id, j + 1); - rlc_reports[j]->has_tx_queue_hol_delay = 1; - //TODO:Set retransmission queue size in bytes - rlc_reports[j]->retransmission_queue_size = 10; - rlc_reports[j]->has_retransmission_queue_size = 0; - //TODO:Set retransmission queue head of line delay in ms - rlc_reports[j]->retransmission_queue_hol_delay = 100; - rlc_reports[j]->has_retransmission_queue_hol_delay = 0; - //TODO DONE:Set current size of the pending message in bytes - rlc_reports[j]->status_pdu_size = flexran_get_num_pdus_buffer(enb_id, UE_id, j + 1); - rlc_reports[j]->has_status_pdu_size = 1; - - } - // Add RLC buffer status reports to the full report - if (ue_report[i]->n_rlc_report > 0) - ue_report[i]->rlc_report = rlc_reports; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS; - - } - - /* Check flag for creation of MAC CE buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { - // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id, UE_id, 0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; - // Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the - // PROTOCOL__FLEX_CE_TYPE__FLPCET_ values - // found in stats_common.pb-c.h. See - // flex_ce_type in FlexRAN specification - ue_report[i]->has_pending_mac_ces = 1; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS; - } - - /* Check flag for creation of DL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { - // TODO: Fill in the actual DL CQI report for the UE based on its configuration - Protocol__FlexDlCqiReport * dl_report; - dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); - if (dl_report == NULL) - goto error; - protocol__flex_dl_cqi_report__init(dl_report); - - dl_report->sfn_sn = flexran_get_sfn_sf(enb_id); - dl_report->has_sfn_sn = 1; - //Set the number of DL CQI reports for this UE. One for each CC - dl_report->n_csi_report = flexran_get_active_CC(enb_id, UE_id); - dl_report->n_csi_report = 1 ; - //Create the actual CSI reports. - Protocol__FlexDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); - if (csi_reports == NULL) { - free(dl_report); - goto error; - } - for (j = 0; j < dl_report->n_csi_report; j++) { - - csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); - if (csi_reports[j] == NULL) { - for (k = 0; k < j; k++) { - free(csi_reports[k]); - } - free(csi_reports); - csi_reports = NULL; - goto error; - } - protocol__flex_dl_csi__init(csi_reports[j]); - //The servCellIndex for this report - csi_reports[j]->serv_cell_index = j; - csi_reports[j]->has_serv_cell_index = 1; - //The rank indicator value for this cc - csi_reports[j]->ri = flexran_get_current_RI(enb_id, UE_id, j); - csi_reports[j]->has_ri = 1; - //TODO: the type of CSI report based on the configuration of the UE - //For now we only support type P10, which only needs a wideband value - //The full set of types can be found in stats_common.pb-c.h and - //in the FlexRAN specifications - csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; - csi_reports[j]->has_type = 1; - csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; - - if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI){ - - Protocol__FlexCsiP10 *csi10; - csi10 = malloc(sizeof(Protocol__FlexCsiP10)); - if (csi10 == NULL) { - for (k = 0; k <= j; k++) { - free(csi_reports[k]); - } - free(csi_reports); - csi_reports = NULL; - goto error; - } - protocol__flex_csi_p10__init(csi10); - //TODO: set the wideband value - // NN: this is also depends on cc_id - csi10->wb_cqi = flexran_get_ue_wcqi (enb_id, UE_id); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,UE_id)][UE_id].dl_cqi; - csi10->has_wb_cqi = 1; - //Add the type of measurements to the csi report in the proper union type - csi_reports[j]->p10csi = csi10; - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ - - - Protocol__FlexCsiP11 *csi11; - csi11 = malloc(sizeof(Protocol__FlexCsiP11)); - if (csi11 == NULL) { - for (k = 0; k <= j; k++) { - free(csi_reports[k]); - } - free(csi_reports); - csi_reports = NULL; - goto error; - } - protocol__flex_csi_p11__init(csi11); - - csi11->wb_cqi = malloc(sizeof(csi11->wb_cqi)); - csi11->n_wb_cqi = 1; - csi11->wb_cqi[0] = flexran_get_ue_wcqi (enb_id, UE_id); - // According To spec 36.213 - - if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { - // TODO PMI - csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, UE_id, 0); - csi11->has_wb_pmi = 1; - - } - - else if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 2){ - // TODO PMI - csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, UE_id, 0); - csi11->has_wb_pmi = 1; - - } - - else if (flexran_get_antenna_ports(enb_id, j) == 4 && csi_reports[j]->ri == 2){ - // TODO PMI - csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, UE_id, 0); - csi11->has_wb_pmi = 1; - - - } - - csi11->has_wb_pmi = 0; - - csi_reports[j]->p11csi = csi11; - - } - - - - - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ - - Protocol__FlexCsiP20 *csi20; - csi20 = malloc(sizeof(Protocol__FlexCsiP20)); - if (csi20 == NULL) { - for (k = 0; k <= j; k++) { - free(csi_reports[k]); - } - free(csi_reports); - csi_reports = NULL; - goto error; - } - protocol__flex_csi_p20__init(csi20); - - csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, UE_id); - csi20->has_wb_cqi = 1; - - - csi20->bandwidth_part_index = 1 ;//TODO - csi20->has_bandwidth_part_index = 1; - - csi20->sb_index = 1 ;//TODO - csi20->has_sb_index = 1 ; - - - csi_reports[j]->p20csi = csi20; - - - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ - - // Protocol__FlexCsiP21 *csi21; - // csi21 = malloc(sizeof(Protocol__FlexCsiP21)); - // if (csi21 == NULL) - // goto error; - // protocol__flex_csi_p21__init(csi21); - - // csi21->wb_cqi = flexran_get_ue_wcqi (enb_id, UE_id); - - - // csi21->wb_pmi = flexran_get_ue_pmi(enb_id); //TDO inside - // csi21->has_wb_pmi = 1; - - // csi21->sb_cqi = 1; // TODO - - // csi21->bandwidth_part_index = 1 ; //TDO inside - // csi21->has_bandwidth_part_index = 1 ; - - // csi21->sb_index = 1 ;//TODO - // csi21->has_sb_index = 1 ; - - - // csi_reports[j]->p20csi = csi21; - - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ - - - // Protocol__FlexCsiA12 *csi12; - // csi12 = malloc(sizeof(Protocol__FlexCsiA12)); - // if (csi12 == NULL) - // goto error; - // protocol__flex_csi_a12__init(csi12); - - // csi12->wb_cqi = flexran_get_ue_wcqi (enb_id, UE_id); - - // csi12->sb_pmi = 1 ; //TODO inside - - // TODO continou - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ - - // Protocol__FlexCsiA22 *csi22; - // csi22 = malloc(sizeof(Protocol__FlexCsiA22)); - // if (csi22 == NULL) - // goto error; - // protocol__flex_csi_a22__init(csi22); - - // csi22->wb_cqi = flexran_get_ue_wcqi (enb_id, UE_id); - - // csi22->sb_cqi = 1 ; //TODO inside - - // csi22->wb_pmi = flexran_get_ue_wcqi (enb_id, UE_id); - // csi22->has_wb_pmi = 1; - - // csi22->sb_pmi = 1 ; //TODO inside - // csi22->has_wb_pmi = 1; - - // csi22->sb_list = flexran_get_ue_wcqi (enb_id, UE_id); - - - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ - - // Protocol__FlexCsiA20 *csi20; - // csi20 = malloc(sizeof(Protocol__FlexCsiA20)); - // if (csi20 == NULL) - // goto error; - // protocol__flex_csi_a20__init(csi20); - - // csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, UE_id); - // csi20->has_wb_cqi = 1; - - // csi20>sb_cqi = 1 ; //TODO inside - // csi20>has_sb_cqi = 1 ; - - // csi20->sb_list = 1; // TODO inside - - - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ - - } - - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ - - } - - } - //Add the csi reports to the full DL CQI report - dl_report->csi_report = csi_reports; - //Add the DL CQI report to the stats report - ue_report[i]->dl_cqi_report = dl_report; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI; - } - - /* Check flag for creation of paging buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { - //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI - //set in the report must be a P-RNTI - Protocol__FlexPagingBufferReport *paging_report; - paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); - if (paging_report == NULL) - goto error; - protocol__flex_paging_buffer_report__init(paging_report); - //Set the number of pending paging messages - paging_report->n_paging_info = 1; - //Provide a report for each pending paging message - Protocol__FlexPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); - if (p_info == NULL){ - free(paging_report); - goto error; - } - - for (j = 0; j < paging_report->n_paging_info; j++) { - - p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); - if (p_info[j] == NULL) { - for (k = 0; k < j; k++) { - free(p_info[k]); - } - free(p_info); - p_info = NULL; - free(paging_report); - goto error; - } - protocol__flex_paging_info__init(p_info[j]); - //TODO: Set paging index. This index is the same that will be used for the scheduling of the - //paging message by the controller - p_info[j]->paging_index = 10; - p_info[j]->has_paging_index = 1; - //TODO:Set the paging message size - p_info[j]->paging_message_size = 100; - p_info[j]->has_paging_message_size = 1; - //TODO: Set the paging subframe - p_info[j]->paging_subframe = 10; - p_info[j]->has_paging_subframe = 1; - //TODO: Set the carrier index for the pending paging message - p_info[j]->carrier_index = 0; - p_info[j]->has_carrier_index = 1; - - } - //Add all paging info to the paging buffer rerport - paging_report->paging_info = p_info; - //Add the paging report to the UE report - ue_report[i]->pbr = paging_report; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS; - } - - /* Check flag for creation of UL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { - - //Fill in the full UL CQI report of the UE - Protocol__FlexUlCqiReport *full_ul_report; - full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); - if(full_ul_report == NULL) - goto error; - protocol__flex_ul_cqi_report__init(full_ul_report); - //TODO:Set the SFN and SF of the generated report - full_ul_report->sfn_sn = flexran_get_sfn_sf(enb_id); - full_ul_report->has_sfn_sn = 1; - //TODO:Set the number of UL measurement reports based on the types of measurements - //configured for this UE and on the servCellIndex - full_ul_report->n_cqi_meas = 1; - Protocol__FlexUlCqi **ul_report; - ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); - if(ul_report == NULL) { - free(full_ul_report); - goto error; - } - //Fill each UL report of the UE for each of the configured report types - for(j = 0; j < full_ul_report->n_cqi_meas; j++) { - - ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); - if(ul_report[j] == NULL) { - for (k = 0; k < j; k++) { - free(ul_report[k]); - } - free(ul_report); - free(full_ul_report); - goto error; - } - protocol__flex_ul_cqi__init(ul_report[j]); - //TODO: Set the type of the UL report. As an example set it to SRS UL report - // See enum flex_ul_cqi_type in FlexRAN specification for more details - ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; - ul_report[j]->has_type = 1; - //TODO:Set the number of SINR measurements based on the report type - //See struct flex_ul_cqi in FlexRAN specification for more details - ul_report[j]->n_sinr = 0; - uint32_t *sinr_meas; - sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); - if (sinr_meas == NULL) { - for (k = 0; k < j; k++) { - free(ul_report[k]); - } - free(ul_report); - free(full_ul_report); - goto error; - } - //TODO:Set the SINR measurements for the specified type - for (k = 0; k < ul_report[j]->n_sinr; k++) { - sinr_meas[k] = 10; - } - ul_report[j]->sinr = sinr_meas; - //TODO: Set the servCellIndex for this report - ul_report[j]->serv_cell_index = 0; - ul_report[j]->has_serv_cell_index = 1; - - //Set the list of UL reports of this UE to the full UL report - full_ul_report->cqi_meas = ul_report; - - full_ul_report->n_pucch_dbm = MAX_NUM_CCs; - full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); - - for (j = 0; j < MAX_NUM_CCs; j++) { - - full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); - protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); - full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; - full_ul_report->pucch_dbm[j]->serv_cell_index = j; - - if(flexran_get_p0_pucch_dbm(enb_id, UE_id, j) != -1){ - full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(enb_id, UE_id, j); - full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; - } - } - - - } - // Add full UL CQI report to the UE report - ue_report[i]->ul_cqi_report = full_ul_report; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI; - - } - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_STATS) { - - Protocol__FlexMacStats *macstats; - macstats = malloc(sizeof(Protocol__FlexMacStats)); - if (macstats == NULL) - goto error; - protocol__flex_mac_stats__init(macstats); - - - macstats->total_bytes_sdus_dl = flexran_get_total_size_dl_mac_sdus(mod_id, UE_id, cc_id); - macstats->has_total_bytes_sdus_dl = 1; - - macstats->total_bytes_sdus_ul = flexran_get_total_size_ul_mac_sdus(mod_id, UE_id, cc_id); - macstats->has_total_bytes_sdus_ul = 1; - - macstats->tbs_dl = flexran_get_TBS_dl(mod_id, UE_id, cc_id); - macstats->has_tbs_dl = 1; - - macstats->tbs_ul = flexran_get_TBS_ul(mod_id, UE_id, cc_id); - macstats->has_tbs_ul = 1; - - macstats->prb_retx_dl = flexran_get_num_prb_retx_dl_per_ue(mod_id, UE_id, cc_id); - macstats->has_prb_retx_dl = 1; - - macstats->prb_retx_ul = flexran_get_num_prb_retx_ul_per_ue(mod_id, UE_id, cc_id); - macstats->has_prb_retx_ul = 1; - - macstats->prb_dl = flexran_get_num_prb_dl_tx_per_ue(mod_id, UE_id, cc_id); - macstats->has_prb_dl = 1; - - macstats->prb_ul = flexran_get_num_prb_ul_rx_per_ue(mod_id, UE_id, cc_id); - macstats->has_prb_ul = 1; - - macstats->mcs1_dl = flexran_get_mcs1_dl(mod_id, UE_id, cc_id); - macstats->has_mcs1_dl = 1; - - macstats->mcs2_dl = flexran_get_mcs2_dl(mod_id, UE_id, cc_id); - macstats->has_mcs2_dl = 1; - - macstats->mcs1_ul = flexran_get_mcs1_ul(mod_id, UE_id, cc_id); - macstats->has_mcs1_ul = 1; - - macstats->mcs2_ul = flexran_get_mcs2_ul(mod_id, UE_id, cc_id); - macstats->has_mcs2_ul = 1; - - macstats->total_prb_dl = flexran_get_total_prb_dl_tx_per_ue(mod_id, UE_id, cc_id); - macstats->has_total_prb_dl = 1; - - macstats->total_prb_ul = flexran_get_total_prb_ul_rx_per_ue(mod_id, UE_id, cc_id); - macstats->has_total_prb_ul = 1; - - macstats->total_pdu_dl = flexran_get_total_num_pdu_dl(mod_id, UE_id, cc_id); - macstats->has_total_pdu_dl = 1; - - macstats->total_pdu_ul = flexran_get_total_num_pdu_ul(mod_id, UE_id, cc_id); - macstats->has_total_pdu_ul = 1; - - macstats->total_tbs_dl = flexran_get_total_TBS_dl(mod_id, UE_id, cc_id); - macstats->has_total_tbs_dl = 1; - - macstats->total_tbs_ul = flexran_get_total_TBS_ul(mod_id, UE_id, cc_id); - macstats->has_total_tbs_ul = 1; - - macstats->harq_round = flexran_get_harq_round(mod_id, cc_id, UE_id); - macstats->has_harq_round = 1; - - Protocol__FlexMacSdusDl ** mac_sdus; - mac_sdus = malloc(sizeof(Protocol__FlexMacSdusDl) * flexran_get_num_mac_sdu_tx(mod_id, UE_id, cc_id)); - if (mac_sdus == NULL) { - free(macstats); - goto error; - } - - macstats->n_mac_sdus_dl = flexran_get_num_mac_sdu_tx(mod_id, UE_id, cc_id); - - for (j = 0; j < macstats->n_mac_sdus_dl; j++){ - - - mac_sdus[j] = malloc(sizeof(Protocol__FlexMacSdusDl)); - protocol__flex_mac_sdus_dl__init(mac_sdus[j]); - - mac_sdus[j]->lcid = flexran_get_mac_sdu_lcid_index(mod_id, UE_id, cc_id, j); - mac_sdus[j]->has_lcid = 1; - - mac_sdus[j]->sdu_length = flexran_get_mac_sdu_size(mod_id, UE_id, cc_id, mac_sdus[j]->lcid); - mac_sdus[j]->has_sdu_length = 1; - - - } - - - macstats->mac_sdus_dl = mac_sdus; - - - ue_report[i]->mac_stats = macstats; - ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_STATS; - } - - - - - } - - - - - } - - /* Allocate memory for list of cell reports */ - if (report_config->nr_cc > 0) { - - - // Fill in the Cell reports - for (i = 0; i < report_config->nr_cc; i++) { - - - /* Check flag for creation of noise and interference report */ - if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { - // TODO: Fill in the actual noise and interference report for this cell - Protocol__FlexNoiseInterferenceReport *ni_report; - ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); - if(ni_report == NULL) - goto error; - protocol__flex_noise_interference_report__init(ni_report); - // Current frame and subframe number - ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); - ni_report->has_sfn_sf = 1; - //TODO:Received interference power in dbm - ni_report->rip = 0; - ni_report->has_rip = 1; - //TODO:Thermal noise power in dbm - ni_report->tnp = 0; - ni_report->has_tnp = 1; - - ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); - ni_report->has_p0_nominal_pucch = 1; - cell_report[i]->noise_inter_report = ni_report; - cell_report[i]->flags |= PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE; - } +int flexran_agent_mac_stats_reply_ue(mid_t mod_id, + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags) { + const int cc_id = 0; // TODO: make for multiple CCs + + for (int i = 0; i < n_ue; i++) { + const rnti_t rnti = ue_report[i]->rnti; + const int UE_id = flexran_get_mac_ue_id_rnti(mod_id, rnti); + + /* buffer status report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { + ue_report[i]->n_bsr = 4; //TODO should be automated + uint32_t *elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); + if (elem == NULL) + goto error; + for (int j = 0; j < ue_report[i]->n_bsr; j++) { + elem[j] = flexran_get_ue_bsr_ul_buffer_info (mod_id, i, j); + } + ue_report[i]->bsr = elem; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR; + } + + /* power headroom report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { + ue_report[i]->phr = flexran_get_ue_phr (mod_id, UE_id); + ue_report[i]->has_phr = 1; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR; + } + + /* Check flag for creation of RLC buffer status report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { + ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs + Protocol__FlexRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); + if (rlc_reports == NULL) + goto error; + + for (int j = 0; j < ue_report[i]->n_rlc_report; j++) { + rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); + if (rlc_reports[j] == NULL) { + for (int k = 0; k < j; k++) { + free(rlc_reports[k]); + } + free(rlc_reports); + goto error; + } + protocol__flex_rlc_bsr__init(rlc_reports[j]); + rlc_reports[j]->lc_id = j+1; + rlc_reports[j]->has_lc_id = 1; + rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(mod_id, UE_id, j + 1); + rlc_reports[j]->has_tx_queue_size = 1; + + rlc_reports[j]->tx_queue_hol_delay = flexran_get_hol_delay(mod_id, UE_id, j + 1); + rlc_reports[j]->has_tx_queue_hol_delay = 1; + //TODO:Set retransmission queue size in bytes + rlc_reports[j]->retransmission_queue_size = 10; + rlc_reports[j]->has_retransmission_queue_size = 0; + //TODO:Set retransmission queue head of line delay in ms + rlc_reports[j]->retransmission_queue_hol_delay = 100; + rlc_reports[j]->has_retransmission_queue_hol_delay = 0; + rlc_reports[j]->status_pdu_size = flexran_get_num_pdus_buffer(mod_id, UE_id, j + 1); + rlc_reports[j]->has_status_pdu_size = 1; + + } + if (ue_report[i]->n_rlc_report > 0) + ue_report[i]->rlc_report = rlc_reports; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS; + } + + /* MAC CE buffer status report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { + // TODO: Fill in the actual MAC CE buffer status report + ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(mod_id, UE_id, 0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; + // Use as bitmap. Set one or more of the; + // PROTOCOL__FLEX_CE_TYPE__FLPCET_ values + // found in stats_common.pb-c.h. See + // flex_ce_type in FlexRAN specification + ue_report[i]->has_pending_mac_ces = 1; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS; + } + + /* DL CQI report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { + // TODO: Fill in the actual DL CQI report for the UE based on its configuration + Protocol__FlexDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); + if (dl_report == NULL) + goto error; + protocol__flex_dl_cqi_report__init(dl_report); + + dl_report->sfn_sn = flexran_get_sfn_sf(mod_id); + dl_report->has_sfn_sn = 1; + dl_report->n_csi_report = flexran_get_active_CC(mod_id, UE_id); + dl_report->n_csi_report = 1 ; + //Create the actual CSI reports. + Protocol__FlexDlCsi **csi_reports; + csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); + if (csi_reports == NULL) { + free(dl_report); + goto error; + } + for (int j = 0; j < dl_report->n_csi_report; j++) { + csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); + if (csi_reports[j] == NULL) { + for (int k = 0; k < j; k++) { + free(csi_reports[k]); + } + free(csi_reports); + csi_reports = NULL; + goto error; + } + protocol__flex_dl_csi__init(csi_reports[j]); + csi_reports[j]->serv_cell_index = j; + csi_reports[j]->has_serv_cell_index = 1; + csi_reports[j]->ri = flexran_get_current_RI(mod_id, UE_id, j); + csi_reports[j]->has_ri = 1; + //TODO: the type of CSI report based on the configuration of the UE + //For now we only support type P10, which only needs a wideband value + csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; + csi_reports[j]->has_type = 1; + csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; + + if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI) { + Protocol__FlexCsiP10 *csi10; + csi10 = malloc(sizeof(Protocol__FlexCsiP10)); + if (csi10 == NULL) { + for (int k = 0; k <= j; k++) { + free(csi_reports[k]); } + free(csi_reports); + csi_reports = NULL; + goto error; + } + protocol__flex_csi_p10__init(csi10); + csi10->wb_cqi = flexran_get_ue_wcqi(mod_id, UE_id); + csi10->has_wb_cqi = 1; + csi_reports[j]->p10csi = csi10; + } + + /* + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI) { + Protocol__FlexCsiP11 *csi11; + csi11 = malloc(sizeof(Protocol__FlexCsiP11)); + if (csi11 == NULL) { + for (int k = 0; k <= j; k++) { + free(csi_reports[k]); + } + free(csi_reports); + csi_reports = NULL; + goto error; + } + protocol__flex_csi_p11__init(csi11); + + csi11->wb_cqi = malloc(sizeof(csi11->wb_cqi)); + csi11->n_wb_cqi = 1; + csi11->wb_cqi[0] = flexran_get_ue_wcqi (mod_id, UE_id); + // According To spec 36.213 + + if (flexran_get_antenna_ports(mod_id, j) == 2 && csi_reports[j]->ri == 1) { + // TODO PMI + csi11->wb_pmi = flexran_get_ue_wpmi(mod_id, UE_id, 0); + csi11->has_wb_pmi = 1; + + } + + else if (flexran_get_antenna_ports(mod_id, j) == 2 && csi_reports[j]->ri == 2) { + // TODO PMI + csi11->wb_pmi = flexran_get_ue_wpmi(mod_id, UE_id, 0); + csi11->has_wb_pmi = 1; + + } + + else if (flexran_get_antenna_ports(mod_id, j) == 4 && csi_reports[j]->ri == 2) { + // TODO PMI + csi11->wb_pmi = flexran_get_ue_wpmi(mod_id, UE_id, 0); + csi11->has_wb_pmi = 1; + } + + csi11->has_wb_pmi = 0; + csi_reports[j]->p11csi = csi11; + } + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI) { + + Protocol__FlexCsiP20 *csi20; + csi20 = malloc(sizeof(Protocol__FlexCsiP20)); + if (csi20 == NULL) { + for (int k = 0; k <= j; k++) { + free(csi_reports[k]); + } + free(csi_reports); + csi_reports = NULL; + goto error; + } + protocol__flex_csi_p20__init(csi20); + + csi20->wb_cqi = flexran_get_ue_wcqi (mod_id, UE_id); + csi20->has_wb_cqi = 1; + csi20->bandwidth_part_index = 1 ; //TODO + csi20->has_bandwidth_part_index = 0; + csi20->sb_index = 1; //TODO + csi20->has_sb_index = 1; + csi_reports[j]->p20csi = csi20; + } + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI) { + + // Protocol__FlexCsiP21 *csi21; + // csi21 = malloc(sizeof(Protocol__FlexCsiP21)); + // if (csi21 == NULL) + // goto error; + // protocol__flex_csi_p21__init(csi21); + + // csi21->wb_cqi = flexran_get_ue_wcqi (mod_id, UE_id); + + + // csi21->wb_pmi = flexran_get_ue_pmi(mod_id); //TDO inside + // csi21->has_wb_pmi = 1; + + // csi21->sb_cqi = 1; // TODO + + // csi21->bandwidth_part_index = 1 ; //TDO inside + // csi21->has_bandwidth_part_index = 1 ; + + // csi21->sb_index = 1 ;//TODO + // csi21->has_sb_index = 1 ; + + + // csi_reports[j]->p20csi = csi21; + + } + + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI) { + + + // Protocol__FlexCsiA12 *csi12; + // csi12 = malloc(sizeof(Protocol__FlexCsiA12)); + // if (csi12 == NULL) + // goto error; + // protocol__flex_csi_a12__init(csi12); + + // csi12->wb_cqi = flexran_get_ue_wcqi (mod_id, UE_id); + + // csi12->sb_pmi = 1 ; //TODO inside + + // TODO continou + } + + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI) { + + // Protocol__FlexCsiA22 *csi22; + // csi22 = malloc(sizeof(Protocol__FlexCsiA22)); + // if (csi22 == NULL) + // goto error; + // protocol__flex_csi_a22__init(csi22); + + // csi22->wb_cqi = flexran_get_ue_wcqi (mod_id, UE_id); + + // csi22->sb_cqi = 1 ; //TODO inside + + // csi22->wb_pmi = flexran_get_ue_wcqi (mod_id, UE_id); + // csi22->has_wb_pmi = 1; + + // csi22->sb_pmi = 1 ; //TODO inside + // csi22->has_wb_pmi = 1; + + // csi22->sb_list = flexran_get_ue_wcqi (mod_id, UE_id); + + + } + + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI) { + + // Protocol__FlexCsiA20 *csi20; + // csi20 = malloc(sizeof(Protocol__FlexCsiA20)); + // if (csi20 == NULL) + // goto error; + // protocol__flex_csi_a20__init(csi20); + + // csi20->wb_cqi = flexran_get_ue_wcqi (mod_id, UE_id); + // csi20->has_wb_cqi = 1; + + // csi20>sb_cqi = 1 ; //TODO inside + // csi20>has_sb_cqi = 1 ; + + // csi20->sb_list = 1; // TODO inside + + + } + + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI) { + + } + + else if (csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI) { + + } + */ + + } + dl_report->csi_report = csi_reports; + ue_report[i]->dl_cqi_report = dl_report; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI; + } + + /* paging buffer status report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { + //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI + //set in the report must be a P-RNTI + Protocol__FlexPagingBufferReport *paging_report; + paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); + if (paging_report == NULL) + goto error; + protocol__flex_paging_buffer_report__init(paging_report); + paging_report->n_paging_info = 1; + Protocol__FlexPagingInfo **p_info; + p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); + if (p_info == NULL) { + free(paging_report); + goto error; + } + + for (int j = 0; j < paging_report->n_paging_info; j++) { + + p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); + if (p_info[j] == NULL) { + for (int k = 0; k < j; k++) { + free(p_info[k]); + } + free(p_info); + p_info = NULL; + free(paging_report); + goto error; + } + protocol__flex_paging_info__init(p_info[j]); + //TODO: Set paging index. This index is the same that will be used for the scheduling of the + //paging message by the controller + p_info[j]->paging_index = 10; + p_info[j]->has_paging_index = 0; + //TODO:Set the paging message size + p_info[j]->paging_message_size = 100; + p_info[j]->has_paging_message_size = 0; + //TODO: Set the paging subframe + p_info[j]->paging_subframe = 10; + p_info[j]->has_paging_subframe = 0; + //TODO: Set the carrier index for the pending paging message + p_info[j]->carrier_index = 0; + p_info[j]->has_carrier_index = 0; + + } + //Add all paging info to the paging buffer rerport + paging_report->paging_info = p_info; + //Add the paging report to the UE report + ue_report[i]->pbr = paging_report; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS; + } + + /* Check flag for creation of UL CQI report */ + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { + + //Fill in the full UL CQI report of the UE + Protocol__FlexUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); + if (full_ul_report == NULL) + goto error; + protocol__flex_ul_cqi_report__init(full_ul_report); + full_ul_report->sfn_sn = flexran_get_sfn_sf(mod_id); + full_ul_report->has_sfn_sn = 1; + //TODO:Set the number of UL measurement reports based on the types of measurements + //configured for this UE and on the servCellIndex + full_ul_report->n_cqi_meas = 1; + Protocol__FlexUlCqi **ul_report; + ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); + if (ul_report == NULL) { + free(full_ul_report); + goto error; + } + //Fill each UL report of the UE for each of the configured report types + for (int j = 0; j < full_ul_report->n_cqi_meas; j++) { + + ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); + if (ul_report[j] == NULL) { + for (int k = 0; k < j; k++) { + free(ul_report[k]); + } + free(ul_report); + free(full_ul_report); + goto error; + } + protocol__flex_ul_cqi__init(ul_report[j]); + //TODO: Set the type of the UL report. As an example set it to SRS UL report + ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; + ul_report[j]->has_type = 1; + //TODO:Set the number of SINR measurements based on the report type + ul_report[j]->n_sinr = 0; + uint32_t *sinr_meas; + sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); + if (sinr_meas == NULL) { + for (int k = 0; k < j; k++) { + free(ul_report[k]); + } + free(ul_report); + free(full_ul_report); + goto error; + } + //TODO:Set the SINR measurements for the specified type + for (int k = 0; k < ul_report[j]->n_sinr; k++) { + sinr_meas[k] = 10; + } + ul_report[j]->sinr = sinr_meas; + //TODO: Set the servCellIndex for this report + ul_report[j]->serv_cell_index = 0; + ul_report[j]->has_serv_cell_index = 1; + + //Set the list of UL reports of this UE to the full UL report + full_ul_report->cqi_meas = ul_report; + + full_ul_report->n_pucch_dbm = MAX_NUM_CCs; + full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); + + for (int j = 0; j < MAX_NUM_CCs; j++) { + + full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); + protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); + full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; + full_ul_report->pucch_dbm[j]->serv_cell_index = j; + + if (flexran_get_p0_pucch_dbm(mod_id, UE_id, j) != -1) { + full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(mod_id, UE_id, j); + full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; + } + } + + + } + // Add full UL CQI report to the UE report + ue_report[i]->ul_cqi_report = full_ul_report; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI; + + } + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_STATS) { + + Protocol__FlexMacStats *macstats; + macstats = malloc(sizeof(Protocol__FlexMacStats)); + if (macstats == NULL) + goto error; + protocol__flex_mac_stats__init(macstats); + macstats->total_bytes_sdus_dl = flexran_get_total_size_dl_mac_sdus(mod_id, UE_id, cc_id); + macstats->has_total_bytes_sdus_dl = 1; + macstats->total_bytes_sdus_ul = flexran_get_total_size_ul_mac_sdus(mod_id, UE_id, cc_id); + macstats->has_total_bytes_sdus_ul = 1; + macstats->tbs_dl = flexran_get_TBS_dl(mod_id, UE_id, cc_id); + macstats->has_tbs_dl = 1; + macstats->tbs_ul = flexran_get_TBS_ul(mod_id, UE_id, cc_id); + macstats->has_tbs_ul = 1; + macstats->prb_retx_dl = flexran_get_num_prb_retx_dl_per_ue(mod_id, UE_id, cc_id); + macstats->has_prb_retx_dl = 1; + macstats->prb_retx_ul = flexran_get_num_prb_retx_ul_per_ue(mod_id, UE_id, cc_id); + macstats->has_prb_retx_ul = 1; + macstats->prb_dl = flexran_get_num_prb_dl_tx_per_ue(mod_id, UE_id, cc_id); + macstats->has_prb_dl = 1; + macstats->prb_ul = flexran_get_num_prb_ul_rx_per_ue(mod_id, UE_id, cc_id); + macstats->has_prb_ul = 1; + macstats->mcs1_dl = flexran_get_mcs1_dl(mod_id, UE_id, cc_id); + macstats->has_mcs1_dl = 1; + macstats->mcs2_dl = flexran_get_mcs2_dl(mod_id, UE_id, cc_id); + macstats->has_mcs2_dl = 1; + macstats->mcs1_ul = flexran_get_mcs1_ul(mod_id, UE_id, cc_id); + macstats->has_mcs1_ul = 1; + macstats->mcs2_ul = flexran_get_mcs2_ul(mod_id, UE_id, cc_id); + macstats->has_mcs2_ul = 1; + macstats->total_prb_dl = flexran_get_total_prb_dl_tx_per_ue(mod_id, UE_id, cc_id); + macstats->has_total_prb_dl = 1; + macstats->total_prb_ul = flexran_get_total_prb_ul_rx_per_ue(mod_id, UE_id, cc_id); + macstats->has_total_prb_ul = 1; + macstats->total_pdu_dl = flexran_get_total_num_pdu_dl(mod_id, UE_id, cc_id); + macstats->has_total_pdu_dl = 1; + macstats->total_pdu_ul = flexran_get_total_num_pdu_ul(mod_id, UE_id, cc_id); + macstats->has_total_pdu_ul = 1; + macstats->total_tbs_dl = flexran_get_total_TBS_dl(mod_id, UE_id, cc_id); + macstats->has_total_tbs_dl = 1; + macstats->total_tbs_ul = flexran_get_total_TBS_ul(mod_id, UE_id, cc_id); + macstats->has_total_tbs_ul = 1; + macstats->harq_round = flexran_get_harq_round(mod_id, cc_id, UE_id); + macstats->has_harq_round = 1; + + Protocol__FlexMacSdusDl ** mac_sdus; + mac_sdus = malloc(sizeof(Protocol__FlexMacSdusDl) * flexran_get_num_mac_sdu_tx(mod_id, UE_id, cc_id)); + if (mac_sdus == NULL) { + free(macstats); + goto error; + } + + macstats->n_mac_sdus_dl = flexran_get_num_mac_sdu_tx(mod_id, UE_id, cc_id); + for (int j = 0; j < macstats->n_mac_sdus_dl; j++) { + mac_sdus[j] = malloc(sizeof(Protocol__FlexMacSdusDl)); + protocol__flex_mac_sdus_dl__init(mac_sdus[j]); + mac_sdus[j]->lcid = flexran_get_mac_sdu_lcid_index(mod_id, UE_id, cc_id, j); + mac_sdus[j]->has_lcid = 1; + mac_sdus[j]->sdu_length = flexran_get_mac_sdu_size(mod_id, UE_id, cc_id, mac_sdus[j]->lcid); + mac_sdus[j]->has_sdu_length = 1; + } + macstats->mac_sdus_dl = mac_sdus; + ue_report[i]->mac_stats = macstats; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_STATS; + } } - return 0; - error: - - if (cell_report != NULL) { - if (report_config->nr_cc > 0) { - for (i = 0; i < report_config->nr_cc; i++) { - if (cell_report[i]->noise_inter_report != NULL) { - free(cell_report[i]->noise_inter_report); - cell_report[i]->noise_inter_report = NULL; - } - } - } - free(cell_report); - cell_report = NULL; - } - +error: if (ue_report != NULL) { - if (report_config->nr_ue > 0) { - for (i = 0; i < report_config->nr_ue; i++) { + if (n_ue > 0) { + for (int i = 0; i < n_ue; i++) { if (ue_report[i]->bsr != NULL) { free(ue_report[i]->bsr); ue_report[i]->bsr = NULL; } if (ue_report[i]->rlc_report != NULL) { - for (j = 0; j < ue_report[i]->n_rlc_report; j++) { + for (int j = 0; j < ue_report[i]->n_rlc_report; j++) { if (ue_report[i]->rlc_report[j] != NULL) { free(ue_report[i]->rlc_report[j]); ue_report[i]->rlc_report[j] = NULL; @@ -741,7 +594,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } if (ue_report[i]->dl_cqi_report != NULL) { if (ue_report[i]->dl_cqi_report->csi_report != NULL) { - for (j = 0; j < ue_report[i]->dl_cqi_report->n_csi_report; j++) { + for (int j = 0; j < ue_report[i]->dl_cqi_report->n_csi_report; j++) { if (ue_report[i]->dl_cqi_report->csi_report[j] != NULL) { if (ue_report[i]->dl_cqi_report->csi_report[j]->p10csi != NULL) { free(ue_report[i]->dl_cqi_report->csi_report[j]->p10csi); @@ -771,7 +624,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } if (ue_report[i]->pbr != NULL) { if (ue_report[i]->pbr->paging_info != NULL) { - for (j = 0; j < ue_report[i]->pbr->n_paging_info; j++) { + for (int j = 0; j < ue_report[i]->pbr->n_paging_info; j++) { free(ue_report[i]->pbr->paging_info[j]); ue_report[i]->pbr->paging_info[j] = NULL; } @@ -783,7 +636,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } if (ue_report[i]->ul_cqi_report != NULL) { if (ue_report[i]->ul_cqi_report->cqi_meas != NULL) { - for (j = 0; j < ue_report[i]->ul_cqi_report->n_cqi_meas; j++) { + for (int j = 0; j < ue_report[i]->ul_cqi_report->n_cqi_meas; j++) { if (ue_report[i]->ul_cqi_report->cqi_meas[j] != NULL) { if (ue_report[i]->ul_cqi_report->cqi_meas[j]->sinr != NULL) { free(ue_report[i]->ul_cqi_report->cqi_meas[j]->sinr); @@ -797,7 +650,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, ue_report[i]->ul_cqi_report->cqi_meas = NULL; } if (ue_report[i]->ul_cqi_report->pucch_dbm != NULL) { - for (j = 0; j < MAX_NUM_CCs; j++) { + for (int j = 0; j < MAX_NUM_CCs; j++) { if (ue_report[i]->ul_cqi_report->pucch_dbm[j] != NULL) { free(ue_report[i]->ul_cqi_report->pucch_dbm[j]); ue_report[i]->ul_cqi_report->pucch_dbm[j] = NULL; @@ -811,7 +664,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } if (ue_report[i]->mac_stats != NULL) { if (ue_report[i]->mac_stats->mac_sdus_dl != NULL) { - for (j = 0; j < ue_report[i]->mac_stats->n_mac_sdus_dl; j++) { + for (int j = 0; j < ue_report[i]->mac_stats->n_mac_sdus_dl; j++) { if (ue_report[i]->mac_stats->mac_sdus_dl[j] != NULL) { free(ue_report[i]->mac_stats->mac_sdus_dl[j]); ue_report[i]->mac_stats->mac_sdus_dl[j] = NULL; @@ -827,10 +680,36 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } free(ue_report); } - return -1; } +int flexran_agent_mac_stats_reply_cell(mid_t mod_id, + Protocol__FlexCellStatsReport **cell_report, + int n_cc, + uint32_t cc_flags) { + for (int i = 0; i < n_cc; i++) { + /* noise and interference report */ + if(cc_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { + // TODO: Fill in the actual noise and interference report for this cell + Protocol__FlexNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); + AssertFatal(ni_report, "cannot malloc() ni_report\n"); + protocol__flex_noise_interference_report__init(ni_report); + ni_report->sfn_sf = flexran_get_sfn_sf(mod_id); + ni_report->has_sfn_sf = 1; + ni_report->rip = 0; //TODO: Received interference power in dbm + ni_report->has_rip = 0; + ni_report->tnp = 0; //TODO: Thermal noise power in dbm + ni_report->has_tnp = 0; + ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(mod_id, 0); + ni_report->has_p0_nominal_pucch = 1; + cell_report[i]->noise_inter_report = ni_report; + cell_report[i]->flags |= PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE; + } + } + return 0; +} + int flexran_agent_mac_destroy_stats_reply(Protocol__FlexStatsReply *reply) { int i, j, k; @@ -1561,11 +1440,10 @@ int flexran_agent_register_mac_xface(mid_t mod_id) return -1; } - //xface->agent_ctxt = &shared_ctxt[mod_id]; xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; - //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; + xface->flexran_agent_notify_tick = flexran_agent_timer_signal; xface->dl_scheduler_loaded_lib = NULL; xface->ul_scheduler_loaded_lib = NULL; @@ -1688,11 +1566,10 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id) return -1; } AGENT_MAC_xface *xface = agent_mac_xface[mod_id]; - //xface->agent_ctxt = NULL; xface->flexran_agent_send_sr_info = NULL; xface->flexran_agent_send_sf_trigger = NULL; - //xface->flexran_agent_send_update_mac_stats = NULL; xface->flexran_agent_get_pending_dl_mac_config = NULL; + xface->flexran_agent_notify_tick = NULL; xface->dl_scheduler_loaded_lib = NULL; xface->ul_scheduler_loaded_lib = NULL; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h index 8ca855a6b3..2f9f99c740 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h @@ -51,8 +51,15 @@ int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg); -/* Statistics reply protocol message constructor and destructor */ -int flexran_agent_mac_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report); +/* Statistics reply protocol message constructors (for UE and cell stats) and destructor */ +int flexran_agent_mac_stats_reply_ue(mid_t mod_id, + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags); +int flexran_agent_mac_stats_reply_cell(mid_t mod_id, + Protocol__FlexCellStatsReport **cell_report, + int n_cc, + uint32_t cc_flags); int flexran_agent_mac_destroy_stats_reply(Protocol__FlexStatsReply *reply); /* DL MAC scheduling decision protocol message constructor (empty command) and destructor */ diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 5c1fc1379c..dfde583387 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -54,10 +54,9 @@ typedef struct { void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id, Protocol__FlexranMessage **msg); - /// Notify the controller for a state change of a particular UE, by sending the proper - /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) - // int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, - // uint8_t state_change); + /// Notify the controller of another (RU) tick, i.e. new subframe. Used to + /// synchronize the eNB and the agent. + void (*flexran_agent_notify_tick)(mid_t mod_id); void *dl_scheduler_loaded_lib; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h index 01fc51f6a6..957fe6065e 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h @@ -61,12 +61,6 @@ err_code_t flexran_agent_init_cont_mac_stats_update(mid_t mod_id); err_code_t flexran_agent_destroy_cont_mac_stats_update(mid_t mod_id); -/*Enable/Disable the continuous stats update service for the MAC*/ -err_code_t flexran_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid, - stats_request_config_t *stats_req); - -err_code_t flexran_agent_disable_cont_mac_stats_update(mid_t mod_id); - Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_report, Protocol__FlexranMessage *old_report); diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c index 293ebab7a8..67da5fa452 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c @@ -65,25 +65,17 @@ void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id, int flexran_agent_pdcp_stats_reply(mid_t mod_id, - const report_config_t *report_config, - Protocol__FlexUeStatsReport **ue_report, - Protocol__FlexCellStatsReport **cell_report) { - - - // Protocol__FlexHeader *header; - int i; - // int cc_id = 0; - - - /* Allocate memory for list of UE reports */ - if (report_config->nr_ue > 0) { + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags) { + if (n_ue > 0) { - for (i = 0; i < report_config->nr_ue; i++) { - const rnti_t rnti = report_config->ue_report_type[i].ue_rnti; + for (int i = 0; i < n_ue; i++) { + const rnti_t rnti = ue_report[i]->rnti; const uint16_t uid = flexran_get_pdcp_uid_from_rnti(mod_id, rnti); /* Check flag for creation of buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PDCP_STATS) { + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PDCP_STATS) { Protocol__FlexPdcpStats *pdcp_aggr_stats; pdcp_aggr_stats = malloc(sizeof(Protocol__FlexPdcpStats)); @@ -129,12 +121,6 @@ int flexran_agent_pdcp_stats_reply(mid_t mod_id, error: LOG_W(FLEXRAN_AGENT, "Can't allocate PDCP stats\n"); - - /* if (cell_report != NULL) - free(cell_report); - if (ue_report != NULL) - free(ue_report); - */ return -1; } diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h index 246f9709b5..11decf0298 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h @@ -48,9 +48,9 @@ /* Send to the controller all the pdcp stat updates that occured during this subframe*/ int flexran_agent_pdcp_stats_reply(mid_t mod_id, - const report_config_t *report_config, - Protocol__FlexUeStatsReport **ue_report, - Protocol__FlexCellStatsReport **cell_report); + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags); int flexran_agent_pdcp_destroy_stats_reply(Protocol__FlexStatsReply *reply); /* Get the stats from RAN API and aggregate them per USER*/ diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index 6299e101a4..92c9917622 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -380,18 +380,15 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t* measRes int flexran_agent_rrc_stats_reply(mid_t mod_id, - const report_config_t *report_config, - Protocol__FlexUeStatsReport **ue_report, - Protocol__FlexCellStatsReport **cell_report) { - - if (report_config->nr_ue > 0) { - rnti_t rntis[report_config->nr_ue]; - flexran_get_rrc_rnti_list(mod_id, rntis, report_config->nr_ue); - for (int i = 0; i < report_config->nr_ue; i++) { - const rnti_t rnti = rntis[i]; + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags) { + if (n_ue > 0) { + for (int i = 0; i < n_ue; i++) { + const rnti_t rnti = ue_report[i]->rnti; /* Check flag for creation of buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) { + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) { /*Source cell EUTRA Measurements*/ Protocol__FlexRrcMeasurements *rrc_measurements; @@ -531,7 +528,7 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, } return 0; error: - for (int i = 0; i < report_config->nr_ue; i++) { + for (int i = 0; i < n_ue; i++) { if (ue_report[i]->rrc_measurements && ue_report[i]->rrc_measurements->neigh_meas != NULL) { for (int j = 0; j < ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++) { free(ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]); @@ -540,8 +537,6 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, } } - if (cell_report != NULL) - free(cell_report); if (ue_report != NULL) free(ue_report); return -1; @@ -575,20 +570,18 @@ int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply) } int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, - const report_config_t *report_config, - Protocol__FlexUeStatsReport **ue_report, - Protocol__FlexCellStatsReport **cell_report) { + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags) { /* This function fills the GTP part of the statistics. The necessary * information is, for our purposes, completely maintained in the RRC layer. * It would be possible to add a GTP module that handles this, though. */ - if (report_config->nr_ue > 0) { - rnti_t rntis[report_config->nr_ue]; - flexran_get_rrc_rnti_list(mod_id, rntis, report_config->nr_ue); - for (int i = 0; i < report_config->nr_ue; i++) { - const rnti_t rnti = rntis[i]; + if (n_ue > 0) { + for (int i = 0; i < n_ue; i++) { + const rnti_t rnti = ue_report[i]->rnti; /* Check flag for creation of buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) { + if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) { /* get number of rabs for this UE */ const int num_e_rab = flexran_agent_rrc_gtp_num_e_rab(mod_id, rnti); @@ -618,7 +611,7 @@ int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, } return 0; error: - for (int i = 0; i < report_config->nr_ue; i++) { + for (int i = 0; i < n_ue; i++) { if (!ue_report[i]->gtp_stats) continue; for (int r = 0; r < ue_report[i]->n_gtp_stats; ++r) { if (ue_report[i]->gtp_stats[r]) { diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h index fdf00ff841..1aa110a3e9 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h @@ -57,12 +57,18 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t *); /* Statistics reply protocol message constructor and destructor */ -int flexran_agent_rrc_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report); +int flexran_agent_rrc_stats_reply(mid_t mod_id, + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags); int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply); /* Statistic reply for GTP statistics which OAI stores also in the RRC layer. * This might be moved to a separate GTP module in the future */ -int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report); +int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags); int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply); /* Fill the RRC part of a ue_config message */ diff --git a/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.c b/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.c new file mode 100644 index 0000000000..04a47406e1 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.c @@ -0,0 +1,161 @@ +/* + * 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 flexran_agent_s1ap.c + * \brief FlexRAN agent Control Module S1AP + * \author Navid Nikaein + * \date 2019 + * \version 0.1 + */ + +#include "flexran_agent_s1ap.h" + + +/*Array containing the Agent-S1AP interfaces*/ +AGENT_S1AP_xface *agent_s1ap_xface[NUM_MAX_ENB]; + +void flexran_agent_fill_s1ap_cell_config(mid_t mod_id, + Protocol__FlexS1apConfig **s1ap_config) { + *s1ap_config = malloc(sizeof(Protocol__FlexS1apConfig)); + if (!*s1ap_config) return; + protocol__flex_s1ap_config__init(*s1ap_config); + LOG_D(FLEXRAN_AGENT, "flexran_agent_fill_s1ap_cell_config %d\n", mod_id); + + // S1AP status + (*s1ap_config)->has_pending = 1; + (*s1ap_config)->pending = flexran_get_s1ap_mme_pending(mod_id); + + (*s1ap_config)->has_connected = 1; + (*s1ap_config)->connected = flexran_get_s1ap_mme_connected(mod_id); + + (*s1ap_config)->enb_s1_ip = flexran_get_s1ap_enb_s1_ip(mod_id); + if (!(*s1ap_config)->enb_s1_ip) + (*s1ap_config)->enb_s1_ip = ""; + + (*s1ap_config)->enb_name = flexran_get_s1ap_enb_name(mod_id); + + (*s1ap_config)->mme = NULL; + (*s1ap_config)->n_mme = flexran_get_s1ap_nb_mme(mod_id); + if ((*s1ap_config)->n_mme > 0) { + Protocol__FlexS1apMme **mme_conf = calloc((*s1ap_config)->n_mme, + sizeof(Protocol__FlexS1apMme *)); + AssertFatal(mme_conf, "%s(): MME malloc failed\n", __func__); + for(int i = 0; i < (*s1ap_config)->n_mme; i++){ + mme_conf[i] = malloc(sizeof(Protocol__FlexS1apMme)); + AssertFatal(mme_conf[i], "%s(): MME malloc failed\n", __func__); + protocol__flex_s1ap_mme__init(mme_conf[i]); + if (flexran_get_s1ap_mme_conf(mod_id, i, mme_conf[i]) < 0) { + LOG_E(FLEXRAN_AGENT, + "error in flexran_get_s1ap_mme_conf(): cannot retrieve MME state\n"); + (*s1ap_config)->n_mme = 0; + break; + } + } + (*s1ap_config)->mme = mme_conf; + } +} + +int flexran_agent_s1ap_stats_reply(mid_t mod_id, + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags) { + if (n_ue <= 0) + return 0; + if (!(ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_S1AP_STATS)) + return 0; + + for (int i = 0; i < n_ue; i++) { + const rnti_t rnti = ue_report[i]->rnti; + Protocol__FlexS1apUe *ue = malloc(sizeof(Protocol__FlexS1apUe)); + AssertFatal(ue, "%s(): MME malloc failed\n", __func__); + protocol__flex_s1ap_ue__init(ue); + if (flexran_get_s1ap_ue(mod_id, rnti, ue) < 0) { + LOG_E(FLEXRAN_AGENT, "error in %s(): cannot retrieve UE conf\n", __func__); + break; + } + ue_report[i]->s1ap_stats = ue; + ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_S1AP_STATS; + } + return 0; +} + +void flexran_agent_free_s1ap_cell_config(Protocol__FlexS1apConfig **s1ap) { + for (int i = 0; i < (*s1ap)->n_mme; i++) { + /* following structures allocated in the RAN API */ + for(int j = 0; j < (*s1ap)->mme[i]->n_served_gummeis; j++) { + free((*s1ap)->mme[i]->served_gummeis[j]->plmn); + free((*s1ap)->mme[i]->served_gummeis[j]); + } + free((*s1ap)->mme[i]->served_gummeis); + for (int j = 0; j < (*s1ap)->mme[i]->n_requested_plmns; j++) + free((*s1ap)->mme[i]->requested_plmns[j]); + free((*s1ap)->mme[i]->requested_plmns); + free((*s1ap)->mme[i]); + } + free((*s1ap)->mme); + free(*s1ap); + *s1ap = NULL; +} + +void flexran_agent_s1ap_destroy_stats_reply(Protocol__FlexStatsReply *reply) { + for (int i = 0; i < reply->n_ue_report; ++i) { + if (!reply->ue_report[i]->s1ap_stats) + continue; + free(reply->ue_report[i]->s1ap_stats->selected_plmn); + free(reply->ue_report[i]->s1ap_stats); + reply->ue_report[i]->s1ap_stats = NULL; + } +} + +int flexran_agent_register_s1ap_xface(mid_t mod_id) { + if (agent_s1ap_xface[mod_id]) { + LOG_E(FLEXRAN_AGENT, "S1AP agent CM for eNB %d is already registered\n", mod_id); + return -1; + } + + AGENT_S1AP_xface *xface = malloc(sizeof(AGENT_S1AP_xface)); + if (!xface) { + LOG_E(FLEXRAN_AGENT, "could not allocate memory for S1AP agent xface %d\n", mod_id); + return -1; + } + + // not implemented yet + xface->flexran_s1ap_notify_release_request=NULL; + + agent_s1ap_xface[mod_id] = xface; + + return 0; +} + +int flexran_agent_unregister_s1ap_xface(mid_t mod_id) { + if (!agent_s1ap_xface[mod_id]) { + LOG_E(FLEXRAN_AGENT, "S1AP agent for eNB %d is not registered\n", mod_id); + return -1; + } + agent_s1ap_xface[mod_id]->flexran_s1ap_notify_release_request=NULL; + free(agent_s1ap_xface[mod_id]); + agent_s1ap_xface[mod_id] = NULL; + return 0; +} + +AGENT_S1AP_xface *flexran_agent_get_s1ap_xface(mid_t mod_id) { + return agent_s1ap_xface[mod_id]; +} diff --git a/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.h b/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.h new file mode 100644 index 0000000000..1cca6ac9c1 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.h @@ -0,0 +1,69 @@ +/* + * 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 flexran_agent_s1ap.h + * \brief FlexRAN agent S1AP Control Module + * \author navid nikaein + * \date 2017 + * \version 0.1 + */ + +#ifndef FLEXRAN_AGENT_S1AP_H_ +#define FLEXRAN_AGENT_S1AP_H_ + +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "stats_messages.pb-c.h" +#include "stats_common.pb-c.h" + + +#include "flexran_agent_common.h" +#include "flexran_agent_defs.h" +#include "flexran_agent_s1ap_defs.h" +#include "flexran_agent_ran_api.h" + +/*************************************** + * FlexRAN agent - technology S1AP API * + ***************************************/ + +/* Send to the controller all the S1AP configs */ +void flexran_agent_fill_s1ap_cell_config(mid_t mod_id, + Protocol__FlexS1apConfig **s1ap_config); + +/* Free allocated S1AP cell configs */ +void flexran_agent_free_s1ap_cell_config(Protocol__FlexS1apConfig **s1ap); + +/* Fill the stats message for S1AP */ +int flexran_agent_s1ap_stats_reply(mid_t mod_id, + Protocol__FlexUeStatsReport **ue_report, + int n_ue, + uint32_t ue_flags); + +/* Free allocated S1AP stats message */ +void flexran_agent_s1ap_destroy_stats_reply(Protocol__FlexStatsReply *reply); + +/* Register technology specific interface callbacks */ +int flexran_agent_register_s1ap_xface(mid_t mod_id); + +/* Unregister technology specific callbacks */ +int flexran_agent_unregister_s1ap_xface(mid_t mod_id); + +#endif diff --git a/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap_defs.h b/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap_defs.h new file mode 100644 index 0000000000..bbbc75160d --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap_defs.h @@ -0,0 +1,32 @@ +/* + * 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 + */ +#ifndef __FLEXRAN_AGENT_S1AP_PRIMITIVES_H__ +#define __FLEXRAN_AGENT_S1AP_PRIMITIVES_H__ + +#include "flexran_agent_defs.h" + +/* FLEXRAN AGENT-S1AP Interface */ +typedef struct { + // S1AP statistics + void (*flexran_s1ap_notify_release_request)(mid_t mod_id); +} AGENT_S1AP_xface; + +#endif diff --git a/openair2/ENB_APP/MACRLC_paramdef.h b/openair2/ENB_APP/MACRLC_paramdef.h index ef7d598785..724dde6557 100644 --- a/openair2/ENB_APP/MACRLC_paramdef.h +++ b/openair2/ENB_APP/MACRLC_paramdef.h @@ -54,7 +54,6 @@ #define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" #define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" #define CONFIG_STRING_MACRLC_SCHED_MODE "scheduler_mode" -#define CONFIG_STRING_MACRLC_PHY_TEST_MODE "phy_test_mode" #define CONFIG_MACRLC_PUSCH10xSNR "puSch10xSnr" #define CONFIG_MACRLC_PUCCH10xSNR "puCch10xSnr" @@ -81,7 +80,6 @@ {CONFIG_STRING_MACRLC_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_SCHED_MODE, NULL, 0, strptr:NULL, defstrval:"default", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_PHY_TEST_MODE, NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ {CONFIG_MACRLC_PUSCH10xSNR, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_MACRLC_PUCCH10xSNR, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ } @@ -103,7 +101,6 @@ #define MACRLC_LOCAL_S_PORTD_IDX 15 #define MACRLC_REMOTE_S_PORTD_IDX 16 #define MACRLC_SCHED_MODE_IDX 17 -#define MACRLC_PHY_TEST_IDX 18 -#define MACRLC_PUSCH10xSNR_IDX 19 -#define MACRLC_PUCCH10xSNR_IDX 20 +#define MACRLC_PUSCH10xSNR_IDX 18 +#define MACRLC_PUCCH10xSNR_IDX 19 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/ENB_APP/MESSAGES/V2/config_common.proto b/openair2/ENB_APP/MESSAGES/V2/config_common.proto index 4958cdb27b..733d883c92 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_common.proto @@ -336,3 +336,28 @@ message flex_a5_event { optional int64 time_to_trigger = 4; optional int64 max_report_cells = 5; } + +// +// S1AP cell configuration +// +message flex_gummei { + optional flex_plmn plmn = 1; + optional uint32 mme_group_id = 2; + optional uint32 mme_code = 3; +} + +message flex_s1ap_mme { + optional string s1_ip = 1; // S1-MME IP of MME + optional string name = 2; // S1-MME name of MME + optional flex_mme_state state = 3; // State of the MME + repeated flex_gummei served_gummeis = 4; // GUMMEIs served by the MME + repeated flex_plmn requested_plmns = 5; // PLMNs communicated to MME + optional uint32 rel_capacity = 6; // Relative MME capacity, TS23.401 +} + +enum flex_mme_state { + FLMMES_DISCONNECTED = 0; + FLMMES_WAITING = 1; + FLMMES_CONNECTED = 2; + FLMMES_OVERLOAD = 3; +} diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index 6d24e5a0ac..324153613d 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -107,6 +107,10 @@ message flex_lc_ue_config { repeated flex_lc_config lc_config = 2; // A list of LC configurations for the given UE } - - - +message flex_s1ap_config { + optional uint32 pending = 1; // number of pending (to be connected) MMEs + optional uint32 connected = 2; // number of connected MMEs + optional string enb_s1_ip = 3; // S1-MME IP of eNodeB + optional string enb_name = 4; // S1-MME name of eNodeB + repeated flex_s1ap_mme mme = 5; +} diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index 86f2e9329f..3b47ff263b 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -6,7 +6,6 @@ import "header.proto"; import "time_common.proto"; import "config_messages.proto"; import "controller_commands.proto"; -import "control_delegation.proto"; import "config_common.proto"; message flexran_message { @@ -75,12 +74,22 @@ enum flex_bs_capability { PDCP = 5; SDAP = 6; RRC = 7; + S1AP = 8; +} + +enum flex_bs_split { + F1 = 0; + nFAPI = 1; + IF4 = 2; + IF4p5 = 3; + IF5 = 4; } message flex_hello { optional flex_header header = 1; optional uint64 bs_id = 2; // Unique id to distinguish the eNB repeated flex_bs_capability capabilities = 3; + repeated flex_bs_split splits = 4; } message flex_echo_request { @@ -147,6 +156,7 @@ message flex_enb_config_reply { optional flex_header header = 1; repeated flex_cell_config cell_config = 3; optional uint32 device_spec = 4; + optional flex_s1ap_config s1ap = 5; } message flex_ue_config_request { diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index b56ad8eea1..62bd06d707 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -1,6 +1,8 @@ syntax = "proto2"; package protocol; +import "config_common.proto"; // for flex_plmn + // // UE related statistics // @@ -218,25 +220,16 @@ message flex_eutra_cgi_measurements { // Tracking area code of the neighbor cell. optional uint32 tracking_area_code = 2; // Public land mobile network identifiers of neighbor cell. - repeated flex_plmn_identity plmn_id = 3; + repeated flex_plmn plmn = 3; } message flex_cell_global_eutra_id { // Public land mobile network identifier of neighbor cell. - optional flex_plmn_identity plmn_id = 1; + optional flex_plmn plmn = 1; // Cell identifier of neighbor cell. optional uint32 cell_id = 2; } -message flex_plmn_identity { - // Mobile Network Code (MNC). - repeated uint32 mnc = 1; - // Mobile Country Code (MCC). - repeated uint32 mcc = 2; - // tracking area code - repeated uint32 tac = 3; -} - message flex_eutra_ref_signal_meas { // Neighboring Cell RSRP optional int32 rsrp = 1; @@ -317,3 +310,15 @@ message flex_gtp_stats { optional uint32 teid_sgw = 4; optional string addr_sgw = 5; } + +// +// S1AP stats +// + +message flex_s1ap_ue { + optional string mme_s1_ip = 1; // IP of MME to which UE is connected + optional uint32 enb_ue_s1ap_id = 2; // S1AP ID on eNodeB side for UE + optional uint32 mme_ue_s1ap_id = 3; // S1AP ID on MME side for UE + optional flex_plmn selected_plmn = 4; // UE-selected PLMN in RRC Conn Setup Cplt +} + diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index 7cceb04a01..6f67648d82 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -51,6 +51,7 @@ message flex_ue_stats_report { optional flex_pdcp_stats pdcp_stats = 11; optional flex_mac_stats mac_stats = 12; repeated flex_gtp_stats gtp_stats = 13; + optional flex_s1ap_ue s1ap_stats = 14; } // @@ -91,6 +92,7 @@ enum flex_ue_stats_type { FLUST_PDCP_STATS = 1024; FLUST_GTP_STATS = 2048; + FLUST_S1AP_STATS = 4096; FLUST_RRC_MEASUREMENTS = 65536; // To be extended with more types of stats diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 2d5134e0d9..0e1c7e64bc 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -46,6 +46,8 @@ # include "x2ap_eNB.h" # include "x2ap_messages_types.h" +# include "m2ap_eNB.h" +# include "m2ap_messages_types.h" # define X2AP_ENB_REGISTER_RETRY_DELAY 10 #include "openair1/PHY/INIT/phy_init.h" @@ -56,6 +58,90 @@ extern RAN_CONTEXT_t RC; # define ENB_REGISTER_RETRY_DELAY 10 +#include "targets/RT/USER/lte-softmodem.h" + + +/*************************** ENB M2AP **************************/ +//static uint32_t eNB_app_register_MBMS_STA(ngran_node_t node_type,uint32_t enb_id_start, uint32_t enb_id_end) { +// uint32_t enb_id; +// //MessageDef *msg_p; +// uint32_t register_enb_pending = 0; +// +// for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { +// { +// +// //msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ); +// //RCconfig_S1(msg_p, enb_id); +// +// if (enb_id == 0) RCconfig_gtpu(); +// +// //LOG_I(ENB_APP,"default drx %d\n",((S1AP_REGISTER_ENB_REQ(msg_p)).default_drx)); +// +// //LOG_I(ENB_APP,"[eNB %d] eNB_app_register via S1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id)); +// //itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); +// +// register_enb_pending++; +// } +// } +// +// return register_enb_pending; +//} +//*****end M2AP ****/ + +static uint32_t eNB_app_register_m2(uint32_t enb_id_start, uint32_t enb_id_end) { + uint32_t enb_id; + MessageDef *msg_p; + uint32_t register_enb_m2_pending = 0; + +// msg_p = itti_alloc_new_message (TASK_ENB_APP,MESSAGE_TEST ); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + + LOG_D(ENB_APP,"Register ...\n"); + + for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { + { + msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_REGISTER_ENB_REQ); + RCconfig_M2(msg_p, enb_id); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + register_enb_m2_pending++; + } + } + + return register_enb_m2_pending; +} + + +/*************************** M2AP ENB handle **********************************/ +static uint32_t eNB_app_handle_m2ap_mbms_scheduling_information(instance_t instance){ + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SCHEDULING_INFORMATION_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + return 0; +} +static uint32_t eNB_app_handle_m2ap_mbms_session_start_req(instance_t instance){ + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SESSION_START_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + return 0; +} +static uint32_t eNB_app_handle_m2ap_mbms_session_stop_req(instance_t instance){ + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SESSION_STOP_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + return 0; +} +static uint32_t eNB_app_handle_m2ap_mbms_session_update_req(instance_t instance){ + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SESSION_UPDATE_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + return 0; +} + +//// end M2AP ENB handle **********************************/ /*------------------------------------------------------------------------------*/ @@ -126,6 +212,9 @@ void *eNB_app_task(void *args_p) { uint32_t x2_register_enb_pending = 0; uint32_t x2_registered_enb = 0; long x2_enb_register_retry_timer_id; + uint32_t m2_register_enb_pending = 0; + uint32_t m2_registered_enb = 0; + long m2_enb_register_retry_timer_id; MessageDef *msg_p = NULL; instance_t instance; int result; @@ -144,6 +233,22 @@ void *eNB_app_task(void *args_p) { x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end); } + /* Try to register each eNB with MCE each other */ + if (is_m2ap_eNB_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) { + //eNB_app_register_MBMS_STA(RC.rrc[0]->node_type, enb_id_start, enb_id_end); + //m2_register_enb_pending = eNB_app_register_m2 (enb_id_start, enb_id_end); + + if (timer_setup (5, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + NULL, &m2_enb_register_retry_timer_id) < 0) { + //LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n"); + //sleep(ENB_REGISTER_RETRY_DELAY); + /* Restart the registration process */ + //registered_enb = 0; + //register_enb_pending = eNB_app_register (RC.rrc[0]->node_type,enb_id_start, enb_id_end); + } + + } + do { // Wait for a message itti_receive_msg (TASK_ENB_APP, &msg_p); @@ -272,6 +377,12 @@ void *eNB_app_task(void *args_p) { } } /* if (EPC_MODE_ENABLED) */ + if(TIMER_HAS_EXPIRED (msg_p).timer_id == m2_enb_register_retry_timer_id) { + + LOG_I(ENB_APP, " Received %s: timer_id %ld M2 register\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id); + m2_register_enb_pending = eNB_app_register_m2 (enb_id_start, enb_id_end); + } + break; case X2AP_DEREGISTERED_ENB_IND: @@ -316,6 +427,123 @@ void *eNB_app_task(void *args_p) { break; + case M2AP_DEREGISTERED_ENB_IND: + LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p), + M2AP_DEREGISTERED_ENB_IND(msg_p).nb_m2); + /* TODO handle recovering of registration */ + break; + + case M2AP_REGISTER_ENB_CNF: + LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p), + M2AP_REGISTER_ENB_CNF(msg_p).nb_m2); + DevAssert(m2_register_enb_pending > 0); + m2_register_enb_pending--; + + /* Check if at least eNB is registered with one target eNB */ + if (M2AP_REGISTER_ENB_CNF(msg_p).nb_m2 > 0) { + m2_registered_enb++; + } + + /* Check if all register eNB requests have been processed */ + if (m2_register_enb_pending == 0) { + if (m2_registered_enb == enb_nb) { + /* If all eNB are registered, start RRC HO task */ + } else { + uint32_t m2_not_associated = enb_nb - m2_registered_enb; + LOG_W(ENB_APP, " %d eNB %s not associated with the target\n", + m2_not_associated, m2_not_associated > 1 ? "are" : "is"); + + // timer to retry + /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */ + //if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, + // INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL, + // &x2_enb_register_retry_timer_id) < 0) { + // LOG_E(ENB_APP, " Can not start eNB X2AP register: retry timer, use \"sleep\" instead!\n"); + // sleep(X2AP_ENB_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // x2_registered_enb = 0; + // x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end); + //} + } + } + break; + + case M2AP_SETUP_RESP: + LOG_I(ENB_APP,"M2AP_SETUP_RESP RESPONSE received\n"); + // AssertFatal(NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received F1AP_REGISTER_ENB_CNF in CU/eNB\n"); + + // LOG_I(ENB_APP, "Received %s: associated ngran_eNB_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p), + // F1AP_SETUP_RESP(msg_p).gNB_CU_name,F1AP_SETUP_RESP(msg_p).num_cells_to_activate); + // + // handle_f1ap_setup_resp(&F1AP_SETUP_RESP(msg_p)); + + // DevAssert(register_enb_pending > 0); + // register_enb_pending--; + + // /* Check if at least eNB is registered with one MME */ + // if (F1AP_SETUP_RESP(msg_p).num_cells_to_activate > 0) { + // registered_enb++; + // } + + // /* Check if all register eNB requests have been processed */ + // if (register_enb_pending == 0) { + // if (registered_enb == enb_nb) { + // /* If all eNB cells are registered, start L2L1 task */ + // MessageDef *msg_init_p; + + // msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE); + // itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); + + // } else { + // LOG_W(ENB_APP, " %d eNB not associated with a MME, retrying registration in %d seconds ...\n", + // enb_nb - registered_enb, ENB_REGISTER_RETRY_DELAY); + + // /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + // NULL, &enb_register_retry_timer_id) < 0) { + // LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n"); + + // sleep(ENB_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // registered_enb = 0; + // register_enb_pending = eNB_app_register (RC.rrc[0]->node_type,enb_id_start, enb_id_end);//, enb_properties_p); + // } + // } + // } + break; + + case M2AP_MBMS_SCHEDULING_INFORMATION: + LOG_I(ENB_APP,"M2AP_SCHEDULING_INFORMATION received\n"); + eNB_app_handle_m2ap_mbms_scheduling_information(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + break; + case M2AP_MBMS_SESSION_START_REQ: + LOG_I(ENB_APP,"M2AP_MBMS_SESSION_START_REQ received\n"); + eNB_app_handle_m2ap_mbms_session_start_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + break; + case M2AP_MBMS_SESSION_STOP_REQ: + LOG_I(ENB_APP,"M2AP_MBMS_SESSION_STOP_REQ received\n"); + eNB_app_handle_m2ap_mbms_session_stop_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + break; + case M2AP_RESET: + LOG_I(ENB_APP,"M2AP_RESET received\n"); + break; + case M2AP_ENB_CONFIGURATION_UPDATE_ACK: + LOG_I(ENB_APP,"M2AP_ENB_CONFIGURATION_UPDATE_ACK received\n"); + break; + case M2AP_ENB_CONFIGURATION_UPDATE_FAILURE: + LOG_I(ENB_APP,"M2AP_ENB_CONFIGURATION_UPDATE_FAILURE received\n"); + break; + case M2AP_ERROR_INDICATION: + LOG_I(ENB_APP,"M2AP_MBMS_SESSION_UPDATE_REQ\n"); + eNB_app_handle_m2ap_mbms_session_update_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + break; + case M2AP_MBMS_SERVICE_COUNTING_REQ: + LOG_I(ENB_APP,"M2AP_MBMS_SERVICE_COUNTING_REQ\n"); + break; + case M2AP_MCE_CONFIGURATION_UPDATE: + LOG_I(ENB_APP,"M2AP_MCE_CONFIGURATION_UPDATE\n"); + break; + default: LOG_E(ENB_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); break; diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 06386adbb7..6dcc574746 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -214,8 +214,6 @@ void RCconfig_macrlc(int macrlc_has_f1[MAX_MAC_INST]) { RC.mac[j]->puSch10xSnr = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCH10xSNR_IDX ].iptr); RC.mac[j]->puCch10xSnr = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCH10xSNR_IDX ].iptr); RC.nb_mac_CC[j] = *(MacRLC_ParamList.paramarray[j][MACRLC_CC_IDX].iptr); - //RC.mac[j]->phy_test = *(MacRLC_ParamList.paramarray[j][MACRLC_PHY_TEST_IDX].iptr); - //printf("PHY_TEST = %d,%d\n", RC.mac[j]->phy_test, j); if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_RRC") == 0) { // check number of instances is same as RRC/PDCP @@ -380,7 +378,6 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I) PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); - //RRC_CONFIGURATION_REQ (msg_p).rrc_inactivity_timer_thres = RRC_INACTIVITY_THRESH; // set to 0 to deactivate // In the configuration file it is in seconds. For RRC it has to be in milliseconds RRC_CONFIGURATION_REQ (msg_p).rrc_inactivity_timer_thres = (*ENBParamList.paramarray[i][ENB_RRC_INACTIVITY_THRES_IDX].uptr) * 1000; RRC_CONFIGURATION_REQ (msg_p).cell_identity = enb_id; @@ -428,6 +425,14 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { else RRC_CONFIGURATION_REQ (msg_p).enable_x2 = 0; + /* m2 enabled */ + if (ENBParamList.paramarray[i][ENB_ENABLE_ENB_M2].strptr != NULL && + *(ENBParamList.paramarray[i][ENB_ENABLE_ENB_M2].strptr) != NULL && + !strcmp(*(ENBParamList.paramarray[i][ENB_ENABLE_ENB_M2].strptr), "yes")) + RRC_CONFIGURATION_REQ (msg_p).eMBMS_M2_configured = 1; + else + RRC_CONFIGURATION_REQ (msg_p).eMBMS_M2_configured = 0; + // Parse optional physical parameters config_getlist( &CCsParamList,NULL,0,enbpath); LOG_I(RRC,"num component carriers %d \n",CCsParamList.numelt); @@ -2044,6 +2049,266 @@ int RCconfig_gtpu(void ) { return 0; } +int RCconfig_M2(MessageDef *msg_p, uint32_t i) { + int I, J, j, k, l; + int enb_id; + char *address = NULL; + char *cidr = NULL; + ccparams_lte_t ccparams_lte; + memset((void *)&ccparams_lte,0,sizeof(ccparams_lte_t)); + paramdef_t ENBSParams[] = ENBSPARAMS_DESC; + paramdef_t ENBParams[] = ENBPARAMS_DESC; + paramlist_def_t ENBParamList = {ENB_CONFIG_STRING_ENB_LIST,NULL,0}; + /* get global parameters, defined outside any section in the config file */ + config_get( ENBSParams,sizeof(ENBSParams)/sizeof(paramdef_t),NULL); + checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK; + paramdef_t CCsParams[] = CCPARAMS_DESC(ccparams_lte); + paramlist_def_t CCsParamList = {ENB_CONFIG_STRING_COMPONENT_CARRIERS, NULL, 0}; + + // ccparams_MCE_t MCEconfig; + // memset((void *)&MCEconfig,0,sizeof(ccparams_MCE_t)); + // paramdef_t MCEParams[] = MCEPARAMS_DESC((&MCEconfig)); + // checkedparam_t config_check_MCEparams[] = MCEPARAMS_CHECK; + + + /* map parameter checking array instances to parameter definition array instances */ + for (I = 0; I < (sizeof(CCsParams) / sizeof(paramdef_t)); I++) { + CCsParams[I].chkPptr = &(config_check_CCparams[I]); + } + + AssertFatal(i < ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt, + "Failed to parse config file %s, %uth attribute %s \n", + RC.config_file_name, i, ENB_CONFIG_STRING_ACTIVE_ENBS); + + if (ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt > 0) { + // Output a list of all eNBs. + config_getlist( &ENBParamList,ENBParams,sizeof(ENBParams)/sizeof(paramdef_t),NULL); + + if (ENBParamList.numelt > 0) { + for (k = 0; k < ENBParamList.numelt; k++) { + if (ENBParamList.paramarray[k][ENB_ENB_ID_IDX].uptr == NULL) { + // Calculate a default eNB ID + if (EPC_MODE_ENABLED) { + uint32_t hash; + hash = s1ap_generate_eNB_id (); + enb_id = k + (hash & 0xFFFF8); + } else { + enb_id = k; + } + } else { + enb_id = *(ENBParamList.paramarray[k][ENB_ENB_ID_IDX].uptr); + } + + // search if in active list + for (j = 0; j < ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt; j++) { + if (strcmp(ENBSParams[ENB_ACTIVE_ENBS_IDX].strlistptr[j], *(ENBParamList.paramarray[k][ENB_ENB_NAME_IDX].strptr)) == 0) { + paramdef_t PLMNParams[] = PLMNPARAMS_DESC; + paramlist_def_t PLMNParamList = {ENB_CONFIG_STRING_PLMN_LIST, NULL, 0}; + /* map parameter checking array instances to parameter definition array instances */ + checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK; + + for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I) + PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); + + paramdef_t M2Params[] = M2PARAMS_DESC; + paramlist_def_t M2ParamList = {ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS,NULL,0}; + paramdef_t SCTPParams[] = SCTPPARAMS_DESC; + paramdef_t NETParams[] = NETPARAMS_DESC; + paramdef_t MBMSConfigParams[] = MBMS_CONFIG_PARAMS_DESC; + paramdef_t MBMSParams[] = MBMSPARAMS_DESC; + paramlist_def_t MBMSConfigParamList = {ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST,NULL,0}; + paramlist_def_t MBMSParamList = {ENB_CONFIG_STRING_MBMS_SERVICE_AREA_LIST,NULL,0}; + /* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */ + /* this is most probably a problem with the config module */ + char aprefix[MAX_OPTNAME_SIZE*80 + 8]; + sprintf(aprefix,"%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k); + /* Some default/random parameters */ + M2AP_REGISTER_ENB_REQ (msg_p).eNB_id = enb_id; + + if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_MACRO_ENB") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_ENB; + } else if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_HOME_ENB") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_HOME_ENB; + } else { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n", + RC.config_file_name, i, *(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr)); + } + + M2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(ENBParamList.paramarray[k][ENB_ENB_NAME_IDX].strptr)); + M2AP_REGISTER_ENB_REQ (msg_p).tac = *ENBParamList.paramarray[k][ENB_TRACKING_AREA_CODE_IDX].uptr; + config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix); + + + +// char aprefix2[MAX_OPTNAME_SIZE*80 + 8]; +// sprintf(aprefix2,"%s.[%i].%s.[0]",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST); +// config_getlist(&MBMSParamList, MBMSParams, sizeof(MBMSParams)/sizeof(paramdef_t), aprefix2); +// if (MBMSParamList.numelt < 1 || MBMSParamList.numelt > 8) +// AssertFatal(0, "The number of MBMS Areas must be in [1,8], but is %d\n", +// MBMSParamList.numelt); +// M2AP_REGISTER_ENB_REQ (msg_p).num_mbms_service_area_list = MBMSParamList.numelt; +// for(J=0; J 8) + AssertFatal(0, "The number of MBMS Config Data must be in [1,8], but is %d\n", + MBMSConfigParamList.numelt); + M2AP_REGISTER_ENB_REQ (msg_p).num_mbms_configuration_data_list = MBMSConfigParamList.numelt; + for(int I=0; I < MBMSConfigParamList.numelt; I++){ + + sprintf(aprefix2,"%s.[%i].%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST,I); + config_getlist(&MBMSParamList, MBMSParams, sizeof(MBMSParams)/sizeof(paramdef_t), aprefix2); + if (MBMSParamList.numelt < 1 || MBMSParamList.numelt > 8) + AssertFatal(0, "The number of MBMS Areas must be in [1,8], but is %d\n", + MBMSParamList.numelt); + M2AP_REGISTER_ENB_REQ (msg_p).mbms_configuration_data_list[I].num_mbms_service_area_list = MBMSParamList.numelt; + for(J=0; J 6) + AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", + PLMNParamList.numelt); + + if (PLMNParamList.numelt > 1) + LOG_W(M2AP, "M2AP currently handles only one PLMN, ignoring the others!\n"); + + M2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][ENB_MOBILE_COUNTRY_CODE_IDX].uptr; + M2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][ENB_MOBILE_NETWORK_CODE_IDX].uptr; + M2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][ENB_MNC_DIGIT_LENGTH].u8ptr; + AssertFatal(M2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3 + || M2AP_REGISTER_ENB_REQ(msg_p).mnc < 100, + "MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n", + M2AP_REGISTER_ENB_REQ(msg_p).mnc); + /* CC params */ + config_getlist(&CCsParamList, NULL, 0, aprefix); + M2AP_REGISTER_ENB_REQ (msg_p).num_cc = CCsParamList.numelt; + + if (CCsParamList.numelt > 0) { + //char ccspath[MAX_OPTNAME_SIZE*2 + 16]; + for (J = 0; J < CCsParamList.numelt ; J++) { + sprintf(aprefix, "%s.[%i].%s.[%i]", ENB_CONFIG_STRING_ENB_LIST, k, ENB_CONFIG_STRING_COMPONENT_CARRIERS, J); + config_get(CCsParams, sizeof(CCsParams)/sizeof(paramdef_t), aprefix); + M2AP_REGISTER_ENB_REQ (msg_p).eutra_band[J] = ccparams_lte.eutra_band; + M2AP_REGISTER_ENB_REQ (msg_p).downlink_frequency[J] = (uint32_t) ccparams_lte.downlink_frequency; + M2AP_REGISTER_ENB_REQ (msg_p).uplink_frequency_offset[J] = (unsigned int) ccparams_lte.uplink_frequency_offset; + M2AP_REGISTER_ENB_REQ (msg_p).Nid_cell[J]= ccparams_lte.Nid_cell; + + if (ccparams_lte.Nid_cell>503) { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for Nid_cell choice: 0...503 !\n", + RC.config_file_name, k, ccparams_lte.Nid_cell); + } + + M2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J]= ccparams_lte.N_RB_DL; + + if ((ccparams_lte.N_RB_DL!=6) && (ccparams_lte.N_RB_DL!=15) && (ccparams_lte.N_RB_DL!=25) && (ccparams_lte.N_RB_DL!=50) && (ccparams_lte.N_RB_DL!=75) && (ccparams_lte.N_RB_DL!=100)) { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for N_RB_DL choice: 6,15,25,50,75,100 !\n", + RC.config_file_name, k, ccparams_lte.N_RB_DL); + } + + if (strcmp(ccparams_lte.frame_type, "FDD") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = FDD; + } else if (strcmp(ccparams_lte.frame_type, "TDD") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD; + } else { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n", + RC.config_file_name, k, ccparams_lte.frame_type); + } + + M2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_DL[J] = to_earfcn_DL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency, ccparams_lte.N_RB_DL); + M2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_UL[J] = to_earfcn_UL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency + ccparams_lte.uplink_frequency_offset, ccparams_lte.N_RB_DL); + } + } + + sprintf(aprefix,"%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k); + config_getlist( &M2ParamList,M2Params,sizeof(M2Params)/sizeof(paramdef_t),aprefix); + AssertFatal(M2ParamList.numelt <= M2AP_MAX_NB_ENB_IP_ADDRESS, + "value of M2ParamList.numelt %d must be lower than M2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase M2AP_MAX_NB_ENB_IP_ADDRESS\n", + M2ParamList.numelt,M2AP_MAX_NB_ENB_IP_ADDRESS); + M2AP_REGISTER_ENB_REQ (msg_p).nb_m2 = 0; + + for (l = 0; l < M2ParamList.numelt; l++) { + M2AP_REGISTER_ENB_REQ (msg_p).nb_m2 += 1; + strcpy(M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4_address,*(M2ParamList.paramarray[l][ENB_M2_IPV4_ADDRESS_IDX].strptr)); + strcpy(M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6_address,*(M2ParamList.paramarray[l][ENB_M2_IPV6_ADDRESS_IDX].strptr)); + + if (strcmp(*(M2ParamList.paramarray[l][ENB_M2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4 = 1; + M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6 = 0; + } else if (strcmp(*(M2ParamList.paramarray[l][ENB_M2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4 = 0; + M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6 = 1; + } else if (strcmp(*(M2ParamList.paramarray[l][ENB_M2_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) { + M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4 = 1; + M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6 = 1; + } + } + // timers + //{ + // int t_reloc_prep = 0; + // int tx2_reloc_overall = 0; + // paramdef_t p[] = { + // { "t_reloc_prep", "t_reloc_prep", 0, iptr:&t_reloc_prep, defintval:0, TYPE_INT, 0 }, + // { "tx2_reloc_overall", "tx2_reloc_overall", 0, iptr:&tx2_reloc_overall, defintval:0, TYPE_INT, 0 } + // }; + // config_get(p, sizeof(p)/sizeof(paramdef_t), aprefix); + + // if (t_reloc_prep <= 0 || t_reloc_prep > 10000 || + // tx2_reloc_overall <= 0 || tx2_reloc_overall > 20000) { + // LOG_E(M2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_overall <= 20000]\n"); + // exit(1); + // } + + // M2AP_REGISTER_ENB_REQ (msg_p).t_reloc_prep = t_reloc_prep; + // M2AP_REGISTER_ENB_REQ (msg_p).tx2_reloc_overall = tx2_reloc_overall; + //} + // SCTP SETTING + M2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS; + M2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS; + + if (EPC_MODE_ENABLED) { + sprintf(aprefix,"%s.[%i].%s",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_SCTP_CONFIG); + config_get( SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix); + M2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[ENB_SCTP_INSTREAMS_IDX].uptr); + M2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[ENB_SCTP_OUTSTREAMS_IDX].uptr); + } + + sprintf(aprefix,"%s.[%i].%s",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + // NETWORK_INTERFACES + config_get( NETParams,sizeof(NETParams)/sizeof(paramdef_t),aprefix); + M2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_M2C = (uint32_t)*(NETParams[ENB_PORT_FOR_M2C_IDX].uptr); + + if ((NETParams[ENB_IPV4_ADDR_FOR_M2C_IDX].strptr == NULL) || (M2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_M2C == 0)) { + LOG_E(RRC,"Add eNB IPv4 address and/or port for M2C in the CONF file!\n"); + exit(1); + } + + cidr = *(NETParams[ENB_IPV4_ADDR_FOR_M2C_IDX].strptr); + address = strtok(cidr, "/"); + M2AP_REGISTER_ENB_REQ (msg_p).enb_m2_ip_address.ipv6 = 0; + M2AP_REGISTER_ENB_REQ (msg_p).enb_m2_ip_address.ipv4 = 1; + strcpy(M2AP_REGISTER_ENB_REQ (msg_p).enb_m2_ip_address.ipv4_address, address); + } + } + } + } + } + + return 0; +} + //----------------------------------------------------------------------------- /* * Configure the s1ap_register_enb_req in itti message for future @@ -2124,6 +2389,11 @@ int RCconfig_S1( S1AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_ENB; } else if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_HOME_ENB") == 0) { S1AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_HOME_ENB; + // Temporary option to be able to parse an eNB configuration file which is treated as gNB from + // the X2AP layer and test the setup of an ENDC X2AP connection. To be removed when we are ready to + // parse an actual gNB configuration file wrt. the X2AP parameters instead. + } else if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) { + S1AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_GNB; } else { AssertFatal(0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n", @@ -2353,7 +2623,7 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_ENB; } else if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_HOME_ENB") == 0) { X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_HOME_ENB; - } else { + }else { AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n", RC.config_file_name, i, *(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr)); @@ -2837,4 +3107,6 @@ void read_config_and_init(void) { memset((void *)RC.rrc[enb_id], 0, sizeof(eNB_RRC_INST)); RCconfig_RRC(enb_id, RC.rrc[enb_id],macrlc_has_f1[enb_id]); } + + RCconfig_flexran(); } diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index e9c7085d3e..4bc4f5bf22 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -116,6 +116,7 @@ int RCconfig_S1(MessageDef *msg_p, uint32_t i); void read_config_and_init(void); int RCconfig_X2(MessageDef *msg_p, uint32_t i); +int RCconfig_M2(MessageDef *msg_p, uint32_t i); void fill_SL_configuration(MessageDef *msg_p, ccparams_sidelink_t *SLconfig,int cell_idx,int cc_idx,char *config_fname); void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, int cell_idx,int cc_idx,char *config_fname,char *brparamspath); diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index ff3b741d56..f91c7056c5 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -153,7 +153,7 @@ typedef enum { {CONFIG_STRING_RU_END_OF_BURST_DELAY, NULL, 0, uptr:NULL, defuintval:400, TYPE_UINT, 0}, \ {CONFIG_STRING_RU_OTA_SYNC_ENABLE, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ {CONFIG_STRING_RU_BF_WEIGHTS_LIST, NULL, 0, iptr:NULL, defintarrayval:DEFBFW, TYPE_INTARRAY, 0}, \ - {CONFIG_STRING_RU_IF_FREQUENCY, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT64, 0}, \ + {CONFIG_STRING_RU_IF_FREQUENCY, NULL, 0, u64ptr:NULL, defuintval:0, TYPE_UINT64, 0}, \ } /*---------------------------------------------------------------------------------------------------------------------------------------*/ @@ -205,6 +205,8 @@ typedef enum { #define ENB_CONFIG_STRING_RRC_INACTIVITY_THRESHOLD "rrc_inactivity_threshold" #define ENB_CONFIG_STRING_MEASUREMENT_REPORTS "enable_measurement_reports" #define ENB_CONFIG_STRING_X2 "enable_x2" +#define ENB_CONFIG_STRING_ENB_M2 "enable_enb_m2" +#define ENB_CONFIG_STRING_MCE_M2 "enable_mce_m2" /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -228,7 +230,10 @@ typedef enum { {ENB_CONFIG_STRING_RRC_INACTIVITY_THRESHOLD, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ {ENB_CONFIG_STRING_MEASUREMENT_REPORTS, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ {ENB_CONFIG_STRING_X2, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ + {ENB_CONFIG_STRING_ENB_M2, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ + {ENB_CONFIG_STRING_MCE_M2, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ } + #define ENB_ENB_ID_IDX 0 #define ENB_CELL_TYPE_IDX 1 #define ENB_ENB_NAME_IDX 2 @@ -247,6 +252,8 @@ typedef enum { #define ENB_RRC_INACTIVITY_THRES_IDX 15 #define ENB_ENABLE_MEASUREMENT_REPORTS 16 #define ENB_ENABLE_X2 17 +#define ENB_ENABLE_ENB_M2 18 +#define ENB_ENABLE_MCE_M2 19 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define ENBPARAMS_CHECK { \ @@ -266,6 +273,8 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ @@ -300,6 +309,32 @@ typedef enum { } +/*-------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST "mbms_configuration_data_list" + +#define ENB_CONFIG_STRING_MBMS_SYNC_AREA "mbms_sync_area" + +#define ENB_MBMS_SYNC_AREA_IDX 0 + +#define MBMS_CONFIG_PARAMS_DESC { \ +/* optname helpstr paramflags XXXptr def val type numelt */ \ + {ENB_CONFIG_STRING_MBMS_SYNC_AREA , NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} + + +/*-------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define ENB_CONFIG_STRING_MBMS_SERVICE_AREA_LIST "mbms_service_area_list" + +#define ENB_CONFIG_STRING_MBMS_SERVICE_AREA "mbms_service_area" + +#define ENB_MBMS_SERVICE_AREA_IDX 0 + +#define MBMSPARAMS_DESC { \ +/* optname helpstr paramflags XXXptr def val type numelt */ \ + {ENB_CONFIG_STRING_MBMS_SERVICE_AREA, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} + + /* component carries configuration parameters name */ #define ENB_CONFIG_STRING_NB_ANT_PORTS "nb_antenna_ports" @@ -912,6 +947,39 @@ typedef struct srb1_params_s { #define ENB_X2_IPV4_ADDRESS_IDX 0 #define ENB_X2_IPV6_ADDRESS_IDX 1 #define ENB_X2_IP_ADDRESS_PREFERENCE_IDX 2 + + +/*---------------------------------------------------------------------------------------------------------------------------------------*/ + +/* M2 configuration parameters section name */ +#define ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS "target_mce_m2_ip_address" + +/* M2 configuration parameters names */ + + +#define ENB_CONFIG_STRING_TARGET_MCE_M2_IPV4_ADDRESS "ipv4" +#define ENB_CONFIG_STRING_TARGET_MCE_M2_IPV6_ADDRESS "ipv6" +#define ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS_PREFERENCE "preference" + +/*---------------------------------------------------------------------------------------------------------------------------------------*/ + + + +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +/* M2 configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +#define M2PARAMS_DESC { \ +{ENB_CONFIG_STRING_TARGET_MCE_M2_IPV4_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{ENB_CONFIG_STRING_TARGET_MCE_M2_IPV6_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS_PREFERENCE, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +} + +#define ENB_M2_IPV4_ADDRESS_IDX 0 +#define ENB_M2_IPV6_ADDRESS_IDX 1 +#define ENB_M2_IP_ADDRESS_PREFERENCE_IDX 2 +/*---------------------------------------------------------------------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------------------------------------------------------------*/ /* SCTP configuration parameters section name */ #define ENB_CONFIG_STRING_SCTP_CONFIG "SCTP" @@ -945,7 +1013,10 @@ typedef struct srb1_params_s { #define ENB_PORT_FOR_S1U_IDX 4 #define ENB_IPV4_ADDR_FOR_X2C_IDX 5 #define ENB_PORT_FOR_X2C_IDX 6 - +#define ENB_IPV4_ADDR_FOR_M2C_IDX 7 +#define ENB_PORT_FOR_M2C_IDX 8 +#define MCE_IPV4_ADDR_FOR_M2C_IDX 9 +#define MCE_PORT_FOR_M2C_IDX 10 /* S1 interface configuration parameters names */ #define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME "ENB_INTERFACE_NAME_FOR_S1_MME" @@ -958,6 +1029,13 @@ typedef struct srb1_params_s { #define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C "ENB_IPV4_ADDRESS_FOR_X2C" #define ENB_CONFIG_STRING_ENB_PORT_FOR_X2C "ENB_PORT_FOR_X2C" +/* M2 interface configuration parameters names */ +#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_M2C "ENB_IPV4_ADDRESS_FOR_M2C" +#define ENB_CONFIG_STRING_ENB_PORT_FOR_M2C "ENB_PORT_FOR_M2C" +#define ENB_CONFIG_STRING_MCE_IPV4_ADDR_FOR_M2C "MCE_IPV4_ADDRESS_FOR_M2C" +#define ENB_CONFIG_STRING_MCE_PORT_FOR_M2C "MCE_PORT_FOR_M2C" + + /*--------------------------------------------------------------------------------------------------------------------------------------------------*/ /* S1/X2 interface configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -970,6 +1048,10 @@ typedef struct srb1_params_s { {ENB_CONFIG_STRING_ENB_PORT_FOR_S1U, NULL, 0, uptr:NULL, defintval:2152L, TYPE_UINT, 0}, \ {ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ {ENB_CONFIG_STRING_ENB_PORT_FOR_X2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0}, \ + {ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_M2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ + {ENB_CONFIG_STRING_ENB_PORT_FOR_M2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0}, \ + {ENB_CONFIG_STRING_MCE_IPV4_ADDR_FOR_M2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ + {ENB_CONFIG_STRING_MCE_PORT_FOR_M2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0}, \ } /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ @@ -988,8 +1070,6 @@ typedef struct srb1_params_s { #define CONFIG_STRING_L1_LIST "L1s" #define CONFIG_STRING_L1_CONFIG "l1_config" - - /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ @@ -1095,7 +1175,6 @@ typedef struct srb1_params_s { #define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" #define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" #define CONFIG_STRING_MACRLC_SCHED_MODE "scheduler_mode" -#define CONFIG_STRING_MACRLC_PHY_TEST_MODE "phy_test_mode" #define MACRLC_CC_IDX 0 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 @@ -1115,7 +1194,6 @@ typedef struct srb1_params_s { #define MACRLC_LOCAL_S_PORTD_IDX 15 #define MACRLC_REMOTE_S_PORTD_IDX 16 #define MACRLC_SCHED_MODE_IDX 17 -#define MACRLC_PHY_TEST_IDX 18 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* thread configuration parameters section name */ @@ -1145,4 +1223,6 @@ typedef struct srb1_params_s { #include "enb_paramdef_emtc.h" #include "enb_paramdef_sidelink.h" +#include "enb_paramdef_mce.h" +#include "enb_paramdef_mme.h" #endif diff --git a/openair2/ENB_APP/enb_paramdef_mce.h b/openair2/ENB_APP/enb_paramdef_mce.h new file mode 100644 index 0000000000..8a4dd15766 --- /dev/null +++ b/openair2/ENB_APP/enb_paramdef_mce.h @@ -0,0 +1,239 @@ +/* + * 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 openair2/ENB_APP/enb_paramdef_mce.h + * \brief definition of configuration parameters for MCE modules + * \author Javier MORGADE + * \date 2019 + * \version 0.1 + * \company VICOMTECH Spain + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "common/config/config_paramdesc.h" +#include "RRC_paramsvalues.h" + + + +/* mce configuration parameters names */ + +#define MCE_CONFIG_STRING_MCE_ID "MCE_ID" +#define MCE_CONFIG_STRING_MCE_NAME "MCE_name" +#define MCE_CONFIG_STRING_MCE_M2 "enable_mce_m2" +#define MCE_CONFIG_STRING_MCE_M3 "enable_mce_m3" + +#define MCE_PARAMS_DESC {\ +{MCE_CONFIG_STRING_MCE_ID, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCE_NAME, NULL, 0, strptr:NULL, defstrval:"OAIMCE", TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_MCE_M2, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_MCE_M3, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ +} + +#define MCE_MCE_ID_IDX 0 +#define MCE_MCE_NAME_IDX 1 +#define MCE_ENABLE_MCE_M2_IDX 2 +#define MCE_ENABLE_MCE_M3_IDX 3 + +#define MCE_PARAMS_CHECK { \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ +} + + +#define MCE_CONFIG_STRING_NETWORK_INTERFACES_CONFIG "NETWORK_INTERFACES" + +#define MCE2_INTERFACE_NAME_FOR_M2_ENB_IDX 0 +#define MCE2_IPV4_ADDR_FOR_M2C_IDX 1 +#define MCE2_PORT_FOR_M2C_IDX 2 +#define MCE2_INTERFACE_NAME_FOR_M3_MME_IDX 3 +#define MCE2_IPV4_ADDR_FOR_M3C_IDX 4 +#define MCE2_PORT_FOR_M3C_IDX 5 + +/* interface configuration parameters names */ +/* M2 interface configuration parameters names */ +#define MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M2_ENB "ENB_INTERFACE_NAME_FOR_M2_ENB" +#define MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M2C "MCE_IPV4_ADDRESS_FOR_M2C" +#define MCE_CONFIG_STRING_MCE_PORT_FOR_M2C "MCE_PORT_FOR_M2C" + +/* M3 interface configuration parameters names */ +#define MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M3_MME "MCE_INTERFACE_NAME_FOR_M3_MME" +#define MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M3C "MCE_IPV4_ADDRESS_FOR_M3C" +#define MCE_CONFIG_STRING_MCE_PORT_FOR_M3C "MCE_PORT_FOR_M3C" + + +#define MCE_NETPARAMS_DESC { \ +{MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M2_ENB, NULL, 0, strptr:&mce_interface_name_for_m2_enb, defstrval:"lo", TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M2C, NULL, 0, strptr:&mce_ipv4_address_for_m2c, defstrval:NULL, TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_MCE_PORT_FOR_M2C, NULL, 0, uptr:&mce_port_for_m2c, defintval:36443L, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M3_MME, NULL, 0, strptr:&mce_interface_name_for_m3_mme, defstrval:NULL, TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M3C, NULL, 0, strptr:&mce_ipv4_address_for_m3c, defstrval:NULL, TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_MCE_PORT_FOR_M3C, NULL, 0, uptr:&mce_port_for_m3c, defintval:36444L, TYPE_UINT, 0}, \ +} + + +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +/* M3 configuration parameters */ +/* M3 configuration parameters section name */ +#define MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS "target_mme_m3_ip_address" +/* M3 configuration parameters names */ +#define MCE_CONFIG_STRING_TARGET_MME_M3_IPV4_ADDRESS "ipv4" +#define MCE_CONFIG_STRING_TARGET_MME_M3_IPV6_ADDRESS "ipv6" +#define MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS_PREFERENCE "preference" +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +#define M3PARAMS_DESC { \ +{MCE_CONFIG_STRING_TARGET_MME_M3_IPV4_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_TARGET_MME_M3_IPV6_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS_PREFERENCE, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +} + +#define MCE2_M3_IPV4_ADDRESS_IDX 0 +#define MCE2_M3_IPV6_ADDRESS_IDX 1 +#define MCE2_M3_IP_ADDRESS_PREFERENCE_IDX 2 + + +/*-----------------------------------------------------------------------------------------------------------------------------------*/ +/* MCCH related BCCH Configuration per MBSFN area configuration parameters */ +/* MCCH configuration parameters section */ +#define MCE_CONFIG_STRING_MCCH_CONFIG_PER_MBSFN_AREA "mcch_config_per_mbsfn_area" +/* M3 configuration parameters names */ +#define MCE_CONFIG_STRING_MCCH_MBSFN_AREA "mbsfn_area" +#define MCE_CONFIG_STRING_MCCH_PDCCH_LENGTH "pdcch_length" +#define MCE_CONFIG_STRING_MCCH_REPETITION_PERIOD "repetition_period" +#define MCE_CONFIG_STRING_MCCH_OFFSET "offset" +#define MCE_CONFIG_STRING_MCCH_MODIFICATION_PERIOD "modification_period" +#define MCE_CONFIG_STRING_MCCH_SF_ALLOCATION_INFO "subframe_allocation_info" +#define MCE_CONFIG_STRING_MCCH_MCS "mcs" + +/* optname helpstr paramflags XXXptr defXXXval type numelt */ + +#define MCCH_PARAMS_DESC { \ +{MCE_CONFIG_STRING_MCCH_MBSFN_AREA, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCCH_PDCCH_LENGTH, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCCH_REPETITION_PERIOD, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCCH_OFFSET, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCCH_MODIFICATION_PERIOD,NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCCH_SF_ALLOCATION_INFO, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCCH_MCS, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} + +#define MCCH_MBSFN_AREA_IDX 0 +#define MCCH_PDCCH_LENGTH_IDX 1 +#define MCCH_REPETITION_PERIOD_IDX 2 +#define MCCH_OFFSET_IDX 3 +#define MCCH_MODIFICATION_PERIOD_IDX 4 +#define MCCH_SF_ALLOCATION_INFO_IDX 5 +#define MCCH_MCS_IDX 6 +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +/* M3 configuration parameters section name */ +#define MCE_CONFIG_STRING_PLMN "plnm" +/* M3 configuration parameters names */ +#define MCE_CONFIG_STRING_MCC "mcc" +#define MCE_CONFIG_STRING_MNC "mnc" +#define MCE_CONFIG_STRING_MNC_LENGTH "mnc_length" +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +#define MCE_PLMN_PARAMS_DESC { \ +{MCE_CONFIG_STRING_MCC, NULL, 0, uptr:NULL, defuintval:1000, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MNC, NULL, 0, uptr:NULL, defuintval:1000, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MNC_LENGTH, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} + +#define MCE_CONFIG_STRING_MCC_IDX 0 +#define MCE_CONFIG_STRING_MNC_IDX 1 +#define MCE_CONFIG_STRING_MNC_LENGTH_IDX 2 +/*-------------------------------------------------------------------------------------------------------------------------------------*/ + +#define MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO "mbms_sched_info" + +#define MCE_CONFIG_STRING_MCCH_UPDATE_TIME "mcch_update_time" +#define MCE_MBMS_SCHEDULING_INFO_PARAMS_DESC { \ +{MCE_CONFIG_STRING_MCCH_UPDATE_TIME, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} +#define MCE_CONFIG_STRING_MCCH_UPDATE_TIME_IDX 0 + +///*-------------------------------------------------------------------------------------------------------------------------------------*/ +#define MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST "mbms_area_config_list" + +#define MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD "common_sf_allocation_period" +#define MCE_CONFIG_STRING_MBMS_AREA_ID "mbms_area_id" + +#define MCE_MBMS_AREA_CONFIGURATION_LIST_PARAMS_DESC { \ +{MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MBMS_AREA_ID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} +#define MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD_IDX 0 +#define MCE_CONFIG_STRING_MBMS_AREA_ID_IDX 1 +// +///*-------------------------------------------------------------------------------------------------------------------------------------*/ +#define MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST "pmch_config_list" + +#define MCE_CONFIG_STRING_ALLOCATED_SF_END "allocated_sf_end" +#define MCE_CONFIG_STRING_DATA_MCS "data_mcs" +#define MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD "mch_scheduling_period" + +#define MCE_MBMS_PMCH_CONFIGURATION_LIST_PARAMS_DESC { \ +{MCE_CONFIG_STRING_ALLOCATED_SF_END, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_DATA_MCS, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} +#define MCE_CONFIG_STRING_ALLOCATED_SF_END_IDX 0 +#define MCE_CONFIG_STRING_DATA_MCS_IDX 1 +#define MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD_IDX 2 +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +#define MCE_CONFIG_STRING_MBMS_SESSION_LIST "mbms_session_list" + +#define MCE_CONFIG_STRING_MBMS_SERVICE_ID "service_id" +#define MCE_CONFIG_STRING_MBMS_LCID_ID "lcid_id" +#define MCE_CONFIG_STRING_MBMS_LCID "lcid" + +#define MCE_MBMS_MBMS_SESSION_LIST_DESC { \ +{MCE_CONFIG_STRING_MBMS_SERVICE_ID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT32, 0}, \ +{MCE_CONFIG_STRING_MBMS_LCID_ID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_MBMS_LCID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ +} +#define MCE_CONFIG_STRING_MBMS_SERVICE_ID_IDX 0 +#define MCE_CONFIG_STRING_MBMS_LCID_ID_IDX 1 +#define MCE_CONFIG_STRING_MBMS_LCID_IDX 2 + +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +#define MCE_CONFIG_STRING_MBMS_SF_CONFIGURATION_LIST "mbms_sf_config_list" + +#define MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD "radioframe_allocation_period" +#define MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET "radioframe_alloocation_offset" +#define MCE_CONFIG_STRING_NUM_FRAME "num_frame" +#define MCE_CONFIG_STRING_SUBFRAME_ALLOCATION "subframe_allocation" + +#define MCE_MBMS_MBMS_SF_CONFIGURATION_LIST_PARAMS_DESC { \ +{MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{MCE_CONFIG_STRING_NUM_FRAME, NULL, 0, strptr:NULL, defstrval:"oneFrame", TYPE_STRING, 0}, \ +{MCE_CONFIG_STRING_SUBFRAME_ALLOCATION, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +} +#define MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD_IDX 0 +#define MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET_IDX 1 +#define MCE_CONFIG_STRING_NUM_FRAME_IDX 2 +#define MCE_CONFIG_STRING_SUBFRAME_ALLOCATION_IDX 3 + + + diff --git a/openair2/ENB_APP/enb_paramdef_mme.h b/openair2/ENB_APP/enb_paramdef_mme.h new file mode 100644 index 0000000000..0ff1df765c --- /dev/null +++ b/openair2/ENB_APP/enb_paramdef_mme.h @@ -0,0 +1,82 @@ +/* + * 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 openair2/ENB_APP/enb_paramdef_mme.h + * \brief definition of configuration parameters for MME modules + * \author Javier MORGADE + * \date 2019 + * \version 0.1 + * \company VICOMTECH Spain + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "common/config/config_paramdesc.h" +#include "RRC_paramsvalues.h" + + + +/* mme configuration parameters names */ + +#define MME_CONFIG_STRING_MME_ID "MME_ID" +#define MME_CONFIG_STRING_MME_NAME "MME_name" +#define MME_CONFIG_STRING_MME_M3 "enable_mme_m3" + +#define MMEPARAMS_DESC {\ +{MME_CONFIG_STRING_MME_ID, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{MME_CONFIG_STRING_MME_NAME, NULL, 0, strptr:NULL, defstrval:"OAIMME", TYPE_STRING, 0}, \ +{MME_CONFIG_STRING_MME_M3, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ +} + +#define MME_MME_ID_IDX 0 +#define MME_MME_NAME_IDX 1 +#define MME_ENABLE_MME_M3_IDX 2 + +#define MMEPARAMS_CHECK { \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ +} + + +#define MME_CONFIG_STRING_NETWORK_INTERFACES_CONFIG "NETWORK_INTERFACES" + +#define MME_INTERFACE_NAME_FOR_M3_MME_IDX 0 +#define MME_IPV4_ADDRESS_FOR_M3C_IDX 1 +#define MME_PORT_FOR_M3C_IDX 2 + +/* interface configuration parameters names */ +/* M3 interface configuration parameters names */ +#define MME_CONFIG_STRING_MME_INTERFACE_NAME_FOR_M3_MCE "MME_INTERFACE_NAME_FOR_M3_MCE" +#define MME_CONFIG_STRING_MME_IPV4_ADDRESS_FOR_M3C "MME_IPV4_ADDRESS_FOR_M3C" +#define MME_CONFIG_STRING_MME_PORT_FOR_M3C "MME_PORT_FOR_M3C" + + +#define MME_NETPARAMS_DESC { \ +{MME_CONFIG_STRING_MME_INTERFACE_NAME_FOR_M3_MCE, NULL, 0, strptr:&mme_interface_name_for_m3_mce, defstrval:"lo", TYPE_STRING, 0}, \ +{MME_CONFIG_STRING_MME_IPV4_ADDRESS_FOR_M3C, NULL, 0, strptr:&mme_ipv4_address_for_m3c, defstrval:"127.0.0.18/24", TYPE_STRING, 0}, \ +{MME_CONFIG_STRING_MME_PORT_FOR_M3C, NULL, 0, uptr:&mme_port_for_m3c, defintval:36444L, TYPE_UINT, 0}, \ +} + + + + diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index f73e808865..519d2bef4b 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -33,27 +33,14 @@ #include #include -void *receive_thread(void *args); -Protocol__FlexranMessage *flexran_agent_timeout(void* args); - - int agent_task_created = 0; /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller * and can interact with other itti tasks */ void *flexran_agent_task(void *args){ - - //flexran_agent_info_t *d = (flexran_agent_info_t *) args; - Protocol__FlexranMessage *msg; - void *data; - int size; - err_code_t err_code=0; - int priority = 0; - - MessageDef *msg_p = NULL; - int result; - struct flexran_agent_timer_element_s * elem = NULL; + MessageDef *msg_p = NULL; + int result; itti_mark_task_ready(TASK_FLEXRAN_AGENT); @@ -71,20 +58,6 @@ void *flexran_agent_task(void *args){ case MESSAGE_TEST: LOG_I(FLEXRAN_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p)); break; - - case TIMER_HAS_EXPIRED: - msg = flexran_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); - if (msg != NULL){ - data=flexran_agent_pack_message(msg,&size); - elem = get_timer_entry(msg_p->ittiMsg.timer_has_expired.timer_id); - if (flexran_agent_msg_send(elem->agent_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; - goto error; - } - - LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); - } - break; default: LOG_E(FLEXRAN_AGENT, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); @@ -93,10 +66,6 @@ void *flexran_agent_task(void *args){ result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - continue; - error: - if (err_code != 0) - LOG_E(FLEXRAN_AGENT,"flexran_agent_task: error %d occured\n",err_code); } while (1); return NULL; @@ -202,16 +171,14 @@ int flexran_agent_start(mid_t mod_id) *flexran_agent_register_channel(mod_id, channel, FLEXRAN_AGENT_MAC); */ - /*Initialize the continuous stats update mechanism*/ - flexran_agent_init_cont_stats_update(mod_id); pthread_t t; threadCreate(&t, receive_thread, flexran, "flexran", -1, OAI_PRIORITY_RT); /* Register and initialize the control modules depending on capabilities. * After registering, calling flexran_agent_get_*_xface() tells whether a * control module is operational */ - uint16_t caps = flexran_get_capabilities_mask(mod_id); - LOG_I(FLEXRAN_AGENT, "Agent handles BS ID %ld, capabilities=0x%x => handling%s%s%s%s%s%s%s%s\n", + uint32_t caps = flexran_get_capabilities_mask(mod_id); + LOG_I(FLEXRAN_AGENT, "Agent handles BS ID %ld, capabilities=0x%x => handling%s%s%s%s%s%s%s%s%s\n", flexran_get_bs_id(mod_id), caps, FLEXRAN_CAP_LOPHY(caps) ? " LOPHY" : "", FLEXRAN_CAP_HIPHY(caps) ? " HIPHY" : "", @@ -220,7 +187,8 @@ int flexran_agent_start(mid_t mod_id) FLEXRAN_CAP_RLC(caps) ? " RLC" : "", FLEXRAN_CAP_PDCP(caps) ? " PDCP" : "", FLEXRAN_CAP_SDAP(caps) ? " SDAP" : "", - FLEXRAN_CAP_RRC(caps) ? " RRC" : ""); + FLEXRAN_CAP_RRC(caps) ? " RRC" : "", + FLEXRAN_CAP_S1AP(caps) ? " S1AP" : ""); if (FLEXRAN_CAP_LOPHY(caps) || FLEXRAN_CAP_HIPHY(caps)) { flexran_agent_register_phy_xface(mod_id); @@ -243,11 +211,16 @@ int flexran_agent_start(mid_t mod_id) LOG_I(FLEXRAN_AGENT, "registered PDCP interface/CM for eNB %d\n", mod_id); } + if (FLEXRAN_CAP_S1AP(caps)) { + flexran_agent_register_s1ap_xface(mod_id); + LOG_I(FLEXRAN_AGENT, "registered S1AP interface/CM for eNB %d\n", mod_id); + } + /* * initilize a timer */ - flexran_agent_init_timer(); + flexran_agent_timer_init(mod_id); /* * start the enb agent task for tx and interaction with the underlying network function @@ -288,16 +261,3 @@ error: return 1; } - -Protocol__FlexranMessage *flexran_agent_timeout(void* args){ - - // flexran_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); - //memcpy (timer_args, args, sizeof(*timer_args)); - flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args; - - LOG_UI(FLEXRAN_AGENT, "flexran_agent %d timeout\n", timer_args->mod_id); - //LOG_I(FLEXRAN_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); - //LOG_I(FLEXRAN_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); - - return NULL; -} diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index e50a2be4f6..42295fc111 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -40,6 +40,7 @@ #include "flexran_agent_mac.h" #include "flexran_agent_rrc.h" #include "flexran_agent_pdcp.h" +#include "flexran_agent_s1ap.h" #include "common/utils/LOG/log.h" #include "assertions.h" diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index ac18f16069..dc320ef974 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -21,7 +21,7 @@ /*! \file flexran_agent_common.c * \brief common primitives for all agents - * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein, shahab SHARIAT BAGHERI + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2017 * \version 0.1 */ @@ -38,6 +38,7 @@ #include "flexran_agent_phy.h" #include "flexran_agent_mac.h" #include "flexran_agent_rrc.h" +#include "flexran_agent_s1ap.h" //#include "PHY/extern.h" #include "common/utils/LOG/log.h" #include "flexran_agent_mac_internal.h" @@ -128,6 +129,7 @@ int flexran_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessa hello_msg->bs_id = flexran_get_bs_id(mod_id); hello_msg->has_bs_id = 1; hello_msg->n_capabilities = flexran_get_capabilities(mod_id, &hello_msg->capabilities); + hello_msg->n_splits = flexran_get_splits(mod_id, &hello_msg->splits); *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) @@ -161,6 +163,7 @@ int flexran_agent_destroy_hello(Protocol__FlexranMessage *msg) { free(msg->hello_msg->header); free(msg->hello_msg->capabilities); + free(msg->hello_msg->splits); free(msg->hello_msg); free(msg); return 0; @@ -337,6 +340,9 @@ int flexran_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) { free(reply->cell_config[i]); } + + if (reply->s1ap) + flexran_agent_free_s1ap_cell_config(&reply->s1ap); free(reply->cell_config); free(reply); @@ -598,21 +604,7 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl goto error; ue_config_reply_msg->header = header; - ue_config_reply_msg->n_ue_config = 0; - - if (flexran_agent_get_rrc_xface(mod_id)) - ue_config_reply_msg->n_ue_config = flexran_get_rrc_num_ues(mod_id); - else if (flexran_agent_get_mac_xface(mod_id)) - ue_config_reply_msg->n_ue_config = flexran_get_mac_num_ues(mod_id); - - if (flexran_agent_get_rrc_xface(mod_id) && flexran_agent_get_mac_xface(mod_id) - && flexran_get_rrc_num_ues(mod_id) != flexran_get_mac_num_ues(mod_id)) { - const int nrrc = flexran_get_rrc_num_ues(mod_id); - const int nmac = flexran_get_mac_num_ues(mod_id); - ue_config_reply_msg->n_ue_config = nrrc < nmac ? nrrc : nmac; - LOG_E(FLEXRAN_AGENT, "%s(): different numbers of UEs in RRC (%d) and MAC (%d), reporting for %lu UEs\n", - __func__, nrrc, nmac, ue_config_reply_msg->n_ue_config); - } + ue_config_reply_msg->n_ue_config = flexran_agent_get_num_ues(mod_id); Protocol__FlexUeConfig **ue_config; @@ -769,9 +761,12 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F cell_conf[i]->carrier_index = i; cell_conf[i]->has_carrier_index = 1; } - + enb_config_reply_msg->cell_config=cell_conf; } + + if (flexran_agent_get_s1ap_xface(mod_id)) + flexran_agent_fill_s1ap_cell_config(mod_id, &enb_config_reply_msg->s1ap); *msg = malloc(sizeof(Protocol__FlexranMessage)); @@ -910,14 +905,19 @@ int flexran_agent_handle_enb_config_reply(mid_t mod_id, const void *params, Prot if (flexran_agent_get_mac_xface(mod_id) && enb_config->cell_config[0]->slice_config) { prepare_update_slice_config(mod_id, enb_config->cell_config[0]->slice_config); - //} else { - // initiate_soft_restart(mod_id, enb_config->cell_config[0]); - } - - if (flexran_agent_get_rrc_xface(mod_id) && enb_config->cell_config[0]->has_x2_ho_net_control) { - if (flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control) < 0) { + } else if (enb_config->cell_config[0]->has_eutra_band + && enb_config->cell_config[0]->has_dl_freq + && enb_config->cell_config[0]->has_ul_freq + && enb_config->cell_config[0]->has_dl_bandwidth) { + initiate_soft_restart(mod_id, enb_config->cell_config[0]); + } else if (flexran_agent_get_rrc_xface(mod_id) + && enb_config->cell_config[0]->has_x2_ho_net_control) { + LOG_I(FLEXRAN_AGENT, + "setting X2 HO NetControl to %d\n", + enb_config->cell_config[0]->x2_ho_net_control); + const int rc = flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control); + if (rc < 0) LOG_E(FLEXRAN_AGENT, "Error in configuring X2 handover controlled by network"); - } } *msg = NULL; @@ -935,3 +935,24 @@ int flexran_agent_handle_ue_config_reply(mid_t mod_id, const void *params, Proto *msg = NULL; return 0; } + +int flexran_agent_get_num_ues(mid_t mod_id) { + const int has_rrc = flexran_agent_get_rrc_xface(mod_id) != NULL; + const int has_mac = flexran_agent_get_mac_xface(mod_id) != NULL; + DevAssert(has_rrc || has_mac); + if (has_rrc && !has_mac) + return flexran_get_rrc_num_ues(mod_id); + if (!has_rrc && has_mac) + return flexran_get_mac_num_ues(mod_id); + + /* has both */ + const int nrrc = flexran_get_rrc_num_ues(mod_id); + const int nmac = flexran_get_mac_num_ues(mod_id); + if (nrrc != nmac) { + const int n_ue = nrrc < nmac ? nrrc : nmac; + LOG_E(FLEXRAN_AGENT, "%s(): different numbers of UEs in RRC (%d) and MAC (%d), reporting for %d UEs\n", + __func__, nrrc, nmac, n_ue); + return n_ue; + } + return nrrc; +} diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index f116eb6591..fe7b49107c 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -150,24 +150,25 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, uint32_t size); /* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */ -Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args); +Protocol__FlexranMessage *flexran_agent_handle_timed_task( + mid_t mod_id, + Protocol__FlexranMessage *msg); /*Top level Statistics hanlder*/ +Protocol__FlexranMessage *flexran_agent_send_stats_reply( + mid_t mod_id, + const Protocol__FlexranMessage *msg); + int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); /* Function to be used to handle reply message . */ -int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); +int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const Protocol__FlexStatsRequest *stats_req, Protocol__FlexranMessage **msg); int flexran_agent_destroy_stats_reply(Protocol__FlexranMessage *msg); /* Top level Statistics request protocol message constructor and destructor */ -int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); +//int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg); -err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id); - -err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) ; -err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id); - /* Handle a received eNB config reply message as an "order" to reconfigure. It * does not come as a reconfiguration message as this is a "structured" * ProtoBuf message (as opposed to "unstructured" YAML). There is no destructor @@ -183,4 +184,8 @@ int flexran_agent_handle_enb_config_reply(mid_t mod_id, const void* params, Prot * request message. */ int flexran_agent_handle_ue_config_reply(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg); +/* Return the number of UEs in the BS of this agent across RRC/MAC. If they + * disagree, prints an error and returns the minimum of both. */ +int flexran_agent_get_num_ues(mid_t mod_id); + #endif diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index 706688286d..bc1976abd9 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -107,36 +107,6 @@ typedef uint8_t lcid_t; typedef int32_t err_code_t; -/*---------Timer Enums --------- */ - -typedef enum { - /* oneshot timer: */ - FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0, - - /* periodic timer */ - FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 1, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 2, - - /* Max number of states available */ - FLEXRAN_AGENT_TIMER_TYPE_MAX, -} flexran_agent_timer_type_t; - - -typedef enum { - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2, - - /* Max number of states available */ - FLEXRAN_AGENT_TIMER_STATE_MAX, -} flexran_agent_timer_state_t; #define FLEXRAN_CAP_LOPHY(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)) > 0) #define FLEXRAN_CAP_HIPHY(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)) > 0) @@ -146,6 +116,7 @@ typedef enum { #define FLEXRAN_CAP_PDCP(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)) > 0) #define FLEXRAN_CAP_SDAP(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)) > 0) #define FLEXRAN_CAP_RRC(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC)) > 0) +#define FLEXRAN_CAP_S1AP(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP)) > 0) typedef enum { ENB_NORMAL_OPERATION = 0x0, @@ -193,38 +164,4 @@ typedef struct { } agent_reconf_rrc; - -/* These structs will be used to give - instructions for the type of stats reports - we need to create */ - - -typedef struct { - uint16_t ue_rnti; - uint32_t ue_report_flags; /* Indicates the report elements - required for this UE id. See - FlexRAN specification 1.2.4.2 */ -} ue_report_type_t; - -typedef struct { - uint16_t cc_id; - uint32_t cc_report_flags; /* Indicates the report elements - required for this CC index. See - FlexRAN specification 1.2.4.3 */ -} cc_report_type_t; - -typedef struct { - int nr_ue; - ue_report_type_t *ue_report_type; - int nr_cc; - cc_report_type_t *cc_report_type; -} report_config_t; - -typedef struct stats_request_config_s{ - uint8_t report_type; - uint8_t report_frequency; - uint16_t period; /*In number of subframes*/ - report_config_t *config; -} stats_request_config_t; - #endif diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index e1dec8506c..119bc3d44c 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -35,6 +35,7 @@ #include "flexran_agent_mac_defs.h" #include "flexran_agent_rrc_defs.h" #include "flexran_agent_pdcp_defs.h" +#include "flexran_agent_s1ap_defs.h" /* Control module interface for the communication of the PHY control module with the agent */ AGENT_PHY_xface *flexran_agent_get_phy_xface(mid_t mod_id); @@ -48,6 +49,9 @@ AGENT_RRC_xface *flexran_agent_get_rrc_xface(mid_t mod_id); /* Control module interface for the communication of the RRC Control Module with the agent */ AGENT_PDCP_xface *flexran_agent_get_pdcp_xface(mid_t mod_id); +/* Control module interface for the communication of the S1AP Control Module with the agent */ +AGENT_S1AP_xface *flexran_agent_get_s1ap_xface(mid_t mod_id); + /* Requried to know which UEs had a harq updated over some subframe */ extern int harq_pid_updated[NUM_MAX_UE][8]; extern int harq_pid_round[NUM_MAX_UE][8]; diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index e089675b62..d991078cf7 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -31,6 +31,7 @@ #include "flexran_agent_mac.h" #include "flexran_agent_rrc.h" #include "flexran_agent_pdcp.h" +#include "flexran_agent_s1ap.h" #include "flexran_agent_timer.h" #include "flexran_agent_ran_api.h" #include "common/utils/LOG/log.h" @@ -154,39 +155,20 @@ void * flexran_agent_pack_message(Protocol__FlexranMessage *msg, return NULL; } -Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args) { +Protocol__FlexranMessage *flexran_agent_handle_timed_task( + mid_t mod_id, + Protocol__FlexranMessage *msg) { err_code_t err_code; - flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args; - Protocol__FlexranMessage *timed_task, *reply_message; - timed_task = timer_args->msg; - err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); - if ( err_code < 0 ){ - goto error; + Protocol__FlexranMessage *reply_message; + err_code = ((*agent_messages_callback[msg->msg_case-1][msg->msg_dir-1])( + mod_id, msg, &reply_message)); + if (err_code < 0) { + LOG_E(FLEXRAN_AGENT, "could not handle message: errno %d occured\n", err_code); + return NULL; } return reply_message; - - error: - LOG_E(FLEXRAN_AGENT,"errno %d occured\n",err_code); - return NULL; -} - -Protocol__FlexranMessage* flexran_agent_process_timeout(long timer_id, void* timer_args){ - - struct flexran_agent_timer_element_s *found = get_timer_entry(timer_id); - - if (found == NULL ) goto error; - LOG_D(FLEXRAN_AGENT, "Found the entry (%p): timer_id is 0x%lx 0x%lx\n", found, timer_id, found->timer_id); - - if (timer_args == NULL) - LOG_W(FLEXRAN_AGENT,"null timer args\n"); - - return found->cb(timer_args); - - error: - LOG_E(FLEXRAN_AGENT, "can't get the timer element\n"); - return NULL; } err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) { @@ -196,335 +178,175 @@ err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) /* Top Level Statistics Report +*/ - */ - - - -int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ - - // TODO: Must deal with sanitization of input - // TODO: Must check if RNTIs and cell ids of the request actually exist - // TODO: Must resolve conflicts among stats requests - - int i; - err_code_t err_code = 0; - xid_t xid; - uint32_t usec_interval, sec_interval; - - //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 - int enb_id = mod_id; - - //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - //UE_list_t *eNB_UE_list= &eNB->UE_list; - - report_config_t report_config; - - uint32_t ue_flags = 0; - uint32_t c_flags = 0; - +int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { + *msg = NULL; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; - Protocol__FlexStatsRequest *stats_req = input->stats_request_msg; - xid = (stats_req->header)->xid; + const xid_t xid = stats_req->header->xid; - // Check the type of request that is made - switch(stats_req->body_case) { - case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; - Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) { - /*Disable both periodic and continuous updates*/ - // flexran_agent_disable_cont_stats_update(mod_id); - flexran_agent_destroy_timer_by_task_id(xid); - *msg = NULL; - return 0; - } else { //One-off, periodical or continuous reporting - //Set the proper flags - ue_flags = comp_req->ue_report_flags; - c_flags = comp_req->cell_report_flags; - //Create a list of all eNB RNTIs and cells + if (stats_req->body_case != PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST) { + LOG_E(FLEXRAN_AGENT, "only complete stats are supported at the moment\n"); + return -1; + } + Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - //Set the number of UEs and create list with their RNTIs stats configs - report_config.nr_ue = 0; - if (flexran_agent_get_rrc_xface(mod_id)) - report_config.nr_ue = flexran_get_rrc_num_ues(mod_id); - else if (flexran_agent_get_mac_xface(mod_id)) - report_config.nr_ue = flexran_get_mac_num_ues(mod_id); - - if (flexran_agent_get_rrc_xface(mod_id) && flexran_agent_get_mac_xface(mod_id) - && flexran_get_rrc_num_ues(mod_id) != flexran_get_mac_num_ues(mod_id)) { - const int nrrc = flexran_get_rrc_num_ues(mod_id); - const int nmac = flexran_get_mac_num_ues(mod_id); - report_config.nr_ue = nrrc < nmac ? nrrc : nmac; - LOG_E(FLEXRAN_AGENT, "%s(): different numbers of UEs in RRC (%d) and MAC (%d), reporting for %d UEs\n", - __func__, nrrc, nmac, report_config.nr_ue); - } - report_config.ue_report_type = malloc(sizeof(ue_report_type_t) * report_config.nr_ue); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - if (flexran_agent_get_rrc_xface(mod_id)) { - rnti_t rntis[report_config.nr_ue]; - flexran_get_rrc_rnti_list(mod_id, rntis, report_config.nr_ue); - for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = rntis[i]; - report_config.ue_report_type[i].ue_report_flags = ue_flags; - } - } - if (flexran_agent_get_mac_xface(mod_id) && !flexran_agent_get_rrc_xface(mod_id)) { - for (i = 0; i < report_config.nr_ue; i++) { - const int UE_id = flexran_get_mac_ue_id(mod_id, i); - report_config.ue_report_type[i].ue_rnti = flexran_get_mac_ue_crnti(enb_id, UE_id); - report_config.ue_report_type[i].ue_report_flags = ue_flags; - } - } - //Set the number of CCs and create a list with the cell stats configs - report_config.nr_cc = MAX_NUM_CCs; - report_config.cc_report_type = malloc(sizeof(cc_report_type_t) * report_config.nr_cc); - if (report_config.cc_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_cc; i++) { - //TODO: Must fill in the proper cell ids - report_config.cc_report_type[i].cc_id = i; - report_config.cc_report_type[i].cc_report_flags = c_flags; - } - /* Check if request was periodical */ - if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) { - /* Create a one off flexran message as an argument for the periodical task */ - Protocol__FlexranMessage *timer_msg = NULL; - stats_request_config_t request_config; - request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; - request_config.period = 0; - /* Need to make sure that the ue flags are saved (Bug) */ - if (report_config.nr_ue == 0) { - report_config.nr_ue = 1; - report_config.ue_report_type = malloc(sizeof(ue_report_type_t)); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - report_config.ue_report_type[0].ue_rnti = 0; // Dummy value - report_config.ue_report_type[0].ue_report_flags = ue_flags; - } - request_config.config = &report_config; - if (flexran_agent_stats_request(enb_id, xid, &request_config, &timer_msg) == -1) { - err_code = -100; - goto error; - } - /* Create a timer */ - long timer_id = 0; - flexran_agent_timer_args_t *timer_args = malloc(sizeof(flexran_agent_timer_args_t)); - memset (timer_args, 0, sizeof(flexran_agent_timer_args_t)); - timer_args->mod_id = enb_id; - timer_args->msg = timer_msg; - /*Convert subframes to usec time*/ - usec_interval = 1000*comp_req->sf; - sec_interval = 0; - /*add seconds if required*/ - if (usec_interval >= 1000*1000) { - sec_interval = usec_interval/(1000*1000); - usec_interval = usec_interval%(1000*1000); - } - flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT, - enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, - flexran_agent_handle_timed_task,(void*) timer_args, &timer_id); - } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { - /*If request was for continuous updates, disable the previous configuration and - set up a new one*/ - flexran_agent_disable_cont_stats_update(mod_id); - stats_request_config_t request_config; - request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; - request_config.period = 0; - /* Need to make sure that the ue flags are saved (Bug) */ - if (report_config.nr_ue == 0) { - report_config.nr_ue = 1; - report_config.ue_report_type = malloc(sizeof(ue_report_type_t)); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - report_config.ue_report_type[0].ue_rnti = 0; // Dummy value - report_config.ue_report_type[0].ue_report_flags = ue_flags; - } - request_config.config = &report_config; - flexran_agent_enable_cont_stats_update(enb_id, xid, &request_config); - } - } - break; - case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; - Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request; - // UE report config will be blank - report_config.nr_ue = 0; - report_config.ue_report_type = NULL; - report_config.nr_cc = cell_req->n_cell; - report_config.cc_report_type = malloc(sizeof(cc_report_type_t) * report_config.nr_cc); - if (report_config.cc_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_cc; i++) { - //TODO: Must fill in the proper cell ids - report_config.cc_report_type[i].cc_id = cell_req->cell[i]; - report_config.cc_report_type[i].cc_report_flags = cell_req->flags; - } - break; - case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:; - Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request; - // Cell report config will be blank - report_config.nr_cc = 0; - report_config.cc_report_type = NULL; - report_config.nr_ue = ue_req->n_rnti; - report_config.ue_report_type = malloc(sizeof(ue_report_type_t) * report_config.nr_ue); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_ue; i++) { - const int UE_id = flexran_get_mac_ue_id(mod_id, i); - report_config.ue_report_type[i].ue_rnti = ue_req->rnti[UE_id]; - report_config.ue_report_type[i].ue_report_flags = ue_req->flags; - } - break; + switch (comp_req->report_frequency) { + case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF: + flexran_agent_destroy_timer(mod_id, xid); + return 0; + case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE: + LOG_E(FLEXRAN_AGENT, "one-shot timer not implemented yet\n"); + return -1; + case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL: + /* Create a one off flexran message as an argument for the periodical task */ + LOG_I(FLEXRAN_AGENT, "periodical timer xid %d cell_flags %d ue_flags %d\n", + xid, comp_req->cell_report_flags, comp_req->ue_report_flags); + flexran_agent_create_timer(mod_id, comp_req->sf, + FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, + flexran_agent_send_stats_reply, input); + /* return 1: do not dispose comp_req message we received, we still need it */ + return 1; + case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS: + LOG_E(FLEXRAN_AGENT, "unsupported report frequency continuous\n"); + return -1; default: - //TODO: Add appropriate error code - err_code = -100; - goto error; + LOG_E(FLEXRAN_AGENT, "unknown report frequency\n"); + return -1; } - - if (flexran_agent_stats_reply(enb_id, xid, &report_config, msg )) { - err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; - goto error; - } - - if (report_config.ue_report_type) - free(report_config.ue_report_type); - if (report_config.cc_report_type) - free(report_config.cc_report_type); - - return 0; - - error : - LOG_E(FLEXRAN_AGENT, "%s(): errno %d occured\n", __func__, err_code); - return err_code; } /* Top level reply */ +Protocol__FlexranMessage *flexran_agent_send_stats_reply( + mid_t mod_id, + const Protocol__FlexranMessage *msg) { + const Protocol__FlexStatsRequest *stats_req = msg->stats_request_msg; + const xid_t xid = stats_req->header->xid; -int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg){ + Protocol__FlexranMessage *reply = NULL; + err_code_t rc = flexran_agent_stats_reply(mod_id, xid, stats_req, &reply); + if (rc < 0) { + LOG_E(FLEXRAN_AGENT, "%s(): errno %d occured, cannot send stats_reply\n", + __func__, rc); + return NULL; + } + return reply; +} + +int flexran_agent_stats_reply(mid_t enb_id, + xid_t xid, + const Protocol__FlexStatsRequest *stats_req, + Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header = NULL; Protocol__FlexUeStatsReport **ue_report = NULL; Protocol__FlexCellStatsReport **cell_report = NULL; Protocol__FlexStatsReply *stats_reply_msg = NULL; err_code_t err_code = PROTOCOL__FLEXRAN_ERR__UNEXPECTED; - int i,j; + AssertFatal(stats_req->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST, + "%s() handles only complete stats requests\n", + __func__); + const uint32_t cell_flags = stats_req->complete_stats_request->cell_report_flags; + const uint32_t ue_flags = stats_req->complete_stats_request->ue_report_flags; - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) { - goto error; + int n_ue = flexran_agent_get_num_ues(enb_id); + + rnti_t rntis[n_ue]; + if (flexran_agent_get_rrc_xface(enb_id)) + flexran_get_rrc_rnti_list(enb_id, rntis, n_ue); + if (flexran_agent_get_mac_xface(enb_id) && !flexran_agent_get_rrc_xface(enb_id)) { + for (int i = 0; i < n_ue; i++) { + const int UE_id = flexran_get_mac_ue_id(enb_id, i); + rntis[i] = flexran_get_mac_ue_crnti(enb_id, UE_id); + } } - stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); - - if (stats_reply_msg == NULL) { - goto error; - } - - protocol__flex_stats_reply__init(stats_reply_msg); - stats_reply_msg->header = header; - - stats_reply_msg->n_ue_report = report_config->nr_ue; - stats_reply_msg->n_cell_report = report_config->nr_cc; - - // UE report - - ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue); + int n_cc = MAX_NUM_CCs; + ue_report = calloc(n_ue, sizeof(Protocol__FlexUeStatsReport *)); if (ue_report == NULL) { goto error; } - - for (i = 0; i < report_config->nr_ue; i++) { - - ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); - if (ue_report[i] == NULL) { - goto error; - } - protocol__flex_ue_stats_report__init(ue_report[i]); - ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; - ue_report[i]->has_rnti = 1; - ue_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */ - + for (int i = 0; i < n_ue; i++) { + ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); + if (ue_report[i] == NULL) { + goto error; + } + protocol__flex_ue_stats_report__init(ue_report[i]); + ue_report[i]->rnti = rntis[i]; + ue_report[i]->has_rnti = 1; + ue_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */ } - // cell rpoert - - cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc); + cell_report = calloc(n_cc, sizeof(Protocol__FlexCellStatsReport *)); if (cell_report == NULL) { goto error; } - - for (i = 0; i < report_config->nr_cc; i++) { - - cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); - if(cell_report[i] == NULL) { - goto error; - } - - protocol__flex_cell_stats_report__init(cell_report[i]); - cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; - cell_report[i]->has_carrier_index = 1; - cell_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */ - + for (int i = 0; i < n_cc; i++) { + cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); + if(cell_report[i] == NULL) { + goto error; + } + protocol__flex_cell_stats_report__init(cell_report[i]); + cell_report[i]->carrier_index = i; + cell_report[i]->has_carrier_index = 1; + cell_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */ } /* MAC reply split */ if (flexran_agent_get_mac_xface(enb_id) - && flexran_agent_mac_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) { + && (flexran_agent_mac_stats_reply_ue(enb_id, ue_report, n_ue, ue_flags) < 0 + || flexran_agent_mac_stats_reply_cell(enb_id, cell_report, n_cc, cell_flags) < 0)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } /* RRC reply split */ if (flexran_agent_get_rrc_xface(enb_id) - && flexran_agent_rrc_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) { + && flexran_agent_rrc_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } /* PDCP reply split */ if (flexran_agent_get_pdcp_xface(enb_id) - && flexran_agent_pdcp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) { + && flexran_agent_pdcp_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } /* GTP reply split, currently performed through RRC module */ if (flexran_agent_get_rrc_xface(enb_id) - && flexran_agent_rrc_gtp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) { + && flexran_agent_rrc_gtp_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } - stats_reply_msg->cell_report = cell_report; - stats_reply_msg->ue_report = ue_report; - - *msg = malloc(sizeof(Protocol__FlexranMessage)); - if(*msg == NULL) { + /* S1AP statistics, depends on RRC to find S1AP ID */ + if (flexran_agent_get_rrc_xface(enb_id) + && flexran_agent_get_s1ap_xface(enb_id) + && flexran_agent_s1ap_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) { + goto error; + } + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); + AssertFatal(stats_reply_msg, "no memory for stats_reply_msg\n"); + protocol__flex_stats_reply__init(stats_reply_msg); + stats_reply_msg->header = header; + stats_reply_msg->n_ue_report = n_ue; + stats_reply_msg->ue_report = ue_report; + stats_reply_msg->n_cell_report = n_cc; + stats_reply_msg->cell_report = cell_report; + + *msg = malloc(sizeof(Protocol__FlexranMessage)); + AssertFatal(*msg, "no memory for stats_reply container msg\n"); protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; @@ -546,7 +368,7 @@ error : } if (ue_report != NULL) { - for (j = 0; j < report_config->nr_ue; j++) { + for (int j = 0; j < n_ue; j++) { if (ue_report[j] != NULL) { free(ue_report[j]); } @@ -556,7 +378,7 @@ error : } if (cell_report != NULL) { - for (j = 0; j < report_config->nr_cc; j++) { + for (int j = 0; j < n_cc; j++) { if (cell_report[j] != NULL) { free(cell_report[j]); } @@ -572,6 +394,7 @@ error : Top Level Request */ +/* int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, @@ -678,6 +501,7 @@ int flexran_agent_stats_request(mid_t mod_id, //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } +*/ int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG) @@ -708,6 +532,8 @@ int flexran_agent_destroy_stats_reply(Protocol__FlexranMessage *msg) flexran_agent_mac_destroy_stats_reply(msg->stats_reply_msg); flexran_agent_rrc_destroy_stats_reply(msg->stats_reply_msg); flexran_agent_pdcp_destroy_stats_reply(msg->stats_reply_msg); + flexran_agent_rrc_gtp_destroy_stats_reply(msg->stats_reply_msg); + flexran_agent_s1ap_destroy_stats_reply(msg->stats_reply_msg); for (int i = 0; i < msg->stats_reply_msg->n_cell_report; ++i) free(msg->stats_reply_msg->cell_report[i]); for (int i = 0; i < msg->stats_reply_msg->n_ue_report; ++i) @@ -719,88 +545,3 @@ int flexran_agent_destroy_stats_reply(Protocol__FlexranMessage *msg) free(msg); return 0; } - -err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id) { - /*Disable the continuous updates for the MAC*/ - if (pthread_mutex_lock(stats_context[mod_id].mutex)) { - goto error; - } - stats_context[mod_id].cont_update = 0; - stats_context[mod_id].xid = 0; - if (stats_context[mod_id].stats_req != NULL) { - flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req); - } - if (stats_context[mod_id].prev_stats_reply != NULL) { - flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); - } - if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { - goto error; - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id); - return -1; - -} - -err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, - xid_t xid, stats_request_config_t *stats_req) { - - if (pthread_mutex_lock(stats_context[mod_id].mutex)) { - goto error; - } - - Protocol__FlexranMessage *req_msg = NULL; - - flexran_agent_stats_request(mod_id, xid, stats_req, &req_msg); - - if (req_msg != NULL) { - stats_context[mod_id].stats_req = req_msg; - stats_context[mod_id].prev_stats_reply = NULL; - - stats_context[mod_id].cont_update = 1; - stats_context[mod_id].xid = xid; - } - - if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { - goto error; - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id); - return -1; -} - - -err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id) { - - - /*Initially the continuous update is set to false*/ - stats_context[mod_id].cont_update = 0; - stats_context[mod_id].is_initialized = 1; - stats_context[mod_id].stats_req = NULL; - stats_context[mod_id].prev_stats_reply = NULL; - stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t)); - if (stats_context[mod_id].mutex == NULL) - goto error; - if (pthread_mutex_init(stats_context[mod_id].mutex, NULL) != 0) - goto error; - - return 0; - - error: - return -1; -} - -err_code_t flexran_agent_destroy_cont_stats_update(mid_t mod_id) { - - stats_context[mod_id].cont_update = 0; - stats_context[mod_id].is_initialized = 0; - flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req); - flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); - free(stats_context[mod_id].mutex); - - return 1; -} diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 221786965d..a66081d99f 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -28,6 +28,8 @@ #include #include "flexran_agent_ran_api.h" +#include "s1ap_eNB_ue_context.h" +#include "s1ap_eNB_management_procedures.h" static inline int phy_is_present(mid_t mod_id, uint8_t cc_id) { return RC.eNB && RC.eNB[mod_id] && RC.eNB[mod_id][cc_id]; @@ -3002,6 +3004,14 @@ int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index) { return ue_context_p->ue_context.e_rab[index].param.gtp_teid; } +uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti) +{ + if (!rrc_is_present(mod_id)) return 0; + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + if (!ue_context_p) return -1; + return ue_context_p->ue_context.eNB_ue_s1ap_id; +} + /**************************** SLICING ****************************/ int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id) { if (!mac_is_present(mod_id)) return -1; @@ -3470,6 +3480,195 @@ int flexran_set_ul_slice_scheduler(mid_t mod_id, int slice_idx, char *name) { return RC.mac[mod_id]->slice_info.ul[slice_idx].sched_cb != NULL; } +/************************** S1AP **************************/ +int flexran_get_s1ap_mme_pending(mid_t mod_id){ + if (!rrc_is_present(mod_id)) return -1; + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return -1; + return s1ap->s1ap_mme_pending_nb; +} + +int flexran_get_s1ap_mme_connected(mid_t mod_id){ + if (!rrc_is_present(mod_id)) return -1; + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return -1; + return s1ap->s1ap_mme_associated_nb; +} + +char* flexran_get_s1ap_enb_s1_ip(mid_t mod_id){ + if (!rrc_is_present(mod_id)) return NULL; + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return NULL; + if (s1ap->eNB_s1_ip.ipv4) + return &s1ap->eNB_s1_ip.ipv4_address[0]; + if (s1ap->eNB_s1_ip.ipv6) + return &s1ap->eNB_s1_ip.ipv6_address[0]; + return NULL; +} + +char* flexran_get_s1ap_enb_name(mid_t mod_id){ + if (!rrc_is_present(mod_id)) return NULL; + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return NULL; + return s1ap->eNB_name; +} + +int flexran_get_s1ap_nb_mme(mid_t mod_id) { + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return 0; + struct s1ap_eNB_mme_data_s *mme = NULL; + int count = 0; + RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head) { + count++; + } + return count; +} + +int flexran_get_s1ap_nb_ue(mid_t mod_id) { + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return 0; + struct s1ap_eNB_ue_context_s *ue = NULL; + int count = 0; + RB_FOREACH(ue, s1ap_ue_map, &s1ap->s1ap_ue_head) { + count++; + } + return count; +} + +int flexran_get_s1ap_mme_conf(mid_t mod_id, mid_t mme_index, Protocol__FlexS1apMme * mme_conf){ + if (!rrc_is_present(mod_id)) return -1; + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return -1; + + struct served_gummei_s *gummei_p = NULL; + struct plmn_identity_s *served_plmn_p = NULL; + struct served_group_id_s *group_id_p = NULL; + struct mme_code_s *mme_code_p = NULL; + int i = 0; + Protocol__FlexGummei **served_gummeis; + Protocol__FlexPlmn **requested_plmns; + + struct s1ap_eNB_mme_data_s *mme = NULL; + + RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head){ + if (mme_index == 0) break; + mme_index--; + } + if (mme_index > 0) return -1; + + if (mme->mme_s1_ip.ipv4) { + mme_conf->s1_ip = (char*) &mme->mme_s1_ip.ipv4_address[0]; + } else if (mme->mme_s1_ip.ipv6) { + mme_conf->s1_ip = (char*) &mme->mme_s1_ip.ipv6_address[0]; + } + mme_conf->name = mme->mme_name; + mme_conf->has_state = 1; + mme_conf->state = mme->state; + + mme_conf->n_served_gummeis = 0; + STAILQ_FOREACH(gummei_p, &mme->served_gummei, next) { + mme_conf->n_served_gummeis++; + } + if (mme_conf->n_served_gummeis > 0) { + served_gummeis = calloc(mme_conf->n_served_gummeis, sizeof(Protocol__FlexGummei*)); + if(served_gummeis == NULL) return -1; + + STAILQ_FOREACH(gummei_p, &mme->served_gummei, next) { + served_plmn_p = STAILQ_FIRST(&gummei_p->served_plmns); + group_id_p = STAILQ_FIRST(&gummei_p->served_group_ids); + mme_code_p = STAILQ_FIRST(&gummei_p->mme_codes); + + served_gummeis[i] = malloc(sizeof(Protocol__FlexGummei)); + if (!served_gummeis[i]) return -1; + protocol__flex_gummei__init(served_gummeis[i]); + served_gummeis[i]->plmn = malloc(sizeof(Protocol__FlexPlmn)); + if (!served_gummeis[i]->plmn) return -1; + protocol__flex_plmn__init(served_gummeis[i]->plmn); + + if (served_plmn_p) { + served_gummeis[i]->plmn->has_mcc = 1; + served_gummeis[i]->plmn->mcc = served_plmn_p->mcc; + served_gummeis[i]->plmn->has_mnc = 1; + served_gummeis[i]->plmn->mnc = served_plmn_p->mnc; + served_gummeis[i]->plmn->has_mnc_length = 1; + served_gummeis[i]->plmn->mnc_length = served_plmn_p-> mnc_digit_length; + STAILQ_NEXT(served_plmn_p, next); + } + if (group_id_p) { + served_gummeis[i]->has_mme_group_id = 1; + served_gummeis[i]->mme_group_id = group_id_p->mme_group_id; + STAILQ_NEXT(group_id_p, next); + } + if (mme_code_p){ + served_gummeis[i]->has_mme_code = 1; + served_gummeis[i]->mme_code = mme_code_p->mme_code; + STAILQ_NEXT(mme_code_p, next); + } + i++; + } + + mme_conf->served_gummeis = served_gummeis; + } + + // requested PLMNS + mme_conf->n_requested_plmns = mme->broadcast_plmn_num; + if (mme_conf->n_requested_plmns > 0){ + requested_plmns = calloc(mme_conf->n_requested_plmns, sizeof(Protocol__FlexPlmn*)); + if(requested_plmns == NULL) return -1; + for(int i = 0; i < mme_conf->n_requested_plmns; i++) { + requested_plmns[i] = malloc(sizeof(Protocol__FlexPlmn)); + if (!requested_plmns[i]) return -1; + protocol__flex_plmn__init(requested_plmns[i]); + requested_plmns[i]->mcc = s1ap->mcc[mme->broadcast_plmn_index[i]]; + requested_plmns[i]->has_mcc = 1; + requested_plmns[i]->mnc = s1ap->mnc[mme->broadcast_plmn_index[i]]; + requested_plmns[i]->has_mnc = 1; + requested_plmns[i]->mnc_length = s1ap->mnc_digit_length[mme->broadcast_plmn_index[i]]; + requested_plmns[i]->has_mnc_length = 1; + } + mme_conf->requested_plmns = requested_plmns; + } + + mme_conf->has_rel_capacity = 1; + mme_conf->rel_capacity = mme->relative_mme_capacity; + return 0; +} + +int flexran_get_s1ap_ue(mid_t mod_id, rnti_t rnti, Protocol__FlexS1apUe * ue_conf){ + if (!rrc_is_present(mod_id)) return -1; + s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id); + if (!s1ap) return -1; + + uint32_t enb_ue_s1ap_id = flexran_get_rrc_enb_ue_s1ap_id(mod_id, rnti); + struct s1ap_eNB_ue_context_s *ue = NULL; + RB_FOREACH(ue, s1ap_ue_map, &s1ap->s1ap_ue_head){ + if (ue->eNB_ue_s1ap_id == enb_ue_s1ap_id) break; + } + if (ue == NULL) return -1; + + if (ue->mme_ref->mme_s1_ip.ipv4) + ue_conf->mme_s1_ip = (char*) &ue->mme_ref->mme_s1_ip.ipv4_address[0]; + else if (ue->mme_ref->mme_s1_ip.ipv6) + ue_conf->mme_s1_ip = (char*) &ue->mme_ref->mme_s1_ip.ipv6_address[0]; + + ue_conf->has_enb_ue_s1ap_id = 1; + ue_conf->enb_ue_s1ap_id = ue->eNB_ue_s1ap_id; + ue_conf->has_mme_ue_s1ap_id = 1; + ue_conf->mme_ue_s1ap_id = ue->mme_ue_s1ap_id; + + ue_conf->selected_plmn = malloc(sizeof(Protocol__FlexPlmn)); + if (!ue_conf->selected_plmn) return -1; + protocol__flex_plmn__init(ue_conf->selected_plmn); + + ue_conf->selected_plmn->has_mcc = 1; + ue_conf->selected_plmn->mcc = s1ap->mcc[ue->selected_plmn_identity]; + ue_conf->selected_plmn->has_mnc = 1; + ue_conf->selected_plmn->mnc = s1ap->mnc[ue->selected_plmn_identity]; + ue_conf->selected_plmn->has_mnc_length = 1; + ue_conf->selected_plmn->mnc_length = s1ap->mnc_digit_length[ue->selected_plmn_identity]; + return 0; +} + /**************************** General BS info ****************************/ uint64_t flexran_get_bs_id(mid_t mod_id) { if (!rrc_is_present(mod_id)) return 0; @@ -3488,15 +3687,15 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps) case ngran_eNB_CU: case ngran_ng_eNB_CU: case ngran_gNB_CU: - n_caps = 3; + n_caps = 4; *caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability)); AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n", n_caps * sizeof(Protocol__FlexBsCapability)); (*caps)[0] = PROTOCOL__FLEX_BS_CAPABILITY__PDCP; (*caps)[1] = PROTOCOL__FLEX_BS_CAPABILITY__SDAP; (*caps)[2] = PROTOCOL__FLEX_BS_CAPABILITY__RRC; + (*caps)[3] = PROTOCOL__FLEX_BS_CAPABILITY__S1AP; break; - case ngran_eNB_DU: case ngran_gNB_DU: n_caps = 5; @@ -3509,11 +3708,10 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps) (*caps)[3] = PROTOCOL__FLEX_BS_CAPABILITY__HIMAC; (*caps)[4] = PROTOCOL__FLEX_BS_CAPABILITY__RLC; break; - case ngran_eNB: case ngran_ng_eNB: case ngran_gNB: - n_caps = 8; + n_caps = 9; *caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability)); AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n", n_caps * sizeof(Protocol__FlexBsCapability)); @@ -3525,48 +3723,81 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps) (*caps)[5] = PROTOCOL__FLEX_BS_CAPABILITY__PDCP; (*caps)[6] = PROTOCOL__FLEX_BS_CAPABILITY__SDAP; (*caps)[7] = PROTOCOL__FLEX_BS_CAPABILITY__RRC; + (*caps)[8] = PROTOCOL__FLEX_BS_CAPABILITY__S1AP; break; + case ngran_eNB_MBMS_STA: + AssertFatal(0, "MBMS STA not supported by FlexRAN!\n"); + break; } return n_caps; } -uint16_t flexran_get_capabilities_mask(mid_t mod_id) { +uint32_t flexran_get_capabilities_mask(mid_t mod_id) { if (!rrc_is_present(mod_id)) return 0; - - uint16_t mask = 0; - + uint32_t mask = 0; switch (RC.rrc[mod_id]->node_type) { case ngran_eNB_CU: case ngran_ng_eNB_CU: case ngran_gNB_CU: mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC); + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP); break; - case ngran_eNB_DU: case ngran_gNB_DU: mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC); + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC); break; - case ngran_eNB: case ngran_ng_eNB: case ngran_gNB: mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP) - | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC); + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC) + | (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP); break; + case ngran_eNB_MBMS_STA: + AssertFatal(0, "MBMS STA not supported by FlexRAN!\n"); + break; } return mask; } + +size_t flexran_get_splits(mid_t mod_id, Protocol__FlexBsSplit **splits) { + size_t n_splits = 0; + *splits = NULL; + if (rrc_is_present(mod_id) && !NODE_IS_MONOLITHIC(RC.rrc[mod_id]->node_type)) + n_splits++; + if (NFAPI_MODE != NFAPI_MONOLITHIC) + n_splits++; + if (RC.ru && RC.ru[mod_id] && RC.ru[mod_id]->if_south != LOCAL_RF) + n_splits++; + if (n_splits == 0) + return 0; + + AssertFatal(n_splits < 3, "illegal number of splits (%lu)\n", n_splits); + *splits = calloc(n_splits, sizeof(Protocol__FlexBsSplit)); + AssertFatal(*splits, "could not allocate Protocol__FlexBsSplit array\n"); + int n = 0; + if (rrc_is_present(mod_id) && !NODE_IS_MONOLITHIC(RC.rrc[mod_id]->node_type)) + (*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__F1; + if (NFAPI_MODE != NFAPI_MONOLITHIC) + (*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__nFAPI; + if (RC.ru && RC.ru[mod_id] && RC.ru[mod_id]->if_south == REMOTE_IF4p5) + (*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__IF4p5; + if (RC.ru && RC.ru[mod_id] && RC.ru[mod_id]->if_south == REMOTE_IF5) + (*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__IF5; + DevAssert(n == n_splits); + return n_splits; +} diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index f9d0d97405..ce32883852 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -44,6 +44,7 @@ #include "RRC/LTE/rrc_eNB_UE_context.h" #include "PHY/phy_extern.h" #include "common/utils/LOG/log.h" +#include "nfapi/oai_integration/vendor_ext.h" /**************************** * get generic info from RAN @@ -651,6 +652,9 @@ int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index); /* Get the TEID at the SGW for UE */ int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index); +/* gets the UEs S1AP ID at eNodeB, stored in RRC */ +uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti); + /************************** Slice configuration **************************/ /* Get the DL slice ID for a UE */ @@ -803,6 +807,31 @@ char *flexran_get_ul_slice_scheduler(mid_t mod_id, int slice_idx); /* Set the scheduler name for a slice in UL */ int flexran_set_ul_slice_scheduler(mid_t mod_id, int slice_idx, char *name); +/************************** S1AP **************************/ +/* Get the number of MMEs to be connected */ +int flexran_get_s1ap_mme_pending(mid_t mod_id); + +/* Get the number of connected MMEs */ +int flexran_get_s1ap_mme_connected(mid_t mod_id); + +/* Get the eNB S1AP IP address */ +char* flexran_get_s1ap_enb_s1_ip(mid_t mod_id); + +/* Get the name of the eNB */ +char* flexran_get_s1ap_enb_name(mid_t mod_id); + +/* Get the number of connected MMEs to this eNB */ +int flexran_get_s1ap_nb_mme(mid_t mod_id); + +/* Get the number of connected UEs to this eNB */ +int flexran_get_s1ap_nb_ue(mid_t mod_id); + +/* Get the S1AP MME conf */ +int flexran_get_s1ap_mme_conf(mid_t mod_id, mid_t mme_index, Protocol__FlexS1apMme * mme_conf); + +/* Get the S1AP UE conf */ +int flexran_get_s1ap_ue(mid_t mod_id, rnti_t rnti, Protocol__FlexS1apUe * ue_conf); + /********************* general information *****************/ /* get an ID for this BS (or part of a BS) */ uint64_t flexran_get_bs_id(mid_t mod_id); @@ -814,4 +843,9 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps) /* get the capabilities supported by the underlying network function as a bit * mask. */ -uint16_t flexran_get_capabilities_mask(mid_t mod_id); +uint32_t flexran_get_capabilities_mask(mid_t mod_id); + +/* get the splits used by the underlying network function, + * return the number and stores list of this length in splits. If there are + * zero capabilities, splits will be NULL */ +size_t flexran_get_splits(mid_t mod_id, Protocol__FlexBsSplit **splits); diff --git a/openair2/ENB_APP/flexran_agent_task_manager.c b/openair2/ENB_APP/flexran_agent_task_manager.c index 4a0fee1f5b..f20e6c8969 100644 --- a/openair2/ENB_APP/flexran_agent_task_manager.c +++ b/openair2/ENB_APP/flexran_agent_task_manager.c @@ -33,7 +33,7 @@ #include #include "flexran_agent_task_manager.h" -#include "flexran_agent_common.c" +#include "flexran_agent_common.h" /* Util macros */ diff --git a/openair2/ENB_APP/flexran_agent_timer.c b/openair2/ENB_APP/flexran_agent_timer.c index 143c2df889..ffbac39983 100644 --- a/openair2/ENB_APP/flexran_agent_timer.c +++ b/openair2/ENB_APP/flexran_agent_timer.c @@ -21,187 +21,266 @@ /*! \file flexran_agent_timer.c * \brief FlexRAN Timer - * \author shahab SHARIAT BAGHERI - * \date 2017 - * \version 0.1 - */ - -/* - * timer primitives + * \author Robert Schmidt + * \date 2019 + * \version 0.2 */ #include "flexran_agent_timer.h" +#include "flexran_agent_extern.h" +#include +#include -//struct flexran_agent_map agent_map; -flexran_agent_timer_instance_t timer_instance; -int agent_timer_init = 0; -err_code_t flexran_agent_init_timer(void) { - LOG_I(FLEXRAN_AGENT, "init RB tree\n"); +#define MAX_NUM_TIMERS 10 - if (!agent_timer_init) { - RB_INIT(&timer_instance.flexran_agent_head); - agent_timer_init = 1; +typedef struct flexran_agent_timer_element_s { + mid_t mod_id; + xid_t xid; /* The id of the task as received by the controller message*/ + uint32_t sf; + uint64_t next; + flexran_agent_timer_callback_t cb; + Protocol__FlexranMessage *msg; +} flexran_agent_timer_element_t; + +typedef struct flexran_agent_timer_extern_source_s { + pthread_mutex_t mutex_sync; + pthread_cond_t cond; + int wait; +} flexran_agent_timer_extern_source_t; + +struct timesync { + void *param_sync; + void (*fsync)(void *); + pthread_t thread; + + uint64_t current; + uint64_t next; + + int timer_num; + flexran_agent_timer_element_t *timer[MAX_NUM_TIMERS]; + pthread_mutex_t mutex_timer; + + int exit; +}; +struct timesync timesync[NUM_MAX_ENB]; + +int flexran_agent_timer_signal_init(struct timesync *sync); +int flexran_agent_timer_source_setup(struct timesync *sync); +void *flexran_agent_timer_thread(void *args); +void flexran_agent_timer_remove_internal(struct timesync *sync, int index); +void flexran_agent_timer_process(flexran_agent_timer_element_t *t); + + +err_code_t flexran_agent_timer_init(mid_t mod_id) { + struct timesync *sync = ×ync[mod_id]; + sync->current = 0; + sync->next = 0; + sync->timer_num = 0; + for (int i = 0; i < MAX_NUM_TIMERS; ++i) + sync->timer[i] = NULL; + pthread_mutex_init(&sync->mutex_timer, NULL); + sync->exit = 0; + + /* if there is a MAC, we assume we can have a tick from the MAC interface + * (external tick source). Otherwise, generate a tick internally via the + * timerfd linux library. The init functions set everything up and the thread + * will use whatever is available. */ + int (*init)(struct timesync *) = flexran_agent_get_mac_xface(mod_id) ? + flexran_agent_timer_signal_init : flexran_agent_timer_source_setup; + if (init(timesync) < 0 + || pthread_create(&sync->thread, NULL, flexran_agent_timer_thread, sync) != 0) { + sync->thread = 0; + if (sync->param_sync) + free(sync->param_sync); + LOG_E(FLEXRAN_AGENT, "could not start timer thread\n"); + return TIMER_SETUP_FAILED; } - return PROTOCOL__FLEXRAN_ERR__NO_ERR; } -RB_GENERATE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); +void flexran_agent_timer_exit(mid_t mod_id) { + timesync[mod_id].exit = 1; +} -/* The timer_id might not be the best choice for the comparison */ -int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b) { - if (a->timer_id < b->timer_id) return -1; +void flexran_agent_timer_source_sync(void *sync) { + int fd = *(int *)sync; + uint64_t occ; + int rc __attribute__((unused)) = read(fd, &occ, sizeof(occ)); +} - if (a->timer_id > b->timer_id) return 1; +int flexran_agent_timer_source_setup(struct timesync *sync) { + sync->param_sync = malloc(sizeof(int)); + if (!sync->param_sync) + return -1; + int fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd < 0) + return fd; - // equal timers + const uint64_t period_ns = 1000000; // 1ms + struct itimerspec t; + t.it_interval.tv_sec = period_ns / 1000000000; + t.it_interval.tv_nsec = period_ns % 1000000000; + t.it_value.tv_sec = period_ns / 1000000000; + t.it_value.tv_nsec = period_ns % 1000000000; + int rc = timerfd_settime(fd, 0, &t, NULL); + if (rc != 0) + return -1; + *(int *)sync->param_sync = fd; + sync->fsync = flexran_agent_timer_source_sync; return 0; } -err_code_t flexran_agent_create_timer(uint32_t interval_sec, - uint32_t interval_usec, - agent_id_t agent_id, - instance_t instance, - uint32_t timer_type, - xid_t xid, +void flexran_agent_timer_signal_sync(void *param_sync) { + flexran_agent_timer_extern_source_t *sync = param_sync; + pthread_mutex_lock(&sync->mutex_sync); + while (sync->wait) { + pthread_cond_wait(&sync->cond, &sync->mutex_sync); + } + sync->wait = 1; + pthread_mutex_unlock(&sync->mutex_sync); +} + +int flexran_agent_timer_signal_init(struct timesync *sync) { + flexran_agent_timer_extern_source_t *s = malloc(sizeof(flexran_agent_timer_extern_source_t)); + if (!s) + return TIMER_SETUP_FAILED; + if (pthread_mutex_init(&s->mutex_sync, NULL) < 0) + return TIMER_SETUP_FAILED; + if (pthread_cond_init(&s->cond, NULL) < 0) + return TIMER_SETUP_FAILED; + s->wait = 1; + sync->param_sync = s; + sync->fsync = flexran_agent_timer_signal_sync; + return 0; +} + +void flexran_agent_timer_signal(mid_t mod_id) { + flexran_agent_timer_extern_source_t *sync = timesync[mod_id].param_sync; + pthread_mutex_lock(&sync->mutex_sync); + sync->wait = 0; + pthread_mutex_unlock(&sync->mutex_sync); + pthread_cond_signal(&sync->cond); +} + +void *flexran_agent_timer_thread(void *args) { + struct timesync *sync = args; + while (1) { + sync->fsync(sync->param_sync); + if (sync->exit) + break; + + pthread_mutex_lock(&sync->mutex_timer); + sync->current++; + + if (sync->current < sync->next) { + pthread_mutex_unlock(&sync->mutex_timer); + continue; + } + + for (int i = 0; i < sync->timer_num; ++i) { + flexran_agent_timer_element_t *t = sync->timer[i]; + if (sync->current == t->next) { + flexran_agent_timer_process(t); + t->next += t->sf; + } + if (sync->next == sync->current || t->next < sync->next) + sync->next = t->next; + } + pthread_mutex_unlock(&sync->mutex_timer); + } + LOG_W(FLEXRAN_AGENT, "terminated timer thread\n"); + return NULL; +} + +void flexran_agent_timer_process(flexran_agent_timer_element_t *t) { + Protocol__FlexranMessage *msg = t->cb(t->mod_id, t->msg); + if (!msg) + return; + + int size = 0; + void *data = flexran_agent_pack_message(msg, &size); + if (flexran_agent_msg_send(t->mod_id, FLEXRAN_AGENT_DEFAULT, data, size, 0) < 0) + LOG_E(FLEXRAN_AGENT, "error while sending message for timer xid %d\n", t->xid); +} + + +err_code_t flexran_agent_create_timer(mid_t mod_id, + uint32_t sf, + flexran_agent_timer_type_t timer_type, + xid_t xid, flexran_agent_timer_callback_t cb, - void *timer_args, - long *timer_id) { - struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e)); - DevAssert(e != NULL); - //uint32_t timer_id; - int ret=-1; - - if ((interval_sec == 0) && (interval_usec == 0 )) { - free(e); + Protocol__FlexranMessage *msg) { + if (sf == 0) return TIMER_NULL; - } + if (cb == NULL) + return TIMER_SETUP_FAILED; + AssertFatal(timer_type != FLEXRAN_AGENT_TIMER_TYPE_ONESHOT, + "one shot timer not yet implemented\n"); - if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) { - free(e); - return TIMER_TYPE_INVALIDE; - } - - if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT) { - ret = timer_setup(interval_sec, - interval_usec, - TASK_FLEXRAN_AGENT, - instance, - TIMER_ONE_SHOT, - timer_args, - timer_id); - - e->type = TIMER_ONE_SHOT; - } else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ) { - ret = timer_setup(interval_sec, - interval_usec, - TASK_FLEXRAN_AGENT, - instance, - TIMER_PERIODIC, - timer_args, - timer_id); - e->type = TIMER_PERIODIC; - } - - if (ret < 0 ) { - free(e); + flexran_agent_timer_element_t *t = malloc(sizeof(flexran_agent_timer_element_t)); + if (!t) { + LOG_E(FLEXRAN_AGENT, "no memory for new timer %d\n", xid); return TIMER_SETUP_FAILED; } + t->mod_id = mod_id; + t->xid = xid; + t->sf = sf; + t->cb = cb; + t->msg = msg; - e->agent_id = agent_id; - e->instance = instance; - e->state = FLEXRAN_AGENT_TIMER_STATE_ACTIVE; - e->timer_id = *timer_id; - e->xid = xid; - e->timer_args = timer_args; - e->cb = cb; - /*element should be a real pointer*/ - RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e); - LOG_I(FLEXRAN_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n", - e->timer_id, e->agent_id, e->instance); - return 0; -} - -err_code_t flexran_agent_destroy_timer(long timer_id) { - struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id); - - if (e != NULL ) { - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); + struct timesync *sync = ×ync[mod_id]; + pthread_mutex_lock(&sync->mutex_timer); + if (sync->timer_num >= MAX_NUM_TIMERS) { + pthread_mutex_unlock(&sync->mutex_timer); + LOG_E(FLEXRAN_AGENT, "maximum number of timers (%d) reached while adding timer %d\n", + sync->timer_num, xid); + free(t); + return TIMER_SETUP_FAILED; } - - if (timer_remove(timer_id) < 0 ) - goto error; - + /* TODO check that xid does not exist? */ + t->next = sync->current + 1; + if (sync->next <= sync->current || t->next < sync->next) + sync->next = t->next; + sync->timer[sync->timer_num] = t; + sync->timer_num++; + pthread_mutex_unlock(&sync->mutex_timer); + LOG_D(FLEXRAN_AGENT, "added new timer xid %d for agent %d\n", xid, mod_id); return 0; -error: - LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); - return TIMER_REMOVED_FAILED ; } -err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid) { - struct flexran_agent_timer_element_s *e = NULL; - long timer_id; - RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { - if (e->xid == xid) { - timer_id = e->timer_id; - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); +err_code_t flexran_agent_destroy_timers(mid_t mod_id) { + struct timesync *sync = ×ync[mod_id]; + pthread_mutex_lock(&sync->mutex_timer); + for (int i = sync->timer_num - 1; i < 0; --i) { + flexran_agent_timer_remove_internal(sync, i); + } + pthread_mutex_unlock(&sync->mutex_timer); + return 0; +} - if (timer_remove(timer_id) < 0 ) { - goto error; - } +err_code_t flexran_agent_destroy_timer(mid_t mod_id, xid_t xid) { + struct timesync *sync = ×ync[mod_id]; + pthread_mutex_lock(&sync->mutex_timer); + for (int i = 0; i < sync->timer_num; ++i) { + if (sync->timer[i]->xid == xid) { + flexran_agent_timer_remove_internal(sync, i); + pthread_mutex_unlock(&sync->mutex_timer); + return 0; } } - return 0; -error: - LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); - return TIMER_REMOVED_FAILED ; + pthread_mutex_unlock(&sync->mutex_timer); + LOG_E(FLEXRAN_AGENT, "could not find timer %d\n", xid); + return TIMER_ELEMENT_NOT_FOUND; } -err_code_t flexran_agent_destroy_timers(void) { - struct flexran_agent_timer_element_s *e = NULL; - RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - timer_remove(e->timer_id); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - } - return 0; -} - -void flexran_agent_sleep_until(struct timespec *ts, int delay) { - ts->tv_nsec += delay; - - if(ts->tv_nsec >= 1000*1000*1000) { - ts->tv_nsec -= 1000*1000*1000; - ts->tv_sec++; - } - - clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL); -} - - -err_code_t flexran_agent_stop_timer(long timer_id) { - struct flexran_agent_timer_element_s *e=NULL; - struct flexran_agent_timer_element_s search; - memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); - search.timer_id = timer_id; - e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); - - if (e != NULL ) { - e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED; - } - - timer_remove(timer_id); - return 0; -} - -struct flexran_agent_timer_element_s *get_timer_entry(long timer_id) { - struct flexran_agent_timer_element_s search; - memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); - search.timer_id = timer_id; - return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); +/* this function assumes that the timer lock is held */ +void flexran_agent_timer_remove_internal(struct timesync *sync, int index) { + LOG_I(FLEXRAN_AGENT, "remove timer xid %d (index %d) for agent %d\n", + sync->timer[index]->xid, index, sync->timer[index]->mod_id); + flexran_agent_destroy_flexran_message(sync->timer[index]->msg); + free(sync->timer[index]); + for (int i = index + 1; i < sync->timer_num; ++i) + sync->timer[i - 1] = sync->timer[i]; + sync->timer_num--; + sync->timer[sync->timer_num] = NULL; } diff --git a/openair2/ENB_APP/flexran_agent_timer.h b/openair2/ENB_APP/flexran_agent_timer.h index 06443c14d1..b1cf8df51f 100644 --- a/openair2/ENB_APP/flexran_agent_timer.h +++ b/openair2/ENB_APP/flexran_agent_timer.h @@ -26,107 +26,45 @@ * \version 0.1 */ -#include -#include +#ifndef _FLEXRAN_AGENT_TIMER_ +#define _FLEXRAN_AGENT_TIMER_ #include "flexran_agent_common.h" -#include "flexran_agent_common_internal.h" -#include "flexran_agent_extern.h" #include "flexran_agent_defs.h" - -# include "tree.h" -# include "intertask_interface.h" - - - -/******************* - * timer primitves - *******************/ - #define TIMER_NULL -1 #define TIMER_TYPE_INVALIDE -2 #define TIMER_SETUP_FAILED -3 #define TIMER_REMOVED_FAILED -4 #define TIMER_ELEMENT_NOT_FOUND -5 +typedef enum { + FLEXRAN_AGENT_TIMER_TYPE_ONESHOT, + FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, +} flexran_agent_timer_type_t; /* Type of the callback executed when the timer expired */ -typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*); +typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)( + mid_t mod_id, const Protocol__FlexranMessage *msg); +err_code_t flexran_agent_timer_init(mid_t mod_id); +void flexran_agent_timer_exit(mid_t mod_id); -typedef struct flexran_agent_timer_args_s{ - mid_t mod_id; - Protocol__FlexranMessage *msg; -} flexran_agent_timer_args_t; +/* Signals next subframe for FlexRAN timers */ +void flexran_agent_timer_signal(mid_t mod_id); - -typedef struct flexran_agent_timer_element_s{ - RB_ENTRY(flexran_agent_timer_element_s) entry; - - agent_id_t agent_id; - instance_t instance; - - flexran_agent_timer_type_t type; - flexran_agent_timer_state_t state; - - uint32_t interval_sec; - uint32_t interval_usec; - - long timer_id; /* Timer id returned by the timer API*/ - xid_t xid; /*The id of the task as received by the controller - message*/ - - flexran_agent_timer_callback_t cb; - flexran_agent_timer_args_t *timer_args; - -} flexran_agent_timer_element_t; - -typedef struct flexran_agent_timer_instance_s{ - RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head; -}flexran_agent_timer_instance_t; - - -err_code_t flexran_agent_init_timer(void); - -/* Create a timer for some agent related event with id xid. Will store the id - of the generated timer in timer_id */ -err_code_t flexran_agent_create_timer(uint32_t interval_sec, - uint32_t interval_usec, - agent_id_t agent_id, - instance_t instance, - uint32_t timer_type, - xid_t xid, - flexran_agent_timer_callback_t cb, - void* timer_args, - long *timer_id); +/* Create a timer for some agent related event with id xid. */ +err_code_t flexran_agent_create_timer(mid_t mod_id, + uint32_t sf, + flexran_agent_timer_type_t timer_type, + xid_t xid, + flexran_agent_timer_callback_t cb, + Protocol__FlexranMessage *msg); /* Destroy all existing timers */ -err_code_t flexran_agent_destroy_timers(void); - -/* Destroy the timer with the given timer_id */ -err_code_t flexran_agent_destroy_timer(long timer_id); +err_code_t flexran_agent_destroy_timers(mid_t mod_id); /* Destroy the timer for task with id xid */ -err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid); +err_code_t flexran_agent_destroy_timer(mid_t mod_id, xid_t xid); -/* Stop a timer */ -err_code_t flexran_agent_stop_timer(long timer_id); - -/* Restart the given timer */ -err_code_t flexran_agent_restart_timer(long *timer_id); - -/* Find the timer with the given timer_id */ -struct flexran_agent_timer_element_s * get_timer_entry(long timer_id); - -/* Obtain the protocol message stored in the given expired timer */ -Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args); - -/* Comparator function comparing two timers. Decides the ordering of the timers */ -int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b); - -/*Specify a delay in nanoseconds to timespec and sleep until then*/ -void flexran_agent_sleep_until(struct timespec *ts, int delay); - -/* RB_PROTOTYPE is for .h files */ -RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); +#endif /* _FLEXRAN_AGENT_TIMER_ */ diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 83f3da57b2..341c050f55 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -117,7 +117,7 @@ int DU_send_F1_SETUP_REQUEST(instance_t instance) { ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); /* mandatory */ - /* c2. GNB_DU_ID (integrer value) */ + /* c2. GNB_DU_ID (integer value) */ ie = (F1AP_F1SetupRequestIEs_t *)calloc(1, sizeof(F1AP_F1SetupRequestIEs_t)); ie->id = F1AP_ProtocolIE_ID_id_gNB_DU_ID; ie->criticality = F1AP_Criticality_reject; @@ -138,7 +138,7 @@ int DU_send_F1_SETUP_REQUEST(instance_t instance) { } /* mandatory */ - /* c4. serverd cells list */ + /* c4. served cells list */ ie = (F1AP_F1SetupRequestIEs_t *)calloc(1, sizeof(F1AP_F1SetupRequestIEs_t)); ie->id = F1AP_ProtocolIE_ID_id_gNB_DU_Served_Cells_List; ie->criticality = F1AP_Criticality_reject; @@ -150,7 +150,7 @@ int DU_send_F1_SETUP_REQUEST(instance_t instance) { ivalue.choice.C_RNTI, causing // a compile error -#undef C_RNTI +#undef C_RNTI extern f1ap_setup_req_t *f1ap_du_data; extern RAN_CONTEXT_t RC; @@ -67,8 +69,10 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { LOG_D(F1AP, "DU_handle_DL_RRC_MESSAGE_TRANSFER \n"); + F1AP_DLRRCMessageTransfer_t *container; F1AP_DLRRCMessageTransferIEs_t *ie; + uint64_t cu_ue_f1ap_id; uint64_t du_ue_f1ap_id; uint64_t srb_id; @@ -76,20 +80,25 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sdu_size_t rrc_dl_sdu_len; //uint64_t subscriberProfileIDforRFP; //uint64_t rAT_FrequencySelectionPriority; + DevAssert(pdu != NULL); if (stream != 0) { LOG_E(F1AP, "[SCTP %d] Received F1 on stream != 0 (%d)\n", - assoc_id, stream); + assoc_id, stream); return -1; } container = &pdu->choice.initiatingMessage->value.choice.DLRRCMessageTransfer; + + /* GNB_CU_UE_F1AP_ID */ F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); cu_ue_f1ap_id = ie->value.choice.GNB_CU_UE_F1AP_ID; LOG_D(F1AP, "cu_ue_f1ap_id %lu \n", cu_ue_f1ap_id); + + /* GNB_DU_UE_F1AP_ID */ F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); @@ -107,7 +116,7 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, /* oldgNB_DU_UE_F1AP_ID */ if (0) { F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID, true); + F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID, true); } /* mandatory */ @@ -121,7 +130,7 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, /* ExecuteDuplication */ if (0) { F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_ExecuteDuplication, true); + F1AP_ProtocolIE_ID_id_ExecuteDuplication, true); executeDuplication = ie->value.choice.ExecuteDuplication; LOG_D(F1AP, "ExecuteDuplication %d \n", executeDuplication); } @@ -133,6 +142,7 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, F1AP_ProtocolIE_ID_id_RRCContainer, true); // BK: need check // create an ITTI message and copy SDU + // message_p = itti_alloc_new_message (TASK_CU_F1, RRC_MAC_CCCH_DATA_IND); // memset (RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); rrc_dl_sdu_len = ie->value.choice.RRCContainer.size; @@ -148,17 +158,15 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, /* RAT_FrequencyPriorityInformation */ if (0) { F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_RAT_FrequencyPriorityInformation, true); + F1AP_ProtocolIE_ID_id_RAT_FrequencyPriorityInformation, true); switch(ie->value.choice.RAT_FrequencyPriorityInformation.present) { case F1AP_RAT_FrequencyPriorityInformation_PR_subscriberProfileIDforRFP: //subscriberProfileIDforRFP = ie->value.choice.RAT_FrequencyPriorityInformation.choice.subscriberProfileIDforRFP; break; - case F1AP_RAT_FrequencyPriorityInformation_PR_rAT_FrequencySelectionPriority: //rAT_FrequencySelectionPriority = ie->value.choice.RAT_FrequencyPriorityInformation.choice.rAT_FrequencySelectionPriority; break; - default: LOG_W(F1AP, "unhandled IE RAT_FrequencyPriorityInformation.present\n"); break; @@ -167,26 +175,28 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, // decode RRC Container and act on the message type AssertFatal(srb_id<3,"illegal srb_id\n"); + protocol_ctxt_t ctxt; ctxt.rnti = f1ap_get_rnti_by_du_id(&f1ap_du_inst[instance], du_ue_f1ap_id); ctxt.module_id = instance; ctxt.instance = instance; ctxt.enb_flag = 1; - struct rrc_eNB_ue_context_s *ue_context_p = rrc_eNB_get_ue_context( - RC.rrc[ctxt.module_id], - ctxt.rnti); + + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context( + RC.rrc[ctxt.module_id], + ctxt.rnti); if (srb_id == 0) { - LTE_DL_CCCH_Message_t *dl_ccch_msg=NULL; + LTE_DL_CCCH_Message_t* dl_ccch_msg=NULL; asn_dec_rval_t dec_rval; dec_rval = uper_decode(NULL, - &asn_DEF_LTE_DL_CCCH_Message, - (void **)&dl_ccch_msg, - ie->value.choice.RRCContainer.buf, - rrc_dl_sdu_len,0,0); + &asn_DEF_LTE_DL_CCCH_Message, + (void**)&dl_ccch_msg, + ie->value.choice.RRCContainer.buf, + rrc_dl_sdu_len,0,0); AssertFatal(dec_rval.code == RC_OK, "could not decode F1AP message\n"); - switch (dl_ccch_msg->message.choice.c1.present) { + case LTE_DL_CCCH_MessageType__c1_PR_NOTHING: LOG_I(F1AP, "Received PR_NOTHING on DL-CCCH-Message\n"); break; @@ -206,29 +216,32 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, "Logical Channel DL-CCCH (SRB0), Received RRCConnectionReject \n"); break; - case LTE_DL_CCCH_MessageType__c1_PR_rrcConnectionSetup: { + case LTE_DL_CCCH_MessageType__c1_PR_rrcConnectionSetup: + { LOG_I(F1AP, "Logical Channel DL-CCCH (SRB0), Received RRCConnectionSetup DU_ID %lx/RNTI %x\n", du_ue_f1ap_id, f1ap_get_rnti_by_du_id(&f1ap_du_inst[instance], du_ue_f1ap_id)); - // Get configuration - LTE_RRCConnectionSetup_t *rrcConnectionSetup = &dl_ccch_msg->message.choice.c1.choice.rrcConnectionSetup; + // Get configuration + + LTE_RRCConnectionSetup_t* rrcConnectionSetup = &dl_ccch_msg->message.choice.c1.choice.rrcConnectionSetup; AssertFatal(rrcConnectionSetup!=NULL,"rrcConnectionSetup is null\n"); - LTE_RadioResourceConfigDedicated_t *radioResourceConfigDedicated = &rrcConnectionSetup->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r8.radioResourceConfigDedicated; + LTE_RadioResourceConfigDedicated_t* radioResourceConfigDedicated = &rrcConnectionSetup->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r8.radioResourceConfigDedicated; + // get SRB logical channel information LTE_SRB_ToAddModList_t *SRB_configList; LTE_SRB_ToAddMod_t *SRB1_config; LTE_LogicalChannelConfig_t *SRB1_logicalChannelConfig = NULL; SRB_configList = radioResourceConfigDedicated->srb_ToAddModList; - AssertFatal(SRB_configList!=NULL,"SRB_configList is null\n"); + AssertFatal(SRB_configList!=NULL,"SRB_configList is null\n"); for (int cnt = 0; cnt < (SRB_configList)->list.count; cnt++) { if ((SRB_configList)->list.array[cnt]->srb_Identity == 1) { SRB1_config = (SRB_configList)->list.array[cnt]; if (SRB1_config->logicalChannelConfig) { if (SRB1_config->logicalChannelConfig->present == - LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) { + LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) { SRB1_logicalChannelConfig = &SRB1_config->logicalChannelConfig->choice.explicitValue; } else { SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; @@ -238,32 +251,34 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, } } } // for - rrc_rlc_config_asn1_req(&ctxt, - SRB_configList, - (LTE_DRB_ToAddModList_t *) NULL, - (LTE_DRB_ToReleaseList_t *) NULL, - (LTE_PMCH_InfoList_r9_t *) NULL, - 0,0 - ); - // This should be somewhere in the f1ap_cudu_ue_inst_t - /*int macrlc_instance = 0; + SRB_configList, + (LTE_DRB_ToAddModList_t*) NULL, + (LTE_DRB_ToReleaseList_t*) NULL + , (LTE_PMCH_InfoList_r9_t *) NULL, + 0,0 + ); - rnti_t rnti = f1ap_get_rnti_by_du_id(&f1ap_du_inst[0], du_ue_f1ap_id); - struct rrc_eNB_ue_context_s *ue_context_p = rrc_eNB_get_ue_context(RC.rrc[macrlc_instance],rnti); - */ - eNB_RRC_UE_t *ue_p = &ue_context_p->ue_context; - AssertFatal(ue_p->Srb0.Active == 1,"SRB0 is not active\n"); - memcpy((void *)ue_p->Srb0.Tx_buffer.Payload, - (void *)ie->value.choice.RRCContainer.buf, - rrc_dl_sdu_len); // ie->value.choice.RRCContainer.size - ue_p->Srb0.Tx_buffer.payload_size = rrc_dl_sdu_len; - LTE_MAC_MainConfig_t *mac_MainConfig = NULL; + // This should be somewhere in the f1ap_cudu_ue_inst_t + /*int macrlc_instance = 0; - if (radioResourceConfigDedicated->mac_MainConfig) - mac_MainConfig = &radioResourceConfigDedicated->mac_MainConfig->choice.explicitValue; + rnti_t rnti = f1ap_get_rnti_by_du_id(&f1ap_du_inst[0], du_ue_f1ap_id); + struct rrc_eNB_ue_context_s *ue_context_p = rrc_eNB_get_ue_context(RC.rrc[macrlc_instance],rnti); + */ + eNB_RRC_UE_t *ue_p = &ue_context_p->ue_context; + AssertFatal(ue_p->Srb0.Active == 1,"SRB0 is not active\n"); - rrc_mac_config_req_eNB( + memcpy((void*)ue_p->Srb0.Tx_buffer.Payload, + (void*)ie->value.choice.RRCContainer.buf, + rrc_dl_sdu_len); // ie->value.choice.RRCContainer.size + + ue_p->Srb0.Tx_buffer.payload_size = rrc_dl_sdu_len; + + LTE_MAC_MainConfig_t *mac_MainConfig = NULL; + if (radioResourceConfigDedicated->mac_MainConfig) + mac_MainConfig = &radioResourceConfigDedicated->mac_MainConfig->choice.explicitValue; + + rrc_mac_config_req_eNB( ctxt.module_id, 0, //primaryCC_id, 0,0,0,0,0,0, @@ -273,6 +288,7 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, (LTE_RadioResourceConfigCommonSIB_t *) NULL, radioResourceConfigDedicated->physicalConfigDedicated, (LTE_SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, (LTE_MeasObjectToAddMod_t **) NULL, mac_MainConfig, 1, @@ -281,220 +297,235 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, (LTE_TDD_Config_t *) NULL, NULL, (LTE_SchedulingInfoList_t *) NULL, - 0, NULL, NULL, (LTE_MBSFN_SubframeConfigList_t *) NULL, - 0, (LTE_MBSFN_AreaInfoList_r9_t *) NULL, (LTE_PMCH_InfoList_r9_t *) NULL, - (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, - 0, - (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, - (LTE_SchedulingInfo_MBMS_r14_t *) NULL, - (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, - (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, - (LTE_MBSFN_AreaInfoList_r9_t *) NULL - ); - break; + 0, NULL, NULL, (LTE_MBSFN_SubframeConfigList_t *) NULL + , 0, (LTE_MBSFN_AreaInfoList_r9_t *) NULL, (LTE_PMCH_InfoList_r9_t *) NULL, + (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL + , + 0, + (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, + (LTE_SchedulingInfo_MBMS_r14_t *) NULL, + (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, + (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL + ); + break; } // case default: AssertFatal(1==0, - "Unknown message\n"); + "Unknown message\n"); break; }// switch case - return(0); - } else if (srb_id == 1) { - LTE_DL_DCCH_Message_t *dl_dcch_msg=NULL; + } else if (srb_id == 1) { + + LTE_DL_DCCH_Message_t* dl_dcch_msg=NULL; asn_dec_rval_t dec_rval; dec_rval = uper_decode(NULL, - &asn_DEF_LTE_DL_DCCH_Message, - (void **)&dl_dcch_msg, - &ie->value.choice.RRCContainer.buf[1], // buf[0] includes the pdcp header - rrc_dl_sdu_len,0,0); - - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) + &asn_DEF_LTE_DL_DCCH_Message, + (void**)&dl_dcch_msg, + &ie->value.choice.RRCContainer.buf[1], // buf[0] includes the pdcp header + rrc_dl_sdu_len,0,0); + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) LOG_E(F1AP," Failed to decode DL-DCCH (%zu bytes)\n",dec_rval.consumed); else LOG_D(F1AP, "Received message: present %d and c1 present %d\n", dl_dcch_msg->message.present, dl_dcch_msg->message.choice.c1.present); if (dl_dcch_msg->message.present == LTE_DL_DCCH_MessageType_PR_c1) { + switch (dl_dcch_msg->message.choice.c1.present) { - case LTE_DL_DCCH_MessageType__c1_PR_NOTHING: - LOG_I(F1AP, "Received PR_NOTHING on DL-DCCH-Message\n"); - return 0; + + case LTE_DL_DCCH_MessageType__c1_PR_NOTHING: + LOG_I(F1AP, "Received PR_NOTHING on DL-DCCH-Message\n"); + return 0; + case LTE_DL_DCCH_MessageType__c1_PR_dlInformationTransfer: + LOG_I(F1AP,"Received NAS DL Information Transfer\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_csfbParametersResponseCDMA2000: + LOG_I(F1AP,"Received NAS sfbParametersResponseCDMA2000\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_handoverFromEUTRAPreparationRequest: + LOG_I(F1AP,"Received NAS andoverFromEUTRAPreparationRequest\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_mobilityFromEUTRACommand: + LOG_I(F1AP,"Received NAS mobilityFromEUTRACommand\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionReconfiguration: + // handle RRCConnectionReconfiguration + LOG_I(F1AP, + "Logical Channel DL-DCCH (SRB1), Received RRCConnectionReconfiguration DU_ID %lx/RNTI %x\n", + du_ue_f1ap_id, + f1ap_get_rnti_by_du_id(&f1ap_du_inst[instance], du_ue_f1ap_id)); + + LTE_RRCConnectionReconfiguration_t* rrcConnectionReconfiguration = &dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration; - case LTE_DL_DCCH_MessageType__c1_PR_dlInformationTransfer: - LOG_I(F1AP,"Received NAS DL Information Transfer\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_csfbParametersResponseCDMA2000: - LOG_I(F1AP,"Received NAS sfbParametersResponseCDMA2000\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_handoverFromEUTRAPreparationRequest: - LOG_I(F1AP,"Received NAS andoverFromEUTRAPreparationRequest\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_mobilityFromEUTRACommand: - LOG_I(F1AP,"Received NAS mobilityFromEUTRACommand\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionReconfiguration: - // handle RRCConnectionReconfiguration - LOG_I(F1AP, - "Logical Channel DL-DCCH (SRB1), Received RRCConnectionReconfiguration DU_ID %lx/RNTI %x\n", - du_ue_f1ap_id, - f1ap_get_rnti_by_du_id(&f1ap_du_inst[instance], du_ue_f1ap_id)); - LTE_RRCConnectionReconfiguration_t *rrcConnectionReconfiguration = &dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration; - - if (rrcConnectionReconfiguration->criticalExtensions.present == LTE_RRCConnectionReconfiguration__criticalExtensions_PR_c1) { - if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.present == - LTE_RRCConnectionReconfiguration__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r8) { - LTE_RRCConnectionReconfiguration_r8_IEs_t *rrcConnectionReconfiguration_r8 = - &rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8; - - if (rrcConnectionReconfiguration_r8->mobilityControlInfo) { - LOG_I(F1AP, "Mobility Control Information is present\n"); - AssertFatal(1==0,"Can't handle this yet in DU\n"); + if (rrcConnectionReconfiguration->criticalExtensions.present == LTE_RRCConnectionReconfiguration__criticalExtensions_PR_c1) { + if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.present == + LTE_RRCConnectionReconfiguration__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r8) { + LTE_RRCConnectionReconfiguration_r8_IEs_t* rrcConnectionReconfiguration_r8 = + &rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8; + + if (rrcConnectionReconfiguration_r8->mobilityControlInfo) { + LOG_I(F1AP, "Mobility Control Information is present\n"); + AssertFatal(1==0,"Can't handle this yet in DU\n"); + } + if (rrcConnectionReconfiguration_r8->measConfig != NULL) { + LOG_I(F1AP, "Measurement Configuration is present\n"); + } + + if (rrcConnectionReconfiguration_r8->radioResourceConfigDedicated) { + LOG_I(F1AP, "Radio Resource Configuration is present\n"); + uint8_t DRB2LCHAN[8]; + long drb_id; + int i; + LTE_DRB_ToAddModList_t *DRB_configList = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->drb_ToAddModList; + LTE_SRB_ToAddModList_t *SRB_configList = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->srb_ToAddModList; + LTE_DRB_ToReleaseList_t *DRB_ReleaseList = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->drb_ToReleaseList; + LTE_MAC_MainConfig_t *mac_MainConfig = NULL; + + for (i = 0; i< 8; i++){ + DRB2LCHAN[i] = 0; } - if (rrcConnectionReconfiguration_r8->measConfig != NULL) { - LOG_I(F1AP, "Measurement Configuration is present\n"); - } + if (rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->mac_MainConfig) { + LOG_D(F1AP, "MAC Main Configuration is present\n"); - if (rrcConnectionReconfiguration_r8->radioResourceConfigDedicated) { - LOG_I(F1AP, "Radio Resource Configuration is present\n"); - uint8_t DRB2LCHAN[8]; - long drb_id; - int i; - LTE_DRB_ToAddModList_t *DRB_configList = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->drb_ToAddModList; - LTE_SRB_ToAddModList_t *SRB_configList = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->srb_ToAddModList; - LTE_DRB_ToReleaseList_t *DRB_ReleaseList = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->drb_ToReleaseList; - LTE_MAC_MainConfig_t *mac_MainConfig = NULL; + mac_MainConfig = &rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->mac_MainConfig->choice.explicitValue; - for (i = 0; i< 8; i++) { - DRB2LCHAN[i] = 0; + /* CDRX Configuration */ + if (mac_MainConfig->drx_Config == NULL) { + LOG_W(F1AP, "drx_Configuration parameter is NULL, cannot configure local UE parameters or CDRX is deactivated\n"); + } else { + MessageDef *message_p = NULL; + + /* Send DRX configuration to MAC task to configure timers of local UE context */ + message_p = itti_alloc_new_message(TASK_DU_F1, RRC_MAC_DRX_CONFIG_REQ); + RRC_MAC_DRX_CONFIG_REQ(message_p).rnti = ctxt.rnti; + RRC_MAC_DRX_CONFIG_REQ(message_p).drx_Configuration = mac_MainConfig->drx_Config; + itti_send_msg_to_task(TASK_MAC_ENB, ctxt.module_id, message_p); + LOG_D(F1AP, "DRX configured in MAC Main Configuration for RRC Connection Reconfiguration\n"); } + /* End of CDRX configuration */ + } - if (rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->mac_MainConfig) - mac_MainConfig = &rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->mac_MainConfig->choice.explicitValue; - - LTE_MeasGapConfig_t *measGapConfig = NULL; - struct LTE_PhysicalConfigDedicated *physicalConfigDedicated = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->physicalConfigDedicated; - rrc_rlc_config_asn1_req( - &ctxt, - SRB_configList, // NULL, //LG-RK 14/05/2014 SRB_configList, - DRB_configList, - DRB_ReleaseList, (LTE_PMCH_InfoList_r9_t *) NULL, 0, 0 + LTE_MeasGapConfig_t *measGapConfig = NULL; + struct LTE_PhysicalConfigDedicated* physicalConfigDedicated = rrcConnectionReconfiguration_r8->radioResourceConfigDedicated->physicalConfigDedicated; + rrc_rlc_config_asn1_req( + &ctxt, + SRB_configList, // NULL, //LG-RK 14/05/2014 SRB_configList, + DRB_configList, + DRB_ReleaseList, (LTE_PMCH_InfoList_r9_t *) NULL, 0, 0 ); - if (SRB_configList != NULL) { - for (i = 0; (i < SRB_configList->list.count) && (i < 3); i++) { - if (SRB_configList->list.array[i]->srb_Identity == 1 ) { - ue_context_p->ue_context.Srb1.Active=1; - } else if (SRB_configList->list.array[i]->srb_Identity == 2 ) { - ue_context_p->ue_context.Srb2.Active=1; - ue_context_p->ue_context.Srb2.Srb_info.Srb_id=2; - LOG_I(F1AP, "[DU %d] SRB2 is now active\n",ctxt.module_id); - } else { - LOG_W(F1AP, "[DU %d] invalide SRB identity %ld\n",ctxt.module_id, - SRB_configList->list.array[i]->srb_Identity); - } + if (SRB_configList != NULL) { + for (i = 0; (i < SRB_configList->list.count) && (i < 3); i++) { + if (SRB_configList->list.array[i]->srb_Identity == 1 ){ + ue_context_p->ue_context.Srb1.Active=1; } - } - - if (DRB_configList != NULL) { - for (i = 0; i < DRB_configList->list.count; i++) { // num max DRB (11-3-8) - if (DRB_configList->list.array[i]) { - drb_id = (int)DRB_configList->list.array[i]->drb_Identity; - LOG_I(F1AP, - "[DU %d] Logical Channel UL-DCCH, Received RRCConnectionReconfiguration for UE rnti %x, reconfiguring DRB %d/LCID %d\n", - ctxt.module_id, - ctxt.rnti, - (int)DRB_configList->list.array[i]->drb_Identity, - (int)*DRB_configList->list.array[i]->logicalChannelIdentity); - - if (ue_context_p->ue_context.DRB_active[drb_id] == 0) { - ue_context_p->ue_context.DRB_active[drb_id] = 1; - - if (DRB_configList->list.array[i]->logicalChannelIdentity) { - DRB2LCHAN[i] = (uint8_t) * DRB_configList->list.array[i]->logicalChannelIdentity; - } - - rrc_mac_config_req_eNB( - ctxt.module_id, - 0,0,0,0,0,0, 0, - ue_context_p->ue_context.rnti, - (LTE_BCCH_BCH_Message_t *) NULL, - (LTE_RadioResourceConfigCommonSIB_t *) NULL, - (LTE_RadioResourceConfigCommonSIB_t *) NULL, - physicalConfigDedicated, - (LTE_SCellToAddMod_r10_t *)NULL, - (LTE_MeasObjectToAddMod_t **) NULL, - mac_MainConfig, - DRB2LCHAN[i], - DRB_configList->list.array[i]->logicalChannelConfig, - measGapConfig, - (LTE_TDD_Config_t *) NULL, - NULL, - (LTE_SchedulingInfoList_t *) NULL, - 0, NULL, NULL, (LTE_MBSFN_SubframeConfigList_t *) NULL, 0, - (LTE_MBSFN_AreaInfoList_r9_t *) NULL, (LTE_PMCH_InfoList_r9_t *) NULL, - (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, - 0, - (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, - (LTE_SchedulingInfo_MBMS_r14_t *) NULL, - (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, - (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, - (LTE_MBSFN_AreaInfoList_r9_t *) NULL - ); - } - } else { // remove LCHAN from MAC/PHY - AssertFatal(1==0,"Can't handle this yet in DU\n"); - } + else if (SRB_configList->list.array[i]->srb_Identity == 2 ) { + ue_context_p->ue_context.Srb2.Active=1; + ue_context_p->ue_context.Srb2.Srb_info.Srb_id=2; + LOG_I(F1AP, "[DU %d] SRB2 is now active\n",ctxt.module_id); + } else { + LOG_W(F1AP, "[DU %d] invalide SRB identity %ld\n",ctxt.module_id, + SRB_configList->list.array[i]->srb_Identity); } } } - } - } + if (DRB_configList != NULL) { + for (i = 0; i < DRB_configList->list.count; i++) { // num max DRB (11-3-8) + if (DRB_configList->list.array[i]) { + drb_id = (int)DRB_configList->list.array[i]->drb_Identity; + LOG_I(F1AP, + "[DU %d] Logical Channel UL-DCCH, Received RRCConnectionReconfiguration for UE rnti %x, reconfiguring DRB %d/LCID %d\n", + ctxt.module_id, + ctxt.rnti, + (int)DRB_configList->list.array[i]->drb_Identity, + (int)*DRB_configList->list.array[i]->logicalChannelIdentity); + + if (ue_context_p->ue_context.DRB_active[drb_id] == 0) { + ue_context_p->ue_context.DRB_active[drb_id] = 1; + + if (DRB_configList->list.array[i]->logicalChannelIdentity) { + DRB2LCHAN[i] = (uint8_t) * DRB_configList->list.array[i]->logicalChannelIdentity; + } + + rrc_mac_config_req_eNB( + ctxt.module_id, + 0,0,0,0,0,0, + 0, + ue_context_p->ue_context.rnti, + (LTE_BCCH_BCH_Message_t *) NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + physicalConfigDedicated, + (LTE_SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, + (LTE_MeasObjectToAddMod_t **) NULL, + mac_MainConfig, + DRB2LCHAN[i], + DRB_configList->list.array[i]->logicalChannelConfig, + measGapConfig, + (LTE_TDD_Config_t *) NULL, + NULL, + (LTE_SchedulingInfoList_t *) NULL, + 0, NULL, NULL, (LTE_MBSFN_SubframeConfigList_t *) NULL + , 0, (LTE_MBSFN_AreaInfoList_r9_t *) NULL, (LTE_PMCH_InfoList_r9_t *) NULL, + (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, + 0, + (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, + (LTE_SchedulingInfo_MBMS_r14_t *) NULL, + (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, + (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL + ); + } + + } else { // remove LCHAN from MAC/PHY + AssertFatal(1==0,"Can't handle this yet in DU\n"); + } + } + } + } + } + } + break; + case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionRelease: + // handle RRCConnectionRelease + LOG_I(F1AP, "Received RRCConnectionRelease\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_securityModeCommand: + LOG_I(F1AP, "Received securityModeCommand\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_ueCapabilityEnquiry: + LOG_I(F1AP, "Received ueCapabilityEnquiry\n"); break; - - case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionRelease: - // handle RRCConnectionRelease - LOG_I(F1AP, "Received RRCConnectionRelease\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_securityModeCommand: - LOG_I(F1AP, "Received securityModeCommand\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_ueCapabilityEnquiry: - LOG_I(F1AP, "Received ueCapabilityEnquiry\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_counterCheck: - case LTE_DL_DCCH_MessageType__c1_PR_loggedMeasurementConfiguration_r10: - case LTE_DL_DCCH_MessageType__c1_PR_rnReconfiguration_r10: - case LTE_DL_DCCH_MessageType__c1_PR_spare1: - case LTE_DL_DCCH_MessageType__c1_PR_spare2: - case LTE_DL_DCCH_MessageType__c1_PR_spare3: - break; - - case LTE_DL_DCCH_MessageType__c1_PR_ueInformationRequest_r9: - LOG_I(F1AP, "Received ueInformationRequest_r9\n"); - break; - - case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionResume_r13: - LOG_I(F1AP, "Received rrcConnectionResume_r13\n"); - } - } - } else if (srb_id == 2) { + case LTE_DL_DCCH_MessageType__c1_PR_counterCheck: + case LTE_DL_DCCH_MessageType__c1_PR_loggedMeasurementConfiguration_r10: + case LTE_DL_DCCH_MessageType__c1_PR_rnReconfiguration_r10: + case LTE_DL_DCCH_MessageType__c1_PR_spare1: + case LTE_DL_DCCH_MessageType__c1_PR_spare2: + case LTE_DL_DCCH_MessageType__c1_PR_spare3: + break; + case LTE_DL_DCCH_MessageType__c1_PR_ueInformationRequest_r9: + LOG_I(F1AP, "Received ueInformationRequest_r9\n"); + break; + case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionResume_r13: + LOG_I(F1AP, "Received rrcConnectionResume_r13\n"); + } + } + } + else if (srb_id == 2) { + } LOG_I(F1AP, "Received DL RRC Transfer on srb_id %ld\n", srb_id); rlc_op_status_t rlc_status; boolean_t ret = TRUE; - mem_block_t *pdcp_pdu_p = NULL; + mem_block_t *pdcp_pdu_p = NULL; pdcp_pdu_p = get_free_mem_block(rrc_dl_sdu_len, __func__); //LOG_I(F1AP, "PRRCContainer size %lu:", ie->value.choice.RRCContainer.size); @@ -505,67 +536,75 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, //for (int i=0;idata[i]); //printf("\n"); + if (pdcp_pdu_p != NULL) { memset(pdcp_pdu_p->data, 0, rrc_dl_sdu_len); memcpy(&pdcp_pdu_p->data[0], ie->value.choice.RRCContainer.buf, rrc_dl_sdu_len); - rlc_status = rlc_data_req(&ctxt - , 1 - , MBMS_FLAG_NO - , srb_id - , 0 - , 0 - , rrc_dl_sdu_len - , pdcp_pdu_p - ,NULL - ,NULL - ); - switch (rlc_status) { - case RLC_OP_STATUS_OK: - //LOG_I(F1AP, "Data sending request over RLC succeeded!\n"); - ret=TRUE; - break; + rlc_status = rlc_data_req(&ctxt + , 1 + , MBMS_FLAG_NO + , srb_id + , 0 + , 0 + , rrc_dl_sdu_len + , pdcp_pdu_p + ,NULL + ,NULL + ); + switch (rlc_status) { + case RLC_OP_STATUS_OK: + //LOG_I(F1AP, "Data sending request over RLC succeeded!\n"); + ret=TRUE; + break; - case RLC_OP_STATUS_BAD_PARAMETER: - LOG_W(F1AP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); - ret= FALSE; - break; + case RLC_OP_STATUS_BAD_PARAMETER: + LOG_W(F1AP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); + ret= FALSE; + break; - case RLC_OP_STATUS_INTERNAL_ERROR: - LOG_W(F1AP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); - ret= FALSE; - break; + case RLC_OP_STATUS_INTERNAL_ERROR: + LOG_W(F1AP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); + ret= FALSE; + break; - case RLC_OP_STATUS_OUT_OF_RESSOURCES: - LOG_W(F1AP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); - ret= FALSE; - break; - - default: - LOG_W(F1AP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); - ret= FALSE; - break; - } // switch case - - return ret; - } // if pdcp_pdu_p + case RLC_OP_STATUS_OUT_OF_RESSOURCES: + LOG_W(F1AP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); + ret= FALSE; + break; + default: + LOG_W(F1AP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); + ret= FALSE; + break; + } // switch case + return ret; + } // if pdcp_pdu_p + return 0; + } -int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, const f1ap_ul_rrc_message_t *msg) { +int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, + const f1ap_ul_rrc_message_t *msg) { const rnti_t rnti = msg->rnti; + F1AP_F1AP_PDU_t pdu; F1AP_ULRRCMessageTransfer_t *out; F1AP_ULRRCMessageTransferIEs_t *ie; + uint8_t *buffer = NULL; uint32_t len; + + LOG_I(F1AP, "[DU %d] %s: size %d UE RNTI %x in SRB %d\n", instance, __func__, msg->rrc_container_length, rnti, msg->srb_id); + //LOG_I(F1AP, "%s() RRCContainer size %d: ", __func__, msg->rrc_container_length); //for (int i = 0;i < msg->rrc_container_length; i++) // printf("%02x ", msg->rrc_container[i]); //printf("\n"); + /* Create */ /* 0. Message Type */ memset(&pdu, 0, sizeof(pdu)); @@ -575,14 +614,18 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, const f1ap_ul_rrc_messa pdu.choice.initiatingMessage->criticality = F1AP_Criticality_ignore; pdu.choice.initiatingMessage->value.present = F1AP_InitiatingMessage__value_PR_ULRRCMessageTransfer; out = &pdu.choice.initiatingMessage->value.choice.ULRRCMessageTransfer; + /* mandatory */ /* c1. GNB_CU_UE_F1AP_ID */ ie = (F1AP_ULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_ULRRCMessageTransferIEs_t)); ie->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; ie->criticality = F1AP_Criticality_reject; ie->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie->value.choice.GNB_CU_UE_F1AP_ID = f1ap_get_cu_ue_f1ap_id(&f1ap_du_inst[instance], rnti); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ /* c2. GNB_DU_UE_F1AP_ID */ ie = (F1AP_ULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_ULRRCMessageTransferIEs_t)); @@ -591,6 +634,7 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, const f1ap_ul_rrc_messa ie->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; ie->value.choice.GNB_DU_UE_F1AP_ID = f1ap_get_du_ue_f1ap_id(&f1ap_du_inst[instance], rnti); ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ /* c3. SRBID */ ie = (F1AP_ULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_ULRRCMessageTransferIEs_t)); @@ -599,6 +643,7 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, const f1ap_ul_rrc_messa ie->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_SRBID; ie->value.choice.SRBID = msg->srb_id; ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + // issue in here /* mandatory */ /* c4. RRCContainer */ @@ -612,90 +657,111 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, const f1ap_ul_rrc_messa ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); if (msg->srb_id == 1 || msg->srb_id == 2) { - struct rrc_eNB_ue_context_s *ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], rnti); - LTE_UL_DCCH_Message_t *ul_dcch_msg=NULL; + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], rnti); + + + LTE_UL_DCCH_Message_t* ul_dcch_msg=NULL; asn_dec_rval_t dec_rval; dec_rval = uper_decode(NULL, - &asn_DEF_LTE_UL_DCCH_Message, - (void **)&ul_dcch_msg, - &ie->value.choice.RRCContainer.buf[1], // buf[0] includes the pdcp header - msg->rrc_container_length, 0, 0); - - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) + &asn_DEF_LTE_UL_DCCH_Message, + (void**)&ul_dcch_msg, + &ie->value.choice.RRCContainer.buf[1], // buf[0] includes the pdcp header + msg->rrc_container_length, 0, 0); + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) LOG_E(F1AP, " Failed to decode UL-DCCH (%zu bytes)\n",dec_rval.consumed); else LOG_I(F1AP, "Received message: present %d and c1 present %d\n", ul_dcch_msg->message.present, ul_dcch_msg->message.choice.c1.present); if (ul_dcch_msg->message.present == LTE_UL_DCCH_MessageType_PR_c1) { + switch (ul_dcch_msg->message.choice.c1.present) { - case LTE_UL_DCCH_MessageType__c1_PR_NOTHING: /* No components present */ + case LTE_UL_DCCH_MessageType__c1_PR_NOTHING: /* No components present */ + break; + + case LTE_UL_DCCH_MessageType__c1_PR_csfbParametersRequestCDMA2000: + break; + + case LTE_UL_DCCH_MessageType__c1_PR_measurementReport: + break; + + case LTE_UL_DCCH_MessageType__c1_PR_rrcConnectionReconfigurationComplete: + LOG_I(F1AP, "[MSG] RRC UL rrcConnectionReconfigurationComplete\n"); + + /* CDRX: activated when RRC Connection Reconfiguration Complete is received */ + int UE_id_mac = find_UE_id(instance, rnti); + + if (UE_id_mac == -1) { + LOG_E(F1AP, "Can't find UE_id(MAC) of UE rnti %x\n", rnti); break; + } + + UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[instance]->UE_list.UE_sched_ctrl[UE_id_mac]); + + if (UE_scheduling_control->cdrx_waiting_ack == TRUE) { + UE_scheduling_control->cdrx_waiting_ack = FALSE; + UE_scheduling_control->cdrx_configured = TRUE; // Set to TRUE when RRC Connection Reconfiguration Complete is received + LOG_I(F1AP, "CDRX configuration activated after RRC Connection Reconfiguration Complete reception\n"); + } + /* End of CDRX processing */ + + break; - case LTE_UL_DCCH_MessageType__c1_PR_csfbParametersRequestCDMA2000: - break; + case LTE_UL_DCCH_MessageType__c1_PR_rrcConnectionReestablishmentComplete: + break; - case LTE_UL_DCCH_MessageType__c1_PR_measurementReport: - break; + case LTE_UL_DCCH_MessageType__c1_PR_rrcConnectionSetupComplete: + LOG_I(F1AP, "[MSG] RRC UL rrcConnectionSetupComplete \n"); + + if(!ue_context_p){ + LOG_E(F1AP, "Did not find the UE context associated with UE RNTOI %x, ue_context_p is NULL\n", rnti); - case LTE_UL_DCCH_MessageType__c1_PR_rrcConnectionReconfigurationComplete: - break; + } else { + LOG_I(F1AP, "Processing RRCConnectionSetupComplete UE %x\n", rnti); + ue_context_p->ue_context.Status = RRC_CONNECTED; + } + break; - case LTE_UL_DCCH_MessageType__c1_PR_rrcConnectionReestablishmentComplete: - break; + case LTE_UL_DCCH_MessageType__c1_PR_securityModeComplete: + LOG_I(F1AP, "[MSG] RRC securityModeComplete \n"); + break; - case LTE_UL_DCCH_MessageType__c1_PR_rrcConnectionSetupComplete: - LOG_I(F1AP, "[MSG] RRC UL rrcConnectionSetupComplete \n"); + case LTE_UL_DCCH_MessageType__c1_PR_securityModeFailure: + break; - if(!ue_context_p) { - LOG_E(F1AP, "Did not find the UE context associated with UE RNTOI %x, ue_context_p is NULL\n", rnti); - } else { - LOG_I(F1AP, "Processing RRCConnectionSetupComplete UE %x\n", rnti); - ue_context_p->ue_context.Status = RRC_CONNECTED; - } + case LTE_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation: + LOG_I(F1AP, "[MSG] RRC ueCapabilityInformation \n"); + break; - break; + case LTE_UL_DCCH_MessageType__c1_PR_ulHandoverPreparationTransfer: + break; - case LTE_UL_DCCH_MessageType__c1_PR_securityModeComplete: - LOG_I(F1AP, "[MSG] RRC securityModeComplete \n"); - break; + case LTE_UL_DCCH_MessageType__c1_PR_ulInformationTransfer: + LOG_I(F1AP,"[MSG] RRC UL Information Transfer \n"); + break; - case LTE_UL_DCCH_MessageType__c1_PR_securityModeFailure: - break; + case LTE_UL_DCCH_MessageType__c1_PR_counterCheckResponse: + break; - case LTE_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation: - LOG_I(F1AP, "[MSG] RRC ueCapabilityInformation \n"); - break; + case LTE_UL_DCCH_MessageType__c1_PR_ueInformationResponse_r9: + break; - case LTE_UL_DCCH_MessageType__c1_PR_ulHandoverPreparationTransfer: - break; + case LTE_UL_DCCH_MessageType__c1_PR_proximityIndication_r9: + break; - case LTE_UL_DCCH_MessageType__c1_PR_ulInformationTransfer: - LOG_I(F1AP,"[MSG] RRC UL Information Transfer \n"); - break; + case LTE_UL_DCCH_MessageType__c1_PR_rnReconfigurationComplete_r10: + break; - case LTE_UL_DCCH_MessageType__c1_PR_counterCheckResponse: - break; + case LTE_UL_DCCH_MessageType__c1_PR_mbmsCountingResponse_r10: + break; - case LTE_UL_DCCH_MessageType__c1_PR_ueInformationResponse_r9: - break; - - case LTE_UL_DCCH_MessageType__c1_PR_proximityIndication_r9: - break; - - case LTE_UL_DCCH_MessageType__c1_PR_rnReconfigurationComplete_r10: - break; - - case LTE_UL_DCCH_MessageType__c1_PR_mbmsCountingResponse_r10: - break; - - case LTE_UL_DCCH_MessageType__c1_PR_interFreqRSTDMeasurementIndication_r10: - break; + case LTE_UL_DCCH_MessageType__c1_PR_interFreqRSTDMeasurementIndication_r10: + break; } } } - - /* encode */ + /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup request\n"); return -1; @@ -708,14 +774,15 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, const f1ap_ul_rrc_messa /* UL RRC Message Transfer */ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, - int CC_idP, - int UE_id, - rnti_t rntiP, - const uint8_t *sduP, - sdu_size_t sdu_lenP) { + int CC_idP, + int UE_id, + rnti_t rntiP, + const uint8_t *sduP, + sdu_size_t sdu_lenP) { F1AP_F1AP_PDU_t pdu; F1AP_InitialULRRCMessageTransfer_t *out; F1AP_InitialULRRCMessageTransferIEs_t *ie; + uint8_t *buffer; uint32_t len; int f1ap_uid = f1ap_add_ue (&f1ap_du_inst[module_idP], module_idP, CC_idP,UE_id, rntiP); @@ -734,6 +801,8 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, pdu.choice.initiatingMessage->criticality = F1AP_Criticality_ignore; pdu.choice.initiatingMessage->value.present = F1AP_InitiatingMessage__value_PR_InitialULRRCMessageTransfer; out = &pdu.choice.initiatingMessage->value.choice.InitialULRRCMessageTransfer; + + /* mandatory */ /* c1. GNB_DU_UE_F1AP_ID */ ie = (F1AP_InitialULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_InitialULRRCMessageTransferIEs_t)); @@ -742,19 +811,23 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, ie->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; ie->value.choice.GNB_DU_UE_F1AP_ID = f1ap_du_inst[module_idP].f1ap_ue[f1ap_uid].du_ue_f1ap_id; ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ /* c2. NRCGI */ ie = (F1AP_InitialULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_InitialULRRCMessageTransferIEs_t)); ie->id = F1AP_ProtocolIE_ID_id_NRCGI; ie->criticality = F1AP_Criticality_reject; ie->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_NRCGI; + F1AP_NRCGI_t nRCGI; memset(&nRCGI, 0, sizeof(F1AP_NRCGI_t)); MCC_MNC_TO_PLMNID(f1ap_du_data->mcc[0], f1ap_du_data->mnc[0], f1ap_du_data->mnc_digit_length[0], - &nRCGI.pLMN_Identity); + &nRCGI.pLMN_Identity); NR_CELL_ID_TO_BIT_STRING(f1ap_du_data->nr_cellid[0], &nRCGI.nRCellIdentity); ie->value.choice.NRCGI = nRCGI; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ /* c3. C_RNTI */ // 16 ie = (F1AP_InitialULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_InitialULRRCMessageTransferIEs_t)); @@ -763,6 +836,7 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, ie->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_C_RNTI; C_RNTI_TO_BIT_STRING(rntiP, &ie->value.choice.C_RNTI); ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ /* c4. RRCContainer */ ie = (F1AP_InitialULRRCMessageTransferIEs_t *)calloc(1, sizeof(F1AP_InitialULRRCMessageTransferIEs_t)); @@ -780,36 +854,32 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, ie->criticality = F1AP_Criticality_reject; ie->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_DUtoCURRCContainer; OCTET_STRING_fromBuf(&ie->value.choice.DUtoCURRCContainer, "dummy_val", - strlen("dummy_val")); + strlen("dummy_val")); ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); } - /* encode */ + /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup request\n"); return -1; } - struct rrc_eNB_ue_context_s *ue_context_p = rrc_eNB_allocate_new_UE_context(RC.rrc[module_idP]); - - ue_context_p->ue_id_rnti = rntiP; + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_allocate_new_UE_context(RC.rrc[module_idP]); + ue_context_p->ue_id_rnti = rntiP; ue_context_p->ue_context.rnti = rntiP; - ue_context_p->ue_context.random_ue_identity = rntiP; - ue_context_p->ue_context.Srb0.Active = 1; - RB_INSERT(rrc_ue_tree_s, &RC.rrc[module_idP]->rrc_ue_head, ue_context_p); - du_f1ap_itti_send_sctp_data_req(module_idP, f1ap_du_data->assoc_id, buffer, len, f1ap_du_data->default_sctp_stream_id); return 0; } - + void init_f1ap_du_ue_inst (void) { - memset(f1ap_du_inst, 0, sizeof(f1ap_du_inst)); + + memset(f1ap_du_inst, 0, sizeof(f1ap_du_inst)); } diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index d287e1e5bf..566391ac7a 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -175,7 +175,7 @@ void *F1AP_DU_task(void *arg) { &received_msg->ittiMsg.sctp_data_ind); break; - case F1AP_UL_RRC_MESSAGE: // from rrc + case F1AP_UL_RRC_MESSAGE: // to rrc LOG_I(F1AP, "DU Task Received F1AP_UL_RRC_MESSAGE\n"); DU_send_UL_RRC_MESSAGE_TRANSFER(ITTI_MESSAGE_GET_INSTANCE(received_msg), &F1AP_UL_RRC_MESSAGE(received_msg)); diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index 2a1267fa7c..f11e302771 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -37,28 +37,18 @@ #include "common/utils/LOG/log.h" -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -# if defined(ENABLE_USE_MME) -# include "s1ap_eNB.h" -# include "sctp_eNB_task.h" -# include "gtpv1u_eNB_task.h" -# endif - -# include "PHY/INIT/phy_init.h" +#include "x2ap_eNB.h" +#include "intertask_interface.h" +#include "s1ap_eNB.h" +#include "sctp_eNB_task.h" +#include "gtpv1u_eNB_task.h" +#include "PHY/INIT/phy_init.h" extern unsigned char NB_gNB_INST; -#endif extern RAN_CONTEXT_t RC; -#if defined(ENABLE_ITTI) - -/*------------------------------------------------------------------------------*/ -# if defined(ENABLE_USE_MME) -# define GNB_REGISTER_RETRY_DELAY 10 -# endif - +#define GNB_REGISTER_RETRY_DELAY 10 /*------------------------------------------------------------------------------*/ static void configure_nr_rrc(uint32_t gnb_id) @@ -82,7 +72,6 @@ static void configure_nr_rrc(uint32_t gnb_id) /*------------------------------------------------------------------------------*/ /* -# if defined(ENABLE_USE_MME) static uint32_t gNB_app_register(uint32_t gnb_id_start, uint32_t gnb_id_end)//, const Enb_properties_array_t *enb_properties) { uint32_t gnb_id; @@ -113,23 +102,36 @@ static uint32_t gNB_app_register(uint32_t gnb_id_start, uint32_t gnb_id_end)//, return register_gnb_pending; } -# endif */ -#endif + +/*------------------------------------------------------------------------------*/ +static uint32_t gNB_app_register_x2(uint32_t gnb_id_start, uint32_t gnb_id_end) { + uint32_t gnb_id; + MessageDef *msg_p; + uint32_t register_gnb_x2_pending = 0; + + for (gnb_id = gnb_id_start; (gnb_id < gnb_id_end) ; gnb_id++) { + { + msg_p = itti_alloc_new_message (TASK_GNB_APP, X2AP_REGISTER_ENB_REQ); + LOG_I(X2AP, "GNB_ID: %d \n", gnb_id); + RCconfig_NR_X2(msg_p, gnb_id); + itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(gnb_id), msg_p); + register_gnb_x2_pending++; + } + } + + return register_gnb_x2_pending; +} /*------------------------------------------------------------------------------*/ void *gNB_app_task(void *args_p) { -#if defined(ENABLE_ITTI) + uint32_t gnb_nb = RC.nb_nr_inst; uint32_t gnb_id_start = 0; uint32_t gnb_id_end = gnb_id_start + gnb_nb; -# if defined(ENABLE_USE_MME) - //uint32_t register_gnb_pending; - //uint32_t registered_gnb; - //long gnb_register_retry_timer_id; -# endif + uint32_t x2_register_gnb_pending = 0; uint32_t gnb_id; MessageDef *msg_p = NULL; const char *msg_name = NULL; @@ -140,7 +142,7 @@ void *gNB_app_task(void *args_p) itti_mark_task_ready (TASK_GNB_APP); - LOG_I(PHY, "%s() Task ready initialise structures\n", __FUNCTION__); + LOG_I(PHY, "%s() Task ready initialize structures\n", __FUNCTION__); RCconfig_NR_L1(); @@ -166,15 +168,20 @@ void *gNB_app_task(void *args_p) configure_nr_rrc(gnb_id); } -# if defined(ENABLE_USE_MME) + if (is_x2ap_enabled() ) { //&& !NODE_IS_DU(RC.rrc[0]->node_type) + LOG_I(X2AP, "X2AP enabled \n"); + x2_register_gnb_pending = gNB_app_register_x2 (gnb_id_start, gnb_id_end); + } + + if (EPC_MODE_ENABLED) { /* Try to register each gNB */ //registered_gnb = 0; //register_gnb_pending = gNB_app_register (gnb_id_start, gnb_id_end);//, gnb_properties_p); -# else + } else { /* Start L2L1 task */ - msg_p = itti_alloc_new_message(TASK_GNB_APP, INITIALIZE_MESSAGE); - itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p); -# endif + msg_p = itti_alloc_new_message(TASK_GNB_APP, INITIALIZE_MESSAGE); + itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p); + } do { // Wait for a message @@ -193,7 +200,7 @@ void *gNB_app_task(void *args_p) LOG_I(GNB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p)); break; -# if defined(ENABLE_USE_MME) + /* case S1AP_REGISTER_ENB_CNF: LOG_I(GNB_APP, "[gNB %d] Received %s: associated MME %d\n", instance, msg_name, @@ -254,7 +261,6 @@ void *gNB_app_task(void *args_p) //} break; -# endif default: LOG_E(GNB_APP, "Received unexpected message %s\n", msg_name); @@ -265,8 +271,6 @@ void *gNB_app_task(void *args_p) AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } while (1); -#endif - return NULL; } diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index e4c20b9cfa..9355517072 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -36,13 +36,9 @@ #include "gnb_config.h" #include "UTIL/OTG/otg.h" #include "UTIL/OTG/otg_externs.h" -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -# if defined(ENABLE_USE_MME) -# include "s1ap_eNB.h" -# include "sctp_eNB_task.h" -# endif -#endif +#include "intertask_interface.h" +#include "s1ap_eNB.h" +#include "sctp_eNB_task.h" #include "sctp_default_values.h" // #include "SystemInformationBlockType2.h" // #include "LAYER2/MAC/extern.h" @@ -216,23 +212,40 @@ void prepare_scc(NR_ServingCellConfigCommon_t *scc) { void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) { int ssbmaplen = (int)scc->ssb_PositionsInBurst->present; + uint8_t curr_bit; + AssertFatal(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap || ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap || ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_longBitmap, "illegal ssbmaplen %d\n",ssbmaplen); + + // changing endianicity of ssbmap and filling the ssb_PositionsInBurst buffers if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap){ scc->ssb_PositionsInBurst->choice.shortBitmap.size = 1; scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused = 4; scc->ssb_PositionsInBurst->choice.shortBitmap.buf = CALLOC(1,1); - scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] = ssbmap; + scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] = 0; + for (int i=0; i<8; i++) { + if (issb_PositionsInBurst->choice.shortBitmap.bits_unused) + curr_bit = 0; + else + curr_bit = (ssbmap>>(7-i))&0x01; + scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] |= curr_bit<ssb_PositionsInBurst->choice.mediumBitmap.size = 1; scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0; scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = CALLOC(1,1); - scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = ssbmap; + scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = 0; + for (int i=0; i<8; i++) + scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] |= (((ssbmap>>(7-i))&0x01)<ssb_PositionsInBurst->choice.longBitmap.size = 8; scc->ssb_PositionsInBurst->choice.longBitmap.bits_unused = 0; scc->ssb_PositionsInBurst->choice.longBitmap.buf = CALLOC(1,8); - for (int i=0; i<8; i++) - scc->ssb_PositionsInBurst->choice.longBitmap.buf[i] = (ssbmap>>(i<<3))&(0xff); + for (int j=0; j<8; j++) { + scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] = 0; + curr_bit = (ssbmap>>(j<<3))&(0xff); + for (int i=0; i<8; i++) + scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] |= (((curr_bit>>(7-i))&0x01)<phy_test = *(MacRLC_ParamList.paramarray[j][MACRLC_PHY_TEST_IDX].iptr); - //printf("PHY_TEST = %d,%d\n", RC.nrmac[j]->phy_test, j); if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_RRC") == 0) { // check number of instances is same as RRC/PDCP @@ -483,7 +493,7 @@ void RCconfig_nr_macrlc() { RC.nrmac[j]->eth_params_s.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr); RC.nrmac[j]->eth_params_s.transp_preference = ETH_UDP_MODE; - //sf_ahead = 2; // Cannot cope with 4 subframes betweem RX and TX - set it to 2 + //sf_ahead = 2; // Cannot cope with 4 subframes between RX and TX - set it to 2 printf("**************** vnf_port:%d\n", RC.mac[j]->eth_params_s.my_portc); configure_nfapi_vnf(RC.nrmac[j]->eth_params_s.my_addr, RC.nrmac[j]->eth_params_s.my_portc); @@ -510,7 +520,7 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(NR_ServingCellConfigCommon_t)); - int ssb_SubcarrierOffset = 0; + int ssb_SubcarrierOffset = 31; int pdsch_AntennaPorts = 1; uint64_t ssb_bitmap=0xff; memset((void*)scc,0,sizeof(NR_ServingCellConfigCommon_t)); @@ -530,6 +540,24 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal (i0) { @@ -538,14 +566,14 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); if (GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr == NULL) { - // Calculate a default gNB ID -# if defined(ENABLE_USE_MME) - uint32_t hash; - hash = s1ap_generate_eNB_id (); - gnb_id = i + (hash & 0xFFFF8); -# else - gnb_id = i; -# endif + // Calculate a default gNB ID + if (EPC_MODE_ENABLED) { + uint32_t hash; + hash = s1ap_generate_eNB_id (); + gnb_id = i + (hash & 0xFFFF8); + } else { + gnb_id = i; + } } else { gnb_id = *(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr); } @@ -570,10 +598,8 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { (int)scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth, (int)scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower); fix_scc(scc,ssb_bitmap); - } printf("NRRRC %d: Southbound Transport %s\n",i,*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr)); - if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) { } else if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "cudu") == 0) { @@ -667,7 +693,7 @@ int RCconfig_nr_gtpu(void ) { paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - paramdef_t GTPUParams[] = GNBGTPUPARAMS_DESC; + paramdef_t GTPUParams[] = GNBGTPUPARAMS_DESC; LOG_I(GTPU,"Configuring GTPu\n"); /* get number of active eNodeBs */ @@ -722,7 +748,7 @@ int RCconfig_NR_S1(MessageDef *msg_p, uint32_t i) { config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); /* -#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) + if (EPC_MODE_ENABLED) { if (strcasecmp( *(GNBSParams[GNB_ASN1_VERBOSITY_IDX].strptr), GNB_CONFIG_STRING_ASN1_VERBOSITY_NONE) == 0) { asn_debug = 0; asn1_xer_print = 0; @@ -736,7 +762,7 @@ int RCconfig_NR_S1(MessageDef *msg_p, uint32_t i) { asn_debug = 0; asn1_xer_print = 0; } -#endif + } */ AssertFatal (i 0) { + // Output a list of all gNBs. + config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); + + if (GNBParamList.numelt > 0) { + for (k = 0; k < GNBParamList.numelt; k++) { + if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) { + // Calculate a default eNB ID + if (EPC_MODE_ENABLED) { + uint32_t hash; + hash = s1ap_generate_eNB_id (); + gnb_id = k + (hash & 0xFFFF8); + } else { + gnb_id = k; + } + } else { + gnb_id = *(GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr); + } + + // search if in active list + for (j = 0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) { + if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) { + paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; + paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; + /* map parameter checking array instances to parameter definition array instances */ + checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK; + + for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I) + PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); + + paramdef_t X2Params[] = X2PARAMS_DESC; + paramlist_def_t X2ParamList = {ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS,NULL,0}; + paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC; + paramdef_t NETParams[] = GNBNETPARAMS_DESC; + /* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */ + /* this is most probably a problem with the config module */ + char aprefix[MAX_OPTNAME_SIZE*80 + 8]; + sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); + /* Some default/random parameters */ + X2AP_REGISTER_ENB_REQ (msg_p).eNB_id = gnb_id; + + if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) { + X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_GNB; + }else { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n", + RC.config_file_name, i, *(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr)); + } + + X2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)); + X2AP_REGISTER_ENB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr; + config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix); + + if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) + AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", + PLMNParamList.numelt); + + if (PLMNParamList.numelt > 1) + LOG_W(X2AP, "X2AP currently handles only one PLMN, ignoring the others!\n"); + + X2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + X2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr; + X2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr; + AssertFatal(X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3 + || X2AP_REGISTER_ENB_REQ(msg_p).mnc < 100, + "MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n", + X2AP_REGISTER_ENB_REQ(msg_p).mnc); + + X2AP_REGISTER_ENB_REQ (msg_p).num_cc = 1; + J = 0; + X2AP_REGISTER_ENB_REQ (msg_p).eutra_band[J] = 78; //ccparams_nr_x2.nr_band; //78 + X2AP_REGISTER_ENB_REQ (msg_p).downlink_frequency[J] = 3600000000; //ccparams_nr_x2.downlink_frequency; //3600000000 + X2AP_REGISTER_ENB_REQ (msg_p).uplink_frequency_offset[J] = 0; //(unsigned int) ccparams_nr_x2.uplink_frequency_offset; //0 + X2AP_REGISTER_ENB_REQ (msg_p).Nid_cell[J]= 0; //ccparams_nr_x2.Nid_cell; //0 + X2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J]= 106; //ccparams_nr_x2.N_RB_DL; //106 + + X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD; + + //Temp out + /*X2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_DL[J] = to_earfcn_DL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency, ccparams_lte.N_RB_DL); + X2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_UL[J] = to_earfcn_UL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency + ccparams_lte.uplink_frequency_offset, ccparams_lte.N_RB_DL);*/ + + sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); + config_getlist( &X2ParamList,X2Params,sizeof(X2Params)/sizeof(paramdef_t),aprefix); + AssertFatal(X2ParamList.numelt <= X2AP_MAX_NB_ENB_IP_ADDRESS, + "value of X2ParamList.numelt %d must be lower than X2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase X2AP_MAX_NB_ENB_IP_ADDRESS\n", + X2ParamList.numelt,X2AP_MAX_NB_ENB_IP_ADDRESS); + X2AP_REGISTER_ENB_REQ (msg_p).nb_x2 = 0; + + for (l = 0; l < X2ParamList.numelt; l++) { + X2AP_REGISTER_ENB_REQ (msg_p).nb_x2 += 1; + strcpy(X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4_address,*(X2ParamList.paramarray[l][ENB_X2_IPV4_ADDRESS_IDX].strptr)); + strcpy(X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6_address,*(X2ParamList.paramarray[l][ENB_X2_IPV6_ADDRESS_IDX].strptr)); + + if (strcmp(*(X2ParamList.paramarray[l][ENB_X2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) { + X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 1; + X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 0; + } else if (strcmp(*(X2ParamList.paramarray[l][ENB_X2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) { + X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 0; + X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 1; + } else if (strcmp(*(X2ParamList.paramarray[l][ENB_X2_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) { + X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 1; + X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 1; + } + } + + // timers + { + int t_reloc_prep = 0; + int tx2_reloc_overall = 0; + paramdef_t p[] = { + { "t_reloc_prep", "t_reloc_prep", 0, iptr:&t_reloc_prep, defintval:0, TYPE_INT, 0 }, + { "tx2_reloc_overall", "tx2_reloc_overall", 0, iptr:&tx2_reloc_overall, defintval:0, TYPE_INT, 0 } + }; + config_get(p, sizeof(p)/sizeof(paramdef_t), aprefix); + + if (t_reloc_prep <= 0 || t_reloc_prep > 10000 || + tx2_reloc_overall <= 0 || tx2_reloc_overall > 20000) { + LOG_E(X2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_overall <= 20000]\n"); + exit(1); + } + + X2AP_REGISTER_ENB_REQ (msg_p).t_reloc_prep = t_reloc_prep; + X2AP_REGISTER_ENB_REQ (msg_p).tx2_reloc_overall = tx2_reloc_overall; + } + // SCTP SETTING + X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS; + X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS; + + if (EPC_MODE_ENABLED) { + sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG); + config_get( SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix); + X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr); + X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr); + } + + sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + // NETWORK_INTERFACES + config_get( NETParams,sizeof(NETParams)/sizeof(paramdef_t),aprefix); + X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C = (uint32_t)*(NETParams[GNB_PORT_FOR_X2C_IDX].uptr); + + //temp out + if ((NETParams[GNB_IPV4_ADDR_FOR_X2C_IDX].strptr == NULL) || (X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C == 0)) { + LOG_E(RRC,"Add eNB IPv4 address and/or port for X2C in the CONF file!\n"); + exit(1); + } + + cidr = *(NETParams[ENB_IPV4_ADDR_FOR_X2C_IDX].strptr); + address = strtok(cidr, "/"); + X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv6 = 0; + X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv4 = 1; + strcpy(X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv4_address, address); + } + } + } + } + } + + return 0; +} + + diff --git a/openair2/GNB_APP/gnb_config.h b/openair2/GNB_APP/gnb_config.h index 8320c5ccdc..e2588d9e4d 100644 --- a/openair2/GNB_APP/gnb_config.h +++ b/openair2/GNB_APP/gnb_config.h @@ -103,6 +103,7 @@ extern void NRRCConfig(void); void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc); int RCconfig_NR_S1(MessageDef *msg_p, uint32_t i); +int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i); #endif /* GNB_CONFIG_H_ */ /** @} */ diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 67dbeca2e7..2d9ecb8c8a 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -45,10 +45,8 @@ #define GNB_CONF_STRING_OTG_APP_TYPE "app_type" #define GNB_CONF_STRING_OTG_BG_TRAFFIC "bg_traffic" -#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) extern int asn_debug; extern int asn1_xer_print; -#endif #ifdef LIBCONFIG_LONG #define libconfig_int long @@ -113,6 +111,29 @@ typedef enum { #define GNB_CONFIG_STRING_LOCAL_S_PORTD "local_s_portd" #define GNB_CONFIG_STRING_REMOTE_S_PORTD "remote_s_portd" +typedef struct ccparams_nr_x2 { + char *frame_type; + int32_t tdd_config; + int32_t tdd_config_s; + int32_t nr_band; + long long int downlink_frequency; + int32_t uplink_frequency_offset; + int32_t Nid_cell; + int32_t N_RB_DL; + } ccparams_nr_x2_t; + + +#define CCPARAMS_NR_X2_DESC(ccparams) { \ + {ENB_CONFIG_STRING_FRAME_TYPE, NULL, 0, strptr:&ccparams.frame_type, defstrval:"TDD", TYPE_STRING, 0}, \ + {ENB_CONFIG_STRING_TDD_CONFIG, NULL, 0, iptr:&ccparams.tdd_config, defintval:3, TYPE_UINT, 0}, \ + {ENB_CONFIG_STRING_TDD_CONFIG_S, NULL, 0, iptr:&ccparams.tdd_config_s, defintval:0, TYPE_UINT, 0}, \ + {ENB_CONFIG_STRING_EUTRA_BAND, NULL, 0, iptr:&ccparams.nr_band, defintval:78, TYPE_UINT, 0}, \ + {ENB_CONFIG_STRING_DOWNLINK_FREQUENCY, NULL, 0, i64ptr:(int64_t *)&ccparams.downlink_frequency, defint64val:3600000000, TYPE_UINT64, 0}, \ + {ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET, NULL, 0, iptr:&ccparams.uplink_frequency_offset, defintval:0, TYPE_INT, 0}, \ + {ENB_CONFIG_STRING_NID_CELL, NULL, 0, iptr:&ccparams.Nid_cell, defintval:0, TYPE_UINT, 0}, \ + {ENB_CONFIG_STRING_N_RB_DL, NULL, 0, iptr:&ccparams.N_RB_DL, defintval:106, TYPE_UINT, 0} \ +} + /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -122,8 +143,8 @@ typedef enum { {GNB_CONFIG_STRING_CELL_TYPE, NULL, 0, strptr:NULL, defstrval:"CELL_MACRO_GNB", TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_GNB_NAME, NULL, 0, strptr:NULL, defstrval:"OAIgNodeB", TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_TRACKING_AREA_CODE, NULL, 0, strptr:NULL, defstrval:"0", TYPE_STRING, 0}, \ -{GNB_CONFIG_STRING_MOBILE_COUNTRY_CODE_OLD, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ -{GNB_CONFIG_STRING_MOBILE_NETWORK_CODE_OLD, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{GNB_CONFIG_STRING_MOBILE_COUNTRY_CODE_OLD, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{GNB_CONFIG_STRING_MOBILE_NETWORK_CODE_OLD, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_TRANSPORT_S_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_mac", TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_LOCAL_S_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_LOCAL_S_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ @@ -262,6 +283,8 @@ typedef enum { #define GNB_INTERFACE_NAME_FOR_S1U_IDX 2 #define GNB_IPV4_ADDR_FOR_S1U_IDX 3 #define GNB_PORT_FOR_S1U_IDX 4 +#define GNB_IPV4_ADDR_FOR_X2C_IDX 5 +#define GNB_PORT_FOR_X2C_IDX 6 /* S1 interface configuration parameters names */ #define GNB_CONFIG_STRING_GNB_INTERFACE_NAME_FOR_S1_MME "GNB_INTERFACE_NAME_FOR_S1_MME" @@ -270,6 +293,10 @@ typedef enum { #define GNB_CONFIG_STRING_GNB_IPV4_ADDR_FOR_S1U "GNB_IPV4_ADDRESS_FOR_S1U" #define GNB_CONFIG_STRING_GNB_PORT_FOR_S1U "GNB_PORT_FOR_S1U" +/* X2 interface configuration parameters names */ +#define GNB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C "GNB_IPV4_ADDRESS_FOR_X2C" +#define GNB_CONFIG_STRING_ENB_PORT_FOR_X2C "GNB_PORT_FOR_X2C" + /*--------------------------------------------------------------------------------------------------------------------------------------------------*/ /* S1 interface configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -279,7 +306,9 @@ typedef enum { {GNB_CONFIG_STRING_GNB_IPV4_ADDRESS_FOR_S1_MME, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_GNB_INTERFACE_NAME_FOR_S1U, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_GNB_IPV4_ADDR_FOR_S1U, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ -{GNB_CONFIG_STRING_GNB_PORT_FOR_S1U, NULL, 0, uptr:NULL, defintval:2152L, TYPE_UINT, 0} \ +{GNB_CONFIG_STRING_GNB_PORT_FOR_S1U, NULL, 0, uptr:NULL, defintval:2152L, TYPE_UINT, 0}, \ +{GNB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \ +{GNB_CONFIG_STRING_ENB_PORT_FOR_X2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0} \ } @@ -355,7 +384,6 @@ typedef enum { #define CONFIG_STRING_MACRLC_REMOTE_S_PORTC "remote_s_portc" #define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" #define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" -#define CONFIG_STRING_MACRLC_PHY_TEST_MODE "phy_test_mode" #define MACRLC_CC_IDX 0 @@ -376,7 +404,6 @@ typedef enum { #define MACRLC_LOCAL_S_PORTD_IDX 15 #define MACRLC_REMOTE_S_PORTD_IDX 16 #define MACRLC_SCHED_MODE_IDX 17 -#define MACRLC_PHY_TEST_IDX 18 /* thread configuration parameters section name */ diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index d503a37d82..76c8e33b16 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -49,6 +49,7 @@ #include "LTE_MBSFN-AreaInfoList-r9.h" #include "LTE_MBSFN-AreaInfo-r9.h" #include "LTE_MBSFN-SubframeConfigList.h" +#include "LTE_MBSFN-SubframeConfig.h" #include "LTE_PMCH-InfoList-r9.h" @@ -610,6 +611,121 @@ config_sib2(int Mod_idP, } } +void +config_sib2_mbsfn_part( int Mod_idP, + int CC_idP, + struct LTE_MBSFN_SubframeConfigList *mbsfn_SubframeConfigListP) { + + //LTE_DL_FRAME_PARMS *fp = &RC.eNB[Mod_idP][CC_idP]->frame_parms; + //int i; + //if(mbsfn_SubframeConfigListP != NULL) { + // fp->num_MBSFN_config = mbsfn_SubframeConfigListP->list.count; + + // for(i = 0; i < mbsfn_SubframeConfigListP->list.count; i++) { + // fp->MBSFN_config[i].radioframeAllocationPeriod = mbsfn_SubframeConfigListP->list.array[i]->radioframeAllocationPeriod; + // fp->MBSFN_config[i].radioframeAllocationOffset = mbsfn_SubframeConfigListP->list.array[i]->radioframeAllocationOffset; + + // if (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { + // fp->MBSFN_config[i].fourFrames_flag = 0; + // fp->MBSFN_config[i].mbsfn_SubframeConfig = mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration + // LOG_I (PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, fp->MBSFN_config[i].mbsfn_SubframeConfig); + // } else if (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration + // fp->MBSFN_config[i].fourFrames_flag = 1; + // fp->MBSFN_config[i].mbsfn_SubframeConfig = + // mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]| + // (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| + // (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]<<16); + + // LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", i, + // fp->MBSFN_config[i].mbsfn_SubframeConfig); + // } + // } + + //} else + // fp->num_MBSFN_config = 0; + + PHY_Config_t phycfg; + phycfg.Mod_id = Mod_idP; + phycfg.CC_id = CC_idP; + phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; + int i; + + if(mbsfn_SubframeConfigListP != NULL) { + phycfg.cfg->embms_mbsfn_config.num_mbsfn_config = mbsfn_SubframeConfigListP->list.count; + + for(i = 0; i < mbsfn_SubframeConfigListP->list.count; i++) { + phycfg.cfg->embms_mbsfn_config.radioframe_allocation_period[i] = mbsfn_SubframeConfigListP->list.array[i]->radioframeAllocationPeriod; + phycfg.cfg->embms_mbsfn_config.radioframe_allocation_offset[i] = mbsfn_SubframeConfigListP->list.array[i]->radioframeAllocationOffset; + + if (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { + phycfg.cfg->embms_mbsfn_config.fourframes_flag[i] = 0; + phycfg.cfg->embms_mbsfn_config.mbsfn_subframeconfig[i] = mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration + LOG_I (MAC, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, phycfg.cfg->embms_mbsfn_config.mbsfn_subframeconfig[i]); + } else if (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration + phycfg.cfg->embms_mbsfn_config.fourframes_flag[i] = 1; + phycfg.cfg->embms_mbsfn_config.mbsfn_subframeconfig[i] = + mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]| + (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| + (mbsfn_SubframeConfigListP->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]<<16); + + LOG_I(MAC, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", i, + phycfg.cfg->embms_mbsfn_config.mbsfn_subframeconfig[i]); + } + } + phycfg.cfg->num_tlv++; + + } else{ + phycfg.cfg->embms_mbsfn_config.num_mbsfn_config = 0; + phycfg.cfg->num_tlv++; + } + + phycfg.cfg->embms_mbsfn_config.tl.tag = NFAPI_EMBMS_MBSFN_CONFIG_TAG; + + if (RC.mac[Mod_idP]->if_inst->PHY_config_update_sib2_req) RC.mac[Mod_idP]->if_inst->PHY_config_update_sib2_req(&phycfg); +} + +void +config_sib13( int Mod_id, + int CC_id, + int mbsfn_Area_idx, + long mbsfn_AreaId_r9){ + + //nfapi_config_request_t *cfg = &RC.mac[Mod_id]->config[CC_id]; + + //work around until PHY_config_re "update" mechanisms get defined +// LTE_DL_FRAME_PARMS *fp = &RC.eNB[Mod_id][CC_id]->frame_parms; +// LOG_I (MAC, "[eNB%d] Applying MBSFN_Area_id %ld for index %d\n", Mod_id, mbsfn_AreaId_r9, mbsfn_Area_idx); +// +// AssertFatal(mbsfn_Area_idx == 0, "Fix me: only called when mbsfn_Area_idx == 0\n"); +// if (mbsfn_Area_idx == 0) { +// fp->Nid_cell_mbsfn = (uint16_t)mbsfn_AreaId_r9; +// LOG_I(MAC,"Fix me: only called when mbsfn_Area_idx == 0)\n"); +// } +// lte_gold_mbsfn (fp, RC.eNB[Mod_id][CC_id]->lte_gold_mbsfn_table, fp->Nid_cell_mbsfn); +// +// lte_gold_mbsfn_khz_1dot25 (fp, RC.eNB[Mod_id][CC_id]->lte_gold_mbsfn_khz_1dot25_table, fp->Nid_cell_mbsfn); +// + PHY_Config_t phycfg; + phycfg.Mod_id = Mod_id; + phycfg.CC_id = CC_id; + phycfg.cfg = &RC.mac[Mod_id]->config[CC_id]; + + phycfg.cfg->embms_sib13_config.mbsfn_area_idx.value = (uint8_t)mbsfn_Area_idx; + phycfg.cfg->embms_sib13_config.mbsfn_area_idx.tl.tag = NFAPI_EMBMS_MBSFN_CONFIG_AREA_IDX_TAG; + phycfg.cfg->num_tlv++; + phycfg.cfg->embms_sib13_config.mbsfn_area_id_r9.value = (uint32_t)mbsfn_AreaId_r9; + phycfg.cfg->embms_sib13_config.mbsfn_area_id_r9.tl.tag = NFAPI_EMBMS_MBSFN_CONFIG_AREA_IDR9_TAG; + phycfg.cfg->num_tlv++; + + if (RC.mac[Mod_id]->if_inst->PHY_config_update_sib13_req) RC.mac[Mod_id]->if_inst->PHY_config_update_sib13_req(&phycfg); + +// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + +} + + + + void config_dedicated(int Mod_idP, int CC_idP, @@ -820,6 +936,7 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP, } RC.mac[Mod_idP]->common_channels[0].MBMS_flag = MBMS_Flag; + config_sib2_mbsfn_part(Mod_idP,0,mbsfn_SubframeConfigList); } if (nonMBSFN_SubframeConfig != NULL) { @@ -856,6 +973,7 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP, LOG_I(MAC,"[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", Mod_idP,i, RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9); // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); + config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); } } @@ -885,6 +1003,10 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP, LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, RC.mac[Mod_idP]->common_channels[0]. mbms_SessionList[i]->list.count); + for(int ii=0; ii < RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i]->list.count;ii++){ + LOG_I(MAC, "PMCH[%d] MBMS Session[%d] is: %lu\n", i,ii, + RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i]->list.array[ii]->logicalChannelIdentity_r9); + } } } @@ -920,55 +1042,53 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP, //----------------------------------------------------------------------------- /* -* Configure local DRX timers and thresholds following the drx_configuration input +* Configure local CDRX timers and thresholds following the drx_configuration input */ -void eNB_Config_Local_DRX( - module_id_t Mod_id, - rnti_t rnti, - LTE_DRX_Config_t *const drx_Configuration -) +void eNB_Config_Local_DRX(instance_t Mod_id, + rrc_mac_drx_config_req_t *rrc_mac_drx_config_req) //----------------------------------------------------------------------------- { UE_list_t *UE_list_mac = NULL; - int UE_id = -1; UE_sched_ctrl_t *UE_scheduling_control = NULL; + int UE_id = -1; + + rnti_t rnti = rrc_mac_drx_config_req->rnti; + LTE_DRX_Config_t *const drx_Configuration = rrc_mac_drx_config_req->drx_Configuration; + UE_list_mac = &(RC.mac[Mod_id]->UE_list); UE_id = find_UE_id(Mod_id, rnti); /* Check UE_id */ if (UE_id == -1) { - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", - __FILE__, - __LINE__, - __FUNCTION__); + LOG_E(MAC, "[eNB_Config_Local_DRX] UE_id == -1\n"); return; } /* Get struct to modify */ UE_scheduling_control = &(UE_list_mac->UE_sched_ctrl[UE_id]); + UE_scheduling_control->cdrx_configured = FALSE; // will be set to true when no error /* Check drx_Configuration */ if (drx_Configuration == NULL) { - LOG_I(MAC, "drx_Configuration parameter is NULL, cannot configure local UE parameters\n"); - UE_scheduling_control->cdrx_configured = FALSE; + LOG_W(MAC, "[eNB_Config_Local_DRX] drx_Configuration parameter is NULL, cannot configure local UE parameters for CDRX\n"); return; } /* Check if drx config present */ if (drx_Configuration->present != LTE_DRX_Config_PR_setup) { - LOG_I(MAC, "No drx_Configuration present, don't configure local UE parameters\n"); - UE_scheduling_control->cdrx_configured = FALSE; + LOG_I(MAC, "[eNB_Config_Local_DRX] No drx_Configuration present, don't configure local UE parameters for CDRX\n"); return; } - /* Modify scheduling control structure according to DRX configuration: doesn't support every configurations! */ - UE_scheduling_control->cdrx_configured = FALSE; // will be set to true when ACK is received - UE_scheduling_control->cdrx_waiting_ack = TRUE; // set to true first, waiting for the UE to configure CDRX on its side + /* Modify scheduling control structure according to DRX configuration: doesn't support every configurations! */ + UE_scheduling_control->cdrx_configured = FALSE; // will be set to true when receiving RRC Reconfiguration Complete + UE_scheduling_control->cdrx_waiting_ack = TRUE; // waiting for RRC Reconfiguration Complete message UE_scheduling_control->in_active_time = FALSE; UE_scheduling_control->dci0_ongoing_timer = 0; UE_scheduling_control->on_duration_timer = 0; + struct LTE_DRX_Config__setup *choiceSetup = &drx_Configuration->choice.setup; - switch (drx_Configuration->choice.setup.onDurationTimer) { + switch (choiceSetup->onDurationTimer) { case 0: UE_scheduling_control->on_duration_timer_thres = 1; break; @@ -1034,13 +1154,13 @@ void eNB_Config_Local_DRX( break; default: - LOG_E(MAC, "Error in local DRX configuration, the on duration timer value specified is unknown\n"); + LOG_E(MAC, "[eNB_Config_Local_DRX] Error in local DRX configuration, the on duration timer value specified is unknown\n"); break; } UE_scheduling_control->drx_inactivity_timer = 0; - switch (drx_Configuration->choice.setup.drx_InactivityTimer) { + switch (choiceSetup->drx_InactivityTimer) { case 0: UE_scheduling_control->drx_inactivity_timer_thres = 1; break; @@ -1134,11 +1254,11 @@ void eNB_Config_Local_DRX( break; default: - LOG_E(MAC, "Error in local DRX configuration, the drx inactivity timer value specified is unknown\n"); + LOG_E(MAC, "[eNB_Config_Local_DRX] Error in local DRX configuration, the drx inactivity timer value specified is unknown\n"); break; } - if (drx_Configuration->choice.setup.shortDRX == NULL) { + if (choiceSetup->shortDRX == NULL) { UE_scheduling_control->in_short_drx_cycle = FALSE; UE_scheduling_control->drx_shortCycle_timer_value = 0; UE_scheduling_control->short_drx_cycle_duration = 0; @@ -1146,9 +1266,9 @@ void eNB_Config_Local_DRX( UE_scheduling_control->drx_shortCycle_timer_thres = -1; } else { UE_scheduling_control->in_short_drx_cycle = FALSE; - UE_scheduling_control->drx_shortCycle_timer_value = (uint8_t) drx_Configuration->choice.setup.shortDRX->drxShortCycleTimer; + UE_scheduling_control->drx_shortCycle_timer_value = (uint8_t) choiceSetup->shortDRX->drxShortCycleTimer; - switch (drx_Configuration->choice.setup.shortDRX->shortDRX_Cycle) { + switch (choiceSetup->shortDRX->shortDRX_Cycle) { case 0: UE_scheduling_control->short_drx_cycle_duration = 2; break; @@ -1214,7 +1334,7 @@ void eNB_Config_Local_DRX( break; default: - LOG_E(MAC, "Error in local DRX configuration, the short drx timer value specified is unknown\n"); + LOG_E(MAC, "[eNB_Config_Local_DRX] Error in local DRX configuration, the short drx timer value specified is unknown\n"); break; } @@ -1225,95 +1345,95 @@ void eNB_Config_Local_DRX( UE_scheduling_control->in_long_drx_cycle = FALSE; UE_scheduling_control->drx_longCycle_timer = 0; - switch (drx_Configuration->choice.setup.longDRX_CycleStartOffset.present) { - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf10: + switch (choiceSetup->longDRX_CycleStartOffset.present) { + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf10: UE_scheduling_control->drx_longCycle_timer_thres = 10; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf10; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf10; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf20: UE_scheduling_control->drx_longCycle_timer_thres = 20; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf20; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf20; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf32: UE_scheduling_control->drx_longCycle_timer_thres = 32; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf32; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf32; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf40: UE_scheduling_control->drx_longCycle_timer_thres = 40; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf40; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf40; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf64: UE_scheduling_control->drx_longCycle_timer_thres = 64; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf64; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf64; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf80: UE_scheduling_control->drx_longCycle_timer_thres = 80; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf80; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf80; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf128: UE_scheduling_control->drx_longCycle_timer_thres = 128; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf128; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf128; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf160: UE_scheduling_control->drx_longCycle_timer_thres = 160; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf160; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf160; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf256: UE_scheduling_control->drx_longCycle_timer_thres = 256; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf256; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf256; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf320: UE_scheduling_control->drx_longCycle_timer_thres = 320; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf320; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf320; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf512: UE_scheduling_control->drx_longCycle_timer_thres = 512; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf512; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf512; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf640: UE_scheduling_control->drx_longCycle_timer_thres = 640; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf640; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf640; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf1024: UE_scheduling_control->drx_longCycle_timer_thres = 1024; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf1024; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf1024; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf1280: UE_scheduling_control->drx_longCycle_timer_thres = 1280; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf1280; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf1280; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf2048: UE_scheduling_control->drx_longCycle_timer_thres = 2048; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf2048; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf2048; break; case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf2560: UE_scheduling_control->drx_longCycle_timer_thres = 2560; - UE_scheduling_control->drx_start_offset = (uint16_t) drx_Configuration->choice.setup.longDRX_CycleStartOffset.choice.sf2560; + UE_scheduling_control->drx_start_offset = (uint16_t) choiceSetup->longDRX_CycleStartOffset.choice.sf2560; break; default: - LOG_E(MAC, "Invalid long_DRX value in DRX local configuration\n"); + LOG_E(MAC, "[eNB_Config_Local_DRX] Invalid long_DRX value in DRX local configuration\n"); break; } memset(UE_scheduling_control->drx_retransmission_timer, 0, sizeof(UE_scheduling_control->drx_retransmission_timer)); - switch (drx_Configuration->choice.setup.drx_RetransmissionTimer) { + switch (choiceSetup->drx_RetransmissionTimer) { case 0: memset(UE_scheduling_control->drx_retransmission_timer_thres, 1, sizeof(UE_scheduling_control->drx_retransmission_timer_thres)); break; @@ -1347,7 +1467,7 @@ void eNB_Config_Local_DRX( break; default: - LOG_E(MAC, "Error in local DRX configuration, the drx retransmission timer value specified is unknown\n"); + LOG_E(MAC, "[eNB_Config_Local_DRX] Error in local DRX configuration, the drx retransmission timer value specified is unknown\n"); break; } } diff --git a/openair2/LAYER2/MAC/config_ue.c b/openair2/LAYER2/MAC/config_ue.c index a0233a5e42..897afbf62b 100644 --- a/openair2/LAYER2/MAC/config_ue.c +++ b/openair2/LAYER2/MAC/config_ue.c @@ -140,7 +140,7 @@ rrc_mac_config_req_ue(module_id_t Mod_idP, phy_config_sib2_ue(Mod_idP, 0, eNB_index, radioResourceConfigCommon, ul_CarrierFreq, ul_Bandwidth, additionalSpectrumEmission, - mbsfn_SubframeConfigList); + NULL/*mbsfn_SubframeConfigList*/); } // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup @@ -469,6 +469,9 @@ rrc_mac_config_req_ue(module_id_t Mod_idP, } if (mbsfn_SubframeConfigList != NULL) { + phy_config_mbsfn_list_ue(Mod_idP, 0, + mbsfn_SubframeConfigList); + LOG_I(MAC, "[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", Mod_idP, mbsfn_SubframeConfigList->list.count); diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 2fa88dcde6..05660b727e 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -320,7 +320,7 @@ typedef struct { /*!\brief DTCH DRB1 logical channel */ #define DTCH 3 // LCID /*!\brief MCCH logical channel */ -#define MCCH 4 +#define MCCH 11 /*!\brief MTCH logical channel */ #define MTCH 1 // DLSCH LCHAN ID diff --git a/openair2/LAYER2/MAC/defs_NB_IoT.h b/openair2/LAYER2/MAC/defs_NB_IoT.h index 0d7dd7d2c0..517f01d1b9 100644 --- a/openair2/LAYER2/MAC/defs_NB_IoT.h +++ b/openair2/LAYER2/MAC/defs_NB_IoT.h @@ -64,7 +64,8 @@ #define DTCH 3 // LCID /*!\brief MCCH logical channel */ //#define MCCH 4 -#define MCCH 62 +//#define MCCH 62 +#define MCCH 11 /*!\brief MTCH logical channel */ #define MTCH 1 // DLSCH LCHAN ID diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index e6484aba3e..eef1f9c976 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -57,9 +57,7 @@ /* for fair round robin SCHED */ #include "eNB_scheduler_fairRR.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "assertions.h" @@ -897,15 +895,22 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, } // end for loop on UE_id #if (!defined(PRE_SCD_THREAD)) - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP); - pdcp_run(&ctxt); - rrc_rx_tx(&ctxt, CC_id); + if (!NODE_IS_DU(RC.rrc[module_idP]->node_type)) { + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP); + pdcp_run(&ctxt); + pdcp_mbms_run(&ctxt); + rrc_rx_tx(&ctxt, CC_id); + } #endif for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { if (cc[CC_id].MBMS_flag > 0) { start_meas(&RC.mac[module_idP]->schedule_mch); - mbsfn_status[CC_id] = schedule_MBMS(module_idP, CC_id, frameP, subframeP); + int(*schedule_mch)(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframe) = NULL; + schedule_mch = schedule_MBMS_NFAPI; + if(schedule_mch){ + mbsfn_status[CC_id] = schedule_mch(module_idP, CC_id, frameP, subframeP); + } stop_meas(&RC.mac[module_idP]->schedule_mch); } } @@ -983,6 +988,8 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, if (flexran_agent_get_mac_xface(module_idP) && subframeP == 9) { flexran_agent_slice_update(module_idP); } + if (flexran_agent_get_mac_xface(module_idP)) + flexran_agent_get_mac_xface(module_idP)->flexran_agent_notify_tick(module_idP); stop_meas(&(eNB->eNB_scheduler)); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index e85255e8ce..fb765e6dac 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -55,14 +55,12 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "SIMULATION/TOOLS/sim.h" // for taus #include "T.h" - +#include "executables/softmodem-common.h" #include "common/ran_context.h" #include "LAYER2/MAC/eNB_scheduler_fairRR.h" @@ -1353,28 +1351,31 @@ initiate_ra_proc(module_id_t module_idP, /* TODO: find better procedure to allocate RNTI */ do { -#if defined(USRP_REC_PLAY) // deterministic rnti in usrp record/playback mode - static int drnti[MAX_MOBILES_PER_ENB] = { 0xbda7, 0x71da, 0x9c40, 0xc350, 0x2710, 0x4e20, 0x7530, 0x1388, 0x3a98, 0x61a8, 0x88b8, 0xafc8, 0xd6d8, 0x1b58, 0x4268, 0x6978 }; - int j = 0; - int nb_ue = 0; + if (IS_SOFTMODEM_IQPLAYER) { /* iq player mode, use deterministic rnti */ + static int drnti[MAX_MOBILES_PER_ENB]; + static int drnti_def[]={ 0xbda7, 0x71da, 0x9c40, 0xc350, 0x2710, 0x4e20, 0x7530, 0x1388, 0x3a98, 0x61a8, 0x88b8, 0xafc8, 0xd6d8, 0x1b58, 0x4268, 0x6978 }; + for (int j=0; j 0) { - nb_ue++; - } else { - break; + for (int j = 0; j < MAX_MOBILES_PER_ENB; j++) { + if (UE_RNTI(module_idP, j) > 0) { + nb_ue++; + } else { + break; + } } - } - if (nb_ue >= MAX_MOBILES_PER_ENB) { - printf("No more free RNTI available, increase MAX_MOBILES_PER_ENB\n"); - abort(); - } + if (nb_ue >= MAX_MOBILES_PER_ENB || nb_ue >= (sizeof(drnti_def)/sizeof(int))) { + printf("No more free RNTI available, increase MAX_MOBILES_PER_ENB\n"); + abort(); + } - ra[i].rnti = drnti[nb_ue]; -#else - ra[i].rnti = taus(); -#endif + ra[i].rnti = drnti[nb_ue]; + } else { + ra[i].rnti = taus(); + } loop++; } while (loop != 100 && /* TODO: this is not correct, the rnti may be in use without diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index f5cd3a0753..5b99578d57 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -44,9 +44,7 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index c717f8b901..eba4bdcee9 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -53,9 +53,7 @@ #include "assertions.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include @@ -507,6 +505,13 @@ schedule_ue_spec(module_id_t module_idP, rrc_eNB_ue_context_t *ue_contextP = NULL; int nb_mac_CC = RC.nb_mac_CC[module_idP]; long dl_Bandwidth; + + if(is_pmch_subframe(frameP,subframeP,&RC.eNB[module_idP][0]->frame_parms)){ + //LOG_E(MAC,"Frame[%d] SF:%d This SF should not be allocated\n",frameP,subframeP); + return ; + } + + start_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c index 8d887409e1..260d8a7417 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c @@ -854,6 +854,12 @@ schedule_ue_spec_fairRR(module_id_t module_idP, #ifdef DEBUG_eNB_SCHEDULER int k; #endif + + if(is_pmch_subframe(frameP,subframeP,&RC.eNB[module_idP][0]->frame_parms)){ + //LOG_E(MAC,"fairRR Frame[%d] SF:%d This SF should not be allocated\n",frameP,subframeP); + return; + } + start_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index 4c667a8279..2953c8e70b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -34,6 +34,7 @@ #include "LAYER2/MAC/mac_proto.h" #include "LAYER2/MAC/mac_extern.h" #include "common/utils/LOG/log.h" +#include "nfapi/oai_integration/vendor_ext.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" #include "OCG.h" @@ -47,11 +48,7 @@ #include "pdcp.h" #include "assertions.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif - -#include "SIMULATION/TOOLS/sim.h" // for taus +#include "SIMULATION/TOOLS/sim.h" // for taus #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 @@ -59,713 +56,1694 @@ extern RAN_CONTEXT_t RC; - -int8_t get_mbsfn_sf_alloction(module_id_t module_idP, uint8_t CC_id, uint8_t mbsfn_sync_area) { - // currently there is one-to-one mapping between sf allocation pattern and sync area - if (mbsfn_sync_area >= MAX_MBSFN_AREA) { - LOG_W(MAC, - "[eNB %d] CC_id %d MBSFN synchronization area %d out of range\n ", - module_idP, CC_id, mbsfn_sync_area); - return -1; - } else if (RC.mac[module_idP]-> - common_channels[CC_id].mbsfn_SubframeConfig[mbsfn_sync_area] - != NULL) { - return mbsfn_sync_area; - } else { - LOG_W(MAC, - "[eNB %d] CC_id %d MBSFN Subframe Config pattern %d not found \n ", - module_idP, CC_id, mbsfn_sync_area); - return -1; - } +int8_t +get_mbsfn_sf_alloction(module_id_t module_idP, uint8_t CC_id, + uint8_t mbsfn_sync_area) +{ + // currently there is one-to-one mapping between sf allocation pattern and sync area + if (mbsfn_sync_area > MAX_MBSFN_AREA) { + LOG_W(MAC, + "[eNB %d] CC_id %d MBSFN synchronization area %d out of range\n ", + module_idP, CC_id, mbsfn_sync_area); + return -1; + } else if (RC.mac[module_idP]-> + common_channels[CC_id].mbsfn_SubframeConfig[mbsfn_sync_area] + != NULL) { + return mbsfn_sync_area; + } else { + LOG_W(MAC, + "[eNB %d] CC_id %d MBSFN Subframe Config pattern %d not found \n ", + module_idP, CC_id, mbsfn_sync_area); + return -1; + } } +static uint32_t bytes_in_buffer=0; +static uint32_t msi_pmch_stop=0; +//static uint8_t msi_active=0; +//static uint8_t msi_pmch_stop2=0; +uint16_t mbms_rab_id = 2047; +static uint32_t msi_sfs=0; + + +//MSI_ELEMENT * ptr =NULL; + +int +schedule_MBMS_NFAPI(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + sub_frame_t subframeP) +{ + + nfapi_dl_config_request_body_t *dl_req; + //nfapi_dl_config_request_pdu_t *dl_config_pdu; + + int mcch_flag = 0, mtch_flag = 0, msi_flag = 0; + int mbsfn_period = 0; // 1<<(RC.mac[module_idP]->mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); + int mcch_period = 0; //32<<(RC.mac[module_idP]->mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + if(RC.mac[module_idP]->common_channels[CC_id]. + pmch_Config[0] == NULL ) + + return 0; + + + + + int mch_scheduling_period = + 8 << (RC.mac[module_idP]->common_channels[CC_id]. + pmch_Config[0]->mch_SchedulingPeriod_r9); + unsigned char mcch_sdu_length; + unsigned char header_len_mcch = 0, header_len_msi = + 0, header_len_mtch = 0, header_len_mtch_temp = + 0, header_len_mcch_temp = 0, header_len_msi_temp = 0; + int ii = 0, msi_pos = 0; + int mcch_mcs = -1; + uint16_t TBS, j = -1, padding = 0, post_padding = 0; + mac_rlc_status_resp_t rlc_status; + //mac_rlc_status_resp_t rlc_status2; + int num_mtch; + int msi_length=0, i, k; + //uint8_t l =0; + unsigned char sdu_lcids[11], num_sdus = 0, offset = 0; + uint16_t sdu_lengths[11], sdu_length_total = 0; + unsigned char mch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; // check the max value, this is for dlsch only + + COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; -int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframeP) { - int mcch_flag = 0, mtch_flag = 0, msi_flag = 0; - int mbsfn_period = 0; // 1<<(RC.mac[module_idP]->mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); - int mcch_period = 0; //32<<(RC.mac[module_idP]->mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); - int mch_scheduling_period = - 8 << (RC.mac[module_idP]->common_channels[CC_id]. - pmch_Config[0]->mch_SchedulingPeriod_r9); - unsigned char mcch_sdu_length; - unsigned char header_len_mcch = 0, header_len_msi = - 0, header_len_mtch = 0, header_len_mtch_temp = - 0, header_len_mcch_temp = 0, header_len_msi_temp = 0; - int ii = 0, msi_pos = 0; - int mcch_mcs = -1; - uint16_t TBS, j = -1, padding = 0, post_padding = 0; - mac_rlc_status_resp_t rlc_status; - int num_mtch; - int msi_length, i, k; - unsigned char sdu_lcids[11], num_sdus = 0, offset = 0; - uint16_t sdu_lengths[11], sdu_length_total = 0; - unsigned char mch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; // check the max value, this is for dlsch only - COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; - cc->MCH_pdu.Pdu_size = 0; - - for (i = 0; i < cc->num_active_mbsfn_area; i++) { - // assume, that there is always a mapping - if ((j = get_mbsfn_sf_alloction(module_idP, CC_id, i)) == -1) { - return 0; - } - - mbsfn_period = - 1 << (cc->mbsfn_SubframeConfig[j]->radioframeAllocationPeriod); - mcch_period = - 32 << (cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_RepetitionPeriod_r9); - msi_pos = 0; - ii = 0; - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d subframeP %d : Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d)\n", - module_idP, CC_id, frameP, subframeP, i, - cc->num_active_mbsfn_area, j, cc->num_sf_allocation_pattern, - mbsfn_period, mcch_period); - - switch (cc->mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) { - case 0: - mcch_mcs = 2; - break; - - case 1: - mcch_mcs = 7; - break; - - case 2: - mcch_mcs = 13; - break; - - case 3: - mcch_mcs = 19; - break; - } - - // 1st: Check the MBSFN subframes from SIB2 info (SF allocation pattern i, max 8 non-overlapping patterns exist) - if (frameP % mbsfn_period == cc->mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP - if (cc->mbsfn_SubframeConfig[j]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format - - // Find the first subframeP in this MCH to transmit MSI - if (frameP % mch_scheduling_period == - cc->mbsfn_SubframeConfig[j]-> - radioframeAllocationOffset) { - while (ii == 0) { - ii = cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & (0x80 >> msi_pos); - msi_pos++; - } - - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d subframeP %d : sync area %d sf allocation pattern %d sf alloc %x msi pos is %d \n", - module_idP, CC_id, frameP, subframeP, i, j, - cc->mbsfn_SubframeConfig[j]-> - subframeAllocation.choice.oneFrame.buf[0], - msi_pos); - } - - // Check if the subframeP is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 - switch (subframeP) { - case 1: - if (cc->tdd_Config == NULL) { - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == - MBSFN_FDD_SF1) { - if (msi_pos == 1) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_FDD_SF1) == - MBSFN_FDD_SF1)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 2: - if (cc->tdd_Config == NULL) { - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == - MBSFN_FDD_SF2) { - if (msi_pos == 2) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_FDD_SF2) == - MBSFN_FDD_SF2)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 3: - if (cc->tdd_Config != NULL) { // TDD - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == - MBSFN_TDD_SF3) { - if (msi_pos == 1) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_TDD_SF3) == - MBSFN_TDD_SF3)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == - MBSFN_FDD_SF3) { - if (msi_pos == 3) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_FDD_SF3) == - MBSFN_FDD_SF3)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 4: - if (cc->tdd_Config != NULL) { - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == - MBSFN_TDD_SF4) { - if (msi_pos == 2) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_TDD_SF4) == - MBSFN_TDD_SF4)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 6: - if (cc->tdd_Config == NULL) { - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == - MBSFN_FDD_SF6) { - if (msi_pos == 4) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_FDD_SF6) == - MBSFN_FDD_SF6)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 7: - if (cc->tdd_Config != NULL) { // TDD - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == - MBSFN_TDD_SF7) { - if (msi_pos == 3) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_TDD_SF7) == - MBSFN_TDD_SF7)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == - MBSFN_FDD_SF7) { - if (msi_pos == 5) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_FDD_SF7) == - MBSFN_FDD_SF7)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 8: - if (cc->tdd_Config != NULL) { //TDD - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == - MBSFN_TDD_SF8) { - if (msi_pos == 4) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_TDD_SF8) == - MBSFN_TDD_SF8)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == - MBSFN_FDD_SF8) { - if (msi_pos == 6) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_FDD_SF8) == - MBSFN_FDD_SF8)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 9: - if (cc->tdd_Config != NULL) { - if ((cc-> - mbsfn_SubframeConfig[j]->subframeAllocation. - choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == - MBSFN_TDD_SF9) { - if (msi_pos == 5) { - msi_flag = 1; - } - - if ((frameP % mcch_period == - cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_Offset_r9) - && - ((cc->mbsfn_AreaInfo[i]-> - mcch_Config_r9.sf_AllocInfo_r9. - buf[0] & MBSFN_TDD_SF9) == - MBSFN_TDD_SF9)) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - } // end switch - - // sf allocation is non-overlapping - if ((msi_flag == 1) || (mcch_flag == 1) - || (mtch_flag == 1)) { - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", - module_idP, CC_id, frameP, subframeP, i, j, - msi_flag, mcch_flag, mtch_flag); - break; - } - } else { // four-frameP format - } - } - } // end of for loop - - cc->msi_active = 0; - cc->mcch_active = 0; - cc->mtch_active = 0; - - // Calculate the mcs - if ((msi_flag == 1) || (mcch_flag == 1)) { - cc->MCH_pdu.mcs = mcch_mcs; - } else if (mtch_flag == 1) { // only MTCH in this subframeP - cc->MCH_pdu.mcs = cc->pmch_Config[0]->dataMCS_r9; - } - - // 2nd: Create MSI, get MCCH from RRC and MTCHs from RLC - - // there is MSI (MCH Scheduling Info) - if (msi_flag == 1) { - // Create MSI here - uint16_t msi_control_element[29], *msi_ptr; - msi_ptr = &msi_control_element[0]; - ((MSI_ELEMENT *) msi_ptr)->lcid = MCCH_LCHANID; //MCCH - - if (mcch_flag == 1) { - ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; - ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0; - } else { // no mcch for this MSP - ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // stop value is 2047 - ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xff; - } - - msi_ptr += sizeof(MSI_ELEMENT); - //Header for MTCHs - num_mtch = cc->mbms_SessionList[0]->list.count; - - for (k = 0; k < num_mtch; k++) { // loop for all session in this MCH (MCH[0]) at this moment - ((MSI_ELEMENT *) msi_ptr)->lcid = cc->mbms_SessionList[0]->list.array[k]->logicalChannelIdentity_r9; //mtch_lcid; - ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now) - ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xB; - msi_ptr += sizeof(MSI_ELEMENT); - } - - msi_length = msi_ptr - msi_control_element; - - if (msi_length < 128) { - header_len_msi = 2; - } else { - header_len_msi = 3; - } - - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d : MSI->MCH, length of MSI is %d bytes \n", - module_idP, CC_id, frameP, msi_length); - //LOG_D(MAC,"Scheduler: MSI is transmitted in this subframeP \n" ); - // LOG_D(MAC,"Scheduler: MSI length is %d bytes\n",msi_length); - // Store MSI data to mch_buffer[0] - memcpy((char *) &mch_buffer[sdu_length_total], - msi_control_element, msi_length); - sdu_lcids[num_sdus] = MCH_SCHDL_INFO; - sdu_lengths[num_sdus] = msi_length; - sdu_length_total += sdu_lengths[num_sdus]; - LOG_I(MAC, "[eNB %d] CC_id %d Create %d bytes for MSI\n", - module_idP, CC_id, sdu_lengths[num_sdus]); - num_sdus++; - cc->msi_active = 1; - } - - // there is MCCH - if (mcch_flag == 1) { - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n", - module_idP, CC_id, frameP, subframeP, i, j); - mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH, 0xFFFC, 1, &cc->MCCH_pdu.payload[0], - i); // this is the mbsfn sync area index - - if (mcch_sdu_length > 0) { - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d subframeP %d : MCCH->MCH, Received %d bytes from RRC \n", - module_idP, CC_id, frameP, subframeP, mcch_sdu_length); - header_len_mcch = 2; - - if (cc->tdd_Config != NULL) { - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (TDD) for MCCH message %d bytes (mcs %d )\n", - module_idP, CC_id, frameP, subframeP, - mcch_sdu_length, mcch_mcs); - } else { - LOG_I(MAC, - "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (FDD) for MCCH message %d bytes (mcs %d)\n", - module_idP, CC_id, frameP, subframeP, - mcch_sdu_length, mcch_mcs); - } - - cc->mcch_active = 1; - memcpy((char *) &mch_buffer[sdu_length_total], - &cc->MCCH_pdu.payload[0], mcch_sdu_length); - sdu_lcids[num_sdus] = MCCH_LCHANID; - sdu_lengths[num_sdus] = mcch_sdu_length; - - if (sdu_lengths[num_sdus] > 128) { - header_len_mcch = 3; - } - - sdu_length_total += sdu_lengths[num_sdus]; - LOG_D(MAC, - "[eNB %d] CC_id %d Got %d bytes for MCCH from RRC \n", - module_idP, CC_id, sdu_lengths[num_sdus]); - num_sdus++; - } - } - - TBS = - get_TBS_DL(cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); - - // do not let mcch and mtch multiplexing when relaying is active - // for sync area 1, so not transmit data - //if ((i == 0) && ((RC.mac[module_idP]->MBMS_flag != multicast_relay) || (RC.mac[module_idP]->mcch_active==0))) { - - // there is MTCHs, loop if there are more than 1 - if (mtch_flag == 1) { - // Calculate TBS - /* if ((msi_flag==1) || (mcch_flag==1)) { - TBS = mac_xface->get_TBS(mcch_mcs, mac_xface->frame_parms->N_RB_DL); - } - else { // only MTCH in this subframeP - TBS = mac_xface->get_TBS(RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9, mac_xface->frame_parms->N_RB_DL); - } - - // get MTCH data from RLC (like for DTCH) - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframe %d: Schedule MTCH (area %d, sfAlloc %d)\n",Mod_id,CC_id,frame,subframe,i,j); - - header_len_mtch = 3; - LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", - Mod_id,CC_id,frame,MTCH,TBS, - TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - - rlc_status = mac_rlc_status_ind(Mod_id,frame,1,RLC_MBMS_YES,MTCH+ (maxDRB + 3) * MAX_MOBILES_PER_RG, - TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - printf("frame %d, subframe %d, rlc_status.bytes_in_buffer is %d\n",frame,subframe, rlc_status.bytes_in_buffer); - - */ - // get MTCH data from RLC (like for DTCH) - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d subframeP %d: Schedule MTCH (area %d, sfAlloc %d)\n", - module_idP, CC_id, frameP, subframeP, i, j); - header_len_mtch = 3; - LOG_D(MAC, - "[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", - module_idP, CC_id, frameP, MTCH, TBS, - TBS - header_len_mcch - header_len_msi - sdu_length_total - - header_len_mtch); - rlc_status = - mac_rlc_status_ind(module_idP, 0, frameP, subframeP, - module_idP, ENB_FLAG_YES, MBMS_FLAG_YES, - MTCH, - TBS - header_len_mcch - header_len_msi - - sdu_length_total - header_len_mtch,0, 0); - LOG_D(MAC, - "e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d\n", - MTCH, frameP, subframeP, rlc_status.bytes_in_buffer); - - if (rlc_status.bytes_in_buffer > 0) { - LOG_I(MAC, - "[eNB %d][MBMS USER-PLANE], CC_id %d, Frame %d, MTCH->MCH, Requesting %d bytes from RLC (header len mtch %d)\n", - module_idP, CC_id, frameP, - TBS - header_len_mcch - header_len_msi - - sdu_length_total - header_len_mtch, header_len_mtch); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES, MTCH, 0, //not used - (char *) &mch_buffer[sdu_length_total],0, 0 - ); - //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(MAX_MOBILES_PER_ENB+1)), (char*)&mch_buffer[sdu_length_total]); - LOG_I(MAC, - "[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d\n", - module_idP, CC_id, sdu_lengths[num_sdus], MTCH); - cc->mtch_active = 1; - sdu_lcids[num_sdus] = MTCH; - sdu_length_total += sdu_lengths[num_sdus]; - - if (sdu_lengths[num_sdus] < 128) { - header_len_mtch = 2; - } - - num_sdus++; - } else { - header_len_mtch = 0; - } - } - - // FINAL STEP: Prepare and multiplexe MSI, MCCH and MTCHs - if ((sdu_length_total + header_len_msi + header_len_mcch + - header_len_mtch) > 0) { - // Adjust the last subheader - /* if ((msi_flag==1) || (mcch_flag==1)) { - RC.mac[module_idP]->MCH_pdu.mcs = mcch_mcs; - } - else if (mtch_flag == 1) { // only MTCH in this subframeP - RC.mac[module_idP]->MCH_pdu.mcs = RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9; - } - */ - header_len_mtch_temp = header_len_mtch; - header_len_mcch_temp = header_len_mcch; - header_len_msi_temp = header_len_msi; - - if (header_len_mtch > 0) { - header_len_mtch = 1; // remove Length field in the subheader for the last PDU - } else if (header_len_mcch > 0) { - header_len_mcch = 1; - } else { - header_len_msi = 1; - } - - // Calculate the padding - if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - - sdu_length_total) < 0) { - LOG_E(MAC, "Error in building MAC PDU, TBS %d < PDU %d \n", - TBS, - header_len_mtch + header_len_mcch + header_len_msi + - sdu_length_total); - return 0; - } else if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - - sdu_length_total) <= 2) { - padding = - (TBS - header_len_mtch - header_len_mcch - header_len_msi - - sdu_length_total); - post_padding = 0; - } else { // using post_padding, give back the Length field of subheader for the last PDU - padding = 0; - - if (header_len_mtch > 0) { - header_len_mtch = header_len_mtch_temp; - } else if (header_len_mcch > 0) { - header_len_mcch = header_len_mcch_temp; - } else { - header_len_msi = header_len_msi_temp; - } - - post_padding = - TBS - sdu_length_total - header_len_msi - header_len_mcch - - header_len_mtch; - } - - // Generate the MAC Header for MCH - // here we use the function for DLSCH because DLSCH & MCH have the same Header structure - offset = generate_dlsch_header((unsigned char *) cc->MCH_pdu.payload, num_sdus, sdu_lengths, sdu_lcids, 255, // no drx - 31, // no timing advance - NULL, // no contention res id - padding, post_padding); - cc->MCH_pdu.Pdu_size = TBS; - cc->MCH_pdu.sync_area = i; - cc->MCH_pdu.msi_active = cc->msi_active; - cc->MCH_pdu.mcch_active = cc->mcch_active; - cc->MCH_pdu.mtch_active = cc->mtch_active; - LOG_D(MAC, - " MCS for this sf is %d (mcch active %d, mtch active %d)\n", - cc->MCH_pdu.mcs, cc->MCH_pdu.mcch_active, - cc->MCH_pdu.mtch_active); - LOG_I(MAC, - "[eNB %d][MBMS USER-PLANE ] CC_id %d Generate header : sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,padding %d,post_padding %d (mcs %d, TBS %d), header MTCH %d, header MCCH %d, header MSI %d\n", - module_idP, CC_id, sdu_length_total, num_sdus, - sdu_lengths[0], sdu_lcids[0], offset, padding, post_padding, - cc->MCH_pdu.mcs, TBS, header_len_mtch, header_len_mcch, - header_len_msi); - // copy SDU to mch_pdu after the MAC Header - memcpy(&cc->MCH_pdu.payload[offset], mch_buffer, sdu_length_total); - - // filling remainder of MCH with random data if necessery - for (j = 0; j < (TBS - sdu_length_total - offset); j++) { - cc->MCH_pdu.payload[offset + sdu_length_total + j] = - (char) (taus() & 0xff); - } - - /* Tracing of PDU is done on UE side */ - trace_pdu(DIRECTION_DOWNLINK, (uint8_t *) cc->MCH_pdu.payload, TBS, module_idP, WS_M_RNTI, 0xffff, // M_RNTI = 6 in wireshark - RC.mac[module_idP]->frame, RC.mac[module_idP]->subframe, 0, 0); - /* - for (j=0;jMCH_pdu.payload[j+offset]); - printf(" \n"); */ - return 1; - } else { cc->MCH_pdu.Pdu_size = 0; - cc->MCH_pdu.sync_area = 0; - cc->MCH_pdu.msi_active = 0; - cc->MCH_pdu.mcch_active = 0; - cc->MCH_pdu.mtch_active = 0; - // for testing purpose, fill with random data - //for (j=0;j<(TBS-sdu_length_total-offset);j++) - // RC.mac[module_idP]->MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff); - return 0; - } - //this is for testing - /* - if (mtch_flag == 1) { - // LOG_D(MAC,"DUY: mch_buffer length so far is : %ld\n", &mch_buffer[sdu_length_total]-&mch_buffer[0]); - return 1; - } - else - return 0; - */ + for (i = 0; i < cc->num_active_mbsfn_area; i++) { + // assume, that there is always a mapping + if ((j = get_mbsfn_sf_alloction(module_idP, CC_id, i)) == -1) { + return 0; + } + + mbsfn_period = + 1 << (cc->mbsfn_SubframeConfig[j]->radioframeAllocationPeriod); + mcch_period = + 32 << (cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_RepetitionPeriod_r9); + msi_pos = 0; + ii = 0; + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d)\n", + module_idP, CC_id, frameP, subframeP, i, + cc->num_active_mbsfn_area, j, cc->num_sf_allocation_pattern, + mbsfn_period, mcch_period); + + + switch (cc->mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) { + case 0: + mcch_mcs = 2; + break; + + case 1: + mcch_mcs = 7; + break; + + case 2: + mcch_mcs = 13; + break; + + case 3: + mcch_mcs = 19; + break; + } + + // 1st: Check the MBSFN subframes from SIB2 info (SF allocation pattern i, max 8 non-overlapping patterns exist) + if (frameP % mbsfn_period == cc->mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP + if (cc->mbsfn_SubframeConfig[j]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format + + // Find the first subframeP in this MCH to transmit MSI + if (frameP % mch_scheduling_period == + cc->mbsfn_SubframeConfig[j]-> + radioframeAllocationOffset) { + while (ii == 0) { + ii = cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & (0x80 >> msi_pos); + msi_pos++; + } + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : sync area %d sf allocation pattern %d sf alloc %x msi pos is %d \n", + module_idP, CC_id, frameP, subframeP, i, j, + cc->mbsfn_SubframeConfig[j]-> + subframeAllocation.choice.oneFrame.buf[0], + msi_pos); + } + // Check if the subframeP is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 + switch (subframeP) { + case 1: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 2: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 3: + if (cc->tdd_Config != NULL) { // TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 4: + if (cc->tdd_Config != NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 6: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 7: + if (cc->tdd_Config != NULL) { // TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 8: + if (cc->tdd_Config != NULL) { //TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8) { + if (msi_pos == 6) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 9: + if (cc->tdd_Config != NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + } // end switch + + // sf allocation is non-overlapping + if ((msi_flag == 1) || (mcch_flag == 1) + || (mtch_flag == 1)) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", + module_idP, CC_id, frameP, subframeP, i, j, + msi_flag, mcch_flag, mtch_flag); + break; + } + } else { // four-frameP format + } + } + } // end of for loop + + cc->msi_active = 0; + cc->mcch_active = 0; + cc->mtch_active = 0; + + // Calculate the mcs + if ((msi_flag == 1) || (mcch_flag == 1)) { + cc->MCH_pdu.mcs = mcch_mcs; + } else if (mtch_flag == 1) { // only MTCH in this subframeP + cc->MCH_pdu.mcs = cc->pmch_Config[0]->dataMCS_r9; + } + + + uint8_t num_sf_alloc=0; + for( int iii=0; iii < 6; iii++) + num_sf_alloc += ( 0x39 & (0x80>>iii)) == (0x80 >> iii); + num_sf_alloc = 1; + + // 2nd: Create MSI, get MCCH from RRC and MTCHs from RLC + + // there is MSI (MCH Scheduling Info) + uint16_t msi_control_element[29], *msi_ptr; + char *buffer_pointer=NULL; + if (msi_flag == 1) { + // Create MSI here + //uint16_t msi_control_element[29], *msi_ptr; + + msi_ptr = &msi_control_element[0]; + //((MSI_ELEMENT *) msi_ptr)->lcid = MCCH_LCHANID; //MCCH + + //if (mcch_flag == 1) { + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0; + //} else { // no mcch for this MSP + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // stop value is 2047 + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xff; + //} + + //msi_ptr += sizeof(MSI_ELEMENT); + + //Header for MTCHs + num_mtch = cc->mbms_SessionList[0]->list.count; + + TBS = + get_TBS_DL(cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); + //l=0; + + for (k = 0; k < num_mtch; k++) { // loop for all session in this MCH (MCH[0]) at this moment + + ((MSI_ELEMENT *) msi_ptr)->lcid = cc->mbms_SessionList[0]->list.array[k]->logicalChannelIdentity_r9; //mtch_lcid; + + if( msi_sfs != 0 ) + msi_pmch_stop = msi_sfs-1; + else + msi_pmch_stop = msi_sfs; + + msi_pmch_stop = msi_sfs; + + //if( msi_pmch_stop > cc->pmch_Config[0]->sf_AllocEnd_r9) + //LOG_W(MAC,"e-MBMS Buffer Overflow\n"); + + if(msi_pmch_stop>=num_sf_alloc /*&& msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9*/) { + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now) & stop_sf limited to 256 + //((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = msi_pmch_stop; + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = (msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9 ? msi_pmch_stop: cc->pmch_Config[0]->sf_AllocEnd_r9); + msi_pmch_stop = (msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9 ? msi_pmch_stop: cc->pmch_Config[0]->sf_AllocEnd_r9); + }else{ + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // last subframeP of this mtch (only one mtch now) + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xFF; + msi_pmch_stop=0; + } + + + + msi_ptr += sizeof(MSI_ELEMENT); + } + + msi_length = msi_ptr - msi_control_element; + + if (msi_length < 128) { + header_len_msi = 2; + } else { + header_len_msi = 3; + } + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : MSI->MCH, length of MSI is %d bytes TBS %d, bytes in buffer %d stop_sf_LSB %d msi_sfs %d cc->pmch_Config[0]->sf_AllocEnd_r9 %ld\n", + module_idP, CC_id, frameP, msi_length,TBS, bytes_in_buffer,msi_pmch_stop,msi_sfs,cc->pmch_Config[0]->sf_AllocEnd_r9); + + msi_sfs = 0; + + //LOG_D(MAC,"Scheduler: MSI is transmitted in this subframeP \n" ); + + // LOG_D(MAC,"Scheduler: MSI length is %d bytes\n",msi_length); + // Store MSI data to mch_buffer[0] + memcpy((char *) &mch_buffer[sdu_length_total], + msi_control_element, msi_length); + + buffer_pointer = (char *) &mch_buffer[sdu_length_total]; + + sdu_lcids[num_sdus] = MCH_SCHDL_INFO; + sdu_lengths[num_sdus] = msi_length; + sdu_length_total += sdu_lengths[num_sdus]; + LOG_D(MAC, "[eNB %d] CC_id %d Create %d bytes for MSI\n", + module_idP, CC_id, sdu_lengths[num_sdus]); + num_sdus++; + cc->msi_active = 1; + } + // there is MCCH + if (mcch_flag == 1) { + + //LOG_E(MAC, + //"[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE COUNTING (mod %d)\n",module_idP, CC_id, frameP, subframeP,frameP%2==0); + if(1/*frameP%2==0*/){ + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); + + mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH, 0xFFFC, 1, &cc->MCCH_pdu.payload[0], + i); // this is the mbsfn sync area index + } + else{ + LOG_E(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE COUNTING (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); + +// +// mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH_COUNTING, 0xFFFC, 1, &cc->MCCH_pdu.payload[0], +// i); // this is the mbsfn sync area index + } + + mcch_sdu_length+=1; //RLC ? + + if (mcch_sdu_length > 0) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : MCCH->MCH, Received %d bytes from RRC \n", + module_idP, CC_id, frameP, subframeP, mcch_sdu_length); + + header_len_mcch = 2; + + if (cc->tdd_Config != NULL) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (TDD) for MCCH message %d bytes (mcs %d )\n", + module_idP, CC_id, frameP, subframeP, + mcch_sdu_length, mcch_mcs); + } else { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (FDD) for MCCH message %d bytes (mcs %d)\n", + module_idP, CC_id, frameP, subframeP, + mcch_sdu_length, mcch_mcs); + } + + cc->mcch_active = 1; + + memcpy((char *) &mch_buffer[sdu_length_total]+1, + &cc->MCCH_pdu.payload[0], mcch_sdu_length); + sdu_lcids[num_sdus] = MCCH_LCHANID; + sdu_lengths[num_sdus] = mcch_sdu_length; + + // LOG_W(MAC,"MCCH RLC %x:",(unsigned char)mch_buffer[sdu_length_total]); + // for (int kk = 7; kk >= 0; kk--) + // { + // printf("%d",(((unsigned char)mch_buffer[sdu_length_total]) >> kk) & 1 ? '1' : '0'); + // } + // printf("\n"); + //mch_buffer[sdu_length_total] = (unsigned char)0; + + + if (sdu_lengths[num_sdus] > 128) { + header_len_mcch = 3; + } + + sdu_length_total += sdu_lengths[num_sdus]; + LOG_D(MAC, + "[eNB %d] CC_id %d Got %d bytes for MCCH from RRC \n", + module_idP, CC_id, sdu_lengths[num_sdus]); + num_sdus++; + } + } + + + TBS = + get_TBS_DL(/*cc->pmch_Config[0]->dataMCS_r9*/cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); + // do not let mcch and mtch multiplexing when relaying is active + // for sync area 1, so not transmit data + //if ((i == 0) && ((RC.mac[module_idP]->MBMS_flag != multicast_relay) || (RC.mac[module_idP]->mcch_active==0))) { + + // there is MTCHs, loop if there are more than 1 + if (mtch_flag == 1 ) { + // Calculate TBS + /* if ((msi_flag==1) || (mcch_flag==1)) { + TBS = mac_xface->get_TBS(mcch_mcs, mac_xface->frame_parms->N_RB_DL); + } + else { // only MTCH in this subframeP + TBS = mac_xface->get_TBS(RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9, mac_xface->frame_parms->N_RB_DL); + } + + // get MTCH data from RLC (like for DTCH) + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframe %d: Schedule MTCH (area %d, sfAlloc %d)\n",Mod_id,CC_id,frame,subframe,i,j); + + header_len_mtch = 3; + LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", + Mod_id,CC_id,frame,MTCH,TBS, + TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + + rlc_status = mac_rlc_status_ind(Mod_id,frame,1,RLC_MBMS_YES,MTCH+ (maxDRB + 3) * MAX_MOBILES_PER_RG, + TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + printf("frame %d, subframe %d, rlc_status.bytes_in_buffer is %d\n",frame,subframe, rlc_status.bytes_in_buffer); + + */ + + // get MTCH data from RLC (like for DTCH) + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Schedule MTCH (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); + + header_len_mtch = 3; + LOG_D(MAC, + "[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", + module_idP, CC_id, frameP, MTCH, TBS, + TBS - header_len_mcch - header_len_msi - sdu_length_total - + header_len_mtch); + + mbms_rab_id = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9; + + rlc_status = + mac_rlc_status_ind(module_idP, 0/*0xfffd*/, frameP, subframeP, + module_idP, ENB_FLAG_YES, MBMS_FLAG_YES, + cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9, + //MTCH, + TBS - header_len_mcch - header_len_msi - + sdu_length_total - header_len_mtch + ,0, 0 + ); + bytes_in_buffer = rlc_status.bytes_in_buffer; + + + if( !(mcch_flag==1 || msi_flag==1) ) + msi_sfs = rlc_status.bytes_in_buffer/(TBS- header_len_mcch - header_len_msi -sdu_length_total - header_len_mtch)+(rlc_status.bytes_in_buffer%(TBS- header_len_mcch - header_len_msi -sdu_length_total - header_len_mtch)?1:0); + //uint16_t msi_control_element[29], *msi_ptr; + // + // + uint16_t TBS_MTCH = + get_TBS_DL(cc->pmch_Config[0]->dataMCS_r9, to_prb(cc->mib->message.dl_Bandwidth)); + if(msi_flag==1 && buffer_pointer!=NULL){ + msi_ptr = &msi_control_element[0]; + + //memcpy(buffer_pointer, + // msi_control_element, msi_length); + + // msi_pmch_stop = rlc_status.bytes_in_buffer/TBS+(rlc_status.bytes_in_buffer%TBS?1:0); + msi_pmch_stop = (rlc_status.bytes_in_buffer - header_len_mcch - header_len_msi -sdu_length_total - header_len_mtch)/(TBS_MTCH/*- header_len_mcch - header_len_msi -sdu_length_total*/ - header_len_mtch)+((rlc_status.bytes_in_buffer-TBS-header_len_mcch - header_len_msi -sdu_length_total)%(TBS_MTCH/*- header_len_mcch - header_len_msi -sdu_length_total*/ - header_len_mtch)?0:0); + + if( msi_pmch_stop > cc->pmch_Config[0]->sf_AllocEnd_r9) + LOG_E(MAC,"e-MBMS Buffer Overflow\n"); + if(msi_pmch_stop>=num_sf_alloc /*&& msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9*/) { + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now) & stop_sf limited to 256 + //((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = msi_pmch_stop; + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = (msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9 ? msi_pmch_stop: cc->pmch_Config[0]->sf_AllocEnd_r9); + msi_pmch_stop = (msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9 ? msi_pmch_stop: cc->pmch_Config[0]->sf_AllocEnd_r9); + }else{ + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // last subframeP of this mtch (only one mtch now) + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xFF; + msi_pmch_stop=0; + } + LOG_I(MAC,"frameP %d, subframeP %d rlc_status.bytes_in_buffer %d stop_sf_LSB %d\n",frameP,subframeP,rlc_status.bytes_in_buffer,((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB); + //LOG_W(MAC,"frameP %d, subframeP %d rlc_status.bytes_in_buffer %d stop_sf_LSB %d msi_calc:%d remainder %d\n",frameP,subframeP,rlc_status.bytes_in_buffer,((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB,rlc_status.bytes_in_buffer/(TBS_MTCH/*- header_len_mcch - header_len_msi -sdu_length_total*/ - header_len_mtch)+((rlc_status.bytes_in_buffer-TBS-header_len_mcch - header_len_msi -sdu_length_total)%(TBS_MTCH/*- header_len_mcch - header_len_msi -sdu_length_total*/ - header_len_mtch)?0:0),((rlc_status.bytes_in_buffer-TBS-header_len_mcch - header_len_msi -sdu_length_total)%(TBS_MTCH/*- header_len_mcch - header_len_msi -sdu_length_total*/ - header_len_mtch)?0:0)); + + memcpy(buffer_pointer, + msi_control_element, msi_length); + + } + + LOG_D(MAC, + "e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d TBS_MTCH %d pmch_stop %d msi_sfs %d\n", + MTCH, frameP, subframeP, rlc_status.bytes_in_buffer,TBS_MTCH,msi_pmch_stop,msi_sfs); + + if ((rlc_status.bytes_in_buffer > 0 && msi_pmch_stop > 0) && ((msi_flag!=1 || mcch_flag!=1)) /*|| (rlc_status.bytes_in_buffer > 0 && (msi_flag==1 || mcch_flag==1))*//*|| msi_sfs > cc->pmch_Config[0]->sf_AllocEnd_r9 */ /*msi_pmch_stop>=num_sf_alloc*/ ) { + //if(rlc_status.bytes_in_buffer > 0){ + LOG_D(MAC, + "[eNB %d][MBMS USER-PLANE], CC_id %d, Frame %d, MTCH->MCH, Requesting %d bytes from RLC (header len mtch %d) rlc_status.bytes_in_buffer %d\n", + module_idP, CC_id, frameP, + TBS - header_len_mcch - header_len_msi - + sdu_length_total - header_len_mtch, header_len_mtch, rlc_status.bytes_in_buffer); + + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0/*0xfffd*/, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9, 0, //not used + (char *) + &mch_buffer[sdu_length_total] + ,0, + 0 + ); + + // LOG_I(MAC,"RLC %x:",(unsigned char)mch_buffer[sdu_length_total]); + // for (int kk = 7; kk >= 0; kk--) + // { + // printf("%d",(((unsigned char)mch_buffer[sdu_length_total]) >> kk) & 1 ? '1' : '0'); + // } + // printf("\n"); + + //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(MAX_MOBILES_PER_ENB+1)), (char*)&mch_buffer[sdu_length_total]); + LOG_D(MAC, + "[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d msi_pmch_stop %d msi_sfs %d sdu_lengths[num_sdus] %d\n", + module_idP, CC_id, sdu_lengths[num_sdus], MTCH,msi_pmch_stop,msi_sfs, sdu_lengths[num_sdus]); + cc->mtch_active = 1; + sdu_lcids[num_sdus] = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9/*MTCH*/; + sdu_length_total += sdu_lengths[num_sdus]; + + if (msi_pmch_stop != 0 && msi_flag !=1) + msi_pmch_stop--; + + + if (sdu_lengths[num_sdus] < 128) { + header_len_mtch = 2; + } + + num_sdus++; + //} + } + else { + // LOG_E(MAC, + // "[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d msi_pmch_stop %d msi_buffer %d msi_sfs %ld msi_buffer_act %ld sdu_lengths[num_sdus] %d\n", + // module_idP, CC_id, sdu_lengths[num_sdus], MTCH,msi_pmch_stop,msi_sfs,msi_buffer_act, sdu_lengths[num_sdus]); + + header_len_mtch = 0; + } + } + // } + + // FINAL STEP: Prepare and multiplexe MSI, MCCH and MTCHs + if ((sdu_length_total + header_len_msi + header_len_mcch + + header_len_mtch) > 0) { + // Adjust the last subheader + /* if ((msi_flag==1) || (mcch_flag==1)) { + RC.mac[module_idP]->MCH_pdu.mcs = mcch_mcs; + } + else if (mtch_flag == 1) { // only MTCH in this subframeP + RC.mac[module_idP]->MCH_pdu.mcs = RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9; + } + */ + header_len_mtch_temp = header_len_mtch; + header_len_mcch_temp = header_len_mcch; + header_len_msi_temp = header_len_msi; + + if (header_len_mtch > 0) { + header_len_mtch = 1; // remove Length field in the subheader for the last PDU + } else if (header_len_mcch > 0) { + header_len_mcch = 1; + } else { + header_len_msi = 1; + } + + // Calculate the padding + if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total) < 0) { + LOG_E(MAC, "Error in building MAC PDU, TBS %d < PDU %d \n", + TBS, + header_len_mtch + header_len_mcch + header_len_msi + + sdu_length_total); + return 0; + } else + if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total) <= 2) { + padding = + (TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total); + post_padding = 0; + } else { // using post_padding, give back the Length field of subheader for the last PDU + padding = 0; + + if (header_len_mtch > 0) { + header_len_mtch = header_len_mtch_temp; + } else if (header_len_mcch > 0) { + header_len_mcch = header_len_mcch_temp; + } else { + header_len_msi = header_len_msi_temp; + } + + post_padding = + TBS - sdu_length_total - header_len_msi - header_len_mcch - + header_len_mtch; + } + + // Generate the MAC Header for MCH + // here we use the function for DLSCH because DLSCH & MCH have the same Header structure + offset = generate_dlsch_header((unsigned char *) cc->MCH_pdu.payload, num_sdus, sdu_lengths, sdu_lcids, 255, // no drx + 31, // no timing advance + NULL, // no contention res id + padding, post_padding); + + cc->MCH_pdu.Pdu_size = TBS; + cc->MCH_pdu.sync_area = i; + cc->MCH_pdu.msi_active = cc->msi_active; + cc->MCH_pdu.mcch_active = cc->mcch_active; + cc->MCH_pdu.mtch_active = cc->mtch_active; + LOG_D(MAC, + " MCS for this sf is %d (mcch active %d, mtch active %d)\n", + cc->MCH_pdu.mcs, cc->MCH_pdu.mcch_active, + cc->MCH_pdu.mtch_active); + LOG_D(MAC, + "[eNB %d][MBMS USER-PLANE ] CC_id %d Generate header : sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,padding %d,post_padding %d (mcs %d, TBS %d), header MTCH %d, header MCCH %d, header MSI %d\n", + module_idP, CC_id, sdu_length_total, num_sdus, + sdu_lengths[0], sdu_lcids[0], offset, padding, post_padding, + cc->MCH_pdu.mcs, TBS, header_len_mtch, header_len_mcch, + header_len_msi); + // copy SDU to mch_pdu after the MAC Header + memcpy(&cc->MCH_pdu.payload[offset], mch_buffer, sdu_length_total); + + // filling remainder of MCH with random data if necessery + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + cc->MCH_pdu.payload[offset + sdu_length_total + j] = + (char) (taus() & 0xff); + } + + /* Tracing of PDU is done on UE side */ + //if (opt_enabled == 1) { + trace_pdu(DIRECTION_DOWNLINK, (uint8_t *) cc->MCH_pdu.payload, TBS, module_idP, WS_M_RNTI , 0xfffd, // M_RNTI = 6 in wirehsark + RC.mac[module_idP]->frame, + RC.mac[module_idP]->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][MCH] CC_id %d Frame %d : MAC PDU with size %d\n", + module_idP, CC_id, frameP, TBS); + //} + + eNB_MAC_INST *eNB = RC.mac[module_idP]; + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + // dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + // memset((void *) dl_config_pdu, + // 0, + // sizeof(nfapi_dl_config_request_pdu_t)); + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + fill_nfapi_mch_config( + dl_req, + TBS, + 0, + 0xfffd, + 0, + get_Qm(cc->MCH_pdu.mcs), + cc->MCH_pdu.mcs, + 6000, //equal to RS power + 0 //mbsfn_area_id + ); + + eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_id].tx_request_body, + (frameP * 10) + subframeP, + TBS, + eNB->pdu_index[CC_id], + (uint8_t*)cc->MCH_pdu.payload); + + + /* + for (j=0;jMCH_pdu.payload[j+offset]); + printf(" \n"); */ + return 1; + } else { + cc->MCH_pdu.Pdu_size = 0; + cc->MCH_pdu.sync_area = 0; + cc->MCH_pdu.msi_active = 0; + cc->MCH_pdu.mcch_active = 0; + cc->MCH_pdu.mtch_active = 0; + // for testing purpose, fill with random data + //for (j=0;j<(TBS-sdu_length_total-offset);j++) + // RC.mac[module_idP]->MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff); + return 0; + } + + //this is for testing + /* + if (mtch_flag == 1) { + // LOG_D(MAC,"DUY: mch_buffer length so far is : %ld\n", &mch_buffer[sdu_length_total]-&mch_buffer[0]); + return 1; + } + else + return 0; + */ +} +int +schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + sub_frame_t subframeP) +{ + + int mcch_flag = 0, mtch_flag = 0, msi_flag = 0; + int mbsfn_period = 0; // 1<<(RC.mac[module_idP]->mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); + int mcch_period = 0; //32<<(RC.mac[module_idP]->mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + if(RC.mac[module_idP]->common_channels[CC_id]. + pmch_Config[0] == NULL ) + + return 0; + + + int mch_scheduling_period = + 8 << (RC.mac[module_idP]->common_channels[CC_id]. + pmch_Config[0]->mch_SchedulingPeriod_r9); + unsigned char mcch_sdu_length; + unsigned char header_len_mcch = 0, header_len_msi = + 0, header_len_mtch = 0, header_len_mtch_temp = + 0, header_len_mcch_temp = 0, header_len_msi_temp = 0; + int ii = 0, msi_pos = 0; + int mcch_mcs = -1; + uint16_t TBS, j = -1, padding = 0, post_padding = 0; + mac_rlc_status_resp_t rlc_status; + int num_mtch; + int msi_length, i, k; + //uint8_t l =0; + unsigned char sdu_lcids[11], num_sdus = 0, offset = 0; + uint16_t sdu_lengths[11], sdu_length_total = 0; + unsigned char mch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; // check the max value, this is for dlsch only + + COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; + + cc->MCH_pdu.Pdu_size = 0; + + for (i = 0; i < cc->num_active_mbsfn_area; i++) { + // assume, that there is always a mapping + if ((j = get_mbsfn_sf_alloction(module_idP, CC_id, i)) == -1) { + return 0; + } + + mbsfn_period = + 1 << (cc->mbsfn_SubframeConfig[j]->radioframeAllocationPeriod); + mcch_period = + 32 << (cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_RepetitionPeriod_r9); + msi_pos = 0; + ii = 0; + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d)\n", + module_idP, CC_id, frameP, subframeP, i, + cc->num_active_mbsfn_area, j, cc->num_sf_allocation_pattern, + mbsfn_period, mcch_period); + + + switch (cc->mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) { + case 0: + mcch_mcs = 2; + break; + + case 1: + mcch_mcs = 7; + break; + + case 2: + mcch_mcs = 13; + break; + + case 3: + mcch_mcs = 19; + break; + } + + // 1st: Check the MBSFN subframes from SIB2 info (SF allocation pattern i, max 8 non-overlapping patterns exist) + if (frameP % mbsfn_period == cc->mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP + if (cc->mbsfn_SubframeConfig[j]->subframeAllocation.present == LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format + + // Find the first subframeP in this MCH to transmit MSI + if (frameP % mch_scheduling_period == + cc->mbsfn_SubframeConfig[j]-> + radioframeAllocationOffset) { + while (ii == 0) { + ii = cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & (0x80 >> msi_pos); + msi_pos++; + } + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : sync area %d sf allocation pattern %d sf alloc %x msi pos is %d \n", + module_idP, CC_id, frameP, subframeP, i, j, + cc->mbsfn_SubframeConfig[j]-> + subframeAllocation.choice.oneFrame.buf[0], + msi_pos); + } + // Check if the subframeP is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 + switch (subframeP) { + case 1: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 2: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 3: + if (cc->tdd_Config != NULL) { // TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 4: + if (cc->tdd_Config != NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 6: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 7: + if (cc->tdd_Config != NULL) { // TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 8: + if (cc->tdd_Config != NULL) { //TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8) { + if (msi_pos == 6) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 9: + if (cc->tdd_Config != NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + } // end switch + + // sf allocation is non-overlapping + if ((msi_flag == 1) || (mcch_flag == 1) + || (mtch_flag == 1)) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", + module_idP, CC_id, frameP, subframeP, i, j, + msi_flag, mcch_flag, mtch_flag); + break; + } + } else { // four-frameP format + } + } + } // end of for loop + + cc->msi_active = 0; + cc->mcch_active = 0; + cc->mtch_active = 0; + + // Calculate the mcs + if ((msi_flag == 1) || (mcch_flag == 1)) { + cc->MCH_pdu.mcs = mcch_mcs; + } else if (mtch_flag == 1) { // only MTCH in this subframeP + cc->MCH_pdu.mcs = cc->pmch_Config[0]->dataMCS_r9; + } + + + uint8_t num_sf_alloc=0; + for( int iii=0; iii < 6; iii++) + num_sf_alloc += ( 0x39 & (0x80>>iii)) == (0x80 >> iii); + num_sf_alloc = 1; + + // 2nd: Create MSI, get MCCH from RRC and MTCHs from RLC + + // there is MSI (MCH Scheduling Info) + if (msi_flag == 1) { + // Create MSI here + uint16_t msi_control_element[29], *msi_ptr; + + msi_ptr = &msi_control_element[0]; + //((MSI_ELEMENT *) msi_ptr)->lcid = MCCH_LCHANID; //MCCH + + //if (mcch_flag == 1) { + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0; + //} else { // no mcch for this MSP + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // stop value is 2047 + // ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xff; + //} + + //msi_ptr += sizeof(MSI_ELEMENT); + + //Header for MTCHs + num_mtch = cc->mbms_SessionList[0]->list.count; + + TBS = + get_TBS_DL(cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); + //l=0; + + for (k = 0; k < num_mtch; k++) { // loop for all session in this MCH (MCH[0]) at this moment + + ((MSI_ELEMENT *) msi_ptr)->lcid = cc->mbms_SessionList[0]->list.array[k]->logicalChannelIdentity_r9; //mtch_lcid; + + if( msi_sfs != 0 ) + msi_pmch_stop = msi_sfs-1; + else + msi_pmch_stop = msi_sfs; + + if( msi_pmch_stop > cc->pmch_Config[0]->sf_AllocEnd_r9) + LOG_W(MAC,"e-MBMS Buffer Overflow\n"); + + if(msi_pmch_stop>=num_sf_alloc /*&& msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9*/) { + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now) & stop_sf limited to 256 + //((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = msi_pmch_stop; + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = (msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9 ? msi_pmch_stop: cc->pmch_Config[0]->sf_AllocEnd_r9); + msi_pmch_stop = (msi_pmch_stop <=cc->pmch_Config[0]->sf_AllocEnd_r9 ? msi_pmch_stop: cc->pmch_Config[0]->sf_AllocEnd_r9); + }else{ + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // last subframeP of this mtch (only one mtch now) + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xFF; + msi_pmch_stop=0; + } + + + + msi_ptr += sizeof(MSI_ELEMENT); + } + + msi_length = msi_ptr - msi_control_element; + + if (msi_length < 128) { + header_len_msi = 2; + } else { + header_len_msi = 3; + } + + LOG_W(MAC, + "[eNB %d] CC_id %d Frame %d : MSI->MCH, length of MSI is %d bytes TBS %d, bytes in buffer %d stop_sf_LSB %d msi_sfs %d cc->pmch_Config[0]->sf_AllocEnd_r9 %ld\n", + module_idP, CC_id, frameP, msi_length,TBS, bytes_in_buffer,msi_pmch_stop,msi_sfs,cc->pmch_Config[0]->sf_AllocEnd_r9); + + msi_sfs = 0; + + //LOG_D(MAC,"Scheduler: MSI is transmitted in this subframeP \n" ); + + // LOG_D(MAC,"Scheduler: MSI length is %d bytes\n",msi_length); + // Store MSI data to mch_buffer[0] + memcpy((char *) &mch_buffer[sdu_length_total], + msi_control_element, msi_length); + + sdu_lcids[num_sdus] = MCH_SCHDL_INFO; + sdu_lengths[num_sdus] = msi_length; + sdu_length_total += sdu_lengths[num_sdus]; + LOG_D(MAC, "[eNB %d] CC_id %d Create %d bytes for MSI\n", + module_idP, CC_id, sdu_lengths[num_sdus]); + num_sdus++; + cc->msi_active = 1; + } + // there is MCCH + if (mcch_flag == 1) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); + + mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH, 0xFFFC, 1, &cc->MCCH_pdu.payload[0], + i); // this is the mbsfn sync area index + + mcch_sdu_length+=1; //RLC ? + + if (mcch_sdu_length > 0) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : MCCH->MCH, Received %d bytes from RRC \n", + module_idP, CC_id, frameP, subframeP, mcch_sdu_length); + + header_len_mcch = 2; + + if (cc->tdd_Config != NULL) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (TDD) for MCCH message %d bytes (mcs %d )\n", + module_idP, CC_id, frameP, subframeP, + mcch_sdu_length, mcch_mcs); + } else { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (FDD) for MCCH message %d bytes (mcs %d)\n", + module_idP, CC_id, frameP, subframeP, + mcch_sdu_length, mcch_mcs); + } + + cc->mcch_active = 1; + + memcpy((char *) &mch_buffer[sdu_length_total]+1, + &cc->MCCH_pdu.payload[0], mcch_sdu_length); + sdu_lcids[num_sdus] = MCCH_LCHANID; + sdu_lengths[num_sdus] = mcch_sdu_length; + + if (sdu_lengths[num_sdus] > 128) { + header_len_mcch = 3; + } + + sdu_length_total += sdu_lengths[num_sdus]; + LOG_D(MAC, + "[eNB %d] CC_id %d Got %d bytes for MCCH from RRC \n", + module_idP, CC_id, sdu_lengths[num_sdus]); + num_sdus++; + } + } + + TBS = + get_TBS_DL(/*cc->pmch_Config[0]->dataMCS_r9*/cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); + // do not let mcch and mtch multiplexing when relaying is active + // for sync area 1, so not transmit data + //if ((i == 0) && ((RC.mac[module_idP]->MBMS_flag != multicast_relay) || (RC.mac[module_idP]->mcch_active==0))) { + + // there is MTCHs, loop if there are more than 1 + if (mtch_flag == 1 ) { + // Calculate TBS + /* if ((msi_flag==1) || (mcch_flag==1)) { + TBS = mac_xface->get_TBS(mcch_mcs, mac_xface->frame_parms->N_RB_DL); + } + else { // only MTCH in this subframeP + TBS = mac_xface->get_TBS(RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9, mac_xface->frame_parms->N_RB_DL); + } + + // get MTCH data from RLC (like for DTCH) + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframe %d: Schedule MTCH (area %d, sfAlloc %d)\n",Mod_id,CC_id,frame,subframe,i,j); + + header_len_mtch = 3; + LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", + Mod_id,CC_id,frame,MTCH,TBS, + TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + + rlc_status = mac_rlc_status_ind(Mod_id,frame,1,RLC_MBMS_YES,MTCH+ (maxDRB + 3) * MAX_MOBILES_PER_RG, + TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + printf("frame %d, subframe %d, rlc_status.bytes_in_buffer is %d\n",frame,subframe, rlc_status.bytes_in_buffer); + + */ + + // get MTCH data from RLC (like for DTCH) + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Schedule MTCH (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); + + header_len_mtch = 3; + LOG_D(MAC, + "[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", + module_idP, CC_id, frameP, MTCH, TBS, + TBS - header_len_mcch - header_len_msi - sdu_length_total - + header_len_mtch); + + mbms_rab_id = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9; + + rlc_status = + mac_rlc_status_ind(module_idP, 0/*0xfffd*/, frameP, subframeP, + module_idP, ENB_FLAG_YES, MBMS_FLAG_YES, + cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9, + //MTCH, + TBS - header_len_mcch - header_len_msi - + sdu_length_total - header_len_mtch + ,0, 0 + ); + bytes_in_buffer = rlc_status.bytes_in_buffer; + + + msi_sfs = rlc_status.bytes_in_buffer/TBS+(rlc_status.bytes_in_buffer%TBS?1:0); + + LOG_D(MAC, + "e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d TBS %d pmch_stop %d msi_sfs %d\n", + MTCH, frameP, subframeP, rlc_status.bytes_in_buffer,TBS,msi_pmch_stop,msi_sfs); + + if (rlc_status.bytes_in_buffer > 0 || msi_pmch_stop > 0 /*msi_pmch_stop>=num_sf_alloc*/ ) { + //if(rlc_status.bytes_in_buffer > 0){ + LOG_I(MAC, + "[eNB %d][MBMS USER-PLANE], CC_id %d, Frame %d, MTCH->MCH, Requesting %d bytes from RLC (header len mtch %d) rlc_status.bytes_in_buffer %d\n", + module_idP, CC_id, frameP, + TBS - header_len_mcch - header_len_msi - + sdu_length_total - header_len_mtch, header_len_mtch, rlc_status.bytes_in_buffer); + + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0/*0xfffd*/, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9, 0, //not used + (char *) + &mch_buffer[sdu_length_total] + ,0, + 0 + ); + + //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(MAX_MOBILES_PER_ENB+1)), (char*)&mch_buffer[sdu_length_total]); + LOG_I(MAC, + "[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d msi_pmch_stop %d msi_sfs %d sdu_lengths[num_sdus] %d\n", + module_idP, CC_id, sdu_lengths[num_sdus], MTCH,msi_pmch_stop,msi_sfs, sdu_lengths[num_sdus]); + cc->mtch_active = 1; + sdu_lcids[num_sdus] = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9/*MTCH*/; + sdu_length_total += sdu_lengths[num_sdus]; + + if (msi_pmch_stop != 0) + msi_pmch_stop--; + + + if (sdu_lengths[num_sdus] < 128) { + header_len_mtch = 2; + } + + num_sdus++; + //} + } + else { + // LOG_E(MAC, + // "[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d msi_pmch_stop %d msi_buffer %d msi_sfs %ld msi_buffer_act %ld sdu_lengths[num_sdus] %d\n", + // module_idP, CC_id, sdu_lengths[num_sdus], MTCH,msi_pmch_stop,msi_sfs,msi_buffer_act, sdu_lengths[num_sdus]); + + header_len_mtch = 0; + } + } + // } + + // FINAL STEP: Prepare and multiplexe MSI, MCCH and MTCHs + if ((sdu_length_total + header_len_msi + header_len_mcch + + header_len_mtch) > 0) { + // Adjust the last subheader + /* if ((msi_flag==1) || (mcch_flag==1)) { + RC.mac[module_idP]->MCH_pdu.mcs = mcch_mcs; + } + else if (mtch_flag == 1) { // only MTCH in this subframeP + RC.mac[module_idP]->MCH_pdu.mcs = RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9; + } + */ + header_len_mtch_temp = header_len_mtch; + header_len_mcch_temp = header_len_mcch; + header_len_msi_temp = header_len_msi; + + if (header_len_mtch > 0) { + header_len_mtch = 1; // remove Length field in the subheader for the last PDU + } else if (header_len_mcch > 0) { + header_len_mcch = 1; + } else { + header_len_msi = 1; + } + + // Calculate the padding + if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total) < 0) { + LOG_E(MAC, "Error in building MAC PDU, TBS %d < PDU %d \n", + TBS, + header_len_mtch + header_len_mcch + header_len_msi + + sdu_length_total); + return 0; + } else + if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total) <= 2) { + padding = + (TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total); + post_padding = 0; + } else { // using post_padding, give back the Length field of subheader for the last PDU + padding = 0; + + if (header_len_mtch > 0) { + header_len_mtch = header_len_mtch_temp; + } else if (header_len_mcch > 0) { + header_len_mcch = header_len_mcch_temp; + } else { + header_len_msi = header_len_msi_temp; + } + + post_padding = + TBS - sdu_length_total - header_len_msi - header_len_mcch - + header_len_mtch; + } + + // Generate the MAC Header for MCH + // here we use the function for DLSCH because DLSCH & MCH have the same Header structure + offset = generate_dlsch_header((unsigned char *) cc->MCH_pdu.payload, num_sdus, sdu_lengths, sdu_lcids, 255, // no drx + 31, // no timing advance + NULL, // no contention res id + padding, post_padding); + + cc->MCH_pdu.Pdu_size = TBS; + cc->MCH_pdu.sync_area = i; + cc->MCH_pdu.msi_active = cc->msi_active; + cc->MCH_pdu.mcch_active = cc->mcch_active; + cc->MCH_pdu.mtch_active = cc->mtch_active; + LOG_D(MAC, + " MCS for this sf is %d (mcch active %d, mtch active %d)\n", + cc->MCH_pdu.mcs, cc->MCH_pdu.mcch_active, + cc->MCH_pdu.mtch_active); + LOG_D(MAC, + "[eNB %d][MBMS USER-PLANE ] CC_id %d Generate header : sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,padding %d,post_padding %d (mcs %d, TBS %d), header MTCH %d, header MCCH %d, header MSI %d\n", + module_idP, CC_id, sdu_length_total, num_sdus, + sdu_lengths[0], sdu_lcids[0], offset, padding, post_padding, + cc->MCH_pdu.mcs, TBS, header_len_mtch, header_len_mcch, + header_len_msi); + // copy SDU to mch_pdu after the MAC Header + memcpy(&cc->MCH_pdu.payload[offset], mch_buffer, sdu_length_total); + + // filling remainder of MCH with random data if necessery + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + cc->MCH_pdu.payload[offset + sdu_length_total + j] = + (char) (taus() & 0xff); + } + + /* Tracing of PDU is done on UE side */ + //if (opt_enabled == 1) { + trace_pdu(DIRECTION_DOWNLINK, (uint8_t *) cc->MCH_pdu.payload, TBS, module_idP, WS_M_RNTI , 0xffff, // M_RNTI = 6 in wirehsark + RC.mac[module_idP]->frame, + RC.mac[module_idP]->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][MCH] CC_id %d Frame %d : MAC PDU with size %d\n", + module_idP, CC_id, frameP, TBS); + //} + + /* + for (j=0;jMCH_pdu.payload[j+offset]); + printf(" \n"); */ + return 1; + } else { + cc->MCH_pdu.Pdu_size = 0; + cc->MCH_pdu.sync_area = 0; + cc->MCH_pdu.msi_active = 0; + cc->MCH_pdu.mcch_active = 0; + cc->MCH_pdu.mtch_active = 0; + // for testing purpose, fill with random data + //for (j=0;j<(TBS-sdu_length_total-offset);j++) + // RC.mac[module_idP]->MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff); + return 0; + } + + //this is for testing + /* + if (mtch_flag == 1) { + // LOG_D(MAC,"DUY: mch_buffer length so far is : %ld\n", &mch_buffer[sdu_length_total]-&mch_buffer[0]); + return 1; + } + else + return 0; + */ } - -MCH_PDU *get_mch_sdu(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t subframeP) { - // RC.mac[module_idP]->MCH_pdu.mcs=0; - //LOG_D(MAC," MCH_pdu.mcs is %d\n", RC.mac[module_idP]->MCH_pdu.mcs); - //#warning "MCH pdu should take the CC_id index" - return (&RC.mac[module_idP]->common_channels[CC_id].MCH_pdu); +MCH_PDU *get_mch_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframeP) +{ + // RC.mac[module_idP]->MCH_pdu.mcs=0; + //LOG_D(MAC," MCH_pdu.mcs is %d\n", RC.mac[module_idP]->MCH_pdu.mcs); +//#warning "MCH pdu should take the CC_id index" + return (&RC.mac[module_idP]->common_channels[CC_id].MCH_pdu); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 0c6a97823a..e76e6b24ba 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -48,10 +48,8 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif - +#include "intertask_interface.h" +#include "executables/softmodem-common.h" #include "T.h" #define ENABLE_MAC_PAYLOAD_DEBUG @@ -1586,6 +1584,39 @@ fill_nfapi_uci_acknak(module_id_t module_idP, return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10)); } +//------------------------------------------------------------------------------ + +void +fill_nfapi_mch_config(nfapi_dl_config_request_body_t *dl_req, + uint16_t length, + uint16_t pdu_index, + uint16_t rnti, + uint8_t resource_allocation_type, + uint16_t resource_block_coding, + uint8_t modulation, + uint16_t transmission_power, + uint8_t mbsfn_area_id){ + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_mch_pdu)); + dl_config_pdu->mch_pdu.mch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_MCH_PDU_REL8_TAG; + dl_config_pdu->mch_pdu.mch_pdu_rel8.length = length; + dl_config_pdu->mch_pdu.mch_pdu_rel8.pdu_index = pdu_index; + dl_config_pdu->mch_pdu.mch_pdu_rel8.rnti = rnti; + dl_config_pdu->mch_pdu.mch_pdu_rel8.resource_allocation_type = resource_allocation_type; + dl_config_pdu->mch_pdu.mch_pdu_rel8.resource_block_coding = resource_block_coding; + dl_config_pdu->mch_pdu.mch_pdu_rel8.modulation = modulation; + dl_config_pdu->mch_pdu.mch_pdu_rel8.transmission_power = transmission_power; + dl_config_pdu->mch_pdu.mch_pdu_rel8.mbsfn_area_id = mbsfn_area_id; + dl_req->number_pdu++; +} + +//------------------------------------------------------------------------------ + + //------------------------------------------------------------------------------ void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, @@ -2151,9 +2182,8 @@ add_new_ue(module_id_t mod_idP, UE_list->ordered_ULCCids[0][UE_id] = cc_idP; UE_list->num_UEs++; UE_list->active[UE_id] = TRUE; -#if defined(USRP_REC_PLAY) // not specific to record/playback ? - UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0; -#endif + if (IS_SOFTMODEM_IQPLAYER)// not specific to record/playback ? + UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0; UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type; memset((void *) &UE_list->UE_sched_ctrl[UE_id], 0, diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 430f73cd9d..7c3b536de2 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -48,9 +48,7 @@ #include "assertions.h" #include "pdcp.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "ENB_APP/flexran_agent_defs.h" #include "flexran_agent_ran_api.h" @@ -936,6 +934,7 @@ rx_sdu(const module_id_t enb_mod_idP, stop_meas(&mac->rx_ulsch_sdu); } + //----------------------------------------------------------------------------- /* * Return the BSR table index corresponding to the number of bytes in input @@ -1497,38 +1496,33 @@ schedule_ulsch_rnti(module_id_t module_idP, if (status >= RRC_CONNECTED && UE_sched_ctrl_ptr->cqi_req_timer > 30) { if (UE_sched_ctrl_ptr->cqi_received == 0) { - if (NFAPI_MODE != NFAPI_MONOLITHIC) { - cqi_req = 0; - } else { - cqi_req = 1; - LOG_D(MAC,"Setting CQI_REQ (timer %d)\n",UE_sched_ctrl_ptr->cqi_req_timer); + cqi_req = 1; + LOG_D(MAC, + "Setting CQI_REQ (timer %d)\n", + UE_sched_ctrl_ptr->cqi_req_timer); - /* TDD: to be safe, do not ask CQI in special Subframes:36.213/7.2.3 CQI definition */ - if (cc[CC_id].tdd_Config) { - switch (cc[CC_id].tdd_Config->subframeAssignment) { - case 1: - if(subframeP == 1 || subframeP == 6) { - cqi_req=0; - } + /* TDD: to be safe, do not ask CQI in special + * Subframes:36.213/7.2.3 CQI definition */ + if (cc[CC_id].tdd_Config) { + switch (cc[CC_id].tdd_Config->subframeAssignment) { + case 1: + if (subframeP == 1 || subframeP == 6) + cqi_req = 0; + break; - break; + case 3: + if (subframeP == 1) + cqi_req = 0; + break; - case 3: - if(subframeP == 1) { - cqi_req=0; - } - - break; - - default: - LOG_E(MAC," TDD config not supported\n"); - break; - } + default: + LOG_E(MAC, " TDD config not supported\n"); + break; } + } - if(cqi_req == 1) { - UE_sched_ctrl_ptr->cqi_req_flag |= 1 << sched_subframeP; - } + if (cqi_req == 1) { + UE_sched_ctrl_ptr->cqi_req_flag |= 1 << sched_subframeP; } } else { LOG_D(MAC,"Clearing CQI request timer\n"); diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h index 979ec4dace..ac9819cfe2 100644 --- a/openair2/LAYER2/MAC/mac.h +++ b/openair2/LAYER2/MAC/mac.h @@ -411,8 +411,9 @@ typedef struct { #define BCCH_SIB1_BR 6 // SIB1_BR /*!\brief Values of BCCH SIB_BR logical channel (fake) */ #define BCCH_SI_BR 7 // SI-BR -/*!\brief Values of BCCH SIB1_BR logical channel (fake) */ +/*!\brief Values of BCCH SIB1_MBMS logical channel (fake) */ #define BCCH_SIB1_MBMS 60 // SIB1_MBMS //TODO better armonize index +/*!\brief Values of BCCH SI_MBMS logical channel (fake) */ #define BCCH_SI_MBMS 61 // SIB_MBMS //TODO better armonize index /*!\brief Value of CCCH / SRB0 logical channel */ #define CCCH 0 // srb0 @@ -424,7 +425,8 @@ typedef struct { #define DTCH 3 // LCID /*!\brief MCCH logical channel */ //#define MCCH 4 -#define MCCH 62 +//#define MCCH 62 +#define MCCH 11 /*!\brief MTCH logical channel */ #define MTCH 1 // DLSCH LCHAN ID @@ -904,10 +906,8 @@ typedef struct { uint16_t mpdcch_repetition_cnt; frame_t Msg2_frame; sub_frame_t Msg2_subframe; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) /// Repetition column in pusch_repetition Table 8.2.b in TS36.213 uint8_t pusch_repetition_levels; -#endif LTE_PhysicalConfigDedicated_t *physicalConfigDedicated; } UE_TEMPLATE; @@ -1115,10 +1115,8 @@ typedef struct { uint8_t msg2_narrowband; uint8_t msg34_narrowband; int msg4_rrc_sdu_length; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) /// Repetition column in pusch_repetition Table 8.2.b in TS36.213 uint8_t pusch_repetition_levels; -#endif int32_t crnti_rrc_mui; int8_t crnti_harq_pid; } RA_t; diff --git a/openair2/LAYER2/MAC/mac_extern.h b/openair2/LAYER2/MAC/mac_extern.h index 3510e7e7ae..dbf5b57b6b 100644 --- a/openair2/LAYER2/MAC/mac_extern.h +++ b/openair2/LAYER2/MAC/mac_extern.h @@ -34,7 +34,6 @@ //#include "PHY/defs_common.h" #include "mac.h" - #include "RRC/LTE/rrc_defs.h" extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; @@ -51,13 +50,9 @@ extern const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]; extern UE_RRC_INST *UE_rrc_inst; extern UE_MAC_INST *UE_mac_inst; - extern eNB_ULSCH_INFO eNB_ulsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][MAX_MOBILES_PER_ENB]; // eNBxUE = 8x8 extern eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][MAX_MOBILES_PER_ENB]; // eNBxUE = 8x8 - - - extern unsigned char NB_INST; extern unsigned char NB_eNB_INST; extern uint16_t NB_UE_INST; @@ -65,7 +60,6 @@ extern uint16_t NB_THREAD_INST; extern unsigned char NB_RN_INST; extern unsigned short NODE_ID[1]; - extern int cqi_to_mcs[16]; extern uint32_t RRC_CONNECTION_FLAG; diff --git a/openair2/LAYER2/MAC/mac_proto.h b/openair2/LAYER2/MAC/mac_proto.h index cb93b76c91..476fb68584 100644 --- a/openair2/LAYER2/MAC/mac_proto.h +++ b/openair2/LAYER2/MAC/mac_proto.h @@ -31,6 +31,7 @@ #include "LAYER2/MAC/mac.h" #include "PHY/defs_common.h" // for PRACH_RESOURCES_t and lte_subframe_t +#include "openair2/COMMON/mac_messages_types.h" /** \addtogroup _mac @@ -85,6 +86,14 @@ void schedule_SI_MBMS(module_id_t module_idP, frame_t frameP, int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframe); +/** \brief MBMS scheduling: Checking the position for MBSFN subframes. Create MSI, transfer MCCH from RRC to MAC, transfer MTCHs from RLC to MAC. Multiplexing MSI,MCCH&MTCHs. Return 1 if there are MBSFN data being allocated, otherwise return 0; +@param Mod_id Instance ID of eNB +@param frame Frame index +@param subframe Subframe number on which to act +*/ +int schedule_MBMS_NFAPI(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframe); + + /** \brief check the mapping between sf allocation and sync area, Currently only supports 1:1 mapping @param Mod_id Instance ID of eNB @param mbsfn_sync_area index of mbsfn sync area @@ -1192,6 +1201,16 @@ void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, uint8_t num_bf_prb_per_subband, uint8_t num_bf_vector); +void fill_nfapi_mch_config(nfapi_dl_config_request_body_t *dl_req, + uint16_t length, + uint16_t pdu_index, + uint16_t rnti, + uint8_t resource_allocation_type, + uint16_t resource_block_coding, + uint8_t modulation, + uint16_t transmission_power, + uint8_t mbsfn_area_id); + void fill_nfapi_harq_information(module_id_t module_idP, int CC_idP, uint16_t rntiP, @@ -1265,9 +1284,14 @@ int ue_ul_slice_membership(module_id_t mod_id, int UE_id, int slice_idx); /* DRX Configuration */ /* Configure local DRX timers and thresholds in UE context, following the drx_configuration input */ -void eNB_Config_Local_DRX(module_id_t Mod_id, rnti_t rnti, LTE_DRX_Config_t *drx_Configuration); +void eNB_Config_Local_DRX(instance_t Mod_id, rrc_mac_drx_config_req_t *rrc_mac_drx_config_req); /* from here: prototypes to get rid of compilation warnings: doc to be written by function author */ uint8_t ul_subframe2_k_phich(COMMON_channels_t *cc, sub_frame_t ul_subframe); #endif /** @}*/ + +/* MAC ITTI messaging related functions */ +/* Main loop of MAC itti message handling */ +void *mac_enb_task(void *arg); + diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 4e139dcf92..fe8980101d 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -34,15 +34,12 @@ #include "mac_proto.h" #include "mac_extern.h" #include "assertions.h" -//#include "PHY_INTERFACE/phy_extern.h" -//#include "PHY/defs_eNB.h" -//#include "SCHED/sched_eNB.h" #include "LAYER2/PDCP_v10.1.0/pdcp.h" #include "RRC/LTE/rrc_defs.h" #include "common/utils/LOG/log.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" - #include "common/ran_context.h" +#include "intertask_interface.h" extern RAN_CONTEXT_t RC; @@ -223,3 +220,47 @@ int l2_init_eNB(void) return (1); } + +//----------------------------------------------------------------------------- +/* + * Main loop of MAC itti message handling + */ +void *mac_enb_task(void *arg) +//----------------------------------------------------------------------------- +{ + MessageDef *received_msg = NULL; + int result; + + itti_mark_task_ready(TASK_MAC_ENB); // void function 10/2019 + LOG_I(MAC,"Starting main loop of MAC message task\n"); + + while (1) { + itti_receive_msg(TASK_MAC_ENB, &received_msg); + + switch (ITTI_MSG_ID(received_msg)) { + case RRC_MAC_DRX_CONFIG_REQ: + LOG_I(MAC, "MAC Task Received RRC_MAC_DRX_CONFIG_REQ\n"); + /* Set timers and thresholds values in local MAC context of UE */ + eNB_Config_Local_DRX(ITTI_MESSAGE_GET_INSTANCE(received_msg), &received_msg->ittiMsg.rrc_mac_drx_config_req); + break; + + case TERMINATE_MESSAGE: + LOG_W(MAC, " *** Exiting MAC thread\n"); + itti_exit_task(); + break; + + default: + LOG_E(MAC, "MAC instance received unhandled message: %d:%s\n", + ITTI_MSG_ID(received_msg), + ITTI_MSG_NAME(received_msg)); + break; + } // end switch + + result = itti_free(ITTI_MSG_ORIGIN_ID(received_msg), received_msg); + AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + + received_msg = NULL; + } // end while + + return NULL; +} \ No newline at end of file diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 74c834c4d0..1205851915 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -56,9 +56,7 @@ #include "pdcp.h" #include "targets/RT/USER/lte-softmodem.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "assertions.h" @@ -74,6 +72,8 @@ extern UL_IND_t *UL_INFO; extern int next_ra_frame; extern module_id_t next_Mod_id; +int mbms_rab_id = 2047; + /* * #ifndef USER_MODE @@ -744,6 +744,9 @@ ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, LOG_D(MAC, "[UE %d] parse_mch_header, found %d sdus\n", module_idP, num_sdu); + if(sdu[0]==0 && sdu[1]==0) + num_sdu=0; + for (i = 0; i < num_sdu; i++) { if (rx_lcids[i] == MCH_SCHDL_INFO) { if (rx_lengths[i] & 0x01) { @@ -792,6 +795,9 @@ ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, if (j<28 && UE_mac_inst[module_idP].msi_status_v[j]==1) { LOG_D(MAC,"[UE %d] Frame %d : MCH->MTCH for sync area %d (eNB %d, %d bytes), j=%d\n", module_idP, frameP, sync_area, eNB_index, rx_lengths[i], j); + //This sucks I know ... workaround ! + mbms_rab_id = rx_lcids[i]; + //end sucks :-( mac_rlc_data_ind( module_idP, UE_mac_inst[module_idP].crnti, @@ -1096,6 +1102,7 @@ int ue_query_p_mch(module_id_t module_idP, uint32_t frameP, uint32_t subframe, i int ue_query_mch(module_id_t module_idP, uint8_t CC_id, uint32_t frameP, uint32_t subframe, uint8_t eNB_index,uint8_t *sync_area, uint8_t *mcch_active) { int i = 0, j = 0, ii = 0, jj = 0, msi_pos = 0, mcch_mcs = -1, mtch_mcs = -1; + int l =0; int mcch_flag = 0, mtch_flag = 0, msi_flag = 0; long mch_scheduling_period = -1; uint8_t mch_lcid = 0; @@ -1347,28 +1354,40 @@ int ue_query_mch(module_id_t module_idP, uint8_t CC_id, uint32_t frameP, uint32_ // Acount for sf_allocable in CSA int num_sf_alloc = 0; - for (i = 0; i < 8; i++) { - if (UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[i] == NULL) + for (l = 0; l < 8; l++) { + if (UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[l] == NULL) continue; - if (UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[i]->subframeAllocation.present != LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) + if (UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[l]->subframeAllocation.present != LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) continue; - uint32_t common_mbsfn_SubframeConfig = UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]; + uint32_t common_mbsfn_SubframeConfig = UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[l]->subframeAllocation.choice.oneFrame.buf[0]; for (j = 0; j < 6; j++) num_sf_alloc += ((common_mbsfn_SubframeConfig & (0x80 >> j)) == (0x80 >> j)); + //num_sf_alloc=1; } - for (i = 0; i < 28; i++) { - if (UE_mac_inst[module_idP].pmch_stop_mtch[i] >= num_sf_alloc) { - if (UE_mac_inst[module_idP].pmch_stop_mtch[i] != 2047) { - if (UE_mac_inst[module_idP].pmch_Config[UE_mac_inst[module_idP].msi_pmch] != NULL) + for (l = 0; l < 28; l++) { + if (UE_mac_inst[module_idP].pmch_stop_mtch[l] >= 1/*num_sf_alloc*/) { + if (UE_mac_inst[module_idP].pmch_stop_mtch[l] != 2047) { + if (UE_mac_inst[module_idP].pmch_Config[UE_mac_inst[module_idP].msi_pmch] != NULL){ mtch_mcs = UE_mac_inst[module_idP].pmch_Config[UE_mac_inst[module_idP].msi_pmch]->dataMCS_r9; + long common_mbsfn_period = 1 << UE_mac_inst[module_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[0]->radioframeAllocationPeriod; + long commonSF_AllocPeriod = 4 << UE_mac_inst[module_idP].commonSF_AllocPeriod_r9; + if(UE_mac_inst[module_idP].common_num_sf_alloc >= UE_mac_inst[module_idP].pmch_stop_mtch[l]){ + //LOG_E(MAC,"Attemp to UE_mac_inst[module_idP].common_num_sf_alloc %d\n",UE_mac_inst[module_idP].common_num_sf_alloc); + + mtch_mcs = -1; + }/*else + LOG_W(MAC,"Attemp to UE_mac_inst[module_idP].common_num_sf_alloc %d\n",UE_mac_inst[module_idP].common_num_sf_alloc);*/ + UE_mac_inst[module_idP].common_num_sf_alloc++; + UE_mac_inst[module_idP].common_num_sf_alloc = UE_mac_inst[module_idP].common_num_sf_alloc % (num_sf_alloc * commonSF_AllocPeriod / common_mbsfn_period); + } else mtch_mcs = -1; - mch_lcid = (uint8_t)i; + mch_lcid = (uint8_t)l; break; } } @@ -1377,7 +1396,7 @@ int ue_query_mch(module_id_t module_idP, uint8_t CC_id, uint32_t frameP, uint32_ // sf allocation is non-overlapping if ((msi_flag==1) || (mcch_flag==1) || (mtch_flag==1)) { LOG_D(MAC,"[UE %d] Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", - module_idP, frameP, subframe,i,j,msi_flag,mcch_flag,mtch_flag); + module_idP, frameP, subframe,l,j,msi_flag,mcch_flag,mtch_flag); *sync_area=i; break; } @@ -2017,9 +2036,9 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, if (sdu_lengths[num_sdus]) { sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = lcid; - LOG_I(MAC, - "[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LcId%d\n", - module_idP, sdu_lengths[num_sdus], lcid); + //LOG_I(MAC, + // "[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LcId%d\n", + // module_idP, sdu_lengths[num_sdus], lcid); if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + @@ -2139,7 +2158,7 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, if (phr_ce_len == sizeof(POWER_HEADROOM_CMD)) { if(NFAPI_MODE==NFAPI_UE_STUB_PNF) { //Substitute with a static value for the MAC layer abstraction (phy_stub mode) - phr_p->PH = 40; + phr_p->PH = 60; } else { phr_p->PH = get_phr_mapping(module_idP, CC_id, eNB_index); } @@ -2434,10 +2453,8 @@ ue_scheduler(const module_id_t module_idP, struct LTE_RACH_ConfigCommon *rach_ConfigCommon = (struct LTE_RACH_ConfigCommon *) NULL; protocol_ctxt_t ctxt; -#if defined(ENABLE_ITTI) MessageDef *msg_p; int result; -#endif #if UE_TIMING_TRACE start_meas(&UE_mac_inst[module_idP].ue_scheduler); #endif @@ -2446,7 +2463,6 @@ ue_scheduler(const module_id_t module_idP, PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_NO, UE_mac_inst[module_idP].crnti, txFrameP, txSubframeP, eNB_indexP); -#if defined(ENABLE_ITTI) if(module_idP == 0) { do { @@ -2476,8 +2492,6 @@ ue_scheduler(const module_id_t module_idP, } while (msg_p != NULL); } -#endif - //Mac_rlc_xface->frameP=frameP; //Rrc_xface->Frame_index=Mac_rlc_xface->frameP; //if (subframe%5 == 0) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h new file mode 100644 index 0000000000..5801fabcfb --- /dev/null +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -0,0 +1,142 @@ +/* + * 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 nr_mac.h + * \brief common MAC data structures, constant, and function prototype + * \author R. Knopp, K.H. HSU, G. Casati + * \date 2019 + * \version 0.1 + * \company Eurecom / NTUST / Fraunhofer IIS + * \email: knopp@eurecom.fr, kai-hsiang.hsu@eurecom.fr, guido.casati@iis.fraunhofer.de + * \note + * \warning + */ + +#ifndef __LAYER2_NR_MAC_H__ +#define __LAYER2_NR_MAC_H__ + +#include +#include +#include + +#define NR_BCCH_DL_SCH 3 // SI + +#define NR_BCCH_BCH 5 // MIB + +// For both DL/UL-SCH +// Except: +// - UL/DL-SCH: fixed-size MAC CE(known by LCID) +// - UL/DL-SCH: padding +// - UL-SCH: MSG3 48-bits +// |0|1|2|3|4|5|6|7| bit-wise +// |R|F| LCID | +// | L | +// |0|1|2|3|4|5|6|7| bit-wise +// |R|F| LCID | +// | L | +// | L | + +// For both DL/UL-SCH +// For: +// - UL/DL-SCH: fixed-size MAC CE(known by LCID) +// - UL/DL-SCH: padding, for single/multiple 1-oct padding CE(s) +// - UL-SCH: MSG3 48-bits +// |0|1|2|3|4|5|6|7| bit-wise +// |R|R| LCID | +// LCID: The Logical Channel ID field identifies the logical channel instance of the corresponding MAC SDU or the type of the corresponding MAC CE or padding as described in Tables 6.2.1-1 and 6.2.1-2 for the DL-SCH and UL-SCH respectively. There is one LCID field per MAC subheader. The LCID field size is 6 bits; +// L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field; +// F: lenght of L is 0:8 or 1:16 bits wide +// R: Reserved bit, set to zero. + +typedef struct { + uint8_t LCID:6; // octet 1 [5:0] + uint8_t F:1; // octet 1 [6] + uint8_t R:1; // octet 1 [7] + uint8_t L:8; // octet 2 [7:0] +} __attribute__ ((__packed__)) NR_MAC_SUBHEADER_SHORT; + +typedef struct { + uint8_t LCID:6; // octet 1 [5:0] + uint8_t F:1; // octet 1 [6] + uint8_t R:1; // octet 1 [7] + uint8_t L1:8; // octet 2 [7:0] + uint8_t L2:8; // octet 3 [7:0] +} __attribute__ ((__packed__)) NR_MAC_SUBHEADER_LONG; + +typedef struct { + uint8_t LCID:6; // octet 1 [5:0] + uint8_t R:2; // octet 1 [7:6] +} __attribute__ ((__packed__)) NR_MAC_SUBHEADER_FIXED; + +// 38.321 ch. 6.1.3.4 +typedef struct { + uint8_t TA_COMMAND:6; // octet 1 [5:0] + uint8_t TAGID:2; // octet 1 [7:6] +} __attribute__ ((__packed__)) NR_MAC_CE_TA; + +// 38.321 ch6.2.1, 38.331 +#define DL_SCH_LCID_CCCH 0x00 +#define DL_SCH_LCID_DCCH 0x01 +#define DL_SCH_LCID_DCCH1 0x02 +#define DL_SCH_LCID_DTCH 0x03 +#define DL_SCH_LCID_RECOMMENDED_BITRATE 0x2F +#define DL_SCH_LCID_SP_ZP_CSI_RS_RES_SET_ACT 0x30 +#define DL_SCH_LCID_PUCCH_SPATIAL_RELATION_ACT 0x31 +#define DL_SCH_LCID_SP_SRS_ACTIVATION 0x32 +#define DL_SCH_LCID_SP_CSI_REP_PUCCH_ACT 0x33 +#define DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH 0x34 +#define DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH 0x35 +#define DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL 0x36 +#define DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT 0X37 +#define DL_SCH_LCID_DUPLICATION_ACT 0X38 +#define DL_SCH_LCID_SCell_ACT_4_OCT 0X39 +#define DL_SCH_LCID_SCell_ACT_1_OCT 0X3A +#define DL_SCH_LCID_L_DRX 0x3B +#define DL_SCH_LCID_DRX 0x3C +#define DL_SCH_LCID_TA_COMMAND 0x3D +#define DL_SCH_LCID_CON_RES_ID 0x3E +#define DL_SCH_LCID_PADDING 0x3F + +#define UL_SCH_LCID_CCCH 0x00 +#define UL_SCH_LCID_SRB1 0x01 +#define UL_SCH_LCID_SRB2 0x02 +#define UL_SCH_LCID_DTCH 0x03 +#define UL_SCH_LCID_SRB3 0x04 +#define UL_SCH_LCID_CCCH_MSG3 0x21 +#define UL_SCH_LCID_RECOMMENDED_BITRATE_QUERY 0x35 +#define UL_SCH_LCID_MULTI_ENTRY_PHR_4_OCT 0x36 +#define UL_SCH_LCID_CONFIGURED_GRANT_CONFIRMATION 0x37 +#define UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT 0x38 +#define UL_SCH_LCID_SINGLE_ENTRY_PHR 0x39 +#define UL_SCH_LCID_C_RNTI 0x3A +#define UL_SCH_LCID_S_TRUNCATED_BSR 0x3B +#define UL_SCH_LCID_L_TRUNCATED_BSR 0x3C +#define UL_SCH_LCID_S_BSR 0x3D +#define UL_SCH_LCID_L_BSR 0x3E +#define UL_SCH_LCID_PADDING 0x3F + +#define NR_MAX_NUM_LCID 32 +#define NR_MAX_NUM_LCGID 8 +#define MAX_RLC_SDU_SUBHEADER_SIZE 3 + + +#endif /*__LAYER2_MAC_H__ */ + diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c similarity index 99% rename from openair2/LAYER2/NR_MAC_gNB/nr_mac_common.c rename to openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 55cb22f4ec..ae23164194 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -248,7 +248,7 @@ uint32_t to_nrarfcn(int nr_bandP, uint32_t nrarfcn, delta_arfcn; LOG_I(MAC,"Searching for nr band %d DL Carrier frequency %llu bw %u\n",nr_bandP,(long long unsigned int)dl_CarrierFreq,bw); - AssertFatal(nr_bandP < 261, "nr_band %d > 260\n", nr_bandP); + AssertFatal(nr_bandP <= 261, "nr_band %d > 260\n", nr_bandP); for (i = 0; i < NR_BANDTABLE_SIZE && nr_bandtable[i].band != nr_bandP; i++); // selection of correct Deltaf raster according to SCS @@ -296,9 +296,9 @@ uint64_t from_nrarfcn(int nr_bandP, if (dl_nrarfcn > 2016666 && dl_nrarfcn < 3279166) deltaFglobal = 60; - AssertFatal(nr_bandP < 261, "nr_band %d > 260\n", nr_bandP); + AssertFatal(nr_bandP <= 261, "nr_band %d > 260\n", nr_bandP); for (i = 0; i < NR_BANDTABLE_SIZE && nr_bandtable[i].band != nr_bandP; i++); - AssertFatal(dl_nrarfcn>=nr_bandtable[i].N_OFFs_DL,"dl_nrarfcn %u < N_OFFs_DL %llu\n",dl_nrarfcn, (long long unsigned int)nr_bandtable[i].N_OFFs_DL); + AssertFatal(dl_nrarfcn>=nr_bandtable[i].N_OFFs_DL,"dl_nrarfcn %u < N_OFFs_DL[%d] %llu\n",dl_nrarfcn, nr_bandtable[i].band,(long long unsigned int)nr_bandtable[i].N_OFFs_DL); // selection of correct Deltaf raster according to SCS if ( (nr_bandtable[i].deltaf_raster != 100) && (nr_bandtable[i].deltaf_raster != scs_khz)) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h new file mode 100644 index 0000000000..2cfce4766f --- /dev/null +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h @@ -0,0 +1,72 @@ +/* + * 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 extern.h +* \brief NR mac externs +* \author G. Casati +* \date 2019 +* \version 1.0 +* \email guido.casati@iis.fraunhofer.de +* @ingroup _mac + +*/ + +#ifndef __NR_MAC_EXTERN_H__ +#define __NR_MAC_EXTERN_H__ + +//#include "PHY/defs_common.h" +#include "nr_mac.h" +#include "RRC/LTE/rrc_defs.h" +#include "common/ran_context.h" + +/* extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; +extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE]; +extern const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]; +extern const uint8_t cqi2fmt1x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]; +extern const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]; +extern UE_RRC_INST *UE_rrc_inst; +extern eNB_ULSCH_INFO eNB_ulsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][MAX_MOBILES_PER_ENB]; // eNBxUE = 8x8 +extern eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][MAX_MOBILES_PER_ENB]; // eNBxUE = 8x8 +extern int cqi_to_mcs[16]; +extern uint32_t RRC_CONNECTION_FLAG; +extern uint8_t rb_table[34]; +extern mac_rlc_am_muilist_t rlc_am_mui; +extern SCHEDULER_MODES global_scheduler_mode; +extern unsigned char NB_UE_INST;*/ + +extern unsigned char NB_INST; +extern unsigned char NB_eNB_INST; +extern unsigned char NB_RN_INST; +extern unsigned short NODE_ID[1]; + +/* Scheduler */ +extern RAN_CONTEXT_t RC; +extern uint8_t nfapi_mode; + +/*#if defined(PRE_SCD_THREAD) +extern uint16_t pre_nb_rbs_required[2][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +extern uint8_t dlsch_ue_select_tbl_in_use; +extern uint8_t new_dlsch_ue_select_tbl_in_use; +extern boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; +extern eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +#endif*/ + +#endif //DEF_H diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index b5041396a4..c983023034 100755 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -221,24 +221,25 @@ void config_common_ue(NR_UE_MAC_INST_t *mac, if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); - cfg->ssb_table.ssb_offset_point_a = absolute_diff/(12*scs_scaling); + cfg->ssb_table.ssb_offset_point_a = absolute_diff/(12*scs_scaling) - 10; cfg->ssb_table.ssb_period = *scc->ssb_periodicityServingCell; cfg->ssb_table.ssb_subcarrier_offset = 0; // TODO currently not in RRC? + switch (scc->ssb_PositionsInBurst->present) { case 1 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0]; + cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0]<<24; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; break; case 2 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]; + cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]<<24; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; break; case 3 : cfg->ssb_table.ssb_mask_list[0].ssb_mask = 0; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; for (i=0; i<4; i++) { - cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]< #include -#define NR_BCCH_DL_SCH 3 // SI - -#define NR_BCCH_BCH 5 // MIB - /*!\brief UE layer 2 status */ typedef enum { UE_CONNECTION_OK = 0, @@ -49,65 +45,4 @@ typedef enum { UE_PHY_HO_PRACH } NR_UE_L2_STATE_t; -typedef struct { - uint8_t LCID:6; // octet 1 [5:0] - uint8_t F:1; // octet 1 [6] - uint8_t R:1; // octet 1 [7] - uint8_t L:8; // octet 2 [7:0] -} __attribute__ ((__packed__)) NR_MAC_SUBHEADER_SHORT; - -typedef struct { - uint8_t LCID:6; // octet 1 [5:0] - uint8_t F:1; // octet 1 [6] - uint8_t R:1; // octet 1 [7] - uint8_t L1:8; // octet 2 [7:0] - uint8_t L2:8; // octet 3 [7:0] -} __attribute__ ((__packed__)) NR_MAC_SUBHEADER_LONG; - -typedef struct { - uint8_t LCID:6; // octet 1 [5:0] - uint8_t R:2; // octet 1 [7:6] -} __attribute__ ((__packed__)) NR_MAC_SUBHEADER_FIXED; - -// 38.321 ch6.2.1, 38.331 -#define DL_SCH_LCID_CCCH 0x00 -#define DL_SCH_LCID_SRB1 0x01 -#define DL_SCH_LCID_SRB2 0x02 -#define DL_SCH_LCID_SRB3 0x03 -#define DL_SCH_LCID_RECOMMENDED_BITRATE 0x2F -#define DL_SCH_LCID_SP_ZP_CSI_RS_RES_SET_ACT 0x30 -#define DL_SCH_LCID_PUCCH_SPATIAL_RELATION_ACT 0x31 -#define DL_SCH_LCID_SP_SRS_ACTIVATION 0x32 -#define DL_SCH_LCID_SP_CSI_REP_PUCCH_ACT 0x33 -#define DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH 0x34 -#define DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH 0x35 -#define DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL 0x36 -#define DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT 0X37 -#define DL_SCH_LCID_DUPLICATION_ACT 0X38 -#define DL_SCH_LCID_SCell_ACT_4_OCT 0X39 -#define DL_SCH_LCID_SCell_ACT_1_OCT 0X3A -#define DL_SCH_LCID_L_DRX 0x3B -#define DL_SCH_LCID_DRX 0x3C -#define DL_SCH_LCID_TA_COMMAND 0x3D -#define DL_SCH_LCID_CON_RES_ID 0x3E -#define DL_SCH_LCID_PADDING 0x3F - -#define UL_SCH_LCID_CCCH 0x00 -#define UL_SCH_LCID_SRB1 0x01 -#define UL_SCH_LCID_SRB2 0x02 -#define UL_SCH_LCID_SRB3 0x03 -#define UL_SCH_LCID_CCCH_MSG3 0x21 -#define UL_SCH_LCID_RECOMMENDED_BITRATE_QUERY 0x35 -#define UL_SCH_LCID_MULTI_ENTRY_PHR_4_OCT 0x36 -#define UL_SCH_LCID_CONFIGURED_GRANT_CONFIRMATION 0x37 -#define UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT 0x38 -#define UL_SCH_LCID_SINGLE_ENTRY_PHR 0x39 -#define UL_SCH_LCID_C_RNTI 0x3A -#define UL_SCH_LCID_S_TRUNCATED_BSR 0x3B -#define UL_SCH_LCID_L_TRUNCATED_BSR 0x3C -#define UL_SCH_LCID_S_BSR 0x3D -#define UL_SCH_LCID_L_BSR 0x3E -#define UL_SCH_LCID_PADDING 0x3F - - -#endif /*__LAYER2_MAC_DEFS_H__ */ +#endif /*__LAYER2_NR_UE_MAC_DEFS_H__ */ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 37d1b1216d..405ea95eb1 100755 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -52,8 +52,14 @@ #include "NR_IF_Module.h" #include "../NR_MAC_gNB/nr_mac_common.h" #include "PHY/defs_nr_common.h" +#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac.h" #define NB_NR_UE_MAC_INST 1 +/*!\brief Maximum number of logical channl group IDs */ + + +/*!\brief value for indicating BSR Timer is not running */ +#define NR_MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) typedef enum { SFN_C_MOD_2_EQ_0, @@ -61,6 +67,68 @@ typedef enum { SFN_C_IMPOSSIBLE } SFN_C_TYPE; +// LTE structure, might need to be adapted for NR +typedef struct { + /// buffer status for each lcgid + uint8_t BSR[NR_MAX_NUM_LCGID]; // should be more for mesh topology + /// keep the number of bytes in rlc buffer for each lcgid + int32_t BSR_bytes[NR_MAX_NUM_LCGID]; + /// after multiplexing buffer remain for each lcid + int32_t LCID_buffer_remain[NR_MAX_NUM_LCID]; + /// sum of all lcid buffer size + uint16_t All_lcid_buffer_size_lastTTI; + /// buffer status for each lcid + uint8_t LCID_status[NR_MAX_NUM_LCID]; + /// SR pending as defined in 36.321 + uint8_t SR_pending; + /// SR_COUNTER as defined in 36.321 + uint16_t SR_COUNTER; + /// logical channel group ide for each LCID + uint8_t LCGID[NR_MAX_NUM_LCID]; + /// retxBSR-Timer, default value is sf2560 + uint16_t retxBSR_Timer; + /// retxBSR_SF, number of subframe before triggering a regular BSR + uint16_t retxBSR_SF; + /// periodicBSR-Timer, default to infinity + uint16_t periodicBSR_Timer; + /// periodicBSR_SF, number of subframe before triggering a periodic BSR + uint16_t periodicBSR_SF; + /// default value is 0: not configured + uint16_t sr_ProhibitTimer; + /// sr ProhibitTime running + uint8_t sr_ProhibitTimer_Running; + /// default value to n5 + uint16_t maxHARQ_Tx; + /// default value is false + uint16_t ttiBundling; + /// default value is release + struct DRX_Config *drx_config; + /// default value is release + struct MAC_MainConfig__phr_Config *phr_config; + ///timer before triggering a periodic PHR + uint16_t periodicPHR_Timer; + ///timer before triggering a prohibit PHR + uint16_t prohibitPHR_Timer; + ///DL Pathloss change value + uint16_t PathlossChange; + ///number of subframe before triggering a periodic PHR + int16_t periodicPHR_SF; + ///number of subframe before triggering a prohibit PHR + int16_t prohibitPHR_SF; + ///DL Pathloss Change in db + uint16_t PathlossChange_db; + + /// default value is false + uint16_t extendedBSR_Sizes_r10; + /// default value is false + uint16_t extendedPHR_r10; + + //Bj bucket usage per lcid + int16_t Bj[NR_MAX_NUM_LCID]; + // Bucket size per lcid + int16_t bucket_size[NR_MAX_NUM_LCID]; +} NR_UE_SCHEDULING_INFO; + #define MAX_NUM_BWP 2 @@ -99,7 +167,6 @@ typedef struct { RA_state_t ra_state; /// RA-rnti uint16_t ra_rnti; - /// Temporary CRNTI uint16_t t_crnti; /// CRNTI @@ -114,6 +181,13 @@ typedef struct { nr_ue_if_module_t *if_module; nr_scheduled_response_t scheduled_response; nr_phy_config_t phy_config; + + /// BSR report flag management + uint8_t BSR_reporting_active; + NR_UE_SCHEDULING_INFO scheduling_info; + + /// PHR + uint8_t PHR_reporting_active; } NR_UE_MAC_INST_t; typedef enum seach_space_mask_e { diff --git a/openair2/LAYER2/NR_MAC_UE/mac_extern.h b/openair2/LAYER2/NR_MAC_UE/mac_extern.h index 960b47e44a..26e0ea2667 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_extern.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_extern.h @@ -30,6 +30,10 @@ * \warning */ +#include "mac_defs.h" + +//extern NR_UE_MAC_INST_t *UE_mac_inst; + // Type0-PDCCH search space extern const int32_t table_38213_13_1_c2[16]; extern const int32_t table_38213_13_1_c3[16]; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 557f1f6ce0..36d285e320 100755 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -125,25 +125,45 @@ uint32_t get_ssb_slot(uint32_t ssb_index); uint32_t mr_ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t eNB_id, uint16_t rnti, sub_frame_t subframe); -void nr_ue_process_mac_pdu( - module_id_t module_idP, - uint8_t CC_id, - uint8_t *pduP, - uint16_t mac_pdu_len, - uint8_t gNB_index); + +/* \brief Get payload (MAC PDU) from UE PHY +@param module_idP Instance id of UE in machine +@param CC_id Component Carrier index +@param frameP Current Rx frame +@param slotP Current Rx slot +@param pdu Pointer to the MAC PDU +@param pdu_len Length of the MAC PDU +@param gNB_id Index of gNB that UE is attached to +@param ul_time_alignment of struct handling the timing advance parameters +@returns void +*/ +void nr_ue_send_sdu(module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + int slotP, + uint8_t * pdu, + uint16_t pdu_len, + uint8_t gNB_index, + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment); + +void nr_ue_process_mac_pdu(module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t *pduP, + uint16_t mac_pdu_len, + uint8_t gNB_index, + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment); int8_t nr_ue_process_dlsch(module_id_t module_id, int cc_id, uint8_t gNB_index, fapi_nr_dci_indication_t *dci_ind, void *pduP, uint32_t pdu_len); -void nr_ue_send_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframeP, uint8_t * sdu, uint16_t sdu_len, uint8_t gNB_index); - void ue_dci_configuration(NR_UE_MAC_INST_t *mac,fapi_nr_dl_config_request_t *dl_config,int frame,int slot); void nr_extract_dci_info(NR_UE_MAC_INST_t *mac, - int dci_format, - uint8_t dci_length, - uint16_t rnti, - uint64_t *dci_pdu, - nr_dci_pdu_rel15_t *nr_pdci_info_extracted); + int dci_format, + uint8_t dci_length, + uint16_t rnti, + uint64_t *dci_pdu, + nr_dci_pdu_rel15_t *nr_pdci_info_extracted); int set_tdd_config_nr_ue(fapi_nr_config_request_t *cfg, int mu, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index be1e852360..61f9ab601e 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -32,7 +32,14 @@ //#include "defs.h" #include "mac_proto.h" -#include "executables/nr-softmodem.h" +#include "../../ARCH/COMMON/common_lib.h" +//#undef MALLOC +#include "assertions.h" +#include "PHY/types.h" +#include "PHY/defs_UE.h" +#include "openair2/LAYER2/RLC/rlc.h" +#include "openair2/LAYER2/PDCP_v10.1.0/pdcp.h" +#include "executables/softmodem-common.h" static NR_UE_MAC_INST_t *nr_ue_mac_inst; 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 412fcf09e3..396e06ff09 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -49,15 +49,20 @@ void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pd LOG_D(MAC,"Filling search candidates for DCI\n"); - rel15->number_of_candidates=1; + rel15->number_of_candidates=3; rel15->CCE[0]=0; rel15->L[0]=4; + rel15->CCE[1]=4; + rel15->L[1]=4; + rel15->CCE[2]=8; + rel15->L[2]=4; + } void ue_dci_configuration(NR_UE_MAC_INST_t *mac,fapi_nr_dl_config_request_t *dl_config,int frame,int slot) { // check if DL slot - if (is_nr_DL_slot(mac->scc->tdd_UL_DL_ConfigurationCommon,slot)==1) { + if (is_nr_DL_slot(mac->scc,slot)==1) { // get BWP 1, Coreset 0, SearchSpace 0 if (mac->DLbwp[0]==NULL) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index e166b34804..58b312038a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -21,28 +21,46 @@ /* \file ue_procedures.c * \brief procedures related to UE - * \author R. Knopp, K.H. HSU + * \author R. Knopp, K.H. HSU, G. Casati * \date 2018 * \version 0.1 * \company Eurecom / NTUST - * \email: knopp@eurecom.fr, kai-hsiang.hsu@eurecom.fr + * \email: knopp@eurecom.fr, kai-hsiang.hsu@eurecom.fr, guido.casati@iis.fraunhofer.de * \note * \warning */ + +/* MAC related headers */ #include "mac_proto.h" +#include "mac_defs.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac.h" #include "mac_extern.h" +#include "common/utils/nr/nr_common.h" + +//#include "LAYER2/MAC/mac_vars.h" // TODO Note that mac_vars.h is not NR specific and this should be updated + // also, the use of the same should be updated in nr-softmodem and nr-uesoftmodem + +/* PHY UE related headers*/ +#include "SCHED_NR_UE/defs.h" + #include "RRC/NR_UE/rrc_proto.h" #include "assertions.h" #include "PHY/defs_nr_UE.h" + +/*Openair Packet Tracer */ +#include "UTIL/OPT/opt.h" +#include "OCG.h" +#include "executables/softmodem-common.h" +/* log utils */ #include "common/utils/LOG/log.h" -#include "mac_defs.h" -#include "../MAC/mac.h" -#include "../NR_MAC_gNB/nr_mac_common.h" -#include "common/utils/nr/nr_common.h" +#include "SIMULATION/TOOLS/sim.h" // for taus +#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac.h" +#include "common/utils/LOG/vcd_signal_dumper.h" #include #include +//int mbms_rab_id = 2047; //#define ENABLE_MAC_PAYLOAD_DEBUG 1 #define DEBUG_EXTRACT_DCI 1 @@ -1670,7 +1688,6 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(fapi_nr_ul_config_pusch_pd /* * TS 38.214 subclause 5.1.2.2.2 Downlink resource allocation type 1 */ - dlsch_config_pdu->number_rbs = NRRIV2BW(riv,n_RB_DLBWP); dlsch_config_pdu->start_rb = NRRIV2PRBOFFSET(riv,n_RB_DLBWP); @@ -2649,392 +2666,48 @@ int8_t nr_ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t e return 0; } +void nr_ue_send_sdu(module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + int slotP, + uint8_t * pdu, uint16_t pdu_len, uint8_t gNB_index, + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){ -void nr_ue_process_mac_pdu( - module_id_t module_idP, - uint8_t CC_id, - uint8_t *pduP, - uint16_t mac_pdu_len, - uint8_t eNB_index){ + LOG_D(MAC, "Handling PDU frame %d slot %d\n", frameP, slotP); - uint8_t *pdu_ptr = pduP; - uint16_t pdu_len = mac_pdu_len; - - uint16_t mac_ce_len; - uint16_t mac_subheader_len; - uint16_t mac_sdu_len; - - // For both DL/UL-SCH - // Except: - // - UL/DL-SCH: fixed-size MAC CE(known by LCID) - // - UL/DL-SCH: padding - // - UL-SCH: MSG3 48-bits - // |0|1|2|3|4|5|6|7| bit-wise - // |R|F| LCID | - // | L | - // |0|1|2|3|4|5|6|7| bit-wise - // |R|F| LCID | - // | L | - // | L | - - // For both DL/UL-SCH - // For: - // - UL/DL-SCH: fixed-size MAC CE(known by LCID) - // - UL/DL-SCH: padding, for single/multiple 1-oct padding CE(s) - // - UL-SCH: MSG3 48-bits - // |0|1|2|3|4|5|6|7| bit-wise - // |R|R| LCID | - // LCID: The Logical Channel ID field identifies the logical channel instance of the corresponding MAC SDU or the type of the corresponding MAC CE or padding as described in Tables 6.2.1-1 and 6.2.1-2 for the DL-SCH and UL-SCH respectively. There is one LCID field per MAC subheader. The LCID field size is 6 bits; - // L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field; - // F: lenght of L is 0:8 or 1:16 bits wide - // R: Reserved bit, set to zero. - - uint8_t done = 0; - - while (!done || pdu_len <= 0){ - mac_ce_len = 0x0000; - mac_subheader_len = 0x0001; // default to fixed-length subheader = 1-oct - mac_sdu_len = 0x0000; - switch(((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID){ - // MAC CE - case DL_SCH_LCID_CCCH: - // MSG4 RRC Connection Setup 38.331 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH: - // 38.321 Ch6.1.3.14 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL: - // 38.321 Ch6.1.3.13 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT: - // 38.321 Ch6.1.3.12 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - break; - case DL_SCH_LCID_SP_SRS_ACTIVATION: - // 38.321 Ch6.1.3.17 - // varialbe length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - break; - - case DL_SCH_LCID_RECOMMENDED_BITRATE: - // 38.321 Ch6.1.3.20 - mac_ce_len = 2; - break; - case DL_SCH_LCID_SP_ZP_CSI_RS_RES_SET_ACT: - // 38.321 Ch6.1.3.19 - mac_ce_len = 2; - break; - case DL_SCH_LCID_PUCCH_SPATIAL_RELATION_ACT: - // 38.321 Ch6.1.3.18 - mac_ce_len = 3; - break; - case DL_SCH_LCID_SP_CSI_REP_PUCCH_ACT: - // 38.321 Ch6.1.3.16 - mac_ce_len = 2; - break; - case DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH: - // 38.321 Ch6.1.3.15 - mac_ce_len = 2; - break; - case DL_SCH_LCID_DUPLICATION_ACT: - // 38.321 Ch6.1.3.11 - mac_ce_len = 1; - break; - case DL_SCH_LCID_SCell_ACT_4_OCT: - // 38.321 Ch6.1.3.10 - mac_ce_len = 4; - break; - case DL_SCH_LCID_SCell_ACT_1_OCT: - // 38.321 Ch6.1.3.10 - mac_ce_len = 1; - break; - case DL_SCH_LCID_L_DRX: - // 38.321 Ch6.1.3.6 - // fixed length but not yet specify. - mac_ce_len = 0; - break; - case DL_SCH_LCID_DRX: - // 38.321 Ch6.1.3.5 - // fixed length but not yet specify. - mac_ce_len = 0; - break; - case DL_SCH_LCID_TA_COMMAND: - // 38.321 Ch6.1.3.4 - mac_ce_len = 1; - break; - case DL_SCH_LCID_CON_RES_ID: - // 38.321 Ch6.1.3.3 - mac_ce_len = 6; - break; - case DL_SCH_LCID_PADDING: - done = 1; - // end of MAC PDU, can ignore the rest. - break; - - // MAC SDU - case DL_SCH_LCID_SRB1: - // check if LCID is valid at current time. - case UL_SCH_LCID_SRB2: - // check if LCID is valid at current time. - case UL_SCH_LCID_SRB3: - // check if LCID is valid at current time. - default: - // check if LCID is valid at current time. - mac_sdu_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - // DRB LCID by RRC - break; - } - pdu_ptr += ( mac_subheader_len + mac_ce_len + mac_sdu_len ); - pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len ); - AssertFatal(pdu_len >= 0, "[MAC] nr_ue_process_mac_pdu, residual mac pdu length < 0!\n"); - } -} - -//--------------------------------------------------------------------------------- - - -unsigned char *parse_header(unsigned char *mac_header, - unsigned char *num_ce, - unsigned char *num_sdu, - unsigned char *rx_ces, - unsigned char *rx_lcids, - unsigned short *rx_lengths, - unsigned short tb_length) -{ - - unsigned char not_done = 1, num_ces = 0, num_cont_res = - 0, num_padding = 0, num_sdus = 0, lcid, num_sdu_cnt; - unsigned char *mac_header_ptr = mac_header; - unsigned short length, ce_len = 0; - - while (not_done == 1) { - - if (((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E == 0) { - // printf("E=0\n"); - not_done = 0; - } - - lcid = ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID; - - if (lcid < UE_CONT_RES) { - //printf("[MAC][UE] header %x.%x.%x\n",mac_header_ptr[0],mac_header_ptr[1],mac_header_ptr[2]); - if (not_done == 0) { // last MAC SDU, length is implicit - mac_header_ptr++; - length = - tb_length - (mac_header_ptr - mac_header) - ce_len; - - for (num_sdu_cnt = 0; num_sdu_cnt < num_sdus; - num_sdu_cnt++) { - length -= rx_lengths[num_sdu_cnt]; - } - } else { - if (((SCH_SUBHEADER_LONG *) mac_header_ptr)->F == 1) { - length = - ((((SCH_SUBHEADER_LONG *) mac_header_ptr)-> - L_MSB & 0x7f) - << 8) | (((SCH_SUBHEADER_LONG *) mac_header_ptr)-> - L_LSB & 0xff); - mac_header_ptr += 3; -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC, "[UE] parse long sdu, size %x \n", length); -#endif - - } else { //if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) { - length = ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L; - mac_header_ptr += 2; - } - } - -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC, "[UE] sdu %d lcid %d length %d (offset now %ld)\n", - num_sdus, lcid, length, mac_header_ptr - mac_header); -#endif - rx_lcids[num_sdus] = lcid; - rx_lengths[num_sdus] = length; - num_sdus++; - } else { // This is a control element subheader - if (lcid == SHORT_PADDING) { - num_padding++; - mac_header_ptr++; - } else { - rx_ces[num_ces] = lcid; - num_ces++; - mac_header_ptr++; - - if (lcid == TIMING_ADV_CMD) { - ce_len++; - } else if (lcid == UE_CONT_RES) { - - // FNA: check MAC Header is one of thoses defined in Annex B of 36.321 - // Check there is only 1 Contention Resolution - if (num_cont_res) { - LOG_W(MAC, - "[UE] Msg4 Wrong received format: More than 1 Contention Resolution\n"); - // exit parsing - return NULL; - - } - // UE_CONT_RES shall never be the last subheader unless this is the only MAC subheader - if ((not_done == 0) - && ((num_sdus) || (num_ces > 1) || (num_padding))) { - LOG_W(MAC, - "[UE] Msg4 Wrong received format: Contention Resolution after num_ces=%d num_sdus=%d num_padding=%d\n", - num_ces, num_sdus, num_padding); - // exit parsing - return NULL; - } - num_cont_res++; - ce_len += 6; - } - } - -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC, "[UE] ce %d lcid %d (offset now %ld)\n", num_ces, - lcid, mac_header_ptr - mac_header); -#endif - } - } - - *num_ce = num_ces; - *num_sdu = num_sdus; - - return (mac_header_ptr); -} - - -//------------------------------------------------------------------------------ -void -nr_ue_send_sdu(module_id_t module_idP, - uint8_t CC_id, - frame_t frameP, - sub_frame_t subframeP, - uint8_t * sdu, uint16_t sdu_len, uint8_t eNB_index) -//------------------------------------------------------------------------------ -{ - - unsigned char rx_ces[MAX_NUM_CE], num_ce, num_sdu, i, *payload_ptr; - unsigned char rx_lcids[NB_RB_MAX]; - unsigned short rx_lengths[NB_RB_MAX]; + uint8_t * pduP = pdu; + NR_UE_MAC_INST_t *UE_mac_inst = get_mac_inst(module_idP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN); //LOG_D(MAC,"sdu: %x.%x.%x\n",sdu[0],sdu[1],sdu[2]); + /* + #ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE %d] ue_send_sdu : Frame %d gNB_index %d : num_ce %d num_sdu %d\n", + module_idP, frameP, gNB_index, num_ce, num_sdu); + #endif + */ - payload_ptr = - parse_header(sdu, &num_ce, &num_sdu, rx_ces, rx_lcids, rx_lengths, - sdu_len); - -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC, - "[UE %d] ue_send_sdu : Frame %d eNB_index %d : num_ce %d num_sdu %d\n", - module_idP, frameP, eNB_index, num_ce, num_sdu); -#endif - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); - - for (i = 0; i < 32; i++) { - LOG_T(MAC, "%x.", sdu[i]); - } - - LOG_T(MAC, "\n"); -#endif - - if (payload_ptr != NULL) { - - for (i = 0; i < num_ce; i++) { - // printf("ce %d : %d\n",i,rx_ces[i]); - switch (rx_ces[i]) { - case UE_CONT_RES: - - break; - - case TIMING_ADV_CMD: - - break; - - case DRX_CMD: - - break; - } + /* + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); + for (i = 0; i < 32; i++) { + LOG_T(MAC, "%x.", sdu[i]); } + LOG_T(MAC, "\n"); + #endif + */ - for (i = 0; i < num_sdu; i++) { -#ifdef DEBUG_HEADER_PARSING - LOG_I(MAC, "[UE] SDU %d : LCID %d, length %d\n", i, - rx_lcids[i], rx_lengths[i]); -#endif - if ((rx_lcids[i] < NB_RB_MAX) && (rx_lcids[i] > DCCH1)) { + // Processing MAC PDU + // it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs + if (pduP != NULL) + nr_ue_process_mac_pdu(module_idP, CC_id, frameP, pduP, pdu_len, gNB_index, ul_time_alignment); - LOG_D(MAC, - "[UE %d] Frame %d : DLSCH -> DL-DTCH%d (eNB %d, %d bytes)\n", - module_idP, frameP, rx_lcids[i], eNB_index, - rx_lengths[i]); - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_I(MAC, "Printing MAC PDU contents at slot: %d \n", subframeP); - int j; - for (j = 0; j < 20; j++) //rx_lengths[i] - LOG_I(MAC, "%x.", (unsigned char) payload_ptr[j]); - LOG_I(MAC, "\n"); -#endif - mac_rlc_data_ind(module_idP, - 4660, //UE_mac_inst[module_idP].crnti //hardcode value corresponding to the one from the eNB - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - rx_lcids[i], - (char *) payload_ptr, rx_lengths[i], 1, - NULL); - } else { - LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (eNB %d)\n", - module_idP, frameP, rx_lcids[i], eNB_index); - } - payload_ptr += rx_lengths[i]; - } - } // end if (payload_ptr != NULL) + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT); } - void nr_extract_dci_info(NR_UE_MAC_INST_t *mac, int dci_format, uint8_t dci_size, @@ -3059,7 +2732,7 @@ void nr_extract_dci_info(NR_UE_MAC_INST_t *mac, NRRIV2BW(mac->ULbwp[0]->bwp_Common->genericParameters.locationAndBandwidth,275) : NRRIV2BW(mac->scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth,275); - int pos; + int pos=0; int fsize=0; switch(dci_format) { @@ -3386,3 +3059,441 @@ void nr_extract_dci_info(NR_UE_MAC_INST_t *mac, } +void nr_ue_process_mac_pdu(module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t *pduP, + uint16_t mac_pdu_len, + uint8_t gNB_index, + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){ + + // This function is adapting code from the old + // parse_header(...) and ue_send_sdu(...) functions of OAI LTE + + uint8_t *pdu_ptr = pduP, rx_lcid, done = 0; + int pdu_len = mac_pdu_len; + uint16_t mac_ce_len, mac_subheader_len, mac_sdu_len; + + //NR_UE_MAC_INST_t *UE_mac_inst = get_mac_inst(module_idP); + //uint8_t scs = UE_mac_inst->mib->subCarrierSpacingCommon; + //uint16_t bwp_ul_NB_RB = UE_mac_inst->initial_bwp_ul.N_RB; + + // For both DL/UL-SCH + // Except: + // - UL/DL-SCH: fixed-size MAC CE(known by LCID) + // - UL/DL-SCH: padding + // - UL-SCH: MSG3 48-bits + // |0|1|2|3|4|5|6|7| bit-wise + // |R|F| LCID | + // | L | + // |0|1|2|3|4|5|6|7| bit-wise + // |R|F| LCID | + // | L | + // | L | + + // For both DL/UL-SCH + // For: + // - UL/DL-SCH: fixed-size MAC CE(known by LCID) + // - UL/DL-SCH: padding, for single/multiple 1-oct padding CE(s) + // - UL-SCH: MSG3 48-bits + // |0|1|2|3|4|5|6|7| bit-wise + // |R|R| LCID | + // LCID: The Logical Channel ID field identifies the logical channel instance of the corresponding MAC SDU or the type of the corresponding MAC CE or padding as described in Tables 6.2.1-1 and 6.2.1-2 for the DL-SCH and UL-SCH respectively. There is one LCID field per MAC subheader. The LCID field size is 6 bits; + // L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field; + // F: lenght of L is 0:8 or 1:16 bits wide + // R: Reserved bit, set to zero. + + while (!done && pdu_len > 0){ + mac_ce_len = 0x0000; + mac_subheader_len = 0x0001; // default to fixed-length subheader = 1-oct + mac_sdu_len = 0x0000; + rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID; + + switch(rx_lcid){ + // MAC CE + + /*#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID, pdu_len); + #endif*/ + case DL_SCH_LCID_CCCH: + // MSG4 RRC Connection Setup 38.331 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + + break; + + case DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH: + + // 38.321 Ch6.1.3.14 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + break; + case DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL: + // 38.321 Ch6.1.3.13 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + break; + case DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT: + // 38.321 Ch6.1.3.12 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + break; + case DL_SCH_LCID_SP_SRS_ACTIVATION: + // 38.321 Ch6.1.3.17 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + break; + + case DL_SCH_LCID_RECOMMENDED_BITRATE: + // 38.321 Ch6.1.3.20 + mac_ce_len = 2; + break; + case DL_SCH_LCID_SP_ZP_CSI_RS_RES_SET_ACT: + // 38.321 Ch6.1.3.19 + mac_ce_len = 2; + break; + case DL_SCH_LCID_PUCCH_SPATIAL_RELATION_ACT: + // 38.321 Ch6.1.3.18 + mac_ce_len = 3; + break; + case DL_SCH_LCID_SP_CSI_REP_PUCCH_ACT: + // 38.321 Ch6.1.3.16 + mac_ce_len = 2; + break; + case DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH: + // 38.321 Ch6.1.3.15 + mac_ce_len = 2; + break; + case DL_SCH_LCID_DUPLICATION_ACT: + // 38.321 Ch6.1.3.11 + mac_ce_len = 1; + break; + case DL_SCH_LCID_SCell_ACT_4_OCT: + // 38.321 Ch6.1.3.10 + mac_ce_len = 4; + break; + case DL_SCH_LCID_SCell_ACT_1_OCT: + // 38.321 Ch6.1.3.10 + mac_ce_len = 1; + break; + case DL_SCH_LCID_L_DRX: + // 38.321 Ch6.1.3.6 + // fixed length but not yet specify. + mac_ce_len = 0; + break; + case DL_SCH_LCID_DRX: + // 38.321 Ch6.1.3.5 + // fixed length but not yet specify. + mac_ce_len = 0; + break; + case DL_SCH_LCID_TA_COMMAND: + // 38.321 Ch6.1.3.4 + mac_ce_len = 1; + + /*uint8_t ta_command = ((NR_MAC_CE_TA *)pdu_ptr)[1].TA_COMMAND; + uint8_t tag_id = ((NR_MAC_CE_TA *)pdu_ptr)[1].TAGID;*/ + + ul_time_alignment->apply_ta = 1; + ul_time_alignment->ta_command = ((NR_MAC_CE_TA *)pdu_ptr)[1].TA_COMMAND; + ul_time_alignment->tag_id = ((NR_MAC_CE_TA *)pdu_ptr)[1].TAGID; + + /* + #ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] CE %d : UE Timing Advance : %d\n", i, pdu_ptr[1]); + #endif + */ + + LOG_D(MAC, "Received TA_COMMAND %u TAGID %u CC_id %d\n", ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id); + + break; + case DL_SCH_LCID_CON_RES_ID: + // 38.321 Ch6.1.3.3 + mac_ce_len = 6; + + break; + case DL_SCH_LCID_PADDING: + done = 1; + // end of MAC PDU, can ignore the rest. + break; + + // MAC SDU + + case DL_SCH_LCID_DCCH: + // check if LCID is valid at current time. + + case DL_SCH_LCID_DCCH1: + // check if LCID is valid at current time. + + default: + // check if LCID is valid at current time. + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + //mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + mac_sdu_len = ((uint16_t)(((NR_MAC_SUBHEADER_LONG *) pdu_ptr)->L1 & 0x7f) << 8) + | ((uint16_t)((NR_MAC_SUBHEADER_LONG *) pdu_ptr)->L2 & 0xff); + + } else { + mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + } + + LOG_D(MAC, "[UE %d] Frame %d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, gNB_index, mac_sdu_len); + + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); + + for (i = 0; i < 32; i++) + LOG_T(MAC, "%x.", (pdu_ptr + mac_subheader_len)[i]); + + LOG_T(MAC, "\n"); + #endif + + if (IS_SOFTMODEM_NOS1){ + if (rx_lcid < NB_RB_MAX && rx_lcid >= DL_SCH_LCID_DTCH) { + + mac_rlc_data_ind(module_idP, + 0x1234, + gNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + rx_lcid, + (char *) (pdu_ptr + mac_subheader_len), + mac_sdu_len, + 1, + NULL); + } else { + LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (gNB %d)\n", module_idP, frameP, rx_lcid, gNB_index); + } + } + + break; + } + pdu_ptr += ( mac_subheader_len + mac_ce_len + mac_sdu_len ); + pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len ); + AssertFatal(pdu_len >= 0, "[MAC] nr_ue_process_mac_pdu, residual mac pdu length < 0!\n"); + } +} + +//--------------------------------------------------------------------------------- + + +uint16_t +nr_generate_ulsch_pdu(uint8_t *mac_pdu, + uint8_t *sdus_payload, + uint8_t num_sdus, + uint16_t *sdu_lengths, + uint8_t *sdu_lcids, + uint16_t *crnti, + uint16_t buflen) { + + NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) mac_pdu; + unsigned char * ulsch_buffer_ptr = sdus_payload; + uint8_t last_size=0; + uint16_t sdu_length_total=0; + int i; + int offset=0; + + // 2) Generation of ULSCH MAC SDU subheaders + for (i = 0; i < num_sdus; i++) { + LOG_D(MAC, "[gNB] Generate ULSCH header num sdu %d len sdu %d\n", num_sdus, sdu_lengths[i]); + + if (sdu_lengths[i] < 128) { + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0; + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0; + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = sdu_lcids[i]; + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = (unsigned char) sdu_lengths[i]; + last_size = 2; + } else { + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->R = 0; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->F = 1; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->LCID = sdu_lcids[i]; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L1 = ((unsigned short) sdu_lengths[i] >> 8) & 0x7f; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L2 = (unsigned short) sdu_lengths[i] & 0xff; + last_size = 3; + } + + mac_pdu_ptr += last_size; + + // 3) cycle through SDUs, compute each relevant and place dlsch_buffer in + memcpy((void *) mac_pdu_ptr, (void *) ulsch_buffer_ptr, sdu_lengths[i]); + ulsch_buffer_ptr+= sdu_lengths[i]; + sdu_length_total+= sdu_lengths[i]; + mac_pdu_ptr += sdu_lengths[i]; + } + + offset = ((unsigned char *) mac_pdu_ptr - mac_pdu); + + // 4) Compute final offset for padding + uint16_t padding_bytes = buflen - offset; + LOG_D(MAC, "Number of padding bytes: %d \n", padding_bytes); + if (padding_bytes > 0) { + ((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->R = 0; + ((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->LCID = UL_SCH_LCID_PADDING; + mac_pdu_ptr++; + + } else { + // no MAC subPDU with padding + } + + return offset; +} + + +uint8_t +nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t *ulsch_buffer, uint16_t buflen, uint8_t *access_mode) { + uint8_t total_rlc_pdu_header_len = 0; + int16_t buflen_remain = 0; + uint8_t lcid = 0; + uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + uint16_t payload_offset = 0, num_sdus = 0; + uint8_t ulsch_sdus[MAX_ULSCH_PAYLOAD_BYTES]; + uint16_t sdu_length_total = 0; + //unsigned short post_padding = 0; + + rlc_buffer_occupancy_t lcid_buffer_occupancy_old = + 0, lcid_buffer_occupancy_new = 0; + LOG_D(MAC, + "[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); +#if UE_TIMING_TRACE + start_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); +#endif + + //NR_UE_MAC_INST_t *nr_ue_mac_inst = get_mac_inst(0); + + // Check for DCCH first + // TO DO: Multiplex in the order defined by the logical channel prioritization + for (lcid = UL_SCH_LCID_SRB1; + lcid < NR_MAX_NUM_LCID; lcid++) { + + lcid_buffer_occupancy_old = + //TODO: Replace static value with CRNTI + mac_rlc_get_buffer_occupancy_ind(module_idP, + 0x1234, eNB_index, frameP, //nr_ue_mac_inst->crnti + subframe, ENB_FLAG_NO, + lcid); + lcid_buffer_occupancy_new = lcid_buffer_occupancy_old; + + if(lcid_buffer_occupancy_new){ + + buflen_remain = + buflen - (total_rlc_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE); + LOG_D(MAC, + "[UE %d] Frame %d : UL-DXCH -> ULSCH, RLC %d has %d bytes to " + "send (Transport Block size %d SDU Length Total %d , mac header len %d, buflen_remain %d )\n", //BSR byte before Tx=%d + module_idP, frameP, lcid, lcid_buffer_occupancy_new, + buflen, sdu_length_total, + total_rlc_pdu_header_len, buflen_remain); // ,nr_ue_mac_inst->scheduling_info.BSR_bytes[nr_ue_mac_inst->scheduling_info.LCGID[lcid]] + + while(buflen_remain > 0 && lcid_buffer_occupancy_new){ + + //TODO: Replace static value with CRNTI + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + 0x1234, eNB_index, //nr_ue_mac_inst->crnti + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + buflen_remain, + (char *)&ulsch_sdus[sdu_length_total],0, + 0 + ); + AssertFatal(buflen_remain >= sdu_lengths[num_sdus], + "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", + lcid, sdu_lengths[num_sdus], buflen_remain); + + if (sdu_lengths[num_sdus]) { + sdu_length_total += sdu_lengths[num_sdus]; + sdu_lcids[num_sdus] = lcid; + + + //Update total MAC Header size for RLC PDUs + /*if(sdu_lengths[num_sdus]<128) + total_rlc_pdu_header_len += 2; + else + total_rlc_pdu_header_len += 3;*/ + + total_rlc_pdu_header_len += MAX_RLC_SDU_SUBHEADER_SIZE; //rlc_pdu_header_len_last; + + //Update number of SDU + num_sdus++; + } + + /* Get updated BO after multiplexing this PDU */ + //TODO: Replace static value with CRNTI + + lcid_buffer_occupancy_new = + mac_rlc_get_buffer_occupancy_ind(module_idP, + 0x1234, //nr_ue_mac_inst->crnti + eNB_index, frameP, + subframe, ENB_FLAG_NO, + lcid); + buflen_remain = + buflen - (total_rlc_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE); + } + } + +} + + // Generate ULSCH PDU + if (num_sdus>0) { + payload_offset = nr_generate_ulsch_pdu(ulsch_buffer, // mac header + ulsch_sdus, + num_sdus, // num sdus + sdu_lengths, // sdu length + sdu_lcids, // sdu lcid + NULL, // crnti + buflen); // long_bsr + } + else + return 0; + + // Padding: fill remainder of ULSCH with 0 + if (buflen - payload_offset > 0){ + for (int j = payload_offset; j < buflen; j++) + ulsch_buffer[j] = 0; + } + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_I(MAC, "Printing UL MAC payload UE side, payload_offset: %d \n", payload_offset); + for (int i = 0; i < buflen ; i++) { + //harq_process_ul_ue->a[i] = (unsigned char) rand(); + //printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]); + printf("%02x ",(unsigned char)ulsch_buffer[i]); + } + printf("\n"); +#endif + + return 1; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 2201e4f991..b5fdea6760 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -206,7 +206,9 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); - cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling); + uint16_t sco = absolute_diff%(12*scs_scaling); + AssertFatal(sco==0,"absoluteFrequencySSB has a subcarrier offset of %d while it should be alligned with CRBs\n",sco); + cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; @@ -215,19 +217,19 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm switch (scc->ssb_PositionsInBurst->present) { case 1 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0]; + cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0]<<24; cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; break; case 2 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]; + cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]<<24; cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; break; case 3 : cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = 0; cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; for (i=0; i<4; i++) { - cfg->ssb_table.ssb_mask_list[0].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<ssb_table.ssb_mask_list[1].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<ssb_table.ssb_mask_list[0].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<ssb_table.ssb_mask_list[1].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]< - -#define ENABLE_MAC_PAYLOAD_DEBUG -#define DEBUG_eNB_SCHEDULER 1 - -extern RAN_CONTEXT_t RC; -extern int phy_test; -extern uint8_t nfapi_mode; +#include "executables/softmodem-common.h" uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; @@ -380,20 +371,14 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, //printf("gNB_dlsch_ulsch_scheduler frameRX %d slotRX %d frameTX %d slotTX %d\n",frame_rxP,slot_rxP,frame_txP,slot_txP); protocol_ctxt_t ctxt; - int CC_id; - int UE_id; - uint64_t *dlsch_in_slot_bitmap=NULL; - uint64_t *ulsch_in_slot_bitmap=NULL; + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame_txP, slot_txP,module_idP); + int CC_id, UE_id = 0; + gNB_MAC_INST *gNB = RC.nrmac[module_idP]; + NR_UE_list_t *UE_list = &gNB->UE_list; + UE_sched_ctrl_t *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + NR_COMMON_channels_t *cc = gNB->common_channels; NR_sched_pucch *pucch_sched = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch)); - if (phy_test) UE_id=0; - - NR_COMMON_channels_t *cc = RC.nrmac[module_idP]->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - int num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])>>(7-scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity); - - //nfapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = NULL; - start_meas(&RC.nrmac[module_idP]->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN); @@ -403,27 +388,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, RC.nrmac[module_idP]->frame = frame_rxP; RC.nrmac[module_idP]->slot = slot_rxP; - if (phy_test) { - dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch - ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch - - // hardcoding dlsch to be in slot 1 - if (!(slot_txP%num_slots_per_tdd)) { - if(slot_txP==0) - *dlsch_in_slot_bitmap = 0x02; - else - *dlsch_in_slot_bitmap = 0x00; - } - - // hardcoding ulsch to be in slot 8 - if (!(slot_rxP%num_slots_per_tdd)) { - if(slot_rxP==0) - *ulsch_in_slot_bitmap = 0x100; - else - *ulsch_in_slot_bitmap = 0x00; - } - } - // Check if there are downlink symbols in the slot, if (is_nr_DL_slot(cc->ServingCellConfigCommon,slot_txP)) { @@ -449,22 +413,35 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, rnti = 0;//UE_RNTI(module_idP, i); CC_id = 0;//UE_PCCID(module_idP, i); - } //END if (UE_list->active[i]) - } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++) - */ - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES,NOT_A_RNTI, frame_txP, slot_txP,module_idP); + } //END if (UE_list->active[i]) + } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++) + */ + // This schedules MIB + if((slot_txP == 0) && (frame_txP & 7) == 0){ + schedule_nr_mib(module_idP, frame_txP, slot_txP); + } - // This schedules MIB - if((slot_txP == 0) && (frame_txP & 7) == 0){ - schedule_nr_mib(module_idP, frame_txP, slot_txP); - } + // TbD once RACH is available, start ta_timer when UE is connected + if (ue_sched_ctl->ta_timer) ue_sched_ctl->ta_timer--; - // Phytest scheduling - if (phy_test && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%num_slots_per_tdd))) { - nr_update_pucch_scheduling(module_idP, UE_id, frame_txP, slot_txP, num_slots_per_tdd,pucch_sched); - nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL); - } + if (ue_sched_ctl->ta_timer == 0) { + gNB->ta_command = ue_sched_ctl->ta_update; + /* if time is up, then set the timer to not send it for 5 frames + // regardless of the TA value */ + ue_sched_ctl->ta_timer = 100; + /* reset ta_update */ + ue_sched_ctl->ta_update = 31; + /* MAC CE flag indicating TA length */ + gNB->ta_len = 2; + } + + // Phytest scheduling + if (get_softmodem_params()->phy_test && slot_txP==1){ + nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL); + // resetting ta flag + gNB->ta_len = 0; + } /* // Allocate CCEs for good after scheduling is done @@ -475,11 +452,8 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } //is_nr_DL_slot if (is_nr_UL_slot(cc->ServingCellConfigCommon,slot_rxP)) { - if (phy_test) { - nr_schedule_pucch(module_idP, UE_id, frame_rxP, slot_rxP); - if (is_xlsch_in_slot(*ulsch_in_slot_bitmap,slot_rxP%num_slots_per_tdd)){ - nr_schedule_uss_ulsch_phytest(module_idP, frame_rxP, slot_rxP); - } + if (get_softmodem_params()->phy_test && slot_rxP==8){ + nr_schedule_uss_ulsch_phytest(module_idP, frame_rxP, slot_rxP); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 2983c699c0..2a36425fae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -33,7 +33,7 @@ #include "assertions.h" #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "LAYER2/NR_MAC_gNB/mac_proto.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" @@ -46,9 +46,7 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#if defined(ENABLE_ITTI) #include "intertask_interface.h" -#endif #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 @@ -135,7 +133,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP){ AssertFatal(1==0,"SCS %ld not allowed for SSB \n", *cc->ServingCellConfigCommon->ssbSubcarrierSpacing); } dl_config_pdu->ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = 0; //kSSB - dl_config_pdu->ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA = ssb_offset0/(ratio*12); + dl_config_pdu->ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA = ssb_offset0/(ratio*12) - 10; // absoluteFrequencySSB is the center of SSB dl_config_pdu->ssb_pdu.ssb_pdu_rel15.bchPayloadFlag = 1; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.bchPayload = (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1); dl_req->nPDUs++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c new file mode 100644 index 0000000000..5233270149 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -0,0 +1,181 @@ +/* + * 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 gNB_scheduler_dlsch.c + * \brief procedures related to gNB for the DLSCH transport channel + * \author Guido Casati + * \date 2019 + * \email: guido.casati@iis.fraunhofe.de + * \version 1.0 + * @ingroup _mac + + */ + +/*PHY*/ +#include "PHY/CODING/coding_defs.h" +#include "PHY/defs_nr_common.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +/*MAC*/ +#include "LAYER2/NR_MAC_COMMON/nr_mac.h" +#include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" +#include "LAYER2/MAC/mac.h" + +/*NFAPI*/ +#include "nfapi_nr_interface.h" +/*TAG*/ +#include "NR_TAG-Id.h" + + +int nr_generate_dlsch_pdu(module_id_t module_idP, + unsigned char *sdus_payload, + unsigned char *mac_pdu, + unsigned char num_sdus, + unsigned short *sdu_lengths, + unsigned char *sdu_lcids, + unsigned char drx_cmd, + unsigned char *ue_cont_res_id, + unsigned short post_padding){ + + gNB_MAC_INST *gNB = RC.nrmac[module_idP]; + + NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) mac_pdu; + unsigned char * dlsch_buffer_ptr = sdus_payload; + uint8_t last_size = 0; + int offset = 0, mac_ce_size, i, timing_advance_cmd, tag_id = 0; + + // MAC CEs + uint8_t mac_header_control_elements[16], *ce_ptr; + ce_ptr = &mac_header_control_elements[0]; + + // 1) Compute MAC CE and related subheaders + + // DRX command subheader (MAC CE size 0) + if (drx_cmd != 255) { + mac_pdu_ptr->R = 0; + mac_pdu_ptr->LCID = DL_SCH_LCID_DRX; + //last_size = 1; + mac_pdu_ptr++; + } + + // Timing Advance subheader + /* This was done only when timing_advance_cmd != 31 + // now TA is always send when ta_timer resets regardless of its value + // this is done to avoid issues with the timeAlignmentTimer which is + // supposed to monitor if the UE received TA or not */ + if (gNB->ta_len){ + mac_pdu_ptr->R = 0; + mac_pdu_ptr->LCID = DL_SCH_LCID_TA_COMMAND; + //last_size = 1; + mac_pdu_ptr++; + + // TA MAC CE (1 octet) + timing_advance_cmd = gNB->ta_command; + AssertFatal(timing_advance_cmd < 64,"timing_advance_cmd %d > 63\n", timing_advance_cmd); + ((NR_MAC_CE_TA *) ce_ptr)->TA_COMMAND = timing_advance_cmd; //(timing_advance_cmd+31)&0x3f; + if (gNB->tag->tag_Id != 0){ + tag_id = gNB->tag->tag_Id; + ((NR_MAC_CE_TA *) ce_ptr)->TAGID = tag_id; + } + + LOG_D(MAC, "NR MAC CE timing advance command = %d (%d) TAG ID = %d\n", timing_advance_cmd, ((NR_MAC_CE_TA *) ce_ptr)->TA_COMMAND, tag_id); + mac_ce_size = sizeof(NR_MAC_CE_TA); + + // Copying bytes for MAC CEs to the mac pdu pointer + memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size); + ce_ptr += mac_ce_size; + mac_pdu_ptr += (unsigned char) mac_ce_size; + } + + + // Contention resolution fixed subheader and MAC CE + if (ue_cont_res_id) { + mac_pdu_ptr->R = 0; + mac_pdu_ptr->LCID = DL_SCH_LCID_CON_RES_ID; + mac_pdu_ptr++; + //last_size = 1; + + // contention resolution identity MAC ce has a fixed 48 bit size + // this contains the UL CCCH SDU. If UL CCCH SDU is longer than 48 bits, + // it contains the first 48 bits of the UL CCCH SDU + LOG_T(MAC, "[gNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n", + ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2], + ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]); + + // Copying bytes (6 octects) to CEs pointer + mac_ce_size = 6; + memcpy(ce_ptr, ue_cont_res_id, mac_ce_size); + + // Copying bytes for MAC CEs to mac pdu pointer + memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size); + ce_ptr += mac_ce_size; + mac_pdu_ptr += (unsigned char) mac_ce_size; + } + + + // 2) Generation of DLSCH MAC SDU subheaders + for (i = 0; i < num_sdus; i++) { + LOG_D(MAC, "[gNB] Generate DLSCH header num sdu %d len sdu %d\n", num_sdus, sdu_lengths[i]); + + if (sdu_lengths[i] < 128) { + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0; + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0; + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = sdu_lcids[i]; + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = (unsigned char) sdu_lengths[i]; + last_size = 2; + } else { + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->R = 0; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->F = 1; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->LCID = sdu_lcids[i]; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L1 = ((unsigned short) sdu_lengths[i] >> 8) & 0x7f; + ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L2 = (unsigned short) sdu_lengths[i] & 0xff; + last_size = 3; + } + + mac_pdu_ptr += last_size; + + // 3) cycle through SDUs, compute each relevant and place dlsch_buffer in + memcpy((void *) mac_pdu_ptr, (void *) dlsch_buffer_ptr, sdu_lengths[i]); + dlsch_buffer_ptr+= sdu_lengths[i]; + mac_pdu_ptr += sdu_lengths[i]; + } + + // 4) Compute final offset for padding + if (post_padding > 0) { + ((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->R = 0; + ((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->LCID = DL_SCH_LCID_PADDING; + mac_pdu_ptr++; + + } else { + // no MAC subPDU with padding + } + + // compute final offset + offset = ((unsigned char *) mac_pdu_ptr - mac_pdu); + + //printf("Offset %d \n", ((unsigned char *) mac_pdu_ptr - mac_pdu)); + + return offset; +} + +/* functionalities of this function have been moved to nr_schedule_uss_dlsch_phytest */ +void nr_schedule_ue_spec(module_id_t module_idP, frame_t frameP, sub_frame_t slotP){ +} diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 4c0f529d4c..304004ff8c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -21,9 +21,9 @@ /*! \file gNB_scheduler_phytest.c * \brief gNB scheduling procedures in phy_test mode - * \author Guy De Souza + * \author Guy De Souza, G. Casati * \date 07/2018 - * \email: desouza@eurecom.fr + * \email: desouza@eurecom.fr, guido.casati@iis.fraunhofer.de * \version 1.0 * @ingroup _mac */ @@ -35,8 +35,9 @@ #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "PHY/NR_TRANSPORT/nr_dci.h" #include "executables/nr-softmodem.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac.h" +#include "executables/softmodem-common.h" #include "common/utils/nr/nr_common.h" - #include "NR_SCS-SpecificCarrier.h" #include "NR_TDD-UL-DL-ConfigCommon.h" #include "NR_FrequencyInfoUL.h" @@ -55,7 +56,9 @@ extern RAN_CONTEXT_t RC; //#define ENABLE_MAC_PAYLOAD_DEBUG 1 -/*Scheduling of DLSCH with associated DCI in common search space on initialBWP +//uint8_t mac_pdu[MAX_NR_DLSCH_PAYLOAD_BYTES]; + +/*Scheduling of DLSCH with associated DCI in common search space * current version has only a DCI for type 1 PDCCH for C_RNTI*/ void nr_schedule_css_dlsch_phytest(module_id_t module_idP, frame_t frameP, @@ -246,15 +249,17 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP, } } -int configure_fapi_dl_Tx(int Mod_idP, - sub_frame_t slotP, - int *CCEIndex, - nfapi_nr_dl_tti_request_body_t *dl_req, - nfapi_nr_pdu_t *TX_req, - NR_sched_pucch *pucch_sched, - uint8_t *mcsIndex, - uint16_t *rbSize, - uint16_t *rbStart) { + + + + +int configure_fapi_dl_pdu(int Mod_idP, + int *CCEIndex, + nfapi_nr_dl_tti_request_body_t *dl_req, + NR_sched_pucch *pucch_sched, + uint8_t *mcsIndex, + uint16_t *rbSize, + uint16_t *rbStart) { gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP]; @@ -263,9 +268,7 @@ int configure_fapi_dl_Tx(int Mod_idP, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu; nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu; - int TBS; - int bwp_id=1; - int UE_id = 0; + int TBS, bwp_id = 1, UE_id = 0; NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id]; @@ -368,7 +371,6 @@ int configure_fapi_dl_Tx(int Mod_idP, dci_pdu_rel15[0].tb_scaling, dci_pdu_rel15[0].ndi, dci_pdu_rel15[0].rv); - nr_configure_pdcch(pdcch_pdu_rel15, 1, // ue-specific @@ -401,8 +403,8 @@ int configure_fapi_dl_Tx(int Mod_idP, pdcch_pdu_rel15->DurationSymbols); int x_Overhead = 0; // should be 0 for initialBWP - nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, - x_Overhead); + nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead); + // Hardcode it for now TBS = dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15.TBSize[0]; LOG_D(MAC, "DLSCH PDU: start PRB %d n_PRB %d startSymbolAndLength %d start symbol %d nb_symbols %d nb_layers %d nb_codewords %d mcs %d TBS: %d\n", @@ -415,16 +417,6 @@ int configure_fapi_dl_Tx(int Mod_idP, pdsch_pdu_rel15->NrOfCodewords, pdsch_pdu_rel15->mcsIndex[0], TBS); - - dl_req->nPDUs+=2; - - TX_req->PDU_length = pdsch_pdu_rel15->TBSize[0]; - TX_req->PDU_index = nr_mac->pdu_index[0]++; - - // TX_req->num_TLV = 1; - // TX_req->TLVs[0].length = 8; - // memcpy((void*)&TX_req->TLVs[0].value.direct[0],(void*)&cc[CC_id].RAR_pdu.payload[0],TX_req->TLVs[0].length); - return TBS; //Return TBS in bytes } @@ -461,250 +453,242 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr } +void configure_fapi_dl_Tx(module_id_t Mod_idP, + frame_t frameP, + sub_frame_t slotP, + nfapi_nr_dl_tti_request_body_t *dl_req, + nfapi_nr_pdu_t *tx_req, + int tbs_bytes, + int16_t pdu_index){ + + int CC_id = 0; + + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs+1]; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; + gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP]; + + LOG_D(MAC, "DLSCH PDU: start PRB %d n_PRB %d start symbol %d nb_symbols %d nb_layers %d nb_codewords %d mcs %d TBS (bytes): %d\n", + pdsch_pdu_rel15->rbStart, + pdsch_pdu_rel15->rbSize, + pdsch_pdu_rel15->StartSymbolIndex, + pdsch_pdu_rel15->NrOfSymbols, + pdsch_pdu_rel15->nrOfLayers, + pdsch_pdu_rel15->NrOfCodewords, + pdsch_pdu_rel15->mcsIndex[0], + tbs_bytes); + + dl_req->nPDUs+=2; + + tx_req->PDU_length = pdsch_pdu_rel15->TBSize[0]; + tx_req->PDU_index = nr_mac->pdu_index[0]++; + tx_req->num_TLV = 1; + tx_req->TLVs[0].length = tbs_bytes +2; + + memcpy((void*)&tx_req->TLVs[0].value.direct[0], (void*)&nr_mac->UE_list.DLSCH_pdu[0][0].payload[0], tbs_bytes);; + + nr_mac->TX_req[CC_id].Number_of_PDUs++; + nr_mac->TX_req[CC_id].SFN = frameP; + nr_mac->TX_req[CC_id].Slot = slotP; +} void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, NR_sched_pucch *pucch_sched, - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *dlsch_config) -{ + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *dlsch_config){ + LOG_D(MAC, "In nr_schedule_uss_dlsch_phytest \n"); - gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; + int post_padding = 0, ta_len = 0, header_length_total = 0, sdu_length_total = 0, num_sdus = 0; + int lcid, offset, i, header_length_last, TBS_bytes; + int UE_id = 0, CCEIndex = -1, CC_id = 0; + + gNB_MAC_INST *gNB_mac = RC.nrmac[module_idP]; //NR_COMMON_channels_t *cc = nr_mac->common_channels; //NR_ServingCellConfigCommon_t *scc=cc->ServingCellConfigCommon; - nfapi_nr_dl_tti_request_body_t *dl_req; - nfapi_nr_pdu_t *TX_req; + nfapi_nr_dl_tti_request_body_t *dl_req = &gNB_mac->DL_req[CC_id].dl_tti_request_body; + nfapi_nr_pdu_t *tx_req = &gNB_mac->TX_req[CC_id].pdu_list[gNB_mac->TX_req[CC_id].Number_of_PDUs]; - int TBS; - int TBS_bytes; - int lcid; - int ta_len = 0; - int header_length_total=0; - int header_length_last; - int sdu_length_total = 0; mac_rlc_status_resp_t rlc_status; - uint16_t sdu_lengths[NB_RB_MAX]; - int num_sdus = 0; - unsigned char dlsch_buffer[MAX_NR_DLSCH_PAYLOAD_BYTES]; - int offset; - int UE_id = 0; - unsigned char sdu_lcids[NB_RB_MAX]; - int padding = 0, post_padding = 0; - NR_UE_list_t *UE_list = &nr_mac->UE_list; - uint16_t rnti = UE_list->rnti[UE_id]; - DLSCH_PDU dlsch_pdu; - //PDSCH_PDU *pdsch_pdu = (PDSCH_PDU*) malloc(sizeof(PDSCH_PDU)); + + NR_UE_list_t *UE_list = &gNB_mac->UE_list; if (UE_list->num_UEs ==0) return; - int CCEIndex=-1; + unsigned char sdu_lcids[NB_RB_MAX] = {0}; + uint16_t sdu_lengths[NB_RB_MAX] = {0}; + uint16_t rnti = UE_list->rnti[UE_id]; + + uint8_t mac_sdus[MAX_NR_DLSCH_PAYLOAD_BYTES]; LOG_D(MAC, "Scheduling UE specific search space DCI type 1\n"); - int CC_id=0; - dl_req = &nr_mac->DL_req[CC_id].dl_tti_request_body; - TX_req = &nr_mac->TX_req[CC_id].pdu_list[nr_mac->TX_req[CC_id].Number_of_PDUs]; - + + ta_len = gNB_mac->ta_len; + + CCEIndex = allocate_nr_CCEs(gNB_mac, + 1, // bwp_id + 0, // coreset_id + 4, // aggregation, + 1, // search_space, 0 common, 1 ue-specific + UE_id, + 0); // m + + if (CCEIndex == -1) return; + + AssertFatal(CCEIndex>0,"CCEIndex is negative\n"); + int CCEIndices[2]; + CCEIndices[0] = CCEIndex; + + TBS_bytes = configure_fapi_dl_pdu(module_idP, + CCEIndices, + dl_req, + dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL, + dlsch_config!=NULL ? &dlsch_config->rbSize : NULL, + dlsch_config!=NULL ? &dlsch_config->rbStart : NULL); + //The --NOS1 use case currently schedules DLSCH transmissions only when there is IP traffic arriving //through the LTE stack if (IS_SOFTMODEM_NOS1){ - - memset(&dlsch_pdu, 0, sizeof(DLSCH_PDU)); - int ta_update = 31; - ta_len = 0; - - // Hardcode it for now - TBS = 6784/8; //TBS in bytes - //TBS = dl_tti_pdsch_pdu->pdsch_pdu.dlsch_pdu_rel15.transport_block_size; - + for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) { + // TODO: check if the lcid is active - - LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", - module_idP, frameP, lcid, TBS, - TBS - ta_len - header_length_total - sdu_length_total - 3); - - if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) { - rlc_status = mac_rlc_status_ind(module_idP, - rnti, - module_idP, - frameP, - slotP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - TBS - ta_len - header_length_total - sdu_length_total - 3 - //#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,0, 0 - //#endif - ); - - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, - "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d), TBS: %d \n \n", - module_idP, frameP, - TBS - ta_len - header_length_total - sdu_length_total - 3, - lcid, - header_length_total, - TBS); - CCEIndex = allocate_nr_CCEs(nr_mac, - 1, // bwp_id - 0, // coreset_id - 4, // aggregation, - 1, // search_space, 0 common, 1 ue-specific - UE_id, - 0); // m - if (CCEIndex == -1) return; + LOG_D(MAC, "[gNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (TBS %d bytes, len %d)\n", + module_idP, frameP, lcid, TBS_bytes, TBS_bytes - ta_len - header_length_total - sdu_length_total - 3); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, - TBS, - (char *)&dlsch_buffer[sdu_length_total] - //#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,0, 0 - //#endif - ); - - - - LOG_D(MAC, - "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", - module_idP, sdu_lengths[num_sdus], lcid); - - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128); - header_length_total += header_length_last; - - num_sdus++; - } - } else { - // no TBS left - break; + if (TBS_bytes - ta_len - header_length_total - sdu_length_total - 3 > 0) { + rlc_status = mac_rlc_status_ind(module_idP, + rnti, + module_idP, + frameP, + slotP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + TBS_bytes - ta_len - header_length_total - sdu_length_total - 3, + 0, + 0); + + if (rlc_status.bytes_in_buffer > 0) { + + LOG_D(MAC, "[gNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d), TBS_bytes: %d \n \n", + module_idP, frameP, TBS_bytes - ta_len - header_length_total - sdu_length_total - 3, + lcid, header_length_total, TBS_bytes); + + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + rnti, + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + TBS_bytes, + (char *)&mac_sdus[sdu_length_total], + 0, + 0); + + LOG_D(MAC, "[gNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid); + + sdu_lcids[num_sdus] = lcid; + sdu_length_total += sdu_lengths[num_sdus]; + header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128); + header_length_total += header_length_last; + + num_sdus++; + + //ue_sched_ctl->uplane_inactivity_timer = 0; + } + } else { // no TBS_bytes left + break; } } - - // last header does not have length field - if (header_length_total) { - header_length_total -= header_length_last; - header_length_total++; - } - - - if (ta_len + sdu_length_total + header_length_total > 0) { - - - if (TBS - header_length_total - sdu_length_total - ta_len <= 2) { - padding = TBS - header_length_total - sdu_length_total - ta_len; - post_padding = 0; - } else { - padding = 0; - post_padding = 1; - } - - offset = generate_dlsch_header((unsigned char *)nr_mac->UE_list.DLSCH_pdu[0][0].payload[0], //DLSCH_pdu.payload[0], - num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, post_padding); - - LOG_D(MAC, "Offset bits: %d \n", offset); - - // Probably there should be other actions done before that - // cycle through SDUs and place in dlsch_buffer - - //memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], dlsch_buffer, sdu_length_total); - memcpy(&nr_mac->UE_list.DLSCH_pdu[0][UE_id].payload[0][offset], dlsch_buffer, sdu_length_total); - - - // fill remainder of DLSCH with 0 - for (int j = 0; j < (TBS - sdu_length_total - offset); j++) { - //UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = 0; - nr_mac->UE_list.DLSCH_pdu[0][0].payload[0][offset + sdu_length_total + j] = 0; - } - - AssertFatal(CCEIndex>0,"CCEIndex is negative\n"); - int CCEIndices[2]; - CCEIndices[0] = CCEIndex; - - TBS_bytes = configure_fapi_dl_Tx(module_idP, - slotP, - CCEIndices, - dl_req, - TX_req, - pucch_sched, - dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL, - dlsch_config!=NULL ? &dlsch_config->rbSize : NULL, - dlsch_config!=NULL ? &dlsch_config->rbStart : NULL); -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_I(MAC, "Printing first 10 payload bytes at the gNB side, Frame: %d, slot: %d, , TBS size: %d \n \n", frameP, slotP, TBS_bytes); - for(int i = 0; i < 10; i++) { // TBS_bytes dlsch_pdu_rel15->transport_block_size/8 6784/8 - LOG_I(MAC, "%x. ", ((uint8_t *)nr_mac->UE_list.DLSCH_pdu[CC_id][0][0].payload[0])[i]); - } -#endif - - TX_req->num_TLV=1; - TX_req->TLVs[0].length = TBS_bytes +2; - memcpy((void*)&TX_req->TLVs[0].value.direct[0],(void*)&nr_mac->UE_list.DLSCH_pdu[0][0].payload[0],TBS_bytes);; - - - nr_mac->TX_req[CC_id].Number_of_PDUs++; - nr_mac->TX_req[CC_id].SFN = frameP; - nr_mac->TX_req[CC_id].Slot = slotP; - } //if (ta_len + sdu_length_total + header_length_total > 0) } //if (IS_SOFTMODEM_NOS1) - + else { + //When the --NOS1 option is not enabled, DLSCH transmissions with random data //occur every time that the current function is called (dlsch phytest mode) - else{ - CCEIndex = allocate_nr_CCEs(nr_mac, - 1, // bwp_id - 0, // coreset_id - 4, // aggregation, - 1, // search_space, 0 common, 1 ue-specific - UE_id, - 0); // m - AssertFatal(CCEIndex>=0,"CCEIndex is negative\n"); - if (CCEIndex == -1) return; + LOG_D(MAC,"Configuring DL_TX in %d.%d\n", frameP, slotP); - int CCEIndices[2]; - CCEIndices[0] = CCEIndex; - LOG_D(MAC,"Configuring DL_TX in %d.%d\n",frameP,slotP); - TBS_bytes = configure_fapi_dl_Tx(module_idP,slotP,CCEIndices,dl_req, TX_req, pucch_sched, - dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL, - dlsch_config!=NULL ? &dlsch_config->rbSize : NULL, - dlsch_config!=NULL ? &dlsch_config->rbStart : NULL); -// HOT FIX for all zero pdu problem -// ------------------------------------------------------------------------------------------------ - - LOG_D(MAC,"Filling %d bytes in DL_TX\n",TBS_bytes); - for(int i = 0; i < TBS_bytes; i++) { // - ((uint8_t *)nr_mac->UE_list.DLSCH_pdu[0][0].payload[0])[i] = (unsigned char) (lrand48()&0xff); - //LOG_I(MAC, "%x. ", ((uint8_t *)nr_mac->UE_list.DLSCH_pdu[CC_id][0][0].payload[0])[i]); + // fill dlsch_buffer with random data + for (i = 0; i < TBS_bytes; i++){ + //mac_sdus[i] = (unsigned char) rand(); + ((uint8_t *)gNB_mac->UE_list.DLSCH_pdu[0][0].payload[0])[i] = (unsigned char) (lrand48()&0xff); } -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + + //Sending SDUs with size 1 + //Initialize elements of sdu_lcids and sdu_lengths + sdu_lcids[0] = 0x05; // DRB + sdu_lengths[0] = TBS_bytes - ta_len - 3; + header_length_total += 2 + (sdu_lengths[0] >= 128); + sdu_length_total += sdu_lengths[0]; + num_sdus +=1; + + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) if (frameP%100 == 0){ LOG_I(MAC, "Printing first 10 payload bytes at the gNB side, Frame: %d, slot: %d, TBS size: %d \n", frameP, slotP, TBS_bytes); for(int i = 0; i < 10; i++) { - LOG_I(MAC, "%x. ", ((uint8_t *)nr_mac->UE_list.DLSCH_pdu[CC_id][0][0].payload[0])[i]); + LOG_I(MAC, "%x. ", ((uint8_t *)gNB_mac->UE_list.DLSCH_pdu[CC_id][0][0].payload[0])[i]); } } -#endif - - //TX_req->segments[0].segment_length = 8; - TX_req->num_TLV=1; - TX_req->TLVs[0].length = TBS_bytes +2; - memcpy((void*)&TX_req->TLVs[0].value.direct[0], - (void*)&nr_mac->UE_list.DLSCH_pdu[0][0].payload[0], - TBS_bytes); - - nr_mac->TX_req[CC_id].Number_of_PDUs++; - nr_mac->TX_req[CC_id].SFN = frameP; - nr_mac->TX_req[CC_id].Slot = slotP; - // ------------------------------------------------------------------------------------------------ + #endif + + } // else IS_SOFTMODEM_NOS1 + + // there is at least one SDU or TA command + // if (num_sdus > 0 ){ + if (ta_len + sdu_length_total + header_length_total > 0) { + + // Check if there is data from RLC or CE + if (TBS_bytes >= 2 + header_length_total + sdu_length_total + ta_len) { + // we have to consider padding + // padding param currently not in use + //padding = TBS_bytes - header_length_total - sdu_length_total - ta_len - 1; + post_padding = 1; + } else { + //padding = 0; + post_padding = 0; + } + + offset = nr_generate_dlsch_pdu(module_idP, + (unsigned char *) mac_sdus, + (unsigned char *) gNB_mac->UE_list.DLSCH_pdu[0][0].payload[0], //(unsigned char *) mac_pdu, + num_sdus, //num_sdus + sdu_lengths, + sdu_lcids, + 255, // no drx + NULL, // contention res id + post_padding); + + // Padding: fill remainder of DLSCH with 0 + if (post_padding > 0){ + for (int j = 0; j < (TBS_bytes - offset); j++) + gNB_mac->UE_list.DLSCH_pdu[0][0].payload[0][offset + j] = 0; // mac_pdu[offset + j] = 0; + } + + configure_fapi_dl_Tx(module_idP, frameP, slotP, dl_req, tx_req, TBS_bytes, gNB_mac->pdu_index[CC_id]); + + if(IS_SOFTMODEM_NOS1){ + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_I(MAC, "Printing first 10 payload bytes at the gNB side, Frame: %d, slot: %d, TBS size: %d \n \n", frameP, slotP, TBS_bytes); + for(int i = 0; i < 10; i++) { // TBS_bytes dlsch_pdu_rel15->transport_block_size/8 6784/8 + LOG_I(MAC, "%x. ", mac_payload[i]); + } + #endif + } else { + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) + if (frameP%100 == 0){ + LOG_I(MAC, "Printing first 10 payload bytes at the gNB side, Frame: %d, slot: %d, TBS size: %d \n", frameP, slotP, TBS_bytes); + for(int i = 0; i < 10; i++) { + LOG_I(MAC, "%x. ", ((uint8_t *)gNB_mac->UE_list.DLSCH_pdu[CC_id][0][0].payload[0])[i]); //LOG_I(MAC, "%x. ", mac_payload[i]); + } + } + #endif + } } + else { // There is no data from RLC or MAC header, so don't schedule + } + } @@ -712,9 +696,9 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP, frame_t frameP, sub_frame_t slotP) { - gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP]; - NR_COMMON_channels_t *cc = nr_mac->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP]; + NR_COMMON_channels_t *cc = nr_mac->common_channels; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; int bwp_id=1; @@ -777,7 +761,7 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP, pusch_pdu->data_scrambling_id = 0; //It equals the higher-layer parameter Data-scrambling-Identity if configured and the RNTI equals the C-RNTI, otherwise L2 needs to set it to physical cell id.; pusch_pdu->nrOfLayers = 1; //DMRS - pusch_pdu->ul_dmrs_symb_pos = 1; + pusch_pdu->ul_dmrs_symb_pos = 1<<2; //for now the gnb assumes dmrs in the first symbol of the scheduled pusch resource pusch_pdu->dmrs_config_type = 0; //dmrs-type 1 (the one with a single DMRS symbol in the beginning) pusch_pdu->ul_dmrs_scrambling_id = 0; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. pusch_pdu->scid = 0; //DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]. Should match what is sent in DCI 0_1, otherwise set to 0. @@ -799,13 +783,13 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP, pusch_pdu->pusch_data.rv_index = 0; pusch_pdu->pusch_data.harq_process_id = 0; pusch_pdu->pusch_data.new_data_indicator = 0; - pusch_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_pdu->mcs_index, + pusch_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_pdu->qam_mod_order, pusch_pdu->target_code_rate, pusch_pdu->rb_size, pusch_pdu->nr_of_symbols, 6, //nb_re_dmrs - not sure where this is coming from - its not in the FAPI 0, //nb_rb_oh - pusch_pdu->nrOfLayers = 1); + pusch_pdu->nrOfLayers)>>3; pusch_pdu->pusch_data.num_cb = 0; //CBG not supported //pusch_pdu->pusch_data.cb_present_and_position; //pusch_pdu->pusch_uci; @@ -853,3 +837,4 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP, fill_dci_pdu_rel15(pdcch_pdu_rel15,&dci_pdu_rel15[0],dci_formats,rnti_types); } + diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 9d0365d5ff..2cdcf34841 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -34,7 +34,7 @@ #include "LAYER2/MAC/mac.h" #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "common/utils/LOG/log.h" @@ -51,9 +51,7 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#if defined(ENABLE_ITTI) #include "intertask_interface.h" -#endif #include "T.h" #include "NR_PDCCH-ConfigCommon.h" @@ -757,34 +755,24 @@ void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); pos=fsize; *dci_pdu |= ((dci_pdu_rel15->frequency_domain_assignment&((1< %d (0x%lx)\n",dci_pdu_rel15->frequency_domain_assignment,fsize,N_RB,dci_size-pos,*dci_pdu); -#endif // Time domain assignment pos+=4; *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment&0xf) << (dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"time-domain assignment %d (3 bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment,dci_size-pos,*dci_pdu); -#endif // VRB to PRB mapping pos++; *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping&0x1)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"vrb to prb mapping %d (1 bits)=> %d (0x%lx)\n",dci_pdu_rel15->vrb_to_prb_mapping,dci_size-pos,*dci_pdu); -#endif // MCS pos+=5; *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"mcs %d (5 bits)=> %d (0x%lx)\n",dci_pdu_rel15->mcs,dci_size-pos,*dci_pdu); -#endif // TB scaling pos+=2; *dci_pdu |= ((uint64_t)dci_pdu_rel15->tb_scaling&0x3)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"tb_scaling %d (2 bits)=> %d (0x%lx)\n",dci_pdu_rel15->tb_scaling,dci_size-pos,*dci_pdu); -#endif break; case NR_RNTI_C: @@ -792,18 +780,14 @@ void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, // indicating a DL DCI format 1bit pos++; *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&1)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n",dci_pdu_rel15->format_indicator,1,N_RB,dci_size-pos,*dci_pdu); -#endif // Freq domain assignment (275rb >> fsize = 16) fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); pos+=fsize; *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment&((1< %d (0x%lx)\n",dci_pdu_rel15->frequency_domain_assignment,fsize,dci_size-pos,*dci_pdu); -#endif uint16_t is_ra = 1; for (int i=0; itime_domain_assignment&0xf) << (dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"Time domain assignment %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment,4,dci_size-pos,*dci_pdu); -#endif // VRB to PRB mapping 1bit pos++; *dci_pdu |= (dci_pdu_rel15->vrb_to_prb_mapping&1)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"VRB to PRB %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->vrb_to_prb_mapping,1,dci_size-pos,*dci_pdu); -#endif // MCS 5bit //bit over 32, so dci_pdu ++ pos+=5; *dci_pdu |= (dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"MCS %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->mcs,5,dci_size-pos,*dci_pdu); -#endif // New data indicator 1bit pos++; *dci_pdu |= (dci_pdu_rel15->ndi&1)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"NDI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->ndi,1,dci_size-pos,*dci_pdu); -#endif // Redundancy version 2bit pos+=2; *dci_pdu |= (dci_pdu_rel15->rv&0x3)<<(dci_size-pos); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"RV %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->rv,2,dci_size-pos,*dci_pdu); -#endif // HARQ process number 4bit pos+=4; *dci_pdu |= ((dci_pdu_rel15->harq_pid&0xf)<<(dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"HARQ_PID %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->harq_pid,4,dci_size-pos,*dci_pdu); -#endif // Downlink assignment index 2bit pos+=2; *dci_pdu |= ((dci_pdu_rel15->dai&3)<<(dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"DAI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->dai,2,dci_size-pos,*dci_pdu); -#endif // TPC command for scheduled PUCCH 2bit pos+=2; *dci_pdu |= ((dci_pdu_rel15->tpc&3)<<(dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"TPC %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->tpc,2,dci_size-pos,*dci_pdu); -#endif // PUCCH resource indicator 3bit pos+=3; *dci_pdu |= ((dci_pdu_rel15->pucch_resource_indicator&0x7)<<(dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"PUCCH RI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->pucch_resource_indicator,3,dci_size-pos,*dci_pdu); -#endif // PDSCH-to-HARQ_feedback timing indicator 3bit pos+=3; *dci_pdu |= ((dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator&0x7)<<(dci_size-pos)); -#ifdef DEBUG_FILL_DCI LOG_D(MAC,"PDSCH to HARQ TI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator,3,dci_size-pos,*dci_pdu); -#endif } //end else break; @@ -1141,28 +1105,6 @@ int extract_length(int startSymbolAndLength) { if (tmp > 0 && tmp < (14-tmp2)) return(tmp); else return(15-tmp2); } - -void fill_initialBWPDLtimeDomainAllocaion(nfapi_nr_config_request_t *cfg,int time_domain_assignment,int *k0,int *mappingType,int *start_symbol,int *length) { - AssertFatal(time_domain_assignment < cfg->pdsch_config.num_PDSCHTimeDomainResourceAllocations.value,"DL time_domain_assignment %d >= %d\n", - time_domain_assignment,cfg->pdsch_config.num_PDSCHTimeDomainResourceAllocations.value); - *k0 = cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_k0[time_domain_assignment].value; - *mappingType = cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_mappingType[time_domain_assignment].value; - *start_symbol = extract_startSymbol(cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_startSymbolAndLength[time_domain_assignment].value); - *length = extract_length(cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_startSymbolAndLength[time_domain_assignment].value); - -} - - - -void fill_initialBWPULtimeDomainAllocaion(nfapi_nr_config_request_t *cfg,int time_domain_assignment,int *k2, int *mappingType, int *start_symbol,int *length) { - AssertFatal(time_domain_assignment < cfg->pusch_config.num_PUSCHTimeDomainResourceAllocations.value,"UL time_domain_assignment %d >= %d\n", - time_domain_assignment,cfg->pusch_config.num_PUSCHTimeDomainResourceAllocations.value); - - *k2 = cfg->pusch_config.PUSCHTimeDomainResourceAllocation_k2[time_domain_assignment].value; - *mappingType = cfg->pusch_config.PUSCHTimeDomainResourceAllocation_mappingType[time_domain_assignment].value; - *start_symbol = extract_startSymbol(cfg->pusch_config.PUSCHTimeDomainResourceAllocation_startSymbolAndLength[time_domain_assignment].value); - *length = extract_length(cfg->pusch_config.PUSCHTimeDomainResourceAllocation_startSymbolAndLength[time_domain_assignment].value); -} /* * Dump the UL or DL UE_list into LOG_T(MAC) @@ -1189,9 +1131,7 @@ dump_nr_ue_list(NR_UE_list_t *listP, return; } -int -find_nr_UE_id(module_id_t mod_idP, - rnti_t rntiP) +int find_nr_UE_id(module_id_t mod_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { int UE_id; @@ -1207,9 +1147,8 @@ find_nr_UE_id(module_id_t mod_idP, return -1; } - -int add_new_nr_ue(module_id_t mod_idP, - rnti_t rntiP){ + +int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){ int UE_id; int i; @@ -1716,8 +1655,3 @@ void nr_update_pucch_scheduling(int Mod_idP, } } */ - - - - - diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c new file mode 100644 index 0000000000..ade5200627 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -0,0 +1,285 @@ +/* + * 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 gNB_scheduler_ulsch.c + * \brief gNB procedures for the ULSCH transport channel + * \author Navid Nikaein and Raymond Knopp, Guido Casati + * \date 2019 + * \email: guido.casati@iis.fraunhofer.de + * \version 1.0 + * @ingroup _mac + */ + +#include "LAYER2/NR_MAC_gNB/mac_proto.h" +#include "executables/softmodem-common.h" +//#define ENABLE_MAC_PAYLOAD_DEBUG 1 + +void nr_process_mac_pdu( + module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t *pduP, + uint16_t mac_pdu_len) +{ + + // This function is adapting code from the old + // parse_header(...) and ue_send_sdu(...) functions of OAI LTE + + uint8_t *pdu_ptr = pduP, rx_lcid, done = 0; + int pdu_len = mac_pdu_len; + uint16_t mac_ce_len, mac_subheader_len, mac_sdu_len; + + + // For both DL/UL-SCH + // Except: + // - UL/DL-SCH: fixed-size MAC CE(known by LCID) + // - UL/DL-SCH: padding + // - UL-SCH: MSG3 48-bits + // |0|1|2|3|4|5|6|7| bit-wise + // |R|F| LCID | + // | L | + // |0|1|2|3|4|5|6|7| bit-wise + // |R|F| LCID | + // | L | + // | L | + + // For both DL/UL-SCH + // For: + // - UL/DL-SCH: fixed-size MAC CE(known by LCID) + // - UL/DL-SCH: padding, for single/multiple 1-oct padding CE(s) + // - UL-SCH: MSG3 48-bits + // |0|1|2|3|4|5|6|7| bit-wise + // |R|R| LCID | + // LCID: The Logical Channel ID field identifies the logical channel instance of the corresponding MAC SDU or the type of the corresponding MAC CE or padding as described in Tables 6.2.1-1 and 6.2.1-2 for the DL-SCH and UL-SCH respectively. There is one LCID field per MAC subheader. The LCID field size is 6 bits; + // L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field; + // F: lenght of L is 0:8 or 1:16 bits wide + // R: Reserved bit, set to zero. + + while (!done && pdu_len > 0){ + mac_ce_len = 0; + mac_subheader_len = 1; // default to fixed-length subheader = 1-oct + mac_sdu_len = 0; + rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID; + + LOG_D(MAC, "LCID received at gNB side: %d \n", rx_lcid); + + switch(rx_lcid){ + // MAC CE + + /*#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID, pdu_len); + #endif*/ + + case UL_SCH_LCID_S_BSR: + //38.321 section 6.1.3.1 + //fixed length + mac_ce_len =1; + /* Extract short BSR value */ + break; + + case UL_SCH_LCID_S_TRUNCATED_BSR: + //38.321 section 6.1.3.1 + //fixed length + mac_ce_len =1; + /* Extract short truncated BSR value */ + break; + + case UL_SCH_LCID_L_BSR: + //38.321 section 6.1.3.1 + //variable length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + /* Extract long BSR value */ + break; + + case UL_SCH_LCID_L_TRUNCATED_BSR: + //38.321 section 6.1.3.1 + //variable length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + /* Extract long truncated BSR value */ + break; + + + case UL_SCH_LCID_C_RNTI: + //38.321 section 6.1.3.2 + //fixed length + mac_ce_len = 2; + /* Extract CRNTI value */ + break; + + case UL_SCH_LCID_SINGLE_ENTRY_PHR: + //38.321 section 6.1.3.8 + //fixed length + mac_ce_len = 2; + /* Extract SINGLE ENTRY PHR elements for PHR calculation */ + break; + + case UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT: + //38.321 section 6.1.3.9 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + /* Extract MULTI ENTRY PHR elements from single octet bitmap for PHR calculation */ + break; + + case UL_SCH_LCID_MULTI_ENTRY_PHR_4_OCT: + //38.321 section 6.1.3.9 + // varialbe length + mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + } + /* Extract MULTI ENTRY PHR elements from four octets bitmap for PHR calculation */ + break; + + case UL_SCH_LCID_PADDING: + done = 1; + // end of MAC PDU, can ignore the rest. + break; + + case UL_SCH_LCID_DTCH: + // check if LCID is valid at current time. + if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ + //mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; + mac_subheader_len = 3; + mac_sdu_len = ((uint16_t)(((NR_MAC_SUBHEADER_LONG *) pdu_ptr)->L1 & 0x7f) << 8) + | ((uint16_t)((NR_MAC_SUBHEADER_LONG *) pdu_ptr)->L2 & 0xff); + + } else { + mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; + mac_subheader_len = 2; + } + + LOG_D(MAC, "[UE %d] Frame %d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, module_idP, mac_sdu_len); + + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); + + for (i = 0; i < 32; i++) + LOG_T(MAC, "%x.", (pdu_ptr + mac_subheader_len)[i]); + + LOG_T(MAC, "\n"); + #endif + + if (IS_SOFTMODEM_NOS1){ + if (rx_lcid < NB_RB_MAX && rx_lcid >= UL_SCH_LCID_DTCH) { + + mac_rlc_data_ind(module_idP, + 0x1234, + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + rx_lcid, + (char *) (pdu_ptr + mac_subheader_len), + mac_sdu_len, + 1, + NULL); + } else { + LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (gNB %d)\n", module_idP, frameP, rx_lcid, module_idP); + } + } + + break; + + default: + return; + break; + } + pdu_ptr += ( mac_subheader_len + mac_ce_len + mac_sdu_len ); + pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len ); + + if (pdu_len < 0) { + LOG_E(MAC, "%s() residual mac pdu length < 0!\n", __func__); + return; + } + } +} + + +/* +* When data are received on PHY and transmitted to MAC +*/ +void nr_rx_sdu(const module_id_t gnb_mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP, + uint8_t *sduP, + const uint16_t sdu_lenP, + const uint16_t timing_advance, + const uint8_t ul_cqi){ + int current_rnti = 0, UE_id = -1, harq_pid = 0; + gNB_MAC_INST *gNB_mac = NULL; + NR_UE_list_t *UE_list = NULL; + UE_sched_ctrl_t *UE_scheduling_control = NULL; + + current_rnti = rntiP; + UE_id = find_nr_UE_id(gnb_mod_idP, current_rnti); + gNB_mac = RC.nrmac[gnb_mod_idP]; + UE_list = &gNB_mac->UE_list; + + if (UE_id != -1) { + UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); + + LOG_D(MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n", + gnb_mod_idP, + harq_pid, + CC_idP, + frameP, + subframeP, + UE_scheduling_control->round_UL[CC_idP][harq_pid], + current_rnti, + UE_id, + ul_cqi); + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_I(MAC, "Printing received UL MAC payload at gNB side: %d \n"); + for (int i = 0; i < sdu_lenP ; i++) { + //harq_process_ul_ue->a[i] = (unsigned char) rand(); + //printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]); + printf("%02x ",(unsigned char)sduP[i]); + } + printf("\n"); +#endif + + if (sduP != NULL){ + UE_scheduling_control->ta_update = timing_advance; + LOG_D(MAC, "Received PDU at MAC gNB \n"); + nr_process_mac_pdu(gnb_mod_idP, CC_idP, frameP, sduP, sdu_lenP); + } + } +} diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 657de416a9..e294d118d9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -33,6 +33,7 @@ #include "nr_mac_gNB.h" #include "PHY/defs_gNB.h" +#include "NR_TAG-Id.h" #define MAX_ACK_BITS 2 //only format 0 is available for now @@ -63,23 +64,42 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame_txP, sub_frame_t slot_txP, frame_t frame_rxP, sub_frame_t slot_rxP); +int nr_generate_dlsch_pdu(module_id_t Mod_idP, + unsigned char *sdus_payload, + unsigned char *mac_pdu, + unsigned char num_sdus, + unsigned short *sdu_lengths, + unsigned char *sdu_lcids, + unsigned char drx_cmd, + unsigned char *ue_cont_res_id, + unsigned short post_padding); + +void nr_schedule_ue_spec(module_id_t module_idP, frame_t frameP, sub_frame_t slotP); + void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP); void nr_schedule_css_dlsch_phytest(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP); -int configure_fapi_dl_Tx(int Mod_id, - sub_frame_t slotP, - int *CCEIndeces, - nfapi_nr_dl_tti_request_body_t *dl_req, - nfapi_nr_pdu_t *TX_req, +int configure_fapi_dl_pdu(int Mod_id, + int *CCEIndeces, + nfapi_nr_dl_tti_request_body_t *dl_req, NR_sched_pucch *pucch_sched, - uint8_t *mcsIndex, - uint16_t *rbSize, - uint16_t *rbStart); + uint8_t *mcsIndex, + uint16_t *rbSize, + uint16_t *rbStart); void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, dci_pdu_rel15_t *dci_pdu_rel15, int *dci_formats, int *rnti_types); + +void configure_fapi_dl_Tx(module_id_t Mod_idP, + frame_t frameP, + sub_frame_t slotP, + nfapi_nr_dl_tti_request_body_t *dl_req, + nfapi_nr_pdu_t *tx_req, + int tbs_bytes, + int16_t pdu_index); + void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, @@ -128,14 +148,14 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, uint16_t O_ack, uint8_t SR_flag); void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, - int ss_type, - NR_ServingCellConfigCommon_t *scc, - NR_BWP_Downlink_t *bwp); -void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, - dci_pdu_rel15_t *dci_pdu_rel15, - int *dci_formats, - int *rnti_types); + int ss_type, + NR_ServingCellConfigCommon_t *scc, + NR_BWP_Downlink_t *bwp); +void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, + dci_pdu_rel15_t *dci_pdu_rel15, + int *dci_formats, + int *rnti_types); int get_spf(nfapi_nr_config_request_scf_t *cfg); int to_absslot(nfapi_nr_config_request_scf_t *cfg,int frame,int slot); @@ -156,16 +176,11 @@ int NRRIV2BW(int locationAndBandwidth,int N_RB); int NRRIV2PRBOFFSET(int locationAndBandwidth,int N_RB); -void -dump_nr_ue_list(NR_UE_list_t *listP, - int ul_flag); +void dump_nr_ue_list(NR_UE_list_t *listP, int ul_flag); -int -find_nr_UE_id(module_id_t mod_idP, - rnti_t rntiP); +int find_nr_UE_id(module_id_t mod_idP, rnti_t rntiP); -int add_new_nr_ue(module_id_t mod_idP, - rnti_t rntiP); +int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP); int get_num_dmrs(uint16_t dmrs_mask ); @@ -174,15 +189,59 @@ uint16_t nr_dci_size(nr_dci_format_t format, uint16_t N_RB); int allocate_nr_CCEs(gNB_MAC_INST *nr_mac, - int bwp_id, - int coreset_id, - int aggregation, - int search_space, // 0 common, 1 ue-specific - int UE_id, - int m - ); + int bwp_id, + int coreset_id, + int aggregation, + int search_space, // 0 common, 1 ue-specific + int UE_id, + int m + ); int is_nr_DL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slotP); int is_nr_UL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slotP); +int get_dlscs(nfapi_nr_config_request_t *cfg); + +int get_ulscs(nfapi_nr_config_request_t *cfg); + +int get_symbolsperslot(nfapi_nr_config_request_t *cfg); + +int32_t get_nr_uldl_offset(int nr_bandP); + +void config_nr_mib(int Mod_idP, + int CC_idP, + int p_gNBP, + int subCarrierSpacingCommon, + uint32_t ssb_SubcarrierOffset, + int dmrs_TypeA_Position, + uint32_t pdcch_ConfigSIB1, + int cellBarred, + int intraFreqReselection); + + +void nr_process_mac_pdu( + module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t *pduP, + uint16_t mac_pdu_len); + +/* \brief Function to indicate a received SDU on ULSCH. +@param Mod_id Instance ID of gNB +@param CC_id Component carrier index +@param rnti RNTI of UE transmitting the SDU +@param sdu Pointer to received SDU +@param sdu_len Length of SDU +@param timing_advance timing advance adjustment after this pdu +@param ul_cqi Uplink CQI estimate after this pdu (SNR quantized to 8 bits, -64 ... 63.5 dB in .5dB steps) +*/ +void nr_rx_sdu(const module_id_t gnb_mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP, + uint8_t * sduP, + const uint16_t sdu_lenP, + const uint16_t timing_advance, const uint8_t ul_cqi); + #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 8c2d66af47..9e8415776b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -31,7 +31,7 @@ */ #include "mac_proto.h" -#include "LAYER2/MAC/mac_extern.h" //temporary +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "assertions.h" #include "LAYER2/PDCP_v10.1.0/pdcp.h" @@ -40,7 +40,7 @@ //#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "common/ran_context.h" -#include "executables/nr-softmodem.h" +#include "executables/softmodem-common.h" extern RAN_CONTEXT_t RC; @@ -61,35 +61,42 @@ void mac_top_init_gNB(void) AssertFatal(RC.nrmac != NULL,"can't ALLOCATE %zu Bytes for %d gNB_MAC_INST with size %zu \n", RC.nb_nr_macrlc_inst * sizeof(gNB_MAC_INST *), RC.nb_nr_macrlc_inst, sizeof(gNB_MAC_INST)); - + for (i = 0; i < RC.nb_nr_macrlc_inst; i++) { + RC.nrmac[i] = (gNB_MAC_INST *) malloc16(sizeof(gNB_MAC_INST)); AssertFatal(RC.nrmac != NULL,"can't ALLOCATE %zu Bytes for %d gNB_MAC_INST with size %zu \n", - RC.nb_nr_macrlc_inst * sizeof(gNB_MAC_INST *), - RC.nb_nr_macrlc_inst, sizeof(gNB_MAC_INST)); + RC.nb_nr_macrlc_inst * sizeof(gNB_MAC_INST *), + RC.nb_nr_macrlc_inst, sizeof(gNB_MAC_INST)); LOG_D(MAC,"[MAIN] ALLOCATE %zu Bytes for %d gNB_MAC_INST @ %p\n",sizeof(gNB_MAC_INST), RC.nb_nr_macrlc_inst, RC.mac); bzero(RC.nrmac[i], sizeof(gNB_MAC_INST)); RC.nrmac[i]->Mod_id = i; + + RC.nrmac[i]->tag = (NR_TAG_t*)malloc(sizeof(NR_TAG_t)); + memset((void*)RC.nrmac[i]->tag,0,sizeof(NR_TAG_t)); + + RC.nrmac[i]->ul_handle = 0; + }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++) AssertFatal(rlc_module_init(1) == 0,"Could not initialize RLC layer\n"); // These should be out of here later pdcp_layer_init(); - + if(IS_SOFTMODEM_NOS1) nr_ip_over_LTE_DRB_preconfiguration(); - + rrc_init_nr_global_param(); - + }else { RC.nrmac = NULL; } - + // Initialize Linked-List for Active UEs for (i = 0; i < RC.nb_nr_macrlc_inst; i++) { @@ -101,13 +108,13 @@ void mac_top_init_gNB(void) UE_list->head = -1; UE_list->head_ul = -1; UE_list->avail = 0; - + for (list_el = 0; list_el < MAX_MOBILES_PER_GNB - 1; list_el++) { UE_list->next[list_el] = list_el + 1; UE_list->next_ul[list_el] = list_el + 1; UE_list->active[list_el] = FALSE; } - + UE_list->next[list_el] = -1; UE_list->next_ul[list_el] = -1; UE_list->active[list_el] = FALSE; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 90cd09c021..75d2385412 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -54,7 +54,7 @@ #include "common/ran_context.h" #include "LAYER2/MAC/mac.h" #include "LAYER2/MAC/mac_proto.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "PHY/defs_gNB.h" #include "PHY/TOOLS/time_meas.h" #include "targets/ARCH/COMMON/common_lib.h" @@ -65,6 +65,8 @@ #define MAX_NUM_CORESET 2 #define MAX_NUM_CCE 90 +#include "NR_TAG.h" + /*! \brief gNB common channels */ typedef struct { int physCellId; @@ -121,7 +123,7 @@ typedef struct { DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB]; /// scheduling control info - NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB]; + UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB]; int next[MAX_MOBILES_PER_GNB]; int head; int next_ul[MAX_MOBILES_PER_GNB]; @@ -144,10 +146,16 @@ typedef struct gNB_MAC_INST_s { /// frame counter frame_t frame; /// slot counter - int slot; + int slot; + /// timing advance group + NR_TAG_t *tag; /// Pointer to IF module instance for PHY NR_IF_Module_t *if_inst; - /// Common cell resources + /// TA command + int ta_command; + /// MAC CE flag indicating TA length + int ta_len; + /// Common cell resources NR_COMMON_channels_t common_channels[NFAPI_CC_MAX]; /// current PDU index (BCH,DLSCH) uint16_t pdu_index[NFAPI_CC_MAX]; @@ -155,13 +163,14 @@ typedef struct gNB_MAC_INST_s { /// NFAPI Config Request Structure nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX]; /// NFAPI DL Config Request Structure - nfapi_nr_dl_tti_request_t DL_req[NFAPI_CC_MAX]; + nfapi_nr_dl_tti_request_t DL_req[NFAPI_CC_MAX]; /// NFAPI UL TTI Request Structure (this is from the new SCF specs) nfapi_nr_ul_tti_request_t UL_tti_req[NFAPI_CC_MAX]; /// NFAPI HI/DCI0 Config Request Structure nfapi_nr_ul_dci_request_t UL_dci_req[NFAPI_CC_MAX]; /// NFAPI DL PDU structure - nfapi_nr_tx_data_request_t TX_req[NFAPI_CC_MAX]; + nfapi_nr_tx_data_request_t TX_req[NFAPI_CC_MAX]; + NR_UE_list_t UE_list; /// UL handle @@ -193,64 +202,62 @@ typedef struct gNB_MAC_INST_s { } gNB_MAC_INST; typedef struct { - - -uint8_t format_indicator; //1 bit -uint16_t frequency_domain_assignment; //up to 16 bits -uint8_t time_domain_assignment; // 4 bits -uint8_t frequency_hopping_flag; //1 bit - -uint8_t ra_preamble_index; //6 bits -uint8_t ss_pbch_index; //6 bits -uint8_t prach_mask_index; //4 bits - -uint8_t vrb_to_prb_mapping; //0 or 1 bit -uint8_t mcs; //5 bits -uint8_t ndi; //1 bit -uint8_t rv; //2 bits -uint8_t harq_pid; //4 bits -uint8_t dai; //0, 2 or 4 bits -uint8_t dai1; //1 or 2 bits -uint8_t dai2; //0 or 2 bits -uint8_t tpc; //2 bits -uint8_t pucch_resource_indicator; //3 bits -uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits - -uint8_t short_messages_indicator; //2 bits -uint8_t short_messages; //8 bits -uint8_t tb_scaling; //2 bits - -uint8_t carrier_indicator; //0 or 3 bits -uint8_t bwp_indicator; //0, 1 or 2 bits -uint8_t prb_bundling_size_indicator; //0 or 1 bits -uint8_t rate_matching_indicator; //0, 1 or 2 bits -uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits -uint8_t transmission_configuration_indication; //0 or 3 bits -uint8_t srs_request; //2 bits -uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits -uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit -uint8_t dmrs_sequence_initialization; //0 or 1 bit - -uint8_t srs_resource_indicator; -uint8_t precoding_information; -uint8_t csi_request; -uint8_t ptrs_dmrs_association; -uint8_t beta_offset_indicator; //0 or 2 bits - -uint8_t slot_format_indicator_count; -uint8_t *slot_format_indicators; - -uint8_t pre_emption_indication_count; -uint16_t *pre_emption_indications; //14 bit - -uint8_t block_number_count; -uint8_t *block_numbers; - -uint8_t ul_sul_indicator; //0 or 1 bit -uint8_t antenna_ports; - -uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits -uint16_t padding; + uint8_t format_indicator; //1 bit + uint16_t frequency_domain_assignment; //up to 16 bits + uint8_t time_domain_assignment; // 4 bits + uint8_t frequency_hopping_flag; //1 bit + + uint8_t ra_preamble_index; //6 bits + uint8_t ss_pbch_index; //6 bits + uint8_t prach_mask_index; //4 bits + + uint8_t vrb_to_prb_mapping; //0 or 1 bit + uint8_t mcs; //5 bits + uint8_t ndi; //1 bit + uint8_t rv; //2 bits + uint8_t harq_pid; //4 bits + uint8_t dai; //0, 2 or 4 bits + uint8_t dai1; //1 or 2 bits + uint8_t dai2; //0 or 2 bits + uint8_t tpc; //2 bits + uint8_t pucch_resource_indicator; //3 bits + uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits + + uint8_t short_messages_indicator; //2 bits + uint8_t short_messages; //8 bits + uint8_t tb_scaling; //2 bits + + uint8_t carrier_indicator; //0 or 3 bits + uint8_t bwp_indicator; //0, 1 or 2 bits + uint8_t prb_bundling_size_indicator; //0 or 1 bits + uint8_t rate_matching_indicator; //0, 1 or 2 bits + uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits + uint8_t transmission_configuration_indication; //0 or 3 bits + uint8_t srs_request; //2 bits + uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits + uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit + uint8_t dmrs_sequence_initialization; //0 or 1 bit + + uint8_t srs_resource_indicator; + uint8_t precoding_information; + uint8_t csi_request; + uint8_t ptrs_dmrs_association; + uint8_t beta_offset_indicator; //0 or 2 bits + + uint8_t slot_format_indicator_count; + uint8_t *slot_format_indicators; + + uint8_t pre_emption_indication_count; + uint16_t *pre_emption_indications; //14 bit + + uint8_t block_number_count; + uint8_t *block_numbers; + + uint8_t ul_sul_indicator; //0 or 1 bit + uint8_t antenna_ports; + + uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits + uint16_t padding; } dci_pdu_rel15_t; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index f234e02c04..b0e6143de1 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -959,15 +959,15 @@ pdcp_data_ind( #ifdef MBMS_MULTICAST_OUT if ((MBMS_flagP != 0) && (mbms_socket != -1)) { - struct iphdr *ip_header = (struct iphdr *)&sdu_buffer_pP->data[payload_offset]; - struct udphdr *udp_header = (struct udphdr *)&sdu_buffer_pP->data[payload_offset + sizeof(struct iphdr)]; - struct sockaddr_in dest_addr; - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = udp_header->dest; - dest_addr.sin_addr.s_addr = ip_header->daddr; + // struct iphdr *ip_header = (struct iphdr *)&sdu_buffer_pP->data[payload_offset]; + // struct udphdr *udp_header = (struct udphdr *)&sdu_buffer_pP->data[payload_offset + sizeof(struct iphdr)]; + // struct sockaddr_in dest_addr; + // dest_addr.sin_family = AF_INET; + // dest_addr.sin_port = udp_header->dest; + // dest_addr.sin_addr.s_addr = ip_header->daddr; - sendto(mbms_socket, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); - //packet_forwarded = TRUE; + // sendto(mbms_socket, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); + // //packet_forwarded = TRUE; } @@ -1251,6 +1251,132 @@ pdcp_run ( VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); } +//----------------------------------------------------------------------------- +void +pdcp_mbms_run ( + const protocol_ctxt_t *const ctxt_pP +) +//----------------------------------------------------------------------------- +{ + // if (ctxt_pP->enb_flag) { + // start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); + // } else { + // start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); + // } + + // pdcp_enb[ctxt_pP->module_id].sfn++; // range: 0 to 18,446,744,073,709,551,615 + // pdcp_enb[ctxt_pP->module_id].frame=ctxt_pP->frame; // 1023 + // pdcp_enb[ctxt_pP->module_id].subframe= ctxt_pP->subframe; + // pdcp_update_stats(ctxt_pP); + // VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); + // MessageDef *msg_p; + //int result; + //protocol_ctxt_t ctxt; + +// do { +// // Checks if a message has been sent to PDCP sub-task +// itti_poll_msg (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, &msg_p); +// +// if (msg_p != NULL) { +// switch (ITTI_MSG_ID(msg_p)) { +// case RRC_DCCH_DATA_REQ: +// PROTOCOL_CTXT_SET_BY_MODULE_ID( +// &ctxt, +// RRC_DCCH_DATA_REQ (msg_p).module_id, +// RRC_DCCH_DATA_REQ (msg_p).enb_flag, +// RRC_DCCH_DATA_REQ (msg_p).rnti, +// RRC_DCCH_DATA_REQ (msg_p).frame, +// 0, +// RRC_DCCH_DATA_REQ (msg_p).eNB_index); +// LOG_D(PDCP, PROTOCOL_CTXT_FMT"Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n", +// PROTOCOL_CTXT_ARGS(&ctxt), +// ITTI_MSG_NAME (msg_p), +// ITTI_MSG_ORIGIN_NAME(msg_p), +// ITTI_MSG_INSTANCE (msg_p), +// RRC_DCCH_DATA_REQ (msg_p).rb_id, +// RRC_DCCH_DATA_REQ (msg_p).muip, +// RRC_DCCH_DATA_REQ (msg_p).confirmp, +// RRC_DCCH_DATA_REQ (msg_p).mode); +// LOG_D(PDCP, "Before calling pdcp_data_req from pdcp_run! RRC_DCCH_DATA_REQ (msg_p).rb_id: %d \n", RRC_DCCH_DATA_REQ (msg_p).rb_id); +// result = pdcp_data_req (&ctxt, +// SRB_FLAG_YES, +// RRC_DCCH_DATA_REQ (msg_p).rb_id, +// RRC_DCCH_DATA_REQ (msg_p).muip, +// RRC_DCCH_DATA_REQ (msg_p).confirmp, +// RRC_DCCH_DATA_REQ (msg_p).sdu_size, +// RRC_DCCH_DATA_REQ (msg_p).sdu_p, +// RRC_DCCH_DATA_REQ (msg_p).mode, +// NULL, NULL +// ); +// +// if (result != TRUE) +// LOG_E(PDCP, "PDCP data request failed!\n"); +// +// // Message buffer has been processed, free it now. +// result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ (msg_p).sdu_p); +// AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +// break; +// +// case RRC_PCCH_DATA_REQ: { +// sdu_size_t sdu_buffer_sizeP; +// sdu_buffer_sizeP = RRC_PCCH_DATA_REQ(msg_p).sdu_size; +// uint8_t CC_id = RRC_PCCH_DATA_REQ(msg_p).CC_id; +// uint8_t ue_index = RRC_PCCH_DATA_REQ(msg_p).ue_index; +// RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_paging[ue_index] = sdu_buffer_sizeP; +// +// if (sdu_buffer_sizeP > 0) { +// memcpy(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].paging[ue_index], RRC_PCCH_DATA_REQ(msg_p).sdu_p, sdu_buffer_sizeP); +// } +// +// //paging pdcp log +// LOG_D(PDCP, "PDCP Received RRC_PCCH_DATA_REQ CC_id %d length %d \n", CC_id, sdu_buffer_sizeP); +// } +// break; +// +// default: +// LOG_E(PDCP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); +// break; +// } +// +// result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); +// AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +// } +// } while(msg_p != NULL); +// + // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer + // if (LINK_ENB_PDCP_TO_GTPV1U && ctxt_pP->enb_flag == ENB_FLAG_NO) { + //if (EPC_MODE_ENABLED || ctxt_pP->enb_flag == ENB_FLAG_NO ) { + + pdcp_fifo_read_input_mbms_sdus_fromtun(ctxt_pP); + //} + + // PDCP -> NAS/IP traffic: RX +// if (ctxt_pP->enb_flag) { +// start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); +// } else { +// start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); +// } +// + + //pdcp_fifo_flush_mbms_sdus(ctxt_pP); + +// if (ctxt_pP->enb_flag) { +// stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); +// } else { +// stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); +// } +// +// if (ctxt_pP->enb_flag) { +// stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); +// } else { +// stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); +// } +// +// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); +} + + + void pdcp_init_stats_UE(module_id_t mod, uint16_t uid) { Pdcp_stats_tx_window_ms[mod][uid] = 100; Pdcp_stats_rx_window_ms[mod][uid] = 100; @@ -1695,7 +1821,7 @@ rrc_pdcp_config_asn1_req ( for (j=0; jlist.count; j++) { MBMS_SessionInfo_p = mbms_SessionInfoList_r9_p->list.array[j]; - if (MBMS_SessionInfo_p->sessionId_r9) + if (0/*MBMS_SessionInfo_p->sessionId_r9*/) lc_id = MBMS_SessionInfo_p->sessionId_r9->buf[0]; else lc_id = MBMS_SessionInfo_p->logicalChannelIdentity_r9; @@ -1722,7 +1848,7 @@ rrc_pdcp_config_asn1_req ( } } - LOG_D(PDCP, "lc_id (%02ld) mch_id(%02x,%02x,%02x) drb_id(%ld) action(%d)\n", + LOG_I(PDCP, "lc_id (%02ld) mch_id(%02x,%02x,%02x) drb_id(%ld) action(%d)\n", lc_id, MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[0], MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[1], @@ -2171,19 +2297,33 @@ uint64_t pdcp_module_init( uint64_t pdcp_optmask ) { if(UE_NAS_USE_TUN) { int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 )?MAX_NUMBER_NETIF:1; netlink_init_tun("ue",num_if); - //Add --nr-ip-over-lte option check for next line if (IS_SOFTMODEM_NOS1) nas_config(1, 1, 2, "ue"); + netlink_init_mbms_tun("uem"); + nas_config_mbms(1, 2, 2, "uem"); LOG_I(PDCP, "UE pdcp will use tun interface\n"); } else if(ENB_NAS_USE_TUN) { netlink_init_tun("enb",1); nas_config(1, 1, 1, "enb"); + if(pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT){ + netlink_init_mbms_tun("enm"); + nas_config_mbms(1, 2, 1, "enm"); + LOG_I(PDCP, "ENB pdcp will use mbms tun interface\n"); + } LOG_I(PDCP, "ENB pdcp will use tun interface\n"); } else { LOG_I(PDCP, "pdcp will use kernel modules\n"); netlink_init(); } - } + }else{ + if(pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT){ + LOG_W(PDCP, "ENB pdcp will use tun interface for MBMS\n"); + netlink_init_mbms_tun("enm"); + nas_config_mbms_s1(1, 2, 1, "enm"); + }else + LOG_E(PDCP, "ENB pdcp will not use tun interface\n"); + } + return pdcp_params.optmask ; } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 1d4c612743..e9ac85866c 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -61,6 +61,7 @@ typedef boolean_t (*pdcp_data_ind_func_t)( const protocol_ctxt_t *, const srb_fl /* UEs beyond that will be multiplexed on the same tun */ #define MAX_NUMBER_NETIF 16 +#define ENB_NAS_USE_TUN_W_MBMS_BIT (1<< 10) #define PDCP_USE_NETLINK_BIT (1<< 11) #define LINK_ENB_PDCP_TO_IP_DRIVER_BIT (1<< 13) #define LINK_ENB_PDCP_TO_GTPV1U_BIT (1<< 14) @@ -388,6 +389,17 @@ boolean_t pdcp_remove_UE( */ //void rrc_pdcp_config_release ( const protocol_ctxt_t* const ctxt_pP, rb_id_t); +/*! \fn void pdcp_mbms_run(const protocol_ctxt_t* const ctxt_pP) +* \brief Runs PDCP entity to let it handle incoming/outgoing SDUs +* \param[in] ctxt_pP Running context. +* \return none +* \note None +* @ingroup _pdcp +*/ +void pdcp_mbms_run ( + const protocol_ctxt_t *const ctxt_pP); + + /*! \fn void pdcp_run(const protocol_ctxt_t* const ctxt_pP) * \brief Runs PDCP entity to let it handle incoming/outgoing SDUs * \param[in] ctxt_pP Running context. @@ -413,6 +425,9 @@ void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req); void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind); pdcp_data_ind_func_t get_pdcp_data_ind_func(void); //----------------------------------------------------------------------------- +int pdcp_fifo_flush_mbms_sdus ( const protocol_ctxt_t *const ctxt_pP); +int pdcp_fifo_read_input_mbms_sdus_fromtun ( const protocol_ctxt_t *const ctxt_pP); + /* * Following two types are utilized between NAS driver and PDCP diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 9e873379b1..d203408e55 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -77,6 +77,11 @@ extern struct iovec nas_iov_rx; extern int nas_sock_fd[MAX_MOBILES_PER_ENB]; +extern int nas_sock_mbms_fd; + +extern int mbms_rab_id; + + extern struct msghdr nas_msg_tx; extern struct msghdr nas_msg_rx; @@ -124,17 +129,42 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) { ret = sendto(pdcp_pc5_sockfd, &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]), sizeof(sidelink_pc5s_element), 0, (struct sockaddr *)&prose_pdcp_addr,sizeof(prose_pdcp_addr) ); + } else if (UE_NAS_USE_TUN) { - ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + //ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + if(rb_id == mbms_rab_id){ + ret = write(nas_sock_mbms_fd, &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + LOG_I(PDCP,"[PDCP_FIFOS] ret %d TRIED TO PUSH MBMS DATA TO rb_id %d handle %d sizeToWrite %d\n",ret,rb_id,nas_sock_fd[ctxt_pP->module_id],sizeToWrite); + } + else + { + #if defined(ENABLE_PDCP_PAYLOAD_DEBUG) + LOG_I(PHY, "PDCP output to be sent to TUN interface: \n"); + for (int i = sizeof(pdcp_data_ind_header_t); i < sizeToWrite; i++) { + printf("%02x ",(unsigned char)sdu_p->data[i]); + } + printf("\n"); + #endif + ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + //LOG_I(PDCP,"[PDCP_FIFOS] ret %d TRIED TO PUSH DATA TO rb_id %d handle %d sizeToWrite %d\n",ret,rb_id,nas_sock_fd[ctxt_pP->module_id],sizeToWrite); + } } else if (ENB_NAS_USE_TUN) { - ret = write(nas_sock_fd[0], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + #if defined(ENABLE_PDCP_PAYLOAD_DEBUG) + LOG_I(PHY, "PDCP output to be sent to TUN interface: \n"); + for (int i = sizeof(pdcp_data_ind_header_t); i < sizeToWrite; i++) { + printf("%02x ",(unsigned char)sdu_p->data[i]); + } + printf("\n"); + #endif + ret = write(nas_sock_fd[0], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]), sizeToWrite); + } else if (PDCP_USE_NETLINK) { memcpy(NLMSG_DATA(nas_nlh_tx), (uint8_t *) sdu_p->data, sizeToWrite); nas_nlh_tx->nlmsg_len = sizeToWrite; ret = sendmsg(nas_sock_fd[0],&nas_msg_tx,0); } // PDCP_USE_NETLINK - AssertFatal(ret >= 0,"[PDCP_FIFOS] pdcp_fifo_flush_sdus (errno: %d %s)\n", errno, strerror(errno)); + AssertFatal(ret >= 0,"[PDCP_FIFOS] pdcp_fifo_flush_sdus (errno: %d %s), nas_sock_fd[0]: %d\n", errno, strerror(errno), nas_sock_fd[0]); #if defined(ENABLE_PDCP_PAYLOAD_DEBUG) LOG_I(PDCP, "Printing first bytes of PDCP SDU before removing it from the list: \n"); @@ -150,6 +180,47 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) { return pdcp_nb_sdu_sent; } +int pdcp_fifo_flush_mbms_sdus(const protocol_ctxt_t *const ctxt_pP) { + mem_block_t *sdu_p; + int pdcp_nb_sdu_sent = 0; + //int ret=0; + + while ((sdu_p = list_get_head (&pdcp_sdu_list)) != NULL && ((pdcp_data_ind_header_t *)(sdu_p->data))->inst == ctxt_pP->module_id) { + ((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0; + //int rb_id = ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id; + //int sizeToWrite= sizeof (pdcp_data_ind_header_t) + + //((pdcp_data_ind_header_t *) sdu_p->data)->data_size; + + //if (rb_id == 10) { //hardcoded for PC5-Signaling + // if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { + // debug_pdcp_pc5s_sdu((sidelink_pc5s_element *)&(sdu_p->data[sizeof(pdcp_data_ind_header_t)]), + // "pdcp_fifo_flush_sdus sends a aPC5S message"); + // } + + // ret = sendto(pdcp_pc5_sockfd, &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]), + // sizeof(sidelink_pc5s_element), 0, (struct sockaddr *)&prose_pdcp_addr,sizeof(prose_pdcp_addr) ); + //} else if (UE_NAS_USE_TUN) { + // ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + // LOG_I(PDCP,"[PDCP_FIFOS] ret %d TRIED TO PUSH DATA TO rb_id %d handle %d sizeToWrite %d\n",ret,rb_id,nas_sock_fd[ctxt_pP->module_id],sizeToWrite); + + //} else if (ENB_NAS_USE_TUN) { + // ret = write(nas_sock_fd[0], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + //} else if (PDCP_USE_NETLINK) { + // memcpy(NLMSG_DATA(nas_nlh_tx), (uint8_t *) sdu_p->data, sizeToWrite); + // nas_nlh_tx->nlmsg_len = sizeToWrite; + // ret = sendmsg(nas_sock_fd[0],&nas_msg_tx,0); + //} // PDCP_USE_NETLINK + + //AssertFatal(ret >= 0,"[PDCP_FIFOS] pdcp_fifo_flush_sdus (errno: %d %s)\n", errno, strerror(errno)); + list_remove_head (&pdcp_sdu_list); + free_mem_block (sdu_p, __func__); + pdcp_nb_sdu_sent ++; + } + + return pdcp_nb_sdu_sent; +} + + int pdcp_fifo_read_input_sdus_fromtun (const protocol_ctxt_t *const ctxt_pP) { protocol_ctxt_t ctxt = *ctxt_pP; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; @@ -186,6 +257,15 @@ int pdcp_fifo_read_input_sdus_fromtun (const protocol_ctxt_t *const ctxt_pP) { LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %ld][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %04x][RB %ld]\n", ctxt.frame, ctxt.instance, rab_id, len, ctxt.module_id, ctxt.rnti, rab_id); + +#if defined ENABLE_PDCP_PAYLOAD_DEBUG + LOG_I(PHY, "TUN interface output received from PDCP: \n"); + for (int i = 0; i < 128; i++) { + printf("%02x ",(unsigned char)nl_rx_buf[i]); + } + printf("\n"); +#endif + pdcp_data_req(&ctxt, SRB_FLAG_NO, rab_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, len, (unsigned char *)nl_rx_buf, PDCP_TRANSMISSION_MODE_DATA @@ -203,6 +283,105 @@ int pdcp_fifo_read_input_sdus_fromtun (const protocol_ctxt_t *const ctxt_pP) { return len; } +int pdcp_fifo_read_input_mbms_sdus_fromtun (const protocol_ctxt_t *const ctxt_pP) { + protocol_ctxt_t ctxt = *ctxt_pP; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc = HASH_TABLE_OK; + //pdcp_t *pdcp_p = NULL; + int len; + rb_id_t rab_id = mbms_rab_id;//DEFAULT_RAB_ID; + if(mbms_rab_id > 9 || mbms_rab_id < 4) + h_rc = 2; + + if(UE_NAS_USE_TUN) + return 0; + + do { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_MBMS_FIFO_READ, 1 ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_MBMS_FIFO_READ_BUFFER, 1 ); + len = read(nas_sock_mbms_fd, &nl_rx_buf, NL_MAX_PAYLOAD); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_MBMS_FIFO_READ_BUFFER, 0 ); + + if (len<=0) continue; + + if (UE_NAS_USE_TUN) { + //key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag); + //h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + } else { // => ENB_NAS_USE_TUN + //ctxt.rnti=pdcp_eNB_UE_instance_to_rnti[0]; + // ctxt.enb_flag=ENB_FLAG_YES; + // ctxt.module_id=0; + // key = PDCP_COLL_KEY_VALUE(ctxt.module_id, /*ctxt.rnti*/0, ctxt.enb_flag, /*mbms_rab_id*/8, SRB_FLAG_YES); + // h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + // LOG_W(PDCP,"h_rc %d %d\n",h_rc,rab_id); + } + + LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%x, enb_flag=%d)\n", + ctxt.module_id, ctxt.rnti, ctxt.enb_flag); + + if (h_rc == HASH_TABLE_OK) { + LOG_I(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d on Rab %ld \n", + ctxt.frame, ctxt.instance, len, rab_id); + LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %ld][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %04x][RB %ld]\n", + ctxt.frame, ctxt.instance, rab_id, len, ctxt.module_id, + ctxt.rnti, rab_id); + MSC_LOG_RX_MESSAGE((ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, + (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, + NULL, 0, + MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ctxt.instance, rab_id, rab_id, len); + pdcp_data_req( + &ctxt, + SRB_FLAG_NO, + //DEFAULT_RAB_ID, + rab_id, + RLC_MUI_UNDEFINED, + RLC_SDU_CONFIRM_NO, + len, + (unsigned char *)nl_rx_buf, + PDCP_TRANSMISSION_MODE_TRANSPARENT + , NULL, NULL + ); + + //pdcp_data_req(&ctxt, SRB_FLAG_NO, rab_id, RLC_MUI_UNDEFINED, + // RLC_SDU_CONFIRM_NO, len, (unsigned char *)nl_rx_buf, + // PDCP_TRANSMISSION_MODE_DATA + // , NULL, NULL + // ); + } else { + MSC_LOG_RX_DISCARDED_MESSAGE( + (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, + (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, + NULL, + 0, + MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ctxt.instance, rab_id, rab_id, len); + LOG_D(PDCP, + "[FRAME %5u][UE][IP][INSTANCE %u][RB %ld][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %04x][RB %ld] NON INSTANCIATED INSTANCE key 0x%"PRIx64", DROPPED\n", + ctxt.frame, ctxt.instance, rab_id, len, ctxt.module_id, + ctxt.rnti, rab_id, key); + //if (!UE_NAS_USE_TUN) { + // pdcp_data_req( + // &ctxt, + // SRB_FLAG_NO, + // DEFAULT_RAB_ID, + // RLC_MUI_UNDEFINED, + // RLC_SDU_CONFIRM_NO, + // len, + // (unsigned char *)nl_rx_buf, + // PDCP_TRANSMISSION_MODE_TRANSPARENT + // , NULL, NULL + // ); + //} + } + } while (len > 0); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_MBMS_FIFO_READ, 0 ); + return len; +} + int pdcp_fifo_read_input_sdus_fromnetlinksock (const protocol_ctxt_t *const ctxt_pP) { int len = 1; int rlc_data_req_flag = 3; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c index 8f9ee0af18..cb108f5d26 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c @@ -33,7 +33,7 @@ #include "UTIL/OSA/osa_defs.h" #include "common/utils/LOG/vcd_signal_dumper.h" - +#include "executables/softmodem-common.h" #include "LAYER2/MAC/mac_extern.h" #include "pdcp.h" @@ -213,28 +213,28 @@ pdcp_validate_security( stream_decrypt(pdcp_pP->cipheringAlgorithm, &decrypt_params, &buffer_decrypted); -#if !defined(USRP_REC_PLAY) - if (srb_flagP) { + if (!IS_SOFTMODEM_IQPLAYER) { + if (srb_flagP) { /* Now check the integrity of the complete PDU */ - decrypt_params.message = pdcp_pdu_buffer; - decrypt_params.blength = sdu_buffer_size << 3; - decrypt_params.key = pdcp_pP->kRRCint + 16;// 128; + decrypt_params.message = pdcp_pdu_buffer; + decrypt_params.blength = sdu_buffer_size << 3; + decrypt_params.key = pdcp_pP->kRRCint + 16;// 128; - if (stream_check_integrity(pdcp_pP->integrityProtAlgorithm, - &decrypt_params, - &pdcp_pdu_buffer[sdu_buffer_size]) != 0) { - MSC_LOG_EVENT( - (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, - " Security: failed MAC-I Algo %X UE %"PRIx16" ", - pdcp_pP->integrityProtAlgorithm, - ctxt_pP->rnti); - LOG_E(PDCP, "[OSA][RB %ld] %s failed to validate MAC-I (key %llx) of incoming PDU\n", - rb_id, (pdcp_pP->is_ue != 0) ? "UE" : "eNB",((long long unsigned int*)decrypt_params.key)[0]); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT); - return -1; + if (stream_check_integrity(pdcp_pP->integrityProtAlgorithm, + &decrypt_params, + &pdcp_pdu_buffer[sdu_buffer_size]) != 0) { + MSC_LOG_EVENT( + (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, + " Security: failed MAC-I Algo %X UE %"PRIx16" ", + pdcp_pP->integrityProtAlgorithm, + ctxt_pP->rnti); + LOG_E(PDCP, "[OSA][RB %ld] %s failed to validate MAC-I (key %llx) of incoming PDU\n", + rb_id, (pdcp_pP->is_ue != 0) ? "UE" : "eNB",((long long unsigned int*)decrypt_params.key)[0]); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT); + return -1; + } } - } -#endif + } /* !IQPLAYER */ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT); return 0; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index ddff2cc3d1..02a0247a03 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -26,9 +26,7 @@ //----------------------------------------------------------------------------- #include "platform_types.h" //----------------------------------------------------------------------------- -#if ENABLE_ITTI - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "assertions.h" #include "list.h" #include "rlc_am.h" diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index 49f7420216..85ee4e0571 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -339,7 +339,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t *const ctxt_pP for (j=0; jlist.count; j++) { MBMS_SessionInfo_p = mbms_SessionInfoList_r9_p->list.array[j]; - if (MBMS_SessionInfo_p->sessionId_r9) + if (0/*MBMS_SessionInfo_p->sessionId_r9*/) mbms_session_id = MBMS_SessionInfo_p->sessionId_r9->buf[0]; else mbms_session_id = MBMS_SessionInfo_p->logicalChannelIdentity_r9; @@ -379,7 +379,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t *const ctxt_pP } } - LOG_D(RLC, PROTOCOL_CTXT_FMT" CONFIG REQ MBMS ASN1 LC ID %u RB ID %ld SESSION ID %u SERVICE ID %u\n", + LOG_I(RLC, PROTOCOL_CTXT_FMT" CONFIG REQ MBMS ASN1 LC ID %u RB ID %ld SESSION ID %u SERVICE ID %u\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id, rb_id, @@ -611,14 +611,14 @@ rlc_union_t *rrc_rlc_add_rlc ( } key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_id_p->service_id, mbms_id_p->session_id); - } - - if ((sourceL2Id > 0) && (destinationL2Id > 0) ) { - key = RLC_COLL_KEY_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, sourceL2Id, destinationL2Id, srb_flagP); - key_lcid = RLC_COLL_KEY_LCID_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, sourceL2Id, destinationL2Id, srb_flagP); } else { - key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); - key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, srb_flagP); + if ((sourceL2Id > 0) && (destinationL2Id > 0) ) { + key = RLC_COLL_KEY_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, sourceL2Id, destinationL2Id, srb_flagP); + key_lcid = RLC_COLL_KEY_LCID_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, sourceL2Id, destinationL2Id, srb_flagP); + } else { + key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); + key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, srb_flagP); + } } h_rc = hashtable_get(rlc_coll_p, key, (void **)&rlc_union_p); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 8ee8cdc1c0..88bde65107 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -33,10 +33,13 @@ static nr_rlc_ue_manager_t *nr_rlc_ue_manager; /* TODO: handle time a bit more properly */ +//#if 0 static uint64_t nr_rlc_current_time; static int nr_rlc_current_time_last_frame; static int nr_rlc_current_time_last_subframe; +//#endif +//#if 0 void mac_rlc_data_ind ( const module_id_t module_idP, const rnti_t rntiP, @@ -65,6 +68,9 @@ void mac_rlc_data_ind ( nr_rlc_manager_lock(nr_rlc_ue_manager); ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rntiP); + if(ue == NULL) + LOG_I(RLC, "RLC instance for the given UE was not found \n"); + switch (channel_idP) { case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; @@ -72,6 +78,7 @@ void mac_rlc_data_ind ( } if (rb != NULL) { + LOG_D(RLC, "RB found! (channel ID %d) \n", channel_idP); rb->set_time(rb, nr_rlc_current_time); rb->recv_pdu(rb, buffer_pP, tb_sizeP); } else { @@ -92,11 +99,9 @@ tbs_size_t mac_rlc_data_req( const MBMS_flag_t MBMS_flagP, const logical_chan_id_t channel_idP, const tb_size_t tb_sizeP, - char *buffer_pP -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,const uint32_t sourceL2Id - ,const uint32_t destinationL2Id -#endif + char *buffer_pP, + const uint32_t sourceL2Id, + const uint32_t destinationL2Id ) { int ret; @@ -147,11 +152,9 @@ mac_rlc_status_resp_t mac_rlc_status_ind( const eNB_flag_t enb_flagP, const MBMS_flag_t MBMS_flagP, const logical_chan_id_t channel_idP, - const tb_size_t tb_sizeP -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,const uint32_t sourceL2Id - ,const uint32_t destinationL2Id -#endif + const tb_size_t tb_sizeP, + const uint32_t sourceL2Id, + const uint32_t destinationL2Id ) { nr_rlc_ue_t *ue; @@ -178,11 +181,11 @@ mac_rlc_status_resp_t mac_rlc_status_ind( if (rb != NULL) { nr_rlc_entity_buffer_status_t buf_stat; rb->set_time(rb, nr_rlc_current_time); - /* 36.321 deals with BSR values up to 3000000 bytes, after what it - * reports '> 3000000' (table 6.1.3.1-2). Passing 4000000 is thus + /* 38.321 deals with BSR values up to 81338368 bytes, after what it + * reports '> 81338368' (table 6.1.3.1-2). Passing 100000000 is thus * more than enough. */ - buf_stat = rb->buffer_status(rb, 4000000); + buf_stat = rb->buffer_status(rb, 100000000); ret.bytes_in_buffer = buf_stat.status_size + buf_stat.retx_size + buf_stat.tx_size; @@ -200,9 +203,66 @@ mac_rlc_status_resp_t mac_rlc_status_ind( ret.head_sdu_is_segmented = 0; return ret; } +//#endif + +rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const sub_frame_t subframeP, + const eNB_flag_t enb_flagP, + const logical_chan_id_t channel_idP) +{ + nr_rlc_ue_t *ue; + rlc_buffer_occupancy_t ret; + nr_rlc_entity_t *rb; + + if (enb_flagP) { + LOG_E(RLC, "Tx mac_rlc_get_buffer_occupancy_ind function is not implemented for eNB LcId=%u\n", channel_idP); + exit(1); + } + + /* TODO: handle time a bit more properly */ + if (nr_rlc_current_time_last_frame != frameP || + nr_rlc_current_time_last_subframe != subframeP) { + nr_rlc_current_time++; + nr_rlc_current_time_last_frame = frameP; + nr_rlc_current_time_last_subframe = subframeP; + } + + nr_rlc_manager_lock(nr_rlc_ue_manager); + ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + nr_rlc_entity_buffer_status_t buf_stat; + rb->set_time(rb, nr_rlc_current_time); + /* 38.321 deals with BSR values up to 81338368 bytes, after what it + * reports '> 81338368' (table 6.1.3.1-2). Passing 100000000 is thus + * more than enough. + */ + buf_stat = rb->buffer_status(rb, 100000000); + ret = buf_stat.status_size + + buf_stat.retx_size + + buf_stat.tx_size; + } else { + ret = 0; + } + + nr_rlc_manager_unlock(nr_rlc_ue_manager); + + return ret; +} int oai_emulation; +//#if 0 rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, const MBMS_flag_t MBMS_flagP, @@ -210,11 +270,9 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, const mui_t muiP, confirm_t confirmP, sdu_size_t sdu_sizeP, - mem_block_t *sdu_pP -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,const uint32_t *const sourceL2Id - ,const uint32_t *const destinationL2Id -#endif + mem_block_t *sdu_pP, + const uint32_t *const sourceL2Id, + const uint32_t *const destinationL2Id ) { int rnti = ctxt_pP->rnti; @@ -256,7 +314,9 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, return RLC_OP_STATUS_OK; } +//#endif +//#if 0 int rlc_module_init(int enb_flag) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; @@ -277,10 +337,13 @@ int rlc_module_init(int enb_flag) return 0; } +//#endif +//#if 0 void rlc_util_print_hex_octets(comp_name_t componentP, unsigned char *dataP, const signed long sizeP) { } +//#endif static void deliver_sdu(void *_ue, nr_rlc_entity_t *entity, char *buf, int size) { @@ -467,7 +530,7 @@ rb_found: #endif } -static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s) +__attribute__ ((unused)) static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s) { nr_rlc_entity_t *nr_rlc_am; nr_rlc_ue_t *ue; @@ -735,7 +798,7 @@ static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s) nr_rlc_manager_unlock(nr_rlc_ue_manager); } -static void add_drb(int rnti, struct LTE_DRB_ToAddMod *s) +__attribute__ ((unused)) static void add_drb(int rnti, struct LTE_DRB_ToAddMod *s) { switch (s->rlc_Config->present) { case LTE_RLC_Config_PR_am: @@ -751,16 +814,14 @@ static void add_drb(int rnti, struct LTE_DRB_ToAddMod *s) } } +//#if 0 rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP, const LTE_SRB_ToAddModList_t * const srb2add_listP, const LTE_DRB_ToAddModList_t * const drb2add_listP, - const LTE_DRB_ToReleaseList_t * const drb2release_listP -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) - ,const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP - ,const uint32_t sourceL2Id - ,const uint32_t destinationL2Id -#endif - ) + const LTE_DRB_ToReleaseList_t * const drb2release_listP, + const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP, + const uint32_t sourceL2Id, + const uint32_t destinationL2Id) { int rnti = ctxt_pP->rnti; int i; @@ -798,7 +859,9 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP return RLC_OP_STATUS_OK; } +//#endif +//#if 0 rlc_op_status_t rrc_rlc_config_req ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, @@ -857,12 +920,16 @@ rlc_op_status_t rrc_rlc_config_req ( nr_rlc_manager_unlock(nr_rlc_ue_manager); return RLC_OP_STATUS_OK; } +//#endif +//#if 0 void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_data_conf_cb_t rrc_data_confP) { /* nothing to do */ } +//#endif +//#if 0 rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x) { LOG_D(RLC, "%s:%d:%s: remove UE %d\n", __FILE__, __LINE__, __FUNCTION__, x->rnti); @@ -872,3 +939,4 @@ rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x) return RLC_OP_STATUS_OK; } +//#endif diff --git a/openair2/M2AP/MESSAGES/ASN1/R14/m2ap-14.0.0.asn1 b/openair2/M2AP/MESSAGES/ASN1/R14/m2ap-14.0.0.asn1 new file mode 100644 index 0000000000..997501f1a6 --- /dev/null +++ b/openair2/M2AP/MESSAGES/ASN1/R14/m2ap-14.0.0.asn1 @@ -0,0 +1,1897 @@ +-- 3GPP TS 36.443 V15.0.0 (2018-09) +-- ************************************************************** +-- +-- Elementary Procedure definitions +-- +-- ************************************************************** + +M2AP-PDU-Descriptions { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m2ap (4) version1 (1) m2ap-PDU-Descriptions (0) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + Criticality, + ProcedureCode +FROM M2AP-CommonDataTypes + + + SessionStartRequest, + SessionStartResponse, + SessionStartFailure, + SessionStopRequest, + SessionStopResponse, + SessionUpdateRequest, + SessionUpdateResponse, + SessionUpdateFailure, + MbmsSchedulingInformation, + MbmsSchedulingInformationResponse, + ErrorIndication, + Reset, + ResetAcknowledge, + M2SetupRequest, + M2SetupResponse, + M2SetupFailure, + ENBConfigurationUpdate, + ENBConfigurationUpdateAcknowledge, + ENBConfigurationUpdateFailure, + MCEConfigurationUpdate, + MCEConfigurationUpdateAcknowledge, + MCEConfigurationUpdateFailure, + MbmsServiceCountingRequest, + MbmsServiceCountingResponse, + MbmsServiceCountingFailure, + MbmsServiceCountingResultsReport, + PrivateMessage, + MbmsOverloadNotification +FROM M2AP-PDU-Contents + + id-sessionStart, + id-sessionStop, + id-sessionUpdate, + id-mbmsServiceCounting, + id-mbmsServiceCountingResultsReport, + id-mbmsSchedulingInformation, + id-errorIndication, + id-reset, + id-m2Setup, + id-eNBConfigurationUpdate, + id-mCEConfigurationUpdate, + id-privateMessage, + id-mbmsOverloadNotification +FROM M2AP-Constants; + + +-- ************************************************************** +-- +-- Interface Elementary Procedure Class +-- +-- ************************************************************** + +M2AP-ELEMENTARY-PROCEDURE ::= CLASS { + &InitiatingMessage , + &SuccessfulOutcome OPTIONAL, + &UnsuccessfulOutcome OPTIONAL, + &procedureCode ProcedureCode UNIQUE, + &criticality Criticality DEFAULT ignore +} +WITH SYNTAX { + INITIATING MESSAGE &InitiatingMessage + [SUCCESSFUL OUTCOME &SuccessfulOutcome] + [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome] + PROCEDURE CODE &procedureCode + [CRITICALITY &criticality] +} + +-- ************************************************************** +-- +-- Interface PDU Definition +-- +-- ************************************************************** + +M2AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode M2AP-ELEMENTARY-PROCEDURE.&procedureCode ({M2AP-ELEMENTARY-PROCEDURES}), + criticality M2AP-ELEMENTARY-PROCEDURE.&criticality ({M2AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M2AP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({M2AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode M2AP-ELEMENTARY-PROCEDURE.&procedureCode ({M2AP-ELEMENTARY-PROCEDURES}), + criticality M2AP-ELEMENTARY-PROCEDURE.&criticality ({M2AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M2AP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome ({M2AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode M2AP-ELEMENTARY-PROCEDURE.&procedureCode ({M2AP-ELEMENTARY-PROCEDURES}), + criticality M2AP-ELEMENTARY-PROCEDURE.&criticality ({M2AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M2AP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome ({M2AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + + +-- ************************************************************** +-- +-- Interface Elementary Procedure List +-- +-- ************************************************************** + +M2AP-ELEMENTARY-PROCEDURES M2AP-ELEMENTARY-PROCEDURE ::= { + M2AP-ELEMENTARY-PROCEDURES-CLASS-1 | + M2AP-ELEMENTARY-PROCEDURES-CLASS-2 , + ... +} + +M2AP-ELEMENTARY-PROCEDURES-CLASS-1 M2AP-ELEMENTARY-PROCEDURE ::= { + sessionStart | + sessionStop | + sessionUpdate | + mbmsSchedulingInformation | + reset | + m2Setup | + eNBConfigurationUpdate | + mCEConfigurationUpdate | + mbmsServiceCounting , + ... +} + +M2AP-ELEMENTARY-PROCEDURES-CLASS-2 M2AP-ELEMENTARY-PROCEDURE ::= { + errorIndication | + privateMessage | + mbmsServiceCountingResultsReport | + mbmsOverloadNotification , + ... + +} + + +-- ************************************************************** +-- +-- Interface Elementary Procedures +-- +-- ************************************************************** + +sessionStart M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE SessionStartRequest + SUCCESSFUL OUTCOME SessionStartResponse + UNSUCCESSFUL OUTCOME SessionStartFailure + PROCEDURE CODE id-sessionStart + CRITICALITY reject +} + +sessionStop M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE SessionStopRequest + SUCCESSFUL OUTCOME SessionStopResponse + PROCEDURE CODE id-sessionStop + CRITICALITY reject +} + +sessionUpdate M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE SessionUpdateRequest + SUCCESSFUL OUTCOME SessionUpdateResponse + UNSUCCESSFUL OUTCOME SessionUpdateFailure + PROCEDURE CODE id-sessionUpdate + CRITICALITY reject +} + +mbmsSchedulingInformation M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MbmsSchedulingInformation + SUCCESSFUL OUTCOME MbmsSchedulingInformationResponse + PROCEDURE CODE id-mbmsSchedulingInformation + CRITICALITY reject +} + +errorIndication M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ErrorIndication + PROCEDURE CODE id-errorIndication + CRITICALITY ignore +} + +reset M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Reset + SUCCESSFUL OUTCOME ResetAcknowledge + PROCEDURE CODE id-reset + CRITICALITY reject +} + +m2Setup M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE M2SetupRequest + SUCCESSFUL OUTCOME M2SetupResponse + UNSUCCESSFUL OUTCOME M2SetupFailure + PROCEDURE CODE id-m2Setup + CRITICALITY reject +} + +eNBConfigurationUpdate M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBConfigurationUpdate + SUCCESSFUL OUTCOME ENBConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME ENBConfigurationUpdateFailure + PROCEDURE CODE id-eNBConfigurationUpdate + CRITICALITY reject +} + +mCEConfigurationUpdate M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MCEConfigurationUpdate + SUCCESSFUL OUTCOME MCEConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME MCEConfigurationUpdateFailure + PROCEDURE CODE id-mCEConfigurationUpdate + CRITICALITY reject +} + +mbmsServiceCounting M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MbmsServiceCountingRequest + SUCCESSFUL OUTCOME MbmsServiceCountingResponse + UNSUCCESSFUL OUTCOME MbmsServiceCountingFailure + PROCEDURE CODE id-mbmsServiceCounting + CRITICALITY reject +} + +mbmsServiceCountingResultsReport M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MbmsServiceCountingResultsReport + PROCEDURE CODE id-mbmsServiceCountingResultsReport + CRITICALITY reject +} + +privateMessage M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PrivateMessage + PROCEDURE CODE id-privateMessage + CRITICALITY ignore +} + +mbmsOverloadNotification M2AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MbmsOverloadNotification + PROCEDURE CODE id-mbmsOverloadNotification + CRITICALITY reject +} + +END + +-- ************************************************************** +-- +-- PDU definitions for M2AP. +-- +-- ************************************************************** + +M2AP-PDU-Contents { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m2ap (4) version1 (1) m2ap-PDU-Contents (1) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + + Cause, + CriticalityDiagnostics, + ENB-MBMS-Configuration-data-Item, + ENB-MBMS-Configuration-data-ConfigUpdate-Item, + ENB-MBMS-M2AP-ID, + ENBname, + GlobalENB-ID, + GlobalMCE-ID, + MBSFN-Area-ID, + MBMS-Service-Area, + MBMS-Session-ID, + MBMSsessionListPerPMCH-Item, + MBMS-Service-associatedLogicalM2-ConnectionItem, + MBSFN-Subframe-Configuration, + MCCH-Update-Time, + MCCHrelatedBCCH-ConfigPerMBSFNArea-Item, + MCE-MBMS-M2AP-ID, + MCEname, + PMCH-Configuration, + Common-Subframe-Allocation-Period, + TimeToWait, + TMGI, + TNL-Information, + SFN, + MBMSsessionsToBeSuspendedListPerPMCH-Item, + SC-PTM-Information + +FROM M2AP-Ies + + PrivateIE-Container{}, + ProtocolExtensionContainer{}, + ProtocolIE-Container{}, + ProtocolIE-ContainerList{}, + ProtocolIE-ContainerPair{}, + ProtocolIE-ContainerPairList{}, + ProtocolIE-Single-Container{}, + M2AP-PRIVATE-IES, + M2AP-PROTOCOL-EXTENSION, + M2AP-PROTOCOL-IES, + M2AP-PROTOCOL-IES-PAIR +FROM M2AP-Containers + + id-MCE-MBMS-M2AP-ID, + id-ENB-MBMS-M2AP-ID, + id-TMGI, + id-MBMS-Session-ID, + id-MBMS-Service-Area, + id-TNL-Information, + id-Alternative-TNL-Information, + id-CriticalityDiagnostics, + id-Cause, + id-MBSFN-Area-Configuration-List, + id-MBSFN-Subframe-Configuration-Item, + id-MBSFN-Subframe-Configuration-List, + id-MCCH-Update-Time, + id-PMCH-Configuration-List, + id-PMCH-Configuration-Item, + id-Common-Subframe-Allocation-Period, + id-GlobalENB-ID, + id-ENBname, + id-ENB-MBMS-Configuration-data-List, + id-ENB-MBMS-Configuration-data-Item, + id-GlobalMCE-ID, + id-MCEname, + id-MCCHrelatedBCCH-ConfigPerMBSFNArea, + id-MCCHrelatedBCCH-ConfigPerMBSFNArea-Item, + id-TimeToWait, + id-ENB-MBMS-Configuration-data-List-ConfigUpdate, + id-ENB-MBMS-Configuration-data-ConfigUpdate-Item, + id-MBSFN-Area-ID, + id-ResetType, + id-MBMS-Service-associatedLogicalM2-ConnectionItem, + id-MBMS-Service-associatedLogicalM2-ConnectionListResAck, + id-MBMS-Counting-Request-Session, + id-MBMS-Counting-Request-Session-Item, + id-MBMS-Counting-Result-List, + id-MBMS-Counting-Result-Item, + id-MBMS-Suspension-Notification-List, + id-MBMS-Suspension-Notification-Item, + id-PMCH-Overload-Status, + id-Overload-Status-Per-PMCH-List, + id-Active-MBMS-Session-List, + id-SC-PTM-Information, + maxnoofMBSFN-Allocations, + maxnoofMBSFNareas, + maxnoofPMCHsperMBSFNarea, + maxnoofCells, + maxnoofMBMSServiceAreasPerCell, + maxnoofSessionsPerPMCH, + maxnooferrors, + maxNrOfIndividualM2ConnectionsToReset, + maxnoofCountingService + +FROM M2AP-Constants; + +-- ************************************************************** +-- +-- SESSION START REQUEST +-- +-- ************************************************************** + +SessionStartRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{SessionStartRequest-Ies}}, + ... +} + +SessionStartRequest-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY reject TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory}| + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory}| + { ID id-MBMS-Session-ID CRITICALITY ignore TYPE MBMS-Session-ID PRESENCE optional}| + { ID id-MBMS-Service-Area CRITICALITY reject TYPE MBMS-Service-Area PRESENCE mandatory}| + { ID id-TNL-Information CRITICALITY reject TYPE TNL-Information PRESENCE mandatory}| + { ID id-Alternative-TNL-Information CRITICALITY ignore TYPE TNL-Information PRESENCE optional}| + { ID id-SC-PTM-Information CRITICALITY reject TYPE SC-PTM-Information PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- SESSION START RESPONSE +-- +-- ************************************************************** + +SessionStartResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ SessionStartResponse-Ies}}, + ... +} + +SessionStartResponse-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY ignore TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-ENB-MBMS-M2AP-ID CRITICALITY ignore TYPE ENB-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- SESSION START FAILURE +-- +-- ************************************************************** + +SessionStartFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ SessionStartFailure-Ies}}, + ... +} + +SessionStartFailure-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY ignore TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- SESSION STOP REQUEST +-- +-- ************************************************************** + +SessionStopRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{SessionStopRequest-Ies}}, + ... +} + +SessionStopRequest-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY reject TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-ENB-MBMS-M2AP-ID CRITICALITY reject TYPE ENB-MBMS-M2AP-ID PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- SESSION STOP RESPONSE +-- +-- ************************************************************** + +SessionStopResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ SessionStopResponse-Ies}}, + ... +} + +SessionStopResponse-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY ignore TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-ENB-MBMS-M2AP-ID CRITICALITY ignore TYPE ENB-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} + +-- ************************************************************** +-- +-- SESSION UPDATE REQUEST +-- +-- ************************************************************** + +SessionUpdateRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{SessionUpdateRequest-Ies}}, + ... +} + +SessionUpdateRequest-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY reject TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory}| + { ID id-ENB-MBMS-M2AP-ID CRITICALITY reject TYPE ENB-MBMS-M2AP-ID PRESENCE mandatory}| + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory}| + { ID id-MBMS-Session-ID CRITICALITY ignore TYPE MBMS-Session-ID PRESENCE optional}| + { ID id-MBMS-Service-Area CRITICALITY ignore TYPE MBMS-Service-Area PRESENCE optional}| + { ID id-TNL-Information CRITICALITY reject TYPE TNL-Information PRESENCE optional}| + { ID id-SC-PTM-Information CRITICALITY reject TYPE SC-PTM-Information PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- SESSION UPDATE RESPONSE +-- +-- ************************************************************** + +SessionUpdateResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ SessionUpdateResponse-Ies}}, + ... +} + +SessionUpdateResponse-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY ignore TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-ENB-MBMS-M2AP-ID CRITICALITY ignore TYPE ENB-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- SESSION UPDATE FAILURE +-- +-- ************************************************************** + +SessionUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ SessionUpdateFailure-Ies}}, + ... +} + +SessionUpdateFailure-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY ignore TYPE MCE-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-ENB-MBMS-M2AP-ID CRITICALITY ignore TYPE ENB-MBMS-M2AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MBMS SCHEDULING INFORMATION +-- +-- ************************************************************** + +MbmsSchedulingInformation ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MbmsSchedulingInformation-Ies}}, + ... +} + +MbmsSchedulingInformation-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCCH-Update-Time CRITICALITY reject TYPE MCCH-Update-Time PRESENCE mandatory }| + { ID id-MBSFN-Area-Configuration-List CRITICALITY reject TYPE MBSFN-Area-Configuration-List PRESENCE mandatory }, + ... +} + +MBSFN-Area-Configuration-List ::= SEQUENCE (SIZE(1.. maxnoofMBSFNareas)) OF ProtocolIE-Container { { MBSFN-Area-Configuration-Item } } + +MBSFN-Area-Configuration-Item M2AP-PROTOCOL-IES ::= { + { ID id-PMCH-Configuration-List CRITICALITY reject TYPE PMCH-Configuration-List PRESENCE mandatory }| + { ID id-MBSFN-Subframe-Configuration-List CRITICALITY reject TYPE MBSFN-Subframe-ConfigurationList PRESENCE mandatory }| + { ID id-Common-Subframe-Allocation-Period CRITICALITY reject TYPE Common-Subframe-Allocation-Period PRESENCE mandatory }| + { ID id-MBSFN-Area-ID CRITICALITY reject TYPE MBSFN-Area-ID PRESENCE mandatory }| + { ID id-MBMS-Suspension-Notification-List CRITICALITY ignore TYPE MBMS-Suspension-Notification-List PRESENCE optional }, + ... +} + +PMCH-Configuration-List ::= SEQUENCE (SIZE(0.. maxnoofPMCHsperMBSFNarea)) OF ProtocolIE-Single-Container { { PMCH-Configuration-ItemIEs } } + +PMCH-Configuration-ItemIEs M2AP-PROTOCOL-IES ::= { + { ID id-PMCH-Configuration-Item CRITICALITY reject TYPE PMCH-Configuration-Item PRESENCE mandatory }, + ... +} + +PMCH-Configuration-Item ::= SEQUENCE { + pmch-Configuration PMCH-Configuration, + mbms-Session-List MBMSsessionListPerPMCH-Item, + iE-Extensions ProtocolExtensionContainer { { PMCH-Configuration-ItemExtIEs} } OPTIONAL, + ... +} + +PMCH-Configuration-ItemExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +MBSFN-Subframe-ConfigurationList ::= SEQUENCE (SIZE(1.. maxnoofMBSFN-Allocations)) OF ProtocolIE-Single-Container { { MBSFN-Subframe-ConfigurationItem } } + +MBSFN-Subframe-ConfigurationItem M2AP-PROTOCOL-IES ::= { + { ID id-MBSFN-Subframe-Configuration-Item CRITICALITY reject TYPE MBSFN-Subframe-Configuration PRESENCE mandatory }, + ... +} + +MBMS-Suspension-Notification-List ::= SEQUENCE (SIZE(1.. maxnoofPMCHsperMBSFNarea)) OF ProtocolIE-Single-Container { { MBMS-Suspension-Notification-ItemIEs } } + +MBMS-Suspension-Notification-ItemIEs M2AP-PROTOCOL-IES ::= { + { ID id-MBMS-Suspension-Notification-Item CRITICALITY ignore TYPE MBMS-Suspension-Notification-Item PRESENCE optional}, + ... +} + +MBMS-Suspension-Notification-Item ::= SEQUENCE { + sfn SFN, + mbms-Sessions-To-Be-Suspended-List MBMSsessionsToBeSuspendedListPerPMCH-Item, + iE-Extensions ProtocolExtensionContainer { { MBMS-Suspension-Notification-ItemExtIEs} } OPTIONAL, + ... +} + +MBMS-Suspension-Notification-ItemExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- MBMS SCHEDULING INFORMATION RESPONSE +-- +-- ************************************************************** + +MbmsSchedulingInformationResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MbmsSchedulingInformationResponse-Ies}}, + ... +} + +MbmsSchedulingInformationResponse-Ies M2AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- M2 SETUP REQUEST +-- +-- ************************************************************** + +M2SetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{M2SetupRequest-Ies}}, + ... +} + +M2SetupRequest-Ies M2AP-PROTOCOL-IES ::= { + { ID id-GlobalENB-ID CRITICALITY reject TYPE GlobalENB-ID PRESENCE mandatory}| + { ID id-ENBname CRITICALITY ignore TYPE ENBname PRESENCE optional}| + { ID id-ENB-MBMS-Configuration-data-List CRITICALITY reject TYPE ENB-MBMS-Configuration-data-List PRESENCE mandatory}, + ... +} + +ENB-MBMS-Configuration-data-List ::= SEQUENCE (SIZE(1.. maxnoofCells)) OF ProtocolIE-Single-Container { { ENB-MBMS-Configuration-data-ItemIEs } } + +ENB-MBMS-Configuration-data-ItemIEs M2AP-PROTOCOL-IES ::= { + { ID id-ENB-MBMS-Configuration-data-Item CRITICALITY reject TYPE ENB-MBMS-Configuration-data-Item PRESENCE mandatory }, + ... +} + + +-- ************************************************************** +-- +-- M2 SETUP RESPONSE +-- +-- ************************************************************** + +M2SetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ M2SetupResponse-Ies}}, + ... +} + +M2SetupResponse-Ies M2AP-PROTOCOL-IES ::= { + { ID id-GlobalMCE-ID CRITICALITY reject TYPE GlobalMCE-ID PRESENCE mandatory }| + { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional }| + { ID id-MCCHrelatedBCCH-ConfigPerMBSFNArea CRITICALITY reject TYPE MCCHrelatedBCCH-ConfigPerMBSFNArea PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +MCCHrelatedBCCH-ConfigPerMBSFNArea ::= SEQUENCE (SIZE(1.. maxnoofMBSFNareas)) OF ProtocolIE-Single-Container { { MCCHrelatedBCCH-ConfigPerMBSFNArea-ItemIEs } } + +MCCHrelatedBCCH-ConfigPerMBSFNArea-ItemIEs M2AP-PROTOCOL-IES ::= { + { ID id-MCCHrelatedBCCH-ConfigPerMBSFNArea-Item CRITICALITY reject TYPE MCCHrelatedBCCH-ConfigPerMBSFNArea-Item PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- M2 SETUP FAILURE +-- +-- ************************************************************** + +M2SetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ M2SetupFailure-Ies}}, + ... +} + +M2SetupFailure-Ies M2AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + + ... +} + +-- ************************************************************** +-- +-- ENB CONFIGURATION UPDATE +-- +-- ************************************************************** + +ENBConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ENBConfigurationUpdate-Ies}}, + ... +} + +ENBConfigurationUpdate-Ies M2AP-PROTOCOL-IES ::= { + { ID id-GlobalENB-ID CRITICALITY reject TYPE GlobalENB-ID PRESENCE optional }| + { ID id-ENBname CRITICALITY ignore TYPE ENBname PRESENCE optional }| + { ID id-ENB-MBMS-Configuration-data-List-ConfigUpdate CRITICALITY reject TYPE ENB-MBMS-Configuration-data-List-ConfigUpdate PRESENCE optional }, + ... +} +ENB-MBMS-Configuration-data-List-ConfigUpdate ::= SEQUENCE (SIZE(1.. maxnoofCells)) OF ProtocolIE-Single-Container { { ENB-MBMS-Configuration-data-ConfigUpdate-ItemIEs } } + +ENB-MBMS-Configuration-data-ConfigUpdate-ItemIEs M2AP-PROTOCOL-IES ::= { + { ID id-ENB-MBMS-Configuration-data-ConfigUpdate-Item CRITICALITY reject TYPE ENB-MBMS-Configuration-data-ConfigUpdate-Item PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- ENB CONFIGURATION UPDATE ACKNOWLEDGE +-- +-- ************************************************************** + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBConfigurationUpdateAcknowledge-Ies}}, + ... +} + +ENBConfigurationUpdateAcknowledge-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCCHrelatedBCCH-ConfigPerMBSFNArea CRITICALITY reject TYPE MCCHrelatedBCCH-ConfigPerMBSFNArea PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- ENB CONFIGURATION UPDATE FAILURE +-- +-- ************************************************************** + +ENBConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBConfigurationUpdateFailure-Ies}}, + ... +} + +ENBConfigurationUpdateFailure-Ies M2AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + + ... +} + + +-- ************************************************************** +-- +-- MCE CONFIGURATION UPDATE +-- +-- ************************************************************** + +MCEConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MCEConfigurationUpdate-Ies}}, + ... +} + +MCEConfigurationUpdate-Ies M2AP-PROTOCOL-IES ::= { + { ID id-GlobalMCE-ID CRITICALITY reject TYPE GlobalMCE-ID PRESENCE optional }| + { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional }| + { ID id-MCCHrelatedBCCH-ConfigPerMBSFNArea CRITICALITY reject TYPE MCCHrelatedBCCH-ConfigPerMBSFNArea PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MCE CONFIGURATION UPDATE ACKNOWLEDGE +-- +-- ************************************************************** + +MCEConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MCEConfigurationUpdateAcknowledge-Ies}}, + ... +} + +MCEConfigurationUpdateAcknowledge-Ies M2AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- MCE CONFIGURATION UPDATE FAILURE +-- +-- ************************************************************** + +MCEConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MCEConfigurationUpdateFailure-Ies}}, + ... +} + +MCEConfigurationUpdateFailure-Ies M2AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + + ... +} + + +-- ************************************************************** +-- +-- ERROR INDICATION +-- +-- ************************************************************** + +ErrorIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ErrorIndication-Ies}}, + ... +} + +ErrorIndication-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCE-MBMS-M2AP-ID CRITICALITY ignore TYPE MCE-MBMS-M2AP-ID PRESENCE optional}| + { ID id-ENB-MBMS-M2AP-ID CRITICALITY ignore TYPE ENB-MBMS-M2AP-ID PRESENCE optional}| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- RESET +-- +-- ************************************************************** + +Reset ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{Reset-Ies}}, + ... +} + +Reset-Ies M2AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-ResetType CRITICALITY reject TYPE ResetType PRESENCE mandatory}, + ... +} + +ResetType ::= CHOICE { + m2-Interface ResetAll, + partOfM2-Interface MBMS-Service-associatedLogicalM2-ConnectionListRes, + ... +} + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +MBMS-Service-associatedLogicalM2-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualM2ConnectionsToReset)) OF ProtocolIE-Single-Container { { MBMS-Service-associatedLogicalM2-ConnectionItemRes } } + +MBMS-Service-associatedLogicalM2-ConnectionItemRes M2AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM2-ConnectionItem CRITICALITY reject TYPE MBMS-Service-associatedLogicalM2-ConnectionItem PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- RESET ACKNOWLEDGE +-- +-- ************************************************************** + +ResetAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ResetAcknowledge-Ies}}, + ... +} + +ResetAcknowledge-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM2-ConnectionListResAck CRITICALITY ignore TYPE MBMS-Service-associatedLogicalM2-ConnectionListResAck PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +MBMS-Service-associatedLogicalM2-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualM2ConnectionsToReset)) OF ProtocolIE-Single-Container { { MBMS-Service-associatedLogicalM2-ConnectionItemResAck } } + +MBMS-Service-associatedLogicalM2-ConnectionItemResAck M2AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM2-ConnectionItem CRITICALITY ignore TYPE MBMS-Service-associatedLogicalM2-ConnectionItem PRESENCE mandatory}, + ... +} + + +-- ************************************************************** +-- +-- PRIVATE MESSAGE +-- +-- ************************************************************** + +PrivateMessage ::= SEQUENCE { + privateIEs PrivateIE-Container {{PrivateMessage-Ies}}, + ... +} + +PrivateMessage-Ies M2AP-PRIVATE-IES ::= { + ... +} + + +-- ************************************************************** +-- +-- MBMS SERVICE COUNTING REQUEST +-- +-- ************************************************************** + +MbmsServiceCountingRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MbmsServiceCountingRequest-Ies}}, + ... +} + +MbmsServiceCountingRequest-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MCCH-Update-Time CRITICALITY reject TYPE MCCH-Update-Time PRESENCE mandatory }| + { ID id-MBSFN-Area-ID CRITICALITY reject TYPE MBSFN-Area-ID PRESENCE mandatory }| + { ID id-MBMS-Counting-Request-Session CRITICALITY reject TYPE MBMS-Counting-Request-Session PRESENCE mandatory }, + ... +} + +MBMS-Counting-Request-Session ::= SEQUENCE (SIZE(1.. maxnoofCountingService)) OF ProtocolIE-Container { { MBMS-Counting-Request-Session-Item } } + +MBMS-Counting-Request-Session-Item M2AP-PROTOCOL-IES ::= { + { ID id-MBMS-Counting-Request-Session-Item CRITICALITY reject TYPE MBMS-Counting-Request-SessionIE PRESENCE mandatory }, + ... +} + +MBMS-Counting-Request-SessionIE ::= SEQUENCE{ + tmgi TMGI, + iE-Extensions ProtocolExtensionContainer { { MBMS-Counting-Request-SessionIE-ExtIEs} } OPTIONAL, + ... +} + +MBMS-Counting-Request-SessionIE-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- MBMS SERVICE COUNTING RESPONSE +-- +-- ************************************************************** + +MbmsServiceCountingResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MbmsServiceCountingResponse-Ies}}, + ... +} + +MbmsServiceCountingResponse-Ies M2AP-PROTOCOL-IES ::= { + + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- MBMS SERVICE COUNTING FAILURE +-- +-- ************************************************************** + +MbmsServiceCountingFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MbmsServiceCountingFailure-Ies}}, + ... +} + +MbmsServiceCountingFailure-Ies M2AP-PROTOCOL-IES ::= { + + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- MBMS SERVICE COUNTING RESULTS REPORT +-- +-- ************************************************************** + +MbmsServiceCountingResultsReport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MbmsServiceCountingResultsReport-Ies}}, + ... +} + +MbmsServiceCountingResultsReport-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MBSFN-Area-ID CRITICALITY reject TYPE MBSFN-Area-ID PRESENCE mandatory}| + { ID id-MBMS-Counting-Result-List CRITICALITY reject TYPE MBMS-Counting-Result-List PRESENCE mandatory}, + ... +} + +MBMS-Counting-Result-List ::= SEQUENCE (SIZE(1.. maxnoofCountingService)) OF ProtocolIE-Container { { MBMS-Counting-Result-Item } } + +MBMS-Counting-Result-Item M2AP-PROTOCOL-IES ::= { + { ID id-MBMS-Counting-Result-Item CRITICALITY reject TYPE MBMS-Counting-Result PRESENCE mandatory }, + ... +} + +MBMS-Counting-Result ::= SEQUENCE{ + tmgi TMGI, + countingResult CountingResult, + iE-Extensions ProtocolExtensionContainer { { MBMS-Counting-Result-ExtIEs} } OPTIONAL, + ... +} + +MBMS-Counting-Result-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +CountingResult ::= INTEGER (0..1023) + +-- ************************************************************** +-- +-- MBMS OVERLOAD NOTIFICATION +-- +-- ************************************************************** + +MbmsOverloadNotification ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MbmsOverloadNotification-Ies}}, + ... +} + +MbmsOverloadNotification-Ies M2AP-PROTOCOL-IES ::= { + { ID id-MBSFN-Area-ID CRITICALITY reject TYPE MBSFN-Area-ID PRESENCE mandatory}| + { ID id-Overload-Status-Per-PMCH-List CRITICALITY reject TYPE Overload-Status-Per-PMCH-List PRESENCE mandatory}, + ... +} + +Overload-Status-Per-PMCH-List ::= SEQUENCE (SIZE(1..maxnoofPMCHsperMBSFNarea)) OF ProtocolIE-Container { { Overload-Status-Per-PMCH-Item } } + +Overload-Status-Per-PMCH-Item M2AP-PROTOCOL-IES ::= { + { ID id-PMCH-Overload-Status CRITICALITY reject TYPE PMCH-Overload-Status PRESENCE mandatory }| + { ID id-Active-MBMS-Session-List CRITICALITY reject TYPE Active-MBMS-Session-List PRESENCE optional }, + ... +} + +PMCH-Overload-Status ::= ENUMERATED {normal, overload, ...} + +Active-MBMS-Session-List ::= SEQUENCE (SIZE(1..maxnoofSessionsPerPMCH)) OF ProtocolIE-Container { { Active-MBMS-Session-Item } } + +Active-MBMS-Session-Item M2AP-PROTOCOL-IES ::= { + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory }, + ... +} + +END + +-- ************************************************************** +-- +-- Information Element Definitions +-- +-- ************************************************************** + +M2AP-Ies { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m2ap (4) version1 (1) m2ap-Ies (2) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + id-MCH-Scheduling-PeriodExtended, + id-MCH-Scheduling-PeriodExtended2, + id-Modification-PeriodExtended, + id-Modulation-Coding-Scheme2, + id-Repetition-PeriodExtended, + id-Subcarrier-SpacingMBMS, + id-SubframeAllocationExtended, + maxnoofMBSFNareas, + maxnoofPMCHsperMBSFNarea, + maxnoofCells, + maxnoofMBMSServiceAreasPerCell, + maxnoofSessionsPerPMCH, + maxnooferrors, + maxnoofCellsforMBMS + +FROM M2AP-Constants + + Criticality, + ProcedureCode, + ProtocolIE-ID, + TriggeringMessage +FROM M2AP-CommonDataTypes + + ProtocolExtensionContainer{}, + ProtocolIE-Single-Container{}, + M2AP-PROTOCOL-EXTENSION, + M2AP-PROTOCOL-IES +FROM M2AP-Containers; + +-- A + +AllocatedSubframesEnd ::= INTEGER (0..1535) + +AllocationAndRetentionPriority ::= SEQUENCE { + priorityLevel PriorityLevel, + pre-emptionCapability Pre-emptionCapability, + pre-emptionVulnerability Pre-emptionVulnerability, + iE-Extensions ProtocolExtensionContainer { {AllocationAndRetentionPriority-ExtIEs} } OPTIONAL +} + +AllocationAndRetentionPriority-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- B + +BitRate ::= INTEGER (0..10000000000) + +-- C + +Cause ::= CHOICE { + radioNetwork CauseRadioNetwork, + transport CauseTransport, + nAS CauseNAS, + protocol CauseProtocol, + misc CauseMisc, + ... +} + +CauseMisc ::= ENUMERATED { + control-processing-overload, + hardware-failure, + om-intervention, + unspecified, + ... +} + +CauseNAS ::= ENUMERATED { + unspecified, + ... +} + +CauseProtocol ::= ENUMERATED { + transfer-syntax-error, + abstract-syntax-error-reject, + abstract-syntax-error-ignore-and-notify, + message-not-compatible-with-receiver-state, + semantic-error, + abstract-syntax-error-falsely-constructed-message, + unspecified, + ... +} + +CauseRadioNetwork ::= ENUMERATED { + unknown-or-already-allocated-MCE-MBMS-M2AP-ID, + unknown-or-already-allocated-eNB-MBMS-M2AP-ID, + unknown-or-inconsistent-pair-of-MBMS-M2AP-IDs, + radio-resources-not-available, + interaction-with-other-procedure, + unspecified, + ..., + invalid-QoS-combination, + not-supported-QCI-value + +} + +CauseTransport ::= ENUMERATED { + transport-resource-unavailable, + unspecified, + ... +} + +Cell-Information ::= SEQUENCE { + eCGI ECGI, + cellReservationInfo ENUMERATED {reservedCell, nonReservedCell, ...}, + iE-Extensions ProtocolExtensionContainer { { Cell-Information-ExtIEs} } OPTIONAL, + ... +} + +Cell-Information-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +Cell-Information-List ::= SEQUENCE (SIZE(1..maxnoofCells)) OF Cell-Information + +CriticalityDiagnostics ::= SEQUENCE { + procedureCode ProcedureCode OPTIONAL, + triggeringMessage TriggeringMessage OPTIONAL, + procedureCriticality Criticality OPTIONAL, + iEsCriticalityDiagnostics CriticalityDiagnostics-IE-List OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {CriticalityDiagnostics-ExtIEs} } OPTIONAL, + ... +} + + +CriticalityDiagnostics-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..maxnooferrors)) OF + SEQUENCE { + iECriticality Criticality, + iE-ID ProtocolIE-ID, + typeOfError TypeOfError, + iE-Extensions ProtocolExtensionContainer { {CriticalityDiagnostics-IE-List-ExtIEs} } OPTIONAL, + ... +} + +CriticalityDiagnostics-IE-List-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- D +-- E + +ECGI ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + eUTRANcellIdentifier EUTRANCellIdentifier, + iE-Extensions ProtocolExtensionContainer { {ECGI-ExtIEs} } OPTIONAL, + ... +} + +ECGI-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + + +ENB-ID ::= CHOICE { + macro-eNB-ID BIT STRING (SIZE (20)), + ... , + short-Macro-eNB-ID BIT STRING (SIZE(18)), + long-Macro-eNB-ID BIT STRING (SIZE(21)) +} + +ENB-MBMS-Configuration-data-Item ::= SEQUENCE { + eCGI ECGI, + mbsfnSynchronisationArea MBSFN-SynchronisationArea-ID, + mbmsServiceAreaList MBMS-Service-Area-ID-List, + iE-Extensions ProtocolExtensionContainer { { ENB-MBMS-Configuration-data-Item-ExtIEs} } OPTIONAL, + ... +} + +ENB-MBMS-Configuration-data-Item-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +ENB-MBMS-Configuration-data-ConfigUpdate-Item ::= CHOICE { + mBMSConfigData ENB-MBMS-Configuration-data-Item, + eCGI ECGI, + ... +} + +ENB-MBMS-M2AP-ID ::= INTEGER (0..65535) + +ENBname ::= PrintableString (SIZE (1..150,...)) + +EUTRANCellIdentifier ::= BIT STRING (SIZE (28)) + + +-- F +-- G + +GBR-QosInformation ::= SEQUENCE { + mBMS-E-RAB-MaximumBitrateDL BitRate, + mBMS-E-RAB-GuaranteedBitrateDL BitRate, + iE-Extensions ProtocolExtensionContainer { { GBR-QosInformation-ExtIEs} } OPTIONAL, + ... +} + +GBR-QosInformation-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +GlobalENB-ID ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + eNB-ID ENB-ID, + iE-Extensions ProtocolExtensionContainer { {GlobalENB-ID-ExtIEs} } OPTIONAL, + ... +} + +GlobalENB-ID-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +GlobalMCE-ID ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + mCE-ID MCE-ID, + iE-Extensions ProtocolExtensionContainer { {GlobalMCE-ID-ExtIEs} } OPTIONAL, + ... +} + +GlobalMCE-ID-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +GTP-TEID ::= OCTET STRING (SIZE (4)) + +-- H +-- I + +IPAddress ::= OCTET STRING (SIZE(4..16)) + +-- J +-- K +-- L + +LCID ::= INTEGER (0..28) + +-- M + +MBMS-Cell-List ::= SEQUENCE (SIZE(1.. maxnoofCellsforMBMS)) OF ECGI + +MBMS-E-RAB-QoS-Parameters ::= SEQUENCE { + qCI QCI, + gbrQosInformation GBR-QosInformation OPTIONAL, + allocationAndRetentionPriority AllocationAndRetentionPriority, + iE-Extensions ProtocolExtensionContainer { { MBMS-E-RAB-QoS-Parameters-ExtIEs} } OPTIONAL, + ... +} + +MBMS-E-RAB-QoS-Parameters-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +MBMS-Service-associatedLogicalM2-ConnectionItem ::= SEQUENCE { + eNB-MBMS-M2AP-ID ENB-MBMS-M2AP-ID OPTIONAL, + mCE-MBMS-M2AP-ID MCE-MBMS-M2AP-ID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { MBMS-Service-associatedLogicalM2-ConnectionItemExtIEs} } OPTIONAL, + ... +} + + +MBMS-Service-associatedLogicalM2-ConnectionItemExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +MBMS-Service-Area ::= OCTET STRING + +MBMS-Service-Area-ID-List ::= SEQUENCE (SIZE(1..maxnoofMBMSServiceAreasPerCell)) OF MBMS-Service-Area + +MBMS-Session-ID ::= OCTET STRING (SIZE (1)) + +MBMSsessionListPerPMCH-Item ::= SEQUENCE (SIZE(1..maxnoofSessionsPerPMCH)) OF SEQUENCE { + tmgi TMGI, + lcid LCID, + iE-Extensions ProtocolExtensionContainer { { MBMSsessionListPerPMCH-Item-ExtIEs} } OPTIONAL, + ... +} + +MBMSsessionListPerPMCH-Item-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +MBMSsessionsToBeSuspendedListPerPMCH-Item ::= SEQUENCE (SIZE(1..maxnoofSessionsPerPMCH)) OF SEQUENCE { + tmgi TMGI, + iE-Extensions ProtocolExtensionContainer { { MBMSsessionsToBeSuspendedListPerPMCH-Item-ExtIEs} } OPTIONAL, + ... +} + +MBMSsessionsToBeSuspendedListPerPMCH-Item-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +MBSFN-Area-ID ::= INTEGER (0..255) + +MBSFN-SynchronisationArea-ID ::= INTEGER (0..65535) + +MBSFN-Subframe-Configuration ::= SEQUENCE { + radioframeAllocationPeriod ENUMERATED {n1, n2, n4, n8, n16, n32}, + radioframeAllocationOffset INTEGER (0..7), + subframeAllocation CHOICE { + oneFrame BIT STRING (SIZE (6) ), + fourFrames BIT STRING (SIZE (24) ) }, + iE-Extensions ProtocolExtensionContainer { { MBSFN-Subframe-Configuration-ExtIEs} } OPTIONAL, + ... +} + +MBSFN-Subframe-Configuration-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + {ID id-SubframeAllocationExtended CRITICALITY reject EXTENSION SubframeAllocationExtended PRESENCE optional}, + ... +} + +MCCH-Update-Time ::= INTEGER (0..255) + +MCCHrelatedBCCH-ConfigPerMBSFNArea-Item ::= SEQUENCE { + mbsfnArea MBSFN-Area-ID, + pdcchLength ENUMERATED {s1, s2, ...}, + repetitionPeriod ENUMERATED {rf32, rf64, rf128, rf256}, + offset INTEGER (0..10), + modificationPeriod ENUMERATED {rf512, rf1024}, + subframeAllocationInfo BIT STRING (SIZE(6)), + modulationAndCodingScheme ENUMERATED {n2, n7, n13, n19}, + cellInformationList Cell-Information-List OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { MCCHrelatedBCCH-ConfigPerMBSFNArea-Item-ExtIEs} } OPTIONAL, + ... +} + +MCCHrelatedBCCH-ConfigPerMBSFNArea-Item-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { +-- Extension for Rel-14 to support MCCH repetition period values –- + {ID id-Repetition-PeriodExtended CRITICALITY reject EXTENSION Repetition-PeriodExtended PRESENCE optional}| +-- Extension for Rel-14 to support MCCH modification period values –- + {ID id-Modification-PeriodExtended CRITICALITY reject EXTENSION Modification-PeriodExtended PRESENCE optional}| + {ID id-Subcarrier-SpacingMBMS CRITICALITY reject EXTENSION Subcarrier-SpacingMBMS PRESENCE optional}, + ... +} + +MCE-ID ::= OCTET STRING (SIZE(2)) + +MCE-MBMS-M2AP-ID ::= INTEGER (0.. 16777215) + +MCEname ::= PrintableString (SIZE (1..150,...)) + + +MCH-Scheduling-Period ::= ENUMERATED {rf8, rf16, rf32, rf64, rf128, rf256, rf512, rf1024} + +MCH-Scheduling-PeriodExtended ::= ENUMERATED {rf4, ...} + +MCH-Scheduling-PeriodExtended2 ::= ENUMERATED {rf1, rf2, ...} + + +Modulation-Coding-Scheme2 ::= INTEGER (0..27) + +Modification-PeriodExtended ::= ENUMERATED {rf1, rf2, rf4, rf8, rf16, rf32, rf64, rf128, rf256, ...} + +-- N +-- O +-- P + +PLMN-Identity ::= OCTET STRING (SIZE(3)) + +PMCH-Configuration ::= SEQUENCE { + allocatedSubframesEnd AllocatedSubframesEnd, + dataMCS INTEGER (0..28), + mchSchedulingPeriod MCH-Scheduling-Period, + iE-Extensions ProtocolExtensionContainer { {PMCH-Configuration-ExtIEs} } OPTIONAL, + ... +} + +PMCH-Configuration-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { +-- Extension for Rel-12 to support 256QAM for MTCH – + {ID id-Modulation-Coding-Scheme2 CRITICALITY reject EXTENSION Modulation-Coding-Scheme2 PRESENCE optional}| +-- Extension for Rel-12 to support shorter MCH scheduling period – + {ID id-MCH-Scheduling-PeriodExtended CRITICALITY reject EXTENSION MCH-Scheduling-PeriodExtended PRESENCE optional}| +-- Extension for Rel-14 to support shorter MCH scheduling period values – + {ID id-MCH-Scheduling-PeriodExtended2 CRITICALITY reject EXTENSION MCH-Scheduling-PeriodExtended2 PRESENCE optional}, + ... +} + +Common-Subframe-Allocation-Period ::= ENUMERATED {rf4, rf8, rf16, rf32, rf64, rf128, rf256} + +Pre-emptionCapability ::= ENUMERATED { + shall-not-trigger-pre-emption, + may-trigger-pre-emption +} + +Pre-emptionVulnerability ::= ENUMERATED { + not-pre-emptable, + pre-emptable +} + +PriorityLevel ::= INTEGER { spare (0), highest (1), lowest (14), no-priority (15) } (0..15) + +-- Q + +QCI ::= INTEGER (0..255) + +-- R + +Repetition-PeriodExtended ::= ENUMERATED {rf1, rf2, rf4, rf8, rf16, ...} + +-- S + +SC-PTM-Information ::= SEQUENCE { + mbmsCellList MBMS-Cell-List, + mbms-E-RAB-QoS-Parameters MBMS-E-RAB-QoS-Parameters, + iE-Extensions ProtocolExtensionContainer { {SC-PTM-Information-ExtIEs} } OPTIONAL, + ... +} + +SC-PTM-Information-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +SFN ::= INTEGER (0..1023) + +Subcarrier-SpacingMBMS ::= ENUMERATED {khz-7dot5, khz-1dot25, ...} + +SubframeAllocationExtended ::= CHOICE { + oneFrameExtension BIT STRING (SIZE(2)), + fourFrameExtension BIT STRING (SIZE(8)), + choice-extension ProtocolIE-Single-Container { { SubframeAllocationExtended-ExtIEs} }, + + ... +} + + +SubframeAllocationExtended-ExtIEs M2AP-PROTOCOL-IES ::= { ... +} + +-- T + +TimeToWait ::= ENUMERATED {v1s, v2s, v5s, v10s, v20s, v60s, ...} + +TMGI ::= SEQUENCE { + pLMNidentity PLMN-Identity, + serviceID OCTET STRING (SIZE (3)), + iE-Extensions ProtocolExtensionContainer { {TMGI-ExtIEs} } OPTIONAL, + ... +} + +TMGI-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + + +TNL-Information ::= SEQUENCE { + iPMCAddress IPAddress, + iPSourceAddress IPAddress, + gTP-TEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { {TNL-Information-ExtIEs} } OPTIONAL, + ... +} + +TNL-Information-ExtIEs M2AP-PROTOCOL-EXTENSION ::= { + ... +} + +TypeOfError ::= ENUMERATED { + not-understood, + missing, + ... +} + + +-- U +-- V +-- W +-- X +-- Y +-- Z + +END + +-- ************************************************************** +-- +-- Common definitions +-- +-- ************************************************************** + +M2AP-CommonDataTypes { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m2ap (4) version1 (1) m2ap-CommonDataTypes (3) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- Extension constants +-- +-- ************************************************************** + +maxPrivateIEs INTEGER ::= 65535 +maxProtocolExtensions INTEGER ::= 65535 +maxProtocolIEs INTEGER ::= 65535 + +-- ************************************************************** +-- +-- Common Data Types +-- +-- ************************************************************** + +Criticality ::= ENUMERATED { reject, ignore, notify } + +Presence ::= ENUMERATED { optional, conditional, mandatory } + +PrivateIE-ID ::= CHOICE { + local INTEGER (0.. maxPrivateIEs), + global OBJECT IDENTIFIER +} + +ProcedureCode ::= INTEGER (0..255) + + +ProtocolIE-ID ::= INTEGER (0..maxProtocolIEs) + + +TriggeringMessage ::= ENUMERATED { initiating-message, successful-outcome, unsuccessful-outcome} + +END + +-- ************************************************************** +-- +-- Constant definitions +-- +-- ************************************************************** + +M2AP-Constants { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m2ap (4) version1 (1) m2ap-Constants (4) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + ProcedureCode, + ProtocolIE-ID +FROM M2AP-CommonDataTypes; + +-- ************************************************************** +-- +-- Elementary Procedures +-- +-- ************************************************************** + +id-sessionStart ProcedureCode ::= 0 +id-sessionStop ProcedureCode ::= 1 +id-mbmsSchedulingInformation ProcedureCode ::= 2 +id-errorIndication ProcedureCode ::= 3 +id-reset ProcedureCode ::= 4 +id-m2Setup ProcedureCode ::= 5 +id-eNBConfigurationUpdate ProcedureCode ::= 6 +id-mCEConfigurationUpdate ProcedureCode ::= 7 +id-privateMessage ProcedureCode ::= 8 +id-sessionUpdate ProcedureCode ::= 9 +id-mbmsServiceCounting ProcedureCode ::= 10 +id-mbmsServiceCountingResultsReport ProcedureCode ::= 11 +id-mbmsOverloadNotification ProcedureCode ::= 12 + +-- ************************************************************** +-- +-- Lists +-- +-- ************************************************************** + +maxnoofMBSFNareas INTEGER ::= 256 +maxnoofMBSFN-Allocations INTEGER ::= 8 +maxnoofPMCHsperMBSFNarea INTEGER ::= 15 +maxnoofCells INTEGER ::= 256 +maxnoofMBMSServiceAreasPerCell INTEGER ::= 256 +maxnoofSessionsPerPMCH INTEGER ::= 29 +maxnooferrors INTEGER ::= 256 +maxNrOfIndividualM2ConnectionsToReset INTEGER ::= 256 +maxnoofCountingService INTEGER ::= 16 +maxnoofCellsforMBMS INTEGER ::= 4096 + + +-- ************************************************************** +-- +-- Ies +-- +-- ************************************************************** + +id-MCE-MBMS-M2AP-ID ProtocolIE-ID ::= 0 +id-ENB-MBMS-M2AP-ID ProtocolIE-ID ::= 1 +id-TMGI ProtocolIE-ID ::= 2 +id-MBMS-Session-ID ProtocolIE-ID ::= 3 +id-MBMS-Service-Area ProtocolIE-ID ::= 6 +id-TNL-Information ProtocolIE-ID ::= 7 +id-CriticalityDiagnostics ProtocolIE-ID ::= 8 +id-Cause ProtocolIE-ID ::= 9 +id-MBSFN-Area-Configuration-List ProtocolIE-ID ::= 10 +id-PMCH-Configuration-List ProtocolIE-ID ::= 11 +id-PMCH-Configuration-Item ProtocolIE-ID ::= 12 +id-GlobalENB-ID ProtocolIE-ID ::= 13 +id-ENBname ProtocolIE-ID ::= 14 +id-ENB-MBMS-Configuration-data-List ProtocolIE-ID ::= 15 +id-ENB-MBMS-Configuration-data-Item ProtocolIE-ID ::= 16 +id-GlobalMCE-ID ProtocolIE-ID ::= 17 +id-MCEname ProtocolIE-ID ::= 18 +id-MCCHrelatedBCCH-ConfigPerMBSFNArea ProtocolIE-ID ::= 19 +id-MCCHrelatedBCCH-ConfigPerMBSFNArea-Item ProtocolIE-ID ::= 20 +id-TimeToWait ProtocolIE-ID ::= 21 +id-MBSFN-Subframe-Configuration-List ProtocolIE-ID ::= 22 +id-MBSFN-Subframe-Configuration-Item ProtocolIE-ID ::= 23 +id-Common-Subframe-Allocation-Period ProtocolIE-ID ::= 24 +id-MCCH-Update-Time ProtocolIE-ID ::= 25 +id-ENB-MBMS-Configuration-data-List-ConfigUpdate ProtocolIE-ID ::= 26 +id-ENB-MBMS-Configuration-data-ConfigUpdate-Item ProtocolIE-ID ::= 27 +id-MBMS-Service-associatedLogicalM2-ConnectionItem ProtocolIE-ID ::= 28 +id-MBSFN-Area-ID ProtocolIE-ID ::= 29 +id-ResetType ProtocolIE-ID ::= 30 +id-MBMS-Service-associatedLogicalM2-ConnectionListResAck ProtocolIE-ID ::= 31 +id-MBMS-Counting-Request-Session ProtocolIE-ID ::= 32 +id-MBMS-Counting-Request-Session-Item ProtocolIE-ID ::= 33 +id-MBMS-Counting-Result-List ProtocolIE-ID ::= 34 +id-MBMS-Counting-Result-Item ProtocolIE-ID ::= 35 +id-Modulation-Coding-Scheme2 ProtocolIE-ID ::= 36 +id-MCH-Scheduling-PeriodExtended ProtocolIE-ID ::= 37 +id-Alternative-TNL-Information ProtocolIE-ID ::= 38 +id-Overload-Status-Per-PMCH-List ProtocolIE-ID ::= 39 +id-PMCH-Overload-Status ProtocolIE-ID ::= 41 +id-Active-MBMS-Session-List ProtocolIE-ID ::= 42 +id-MBMS-Suspension-Notification-List ProtocolIE-ID ::= 43 +id-MBMS-Suspension-Notification-Item ProtocolIE-ID ::= 44 +id-SC-PTM-Information ProtocolIE-ID ::= 45 +id-Modification-PeriodExtended ProtocolIE-ID ::= 46 +id-Repetition-PeriodExtended ProtocolIE-ID ::= 47 +id-MCH-Scheduling-PeriodExtended2 ProtocolIE-ID ::= 48 +id-Subcarrier-SpacingMBMS ProtocolIE-ID ::= 49 +id-SubframeAllocationExtended ProtocolIE-ID ::= 50 + +END + + +-- ************************************************************** +-- +-- Container definitions +-- +-- ************************************************************** + +M2AP-Containers { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m2ap (4) version1 (1) m2ap-Containers (5) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + maxPrivateIEs, + maxProtocolExtensions, + maxProtocolIEs, + Criticality, + Presence, + PrivateIE-ID, + ProtocolIE-ID +FROM M2AP-CommonDataTypes; + +-- ************************************************************** +-- +-- Class Definition for Protocol Ies +-- +-- ************************************************************** + +M2AP-PROTOCOL-IES ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol Ies +-- +-- ************************************************************** + +M2AP-PROTOCOL-IES-PAIR ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &firstCriticality Criticality, + &FirstValue, + &secondCriticality Criticality, + &SecondValue, + &presence Presence +} +WITH SYNTAX { + ID &id + FIRST CRITICALITY &firstCriticality + FIRST TYPE &FirstValue + SECOND CRITICALITY &secondCriticality + SECOND TYPE &SecondValue + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol Extensions +-- +-- ************************************************************** + +M2AP-PROTOCOL-EXTENSION ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Extension, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + EXTENSION &Extension + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Private Ies +-- +-- ************************************************************** + +M2AP-PRIVATE-IES ::= CLASS { + &id PrivateIE-ID, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Container for Protocol Ies +-- +-- ************************************************************** + +ProtocolIE-Container {M2AP-PROTOCOL-IES : IesSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-Field {{IesSetParam}} + +ProtocolIE-Single-Container {M2AP-PROTOCOL-IES : IesSetParam} ::= + ProtocolIE-Field {{IesSetParam}} + +ProtocolIE-Field {M2AP-PROTOCOL-IES : IesSetParam} ::= SEQUENCE { + id M2AP-PROTOCOL-IES.&id ({IesSetParam}), + criticality M2AP-PROTOCOL-IES.&criticality ({IesSetParam}{@id}), + value M2AP-PROTOCOL-IES.&Value ({IesSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Protocol IE Pairs +-- +-- ************************************************************** + +ProtocolIE-ContainerPair {M2AP-PROTOCOL-IES-PAIR : IesSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-FieldPair {{IesSetParam}} + +ProtocolIE-FieldPair {M2AP-PROTOCOL-IES-PAIR : IesSetParam} ::= SEQUENCE { + id M2AP-PROTOCOL-IES-PAIR.&id ({IesSetParam}), + firstCriticality M2AP-PROTOCOL-IES-PAIR.&firstCriticality ({IesSetParam}{@id}), + firstValue M2AP-PROTOCOL-IES-PAIR.&FirstValue ({IesSetParam}{@id}), + secondCriticality M2AP-PROTOCOL-IES-PAIR.&secondCriticality ({IesSetParam}{@id}), + secondValue M2AP-PROTOCOL-IES-PAIR.&SecondValue ({IesSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container Lists for Protocol IE Containers +-- +-- ************************************************************** + +ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, M2AP-PROTOCOL-IES : IesSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-Container {{IesSetParam}} + +ProtocolIE-ContainerPairList {INTEGER : lowerBound, INTEGER : upperBound, M2AP-PROTOCOL-IES-PAIR : IesSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-ContainerPair {{IesSetParam}} + +-- ************************************************************** +-- +-- Container for Protocol Extensions +-- +-- ************************************************************** + +ProtocolExtensionContainer {M2AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= + SEQUENCE (SIZE (1..maxProtocolExtensions)) OF + ProtocolExtensionField {{ExtensionSetParam}} + +ProtocolExtensionField {M2AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE { + id M2AP-PROTOCOL-EXTENSION.&id ({ExtensionSetParam}), + criticality M2AP-PROTOCOL-EXTENSION.&criticality ({ExtensionSetParam}{@id}), + extensionValue M2AP-PROTOCOL-EXTENSION.&Extension ({ExtensionSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Private Ies +-- +-- ************************************************************** + +PrivateIE-Container {M2AP-PRIVATE-IES : IesSetParam} ::= + SEQUENCE (SIZE (1..maxPrivateIEs)) OF + PrivateIE-Field {{IesSetParam}} + +PrivateIE-Field {M2AP-PRIVATE-IES : IesSetParam} ::= SEQUENCE { + id M2AP-PRIVATE-IES.&id ({IesSetParam}), + criticality M2AP-PRIVATE-IES.&criticality ({IesSetParam}{@id}), + value M2AP-PRIVATE-IES.&Value ({IesSetParam}{@id}) +} + +END + + diff --git a/openair2/M2AP/MESSAGES/asn1tostruct.py b/openair2/M2AP/MESSAGES/asn1tostruct.py new file mode 100644 index 0000000000..8c0f7e8a16 --- /dev/null +++ b/openair2/M2AP/MESSAGES/asn1tostruct.py @@ -0,0 +1,697 @@ +import re, os, sys, string +import datetime +import getopt +import getpass + +version = "1.0.2" + +lines = "" +iesDefs = {} +ieofielist = {} +outdir = './' + +filenames = [] +verbosity = 0 +prefix = "" + +FAIL = '\033[91m' +WARN = '\033[93m' +ENDC = '\033[0m' + +fileprefix = "" +fileprefix_first_upper = "" + +def printFail(string): + sys.stderr.write(FAIL + string + ENDC + "\n") + +def printWarning(string): + print WARN + string + ENDC + +def printDebug(string): + if verbosity > 0: + print string + +def outputHeaderToFile(f, filename): + now = datetime.datetime.now() + f.write("""/* + * 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 + */ + +""") + f.write("/*******************************************************************************\n") + f.write(" * This file had been created by asn1tostruct.py script v%s\n" % (version)) + f.write(" * Please do not modify this file but regenerate it via script.\n") + f.write(" * Created on: %s by %s\n * from %s\n" % (str(now), getpass.getuser(), filenames)) + f.write(" ******************************************************************************/\n") + +def lowerFirstCamelWord(word): + """ puts the first word in a CamelCase Word in lowercase. + + I.e. CustomerID becomes customerID, XMLInfoTest becomes xmlInfoTest + """ + newstr = '' + swapped = word.swapcase() + idx = 0 + + # if it's all-caps, return an all-lowered version + lowered = word.lower() + + if swapped == lowered: + return lowered + + for c in swapped: + if c in string.lowercase: + newstr += c + idx += 1 + else: + break + if idx < 2: + newstr += word[idx:] + else: + newstr = newstr[:-1]+ word[idx-1:] + + return newstr + +def usage(): + print "Python parser for asn1 v%s" % (version) + print "Usage: python asn1tostruct.py [options]" + print "Available options:" + print "-d Enable script debug" + print "-f [file] Input file to parse" + print "-o [dir] Output files to given directory" + print "-h Print this help and return" + +try: + opts, args = getopt.getopt(sys.argv[1:], "df:ho:", ["debug", "file", "help", "outdir"]) +except getopt.GetoptError as err: + # print help information and exit: + usage() + sys.exit(2) + +for o, a in opts: + if o in ("-f", "--file"): + filenames.append(a) + if o in ("-d", "--debug"): + verbosity = 1 + if o in ("-o", "--outdir"): + outdir = a + if outdir.rfind('/') != len(outdir): + outdir += '/' + if o in ("-h", "--help"): + usage() + sys.exit(2) + +for filename in filenames: + file = open(filename, 'r') + for line in file: + # Removing any comment + if line.find('--') >= 0: + line = line[:line.find('--')] + # Removing any carriage return + lines += re.sub('\r', '', line) + + for m in re.findall(r'([a-zA-Z0-9-]+)\s*::=\s+SEQUENCE\s+\(\s*SIZE\s*\(\s*\d+\s*\.\.\s*[0-9a-zA-Z-]+\s*\)\s*\)\s*OF\s+[a-zA-Z-]+\s*\{\s*\{\s*([0-9a-zA-Z-]+)\s*\}\s*\}', lines, re.MULTILINE): + ieofielist[m[0]] = m[1] + for m in re.findall(r'([a-zA-Z0-9-]+)\s*::=\s+E-RAB-IE-ContainerList\s*\{\s*\{\s*([a-zA-Z0-9-]+)\s*\}\s*\}', lines, re.MULTILINE): + ieofielist[m[0]] = m[1] + + for i in re.findall(r'([a-zA-Z0-9-]+)\s+([A-Z0-9-]+)\s*::=\s*\{\s+([\,\|\{\}\t\n\.{3}\ \-a-zA-Z0-9]+)\s+}\n', lines, re.MULTILINE): + ies = [] + maxLength = 0 + # TODO: handle extensions + if i[1].find('EXTENSION') >= 0: + continue + if fileprefix == "": + fileprefix = i[1][:i[1].find('-')].lower() + for j in re.findall(r'\s*\{\s*([a-zA-Z0-9-\ \t]+)\s*\}\s*[\|,]*', i[2], re.MULTILINE): + for k in re.findall(r'ID\s*([a-zA-Z0-9\-]+)\s*CRITICALITY\s*([a-zA-Z0-9\-]+)\s+[A-Z]+\s+([a-zA-Z0-9\-]+)\s*PRESENCE\s*([a-zA-Z0-9\-]+)', j, re.MULTILINE): + printDebug("Got new ie for message " + i[0] + ": " + str(k)) + if len(k[2]) > maxLength: + maxLength = len(k[2]) + ies.append(k) + + if len(ies) > 0: + iesDefs[i[0]] = { "length": maxLength, "ies": ies } + else: + printWarning("Didn't find any information element for message: " + i[0]) + +if len(iesDefs) == 0: + printFail("No Information Element parsed, exiting") + sys.exit(0) + +fileprefix_first_upper = fileprefix[0].upper() + fileprefix[1:] + +f = open(outdir + fileprefix + '_ies_defs.h', 'w') +outputHeaderToFile(f, filename) +f.write("#include \"%s_common.h\"\n\n" % (fileprefix)) +f.write("#ifndef %s_IES_DEFS_H_\n#define %s_IES_DEFS_H_\n\n" % (fileprefix.upper(), fileprefix.upper())) +f.write("/* Define the version of script used to generate this file */\n") +f.write("#define %s_SCRIPT_VERSION (%s)\n\n" % (fileprefix.upper(), re.sub('\.', '', version))) + +for key in iesDefs: + + if key not in ieofielist.values(): + continue + + for (i, j) in ieofielist.items(): + if j == key: + break + + f.write("typedef struct %sIEs_s {\n" % (re.sub('-', '_', i))) + f.write(" A_SEQUENCE_OF(struct %s_s) %s;\n" % (re.sub('IEs', '', re.sub('-', '_', ieofielist[i])), lowerFirstCamelWord(re.sub('IEs', '', re.sub('-', '_', ieofielist[i]))))) + f.write("} %sIEs_t;\n\n" % (re.sub('-', '_', i))) + +for key in iesDefs: + keyupperunderscore = re.sub('-', '_', key.upper()) + keylowerunderscore = re.sub('-', '_', key.lower()) + shift = 0 + + if len(iesDefs[key]["ies"]) == 0: + continue + + # Presence mask + for ie in iesDefs[key]["ies"]: + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] == "optional" or ie[3] == "conditional": + f.write("#define {0:<{pad}} {1}\n".format("%s_%s_PRESENT" % (keyupperunderscore, ieupperunderscore), "(1 << %d)" % shift, + pad=iesDefs[key]["length"] + len(keyupperunderscore) + 9)) + shift += 1 + if (shift > 0): + f.write("\n") + + f.write("typedef struct %s_s {\n" % (re.sub('-', '_', key))) + if (shift > 0): + f.write(" {0:<{pad}} {1};\n".format("uint16_t", "presenceMask", pad=iesDefs[key]["length"] + 2)) + for ie in iesDefs[key]["ies"]: + ieunderscore = re.sub('-', '_', ie[2]) + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + if ie[2] in ieofielist: + f.write(" %sIEs_t %s;" % (re.sub('-', '_', ie[2]), ienameunderscore)) + else: + f.write(" {0:<{pad}} {1};".format("%s_t" % ieunderscore, ienameunderscore, pad=iesDefs[key]["length"] + 2)) + if ie[3] == "optional": + f.write(" ///< Optional field") + elif ie[3] == "conditional": + f.write(" ///< Conditional field") + f.write("\n") + + f.write("} %s_t;\n\n" % (re.sub('-', '_', key))) + +f.write("typedef struct %s_message_s {\n" % (fileprefix)) +f.write(" %s_ProcedureCode_t procedureCode;\n" % (fileprefix_first_upper)) +f.write(" %s_Criticality_t criticality;\n" % (fileprefix_first_upper)) +f.write(" uint8_t direction;\n") +f.write(" union {\n") + +messageList = iesDefs.keys() +messageList.sort() +for message in messageList: + if message in ieofielist.values(): + continue + if len(iesDefs[message]["ies"]) == 0: + continue + f.write(" %s_t %s;\n" % (re.sub('-', '_', message), lowerFirstCamelWord(re.sub('-', '_', message)))) +f.write(" } msg;\n") +f.write("} %s_message;\n\n" % (fileprefix)) + +for key in iesDefs: + if key in ieofielist.values(): + continue + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + keylowerunderscore = re.sub('-', '_', key.lower()) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + f.write("/** \\brief Decode function for %s ies.\n" % (key)) + if len(iesDefs[key]["ies"]) != 0: + f.write(" * \\param %s Pointer to ASN1 structure in which data will be stored\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" * \\param any_p Pointer to the ANY value to decode.\n") + f.write(" **/\n") + f.write("int %s_decode_%s(\n" % (fileprefix, keylowerunderscore)) + + if len(iesDefs[key]["ies"]) != 0: + f.write(" %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" ANY_t *any_p);\n\n") + + if len(iesDefs[key]["ies"]) == 0: + continue + + f.write("/** \\brief Encode function for %s ies.\n" % (key)) + f.write(" * \\param %s Pointer to the ASN1 structure.\n" % (firstlower)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" **/\n") + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstlower)) + f.write(" %s_t *%s);\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + +for key in iesDefs: + if key not in ieofielist.values(): + continue + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + f.write("/** \\brief Encode function for %s ies.\n" % (key)) + f.write(" * \\param %s Pointer to the ASN1 structure.\n" % (firstlower)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" **/\n") + f.write("int %s_encode_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstlower)) + f.write(" %sIEs_t *%sIEs);\n\n" % (asn1cStruct, firstlower)) + f.write("/** \\brief Decode function for %s ies.\n" % (key)) + f.write(" * \\param any_p Pointer to the ANY value to decode.\n") + f.write(" * \\param callback Callback function called when any_p is successfully decoded.\n") + f.write(" **/\n") + f.write("int %s_decode_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" %sIEs_t *%sIEs,\n" % (asn1cStruct, firstlower)) + f.write(" %s_t *%s);\n\n" % (asn1cStruct, lowerFirstCamelWord(asn1cStruct))) + +for key in iesDefs: + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + if key in ieofielist.values(): + f.write("/** \\brief Display %s encapsulated IE using XER encoding.\n" % (asn1cStruct)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" * \\param file File descriptor to write output.\n") + f.write(" **/\n") + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('item', 'list', firstlower.lower()))) + f.write(" asn_app_consume_bytes_f *cb,\n") + f.write(" void *app_key,\n") + f.write(" %sIEs_t *%sIEs);\n\n" % (re.sub('item', 'list', asn1cStruct), firstlower)) + else: + f.write("/** \\brief Display %s message using XER encoding.\n" % (asn1cStruct)) + f.write(" * \\param message_p Pointer to root message.\n") + f.write(" * \\param file File descriptor to write output.\n") + f.write(" **/\n") + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" asn_app_consume_bytes_f *cb,\n") + f.write(" void *app_key,\n") + f.write(" %s_message *message_p);\n\n" % (fileprefix)) + +f.write("int %s_xer__print2sp(const void *buffer, size_t size, void *app_key);\n\n" % (fileprefix.lower())) +f.write("int %s_xer__print2fp(const void *buffer, size_t size, void *app_key);\n\n" % (fileprefix.lower())) +f.write("extern size_t %s_string_total_size;\n\n" % (fileprefix.lower())) +f.write("#endif /* %s_IES_DEFS_H_ */\n\n" % (fileprefix.upper())) + +#Generate Decode functions +f = open(outdir + fileprefix + '_decoder.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n\n" % (fileprefix, fileprefix)) +for key in iesDefs: + if key in ieofielist.values(): + continue + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + if asn1cStruct.rfind('_') == len(asn1cStruct) - 1: + asn1cStruct = asn1cStruct[:-1] + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + ielistname = re.sub('UE', 'ue', asn1cStruct) + ielistnamefirstlower = ielistname[:1].lower() + ielistname[1:] + asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:] + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + iesaccess = "" + if key not in ieofielist.values(): + iesaccess = "%s_ies." % (firstlower) + + f.write("int %s_decode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + if len(iesDefs[key]["ies"]) != 0: + f.write(" %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" ANY_t *any_p) {\n\n") + + f.write(" %s_t %s;\n %s_t *%s_p = &%s;\n" % (asn1cStruct, asn1cStructfirstlower, asn1cStruct, asn1cStructfirstlower, asn1cStructfirstlower)) + f.write(" int i, decoded = 0;\n") + if len(iesDefs[key]["ies"]) != 0: + f.write(" int tempDecoded = 0;\n") + + f.write(" assert(any_p != NULL);\n") + if len(iesDefs[key]["ies"]) != 0: + f.write(" assert(%s != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + + f.write(" %s_DEBUG(\"Decoding message %s (%%s:%%d)\\n\", __FILE__, __LINE__);\n\n" % (fileprefix.upper(), re.sub('-', '_', keyName))) + f.write(" ANY_to_type_aper(any_p, &asn_DEF_%s, (void**)&%s_p);\n\n" % (asn1cStruct, asn1cStructfirstlower)) + f.write(" for (i = 0; i < %s_p->%slist.count; i++) {\n" % (asn1cStructfirstlower, iesaccess)) + f.write(" %s_IE_t *ie_p;\n" % (fileprefix[0].upper() + fileprefix[1:])) + f.write(" ie_p = %s_p->%slist.array[i];\n" % (asn1cStructfirstlower, iesaccess)) + f.write(" switch(ie_p->id) {\n") + for ie in iesDefs[key]["ies"]: + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + ienameunderscorefirstlower = lowerFirstCamelWord(ienameunderscore) + ietypesubst = re.sub('-', '', ie[2]) + ietypeunderscore = re.sub('-', '_', ie[2]) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" case %s_ProtocolIE_ID_%s:\n" % (fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" {\n") + f.write(" %s_t *%s_p = NULL;\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + if ie[3] != "mandatory": + f.write(" %s->presenceMask |= %s_%s_PRESENT;\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore)) + f.write(" tempDecoded = ANY_to_type_aper(&ie_p->value, &asn_DEF_%s, (void**)&%s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (lowerFirstCamelWord(ietypesubst))) + f.write(" %s_ERROR(\"Decoding of IE %s failed\\n\");\n" % (fileprefix.upper(), ienameunderscore)) + f.write(" if (%s_p)\n" % (lowerFirstCamelWord(ietypesubst))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" decoded += tempDecoded;\n") + f.write(" if (asn1_xer_print)\n") + f.write(" xer_fprint(stdout, &asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + if ie[2] in ieofielist.keys(): + f.write(" if (%s_decode_%s(&%s->%s, %s_p) < 0) {\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" %s_ERROR(\"Decoding of encapsulated IE %s failed\\n\");\n" % (fileprefix.upper(), lowerFirstCamelWord(ietypesubst))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" }\n") + else: + f.write(" memcpy(&%s->%s, %s_p, sizeof(%s_t));\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore, lowerFirstCamelWord(ietypesubst), ietypeunderscore)) + #f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" } break;\n") + f.write(" default:\n") + f.write(" %s_ERROR(\"Unknown protocol IE id (%%d) for message %s\\n\", (int)ie_p->id);\n" % (fileprefix.upper(), re.sub('-', '_', structName.lower()))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return decoded;\n") + f.write("}\n\n") + +for key in iesDefs: + if key not in ieofielist.values(): + continue + + keyname = re.sub('IEs', '', re.sub('Item', 'List', key)) + + f.write("int %s_decode_%s(\n" % (fileprefix, re.sub('-', '_', keyname).lower())) + f.write(" %sIEs_t *%sIEs,\n" % (re.sub('-', '_', keyname), lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" %s_t *%s) {\n\n" % (re.sub('-', '_', keyname), lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" int i, decoded = 0;\n") + f.write(" int tempDecoded = 0;\n\n") + + f.write(" assert(%s != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))); + f.write(" assert(%sIEs != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))); + + f.write(" for (i = 0; i < %s->list.count; i++) {\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" %s_IE_t *ie_p = %s->list.array[i];\n" % (fileprefix[0].upper() + fileprefix[1:], lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" switch (ie_p->id) {\n") + for ie in iesDefs[key]["ies"]: + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + f.write(" case %s_ProtocolIE_ID_%s:\n" % (fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" {\n") + f.write(" %s_t *%s_p = NULL;\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" tempDecoded = ANY_to_type_aper(&ie_p->value, &asn_DEF_%s, (void**)&%s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" %s_ERROR(\"Decoding of IE %s for message %s failed\\n\");\n" % (fileprefix.upper(), ienameunderscore, re.sub('-', '_', keyname))) + f.write(" if (%s_p)\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + #f.write(" free(%s_p);\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" decoded += tempDecoded;\n") + f.write(" if (asn1_xer_print)\n") + f.write(" xer_fprint(stdout, &asn_DEF_%s, %s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" ASN_SEQUENCE_ADD(&%sIEs->%s, %s_p);\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)), + re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" } break;\n") + f.write(" default:\n") + f.write(" %s_ERROR(\"Unknown protocol IE id (%%d) for message %s\\n\", (int)ie_p->id);\n" % (fileprefix.upper(), re.sub('-', '_', structName.lower()))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return decoded;\n") + f.write("}\n\n") + + +#Generate IES Encode functions +f = open(outdir + fileprefix + '_encoder.c', 'w') +outputHeaderToFile(f,filename) +f.write("#include \"%s_common.h\"\n" % (fileprefix)) +f.write("#include \"%s_ies_defs.h\"\n\n" % (fileprefix)) +for key in iesDefs: + if key in ieofielist.values(): + continue + + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + if asn1cStruct.rfind('_') == len(asn1cStruct) - 1: + asn1cStruct = asn1cStruct[:-1] + asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:] + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + iesaccess = "" + if key not in ieofielist.values(): + iesaccess = "%s_ies." % (firstwordlower) + + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + # No IE to encode... + if len(iesDefs[key]["ies"]) == 0: + continue + + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstwordlower)) + f.write(" %s_t *%s) {\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + + f.write(" %s_IE_t *ie;\n\n" % (fileprefix_first_upper)) + + f.write(" assert(%s != NULL);\n" % (firstwordlower)); + f.write(" assert(%s != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))); + + for ie in iesDefs[key]["ies"]: + iename = re.sub('-', '_', re.sub('id-', '', ie[0])) + ienameunderscore = re.sub('-', '_', iename) + ienamefirstwordlower = lowerFirstCamelWord(iename) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + ietypeunderscore = re.sub('-', '_', ie[2]) + + if ie[3] != "mandatory": + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" if (%s->presenceMask & %s_%s_PRESENT) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore)) + #f.write(" == %s_%s_PRESENT) {\n" % (keyupperunderscore, ieupperunderscore)) + f.write(" if ((ie = %s_new_ie(%s_ProtocolIE_ID_%s,\n" % (fileprefix, fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" %s_Criticality_%s,\n" % (fileprefix_first_upper, ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + f.write(" &%s->%s)) == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->%slist, ie);\n" % (firstwordlower, iesaccess)) + f.write(" }\n\n") + else: + if ie[2] in ieofielist.keys(): + f.write(" %s_t %s;\n\n" % (ietypeunderscore, ienamefirstwordlower)) + f.write(" memset(&%s, 0, sizeof(%s_t));\n" % (ienamefirstwordlower, ietypeunderscore)) + f.write("\n") + f.write(" if (%s_encode_%s(&%s, &%s->%s) < 0) return -1;\n" % (fileprefix, ietypeunderscore.lower(), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" if ((ie = %s_new_ie(%s_ProtocolIE_ID_%s,\n" % (fileprefix, fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" %s_Criticality_%s,\n" % (fileprefix_first_upper, ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + if ie[2] in ieofielist.keys(): + f.write(" &%s)) == NULL) {\n" % (ienamefirstwordlower)) + else: + f.write(" &%s->%s)) == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->%slist, ie);\n\n" % (firstwordlower, iesaccess)) + if ie[2] in ieofielist.keys(): + f.write(" /* Free any dynamic allocation that is no more used */\n") + f.write(" ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_%s, &%s);\n\n" % (ietypeunderscore, ienamefirstwordlower)) + + f.write(" return 0;\n") + f.write("}\n\n") + +for (key, value) in iesDefs.items(): + if key not in ieofielist.values(): + continue + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + for (i, j) in ieofielist.items(): + if j == key: + break + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', i).lower())) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstwordlower)) + f.write(" %sIEs_t *%sIEs) {\n\n" % (re.sub('-', '_', i), lowerFirstCamelWord(re.sub('-', '_', i)))) + f.write(" int i;\n") + + f.write(" %s_IE_t *ie;\n\n" % (fileprefix_first_upper)) + + f.write(" assert(%s != NULL);\n" % (firstwordlower)); + f.write(" assert(%sIEs != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', i)))); + + f.write(" for (i = 0; i < %sIEs->%s.count; i++) {\n" % (firstwordlower, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" if ((ie = %s_new_ie(%s_ProtocolIE_ID_%s,\n" % (fileprefix, fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" %s_Criticality_%s,\n" % (fileprefix_first_upper, ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + f.write(" %sIEs->%s.array[i])) == NULL) {\n" % (firstwordlower, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->list, ie);\n" % (firstwordlower)) + f.write(" }\n") + f.write(" return 0;\n") + f.write("}\n\n") + +#Generate xer print functions +f = open(outdir + fileprefix + '_xer_print.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include \n") +f.write("#include \n\n") +f.write("#include \n#include \n\n") +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n\n" % (fileprefix, fileprefix)) + +f.write("size_t %s_string_total_size = 0;\n\n" % (fileprefix.lower())) +f.write("""int +%s_xer__print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + +""" % (fileprefix.lower())) + +f.write("""int %s_xer__print2sp(const void *buffer, size_t size, void *app_key) { + char *string = (char *)app_key; + + /* Copy buffer to the formatted string */ + memcpy(&string[%s_string_total_size], buffer, size); + + %s_string_total_size += size; + + return 0; +} + +""" % (fileprefix.lower(), fileprefix.lower(), fileprefix.lower())) + +f.write("""static asn_enc_rval_t +xer_encode_local(asn_TYPE_descriptor_t *td, void *sptr, + asn_app_consume_bytes_f *cb, void *app_key, int indent) { + asn_enc_rval_t er, tmper; + const char *mname; + size_t mlen; + int xcan = 2; + + if(!td || !sptr) goto cb_failed; + + mname = td->xml_tag; + mlen = strlen(mname); + + _i_ASN_TEXT_INDENT(0, indent); + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = td->xer_encoder(td, sptr, indent + 1, XER_F_BASIC, cb, app_key); + if(tmper.encoded == -1) return tmper; + + _ASN_CALLBACK3("\\n", xcan); + + er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} +""") + +for (key, value) in iesDefs.items(): + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + iesStructName = lowerFirstCamelWord(re.sub('-', '_', key)) + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + + if key in ieofielist.values(): + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('ies', '', re.sub('item', 'list', re.sub('-', '_', key).lower())))) + else: + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('ies', '', re.sub('-', '_', key).lower()))) + #f.write(" FILE *file,\n") + f.write(" asn_app_consume_bytes_f *cb,\n") + f.write(" void *app_key,\n") + if key in ieofielist.values(): + iesStructName = lowerFirstCamelWord(re.sub('Item', 'List', re.sub('-', '_', key))) + f.write(" %sIEs_t *%s) {\n\n" % (re.sub('IEs', '', re.sub('Item', 'List', re.sub('-', '_', key))), iesStructName)) + f.write(" int i;\n") + f.write(" asn_enc_rval_t er;\n") + else: + f.write(" %s_message *message_p)\n{\n" % (fileprefix)) + f.write(" %s_t *%s;\n" % (re.sub('-', '_', key), iesStructName)) + f.write(" asn_enc_rval_t er;\n") + #f.write(" void *app_key = (void *)file;\n") + #f.write(" asn_app_consume_bytes_f *cb = %s_xer__print2fp;\n\n" % (fileprefix.lower())) + + f.write(" %s = &message_p->msg.%s;\n\n" % (iesStructName, iesStructName)) + + if key in ieofielist.values(): + # Increase indentation level + f.write(" for (i = 0; i < %s->%s.count; i++) {\n" % (iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + #f.write(" xer_fprint(file, &asn_DEF_%s, %s->%s.array[i]);\n" % (ietypeunderscore, iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" er = xer_encode(&asn_DEF_%s, %s->%s.array[i], XER_F_BASIC, cb, app_key);\n" % (ietypeunderscore, iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" }\n") + else: + f.write(" cb(\"<%s-PDU>\\n\", %d, app_key);\n" % (key, len("<%s-PDU>\n" % (key)))) + f.write(" xer_encode_local(&asn_DEF_%s_Criticality, &message_p->criticality, cb, app_key, 1);\n" % fileprefix_first_upper) + f.write(" xer_encode_local(&asn_DEF_%s_ProcedureCode, &message_p->procedureCode, cb, app_key, 1);\n" % fileprefix_first_upper) + + f.write(" cb(\" <%s>\\n\", %d, app_key);\n" % (key, len(" <%s>\n" % (key)))) + + for ie in iesDefs[key]["ies"]: + iename = re.sub('-', '_', re.sub('id-', '', ie[0])) + ienameunderscore = re.sub('-', '_', iename) + ienamefirstwordlower = lowerFirstCamelWord(iename) + ietypeunderscore = re.sub('-', '_', ie[2]) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] != "mandatory": + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" if (%s->presenceMask & %s_%s_PRESENT)\n " % (iesStructName, keyupperunderscore, ieupperunderscore)) + + # Is it an encapsulated IE ? + if ie[2] in ieofielist.keys(): + f.write(" %s_xer_print_%s(cb, app_key, &%s->%s);\n" % (fileprefix, re.sub('ies', '', re.sub('-', '_', ie[2]).lower()), iesStructName, ienamefirstwordlower)) + else: + f.write(" xer_encode_local(&asn_DEF_%s, &%s->%s, cb, app_key, 2);\n" % (ietypeunderscore, iesStructName, ienamefirstwordlower)) + f.write(" cb(\" \\n\", %d, app_key);\n" % (key, len(" \n" % (key)))) + f.write(" cb(\"\\n\", %d, app_key);\n" % (key, len("\n" % (key)))) + + f.write(" _ASN_ENCODED_OK(er);\n") + #if key not in ieofielist.values(): + #f.write("cb_failed:\n") + #f.write(" return er;\n") + f.write("}\n\n") diff --git a/openair2/M2AP/m2ap_MCE.c b/openair2/M2AP/m2ap_MCE.c new file mode 100644 index 0000000000..096f3cabee --- /dev/null +++ b/openair2/M2AP/m2ap_MCE.c @@ -0,0 +1,733 @@ +/* + * 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 m2ap_MCE.c + * \brief m2ap tasks for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include +#include +#include +#include + +#include "intertask_interface.h" + +#include "m2ap_MCE.h" +#include "m2ap_MCE_defs.h" +#include "m2ap_MCE_management_procedures.h" +#include "m2ap_MCE_handler.h" +#include "m2ap_MCE_generate_messages.h" +#include "m2ap_common.h" +#include "m2ap_MCE_interface_management.h" +#include "m2ap_ids.h" +#include "m2ap_timers.h" + +#include "queue.h" +#include "assertions.h" +#include "conversions.h" + +struct m2ap_mce_map; +struct m2ap_MCE_data_s; + +m2ap_setup_req_t *m2ap_mce_data_from_enb; + +RB_PROTOTYPE(m2ap_mce_map, m2ap_MCE_data_s, entry, m2ap_MCE_compare_assoc_id); + +static +void m2ap_MCE_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind); + +static +void m2ap_MCE_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp); + +static +void m2ap_MCE_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind); + +static +void m2ap_MCE_handle_register_MCE(instance_t instance, + m2ap_register_mce_req_t *m2ap_register_MCE); +static +void m2ap_MCE_register_MCE(m2ap_MCE_instance_t *instance_p, + net_ip_address_t *target_MCE_ip_addr, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t mce_port_for_M2C, + int multi_sd); + +//static +//void m2ap_MCE_handle_handover_req(instance_t instance, +// m2ap_handover_req_t *m2ap_handover_req); +// +//static +//void m2ap_MCE_handle_handover_req_ack(instance_t instance, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack); +// +//static +//void m2ap_MCE_ue_context_release(instance_t instance, +// m2ap_ue_context_release_t *m2ap_ue_context_release); +// + +static +void m2ap_MCE_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) { + int result; + DevAssert(sctp_data_ind != NULL); + m2ap_MCE_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream, + sctp_data_ind->buffer, sctp_data_ind->buffer_length); + result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +} + +static +void m2ap_MCE_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { + + DevAssert(sctp_new_association_resp != NULL); + + if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + LOG_W(M2AP, "Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n", + sctp_new_association_resp->sctp_state, + instance, + sctp_new_association_resp->ulp_cnx_id); + + if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) + //proto_agent_stop(instance); + //f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); + return; // exit -1 for debugging + } + + // go to an init func + m2ap_mce_data_from_enb = (m2ap_setup_req_t *)calloc(1, sizeof(m2ap_setup_req_t)); + // save the assoc id + m2ap_mce_data_from_enb->assoc_id = sctp_new_association_resp->assoc_id; + m2ap_mce_data_from_enb->sctp_in_streams = sctp_new_association_resp->in_streams; + m2ap_mce_data_from_enb->sctp_out_streams = sctp_new_association_resp->out_streams; + + + + // m2ap_MCE_instance_t *instance_p; + // m2ap_MCE_data_t *m2ap_mce_data_p; + // DevAssert(sctp_new_association_resp != NULL); + // printf("m2ap_MCE_handle_sctp_association_resp at 1\n"); + // dump_mce_trees_m2(); + // instance_p = instance;//m2ap_MCE_get_instance(instance); + // DevAssert(instance_p != NULL); + + // /* if the assoc_id is already known, it is certainly because an IND was received + // * before. In this case, just update streams and return + // */ + // if (sctp_new_association_resp->assoc_id != -1) { + // m2ap_mce_data_p = m2ap_get_MCE(instance_p, sctp_new_association_resp->assoc_id, + // sctp_new_association_resp->ulp_cnx_id); + + // if (m2ap_mce_data_p != NULL) { + // /* some sanity check - to be refined at some point */ + // if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + // M2AP_ERROR("m2ap_mce_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n"); + // abort(); + // } + + // m2ap_mce_data_p->in_streams = sctp_new_association_resp->in_streams; + // m2ap_mce_data_p->out_streams = sctp_new_association_resp->out_streams; + // return; + // } + // } + + // m2ap_mce_data_p = m2ap_get_MCE(instance_p, -1, + // sctp_new_association_resp->ulp_cnx_id); + // DevAssert(m2ap_mce_data_p != NULL); + // printf("m2ap_MCE_handle_sctp_association_resp at 2\n"); + // dump_mce_trees_m2(); + + // if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + // M2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n", + // sctp_new_association_resp->sctp_state, + // instance, + // sctp_new_association_resp->ulp_cnx_id); + // //m2ap_eNB_handle_m2_setup_message(instance_p, m2ap_mce_data_p, + // //sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); + // return; + // } + + // printf("m2ap_MCE_handle_sctp_association_resp at 3\n"); + // dump_mce_trees_m2(); + // /* Update parameters */ + // m2ap_mce_data_p->assoc_id = sctp_new_association_resp->assoc_id; + // m2ap_mce_data_p->in_streams = sctp_new_association_resp->in_streams; + // m2ap_mce_data_p->out_streams = sctp_new_association_resp->out_streams; + // printf("m2ap_MCE_handle_sctp_association_resp at 4\n"); + // dump_mce_trees_m2(); + // /* Prepare new m2 Setup Request */ + // //m2ap_MCE_generate_m2_setup_request(instance_p, m2ap_mce_data_p); +} + +static +void m2ap_MCE_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind) { + //m2ap_MCE_instance_t *instance_p; + //m2ap_MCE_data_t *m2ap_mce_data_p; + //printf("m2ap_MCE_handle_sctp_association_ind at 1 (called for instance %d)\n", instance); + ///dump_mce_trees_m2(); + ///DevAssert(sctp_new_association_ind != NULL); + ///instance_p = instance;//m2ap_MCE_get_instance(instance); + ///DevAssert(instance_p != NULL); + ///m2ap_mce_data_p = m2ap_get_MCE(instance_p, sctp_new_association_ind->assoc_id, -1); + + ///if (m2ap_mce_data_p != NULL) abort(); + + ///// DevAssert(m2ap_enb_data_p != NULL); + ///if (m2ap_mce_data_p == NULL) { + /// /* Create new MCE descriptor */ + /// m2ap_mce_data_p = calloc(1, sizeof(*m2ap_mce_data_p)); + /// DevAssert(m2ap_mce_data_p != NULL); + /// m2ap_mce_data_p->cnx_id = m2ap_MCE_fetch_add_global_cnx_id(); + /// m2ap_mce_data_p->m2ap_MCE_instance = instance_p; + /// /* Insert the new descriptor in list of known MCE + /// * but not yet associated. + /// */ + /// RB_INSERT(m2ap_mce_map, &instance_p->m2ap_mce_head, m2ap_mce_data_p); + /// m2ap_mce_data_p->state = M2AP_MCE_STATE_CONNECTED; + /// instance_p->m2_target_mce_nb++; + + /// if (instance_p->m2_target_mce_pending_nb > 0) { + /// instance_p->m2_target_mce_pending_nb--; + /// } + ///} else { + /// M2AP_WARN("m2ap_mce_data_p already exists\n"); + ///} + + ///printf("m2ap_MCE_handle_sctp_association_ind at 2\n"); + ///dump_mce_trees_m2(); + ////* Update parameters */ + ///m2ap_mce_data_p->assoc_id = sctp_new_association_ind->assoc_id; + ///m2ap_mce_data_p->in_streams = sctp_new_association_ind->in_streams; + ///m2ap_mce_data_p->out_streams = sctp_new_association_ind->out_streams; + ///printf("m2ap_MCE_handle_sctp_association_ind at 3\n"); + ///dump_mce_trees_m2(); +} + +int m2ap_MCE_init_sctp (m2ap_MCE_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t mce_port_for_M2C) { + // Create and alloc new message + MessageDef *message; + sctp_init_t *sctp_init = NULL; + DevAssert(instance_p != NULL); + DevAssert(local_ip_addr != NULL); + message = itti_alloc_new_message (TASK_M2AP_MCE, SCTP_INIT_MSG_MULTI_REQ); + sctp_init = &message->ittiMsg.sctp_init_multi; + sctp_init->port = mce_port_for_M2C; + sctp_init->ppid = M2AP_SCTP_PPID; + sctp_init->ipv4 = 1; + sctp_init->ipv6 = 0; + sctp_init->nb_ipv4_addr = 1; +#if 0 + memcpy(&sctp_init->ipv4_address, + local_ip_addr, + sizeof(*local_ip_addr)); +#endif + sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address); + /* + * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * * * * Disable it for now. + */ + sctp_init->nb_ipv6_addr = 0; + sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1"; + return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message); +} + +static void m2ap_MCE_register_MCE(m2ap_MCE_instance_t *instance_p, + net_ip_address_t *target_MCE_ip_address, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t mce_port_for_M2C, + int multi_sd) { + MessageDef *message = NULL; + sctp_new_association_req_multi_t *sctp_new_association_req = NULL; + m2ap_MCE_data_t *m2ap_mce_data = NULL; + DevAssert(instance_p != NULL); + DevAssert(target_MCE_ip_address != NULL); + message = itti_alloc_new_message(TASK_M2AP_MCE, SCTP_NEW_ASSOCIATION_REQ_MULTI); + sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi; + sctp_new_association_req->port = mce_port_for_M2C; + sctp_new_association_req->ppid = M2AP_SCTP_PPID; + sctp_new_association_req->in_streams = in_streams; + sctp_new_association_req->out_streams = out_streams; + sctp_new_association_req->multi_sd = multi_sd; + memcpy(&sctp_new_association_req->remote_address, + target_MCE_ip_address, + sizeof(*target_MCE_ip_address)); + memcpy(&sctp_new_association_req->local_address, + local_ip_addr, + sizeof(*local_ip_addr)); + /* Create new MCE descriptor */ + m2ap_mce_data = calloc(1, sizeof(*m2ap_mce_data)); + DevAssert(m2ap_mce_data != NULL); + m2ap_mce_data->cnx_id = m2ap_MCE_fetch_add_global_cnx_id(); + sctp_new_association_req->ulp_cnx_id = m2ap_mce_data->cnx_id; + m2ap_mce_data->assoc_id = -1; + m2ap_mce_data->m2ap_MCE_instance = instance_p; + /* Insert the new descriptor in list of known MCE + * but not yet associated. + */ + RB_INSERT(m2ap_mce_map, &instance_p->m2ap_mce_head, m2ap_mce_data); + m2ap_mce_data->state = M2AP_MCE_STATE_WAITING; + instance_p->m2_target_mce_nb ++; + instance_p->m2_target_mce_pending_nb ++; + itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message); +} + +static +void m2ap_MCE_handle_register_MCE(instance_t instance, + m2ap_register_mce_req_t *m2ap_register_MCE) { + m2ap_MCE_instance_t *new_instance; + DevAssert(m2ap_register_MCE != NULL); + /* Look if the provided instance already exists */ + new_instance = m2ap_MCE_get_instance(instance); + + if (new_instance != NULL) { + /* Checks if it is a retry on the same MCE */ + DevCheck(new_instance->MCE_id == m2ap_register_MCE->MCE_id, new_instance->MCE_id, m2ap_register_MCE->MCE_id, 0); + DevCheck(new_instance->cell_type == m2ap_register_MCE->cell_type, new_instance->cell_type, m2ap_register_MCE->cell_type, 0); + DevCheck(new_instance->tac == m2ap_register_MCE->tac, new_instance->tac, m2ap_register_MCE->tac, 0); + DevCheck(new_instance->mcc == m2ap_register_MCE->mcc, new_instance->mcc, m2ap_register_MCE->mcc, 0); + DevCheck(new_instance->mnc == m2ap_register_MCE->mnc, new_instance->mnc, m2ap_register_MCE->mnc, 0); + M2AP_WARN("MCE[%d] already registered\n", instance); + } else { + new_instance = calloc(1, sizeof(m2ap_MCE_instance_t)); + DevAssert(new_instance != NULL); + RB_INIT(&new_instance->m2ap_mce_head); + /* Copy usefull parameters */ + new_instance->instance = instance; + new_instance->MCE_name = m2ap_register_MCE->MCE_name; + new_instance->MCE_id = m2ap_register_MCE->MCE_id; + new_instance->cell_type = m2ap_register_MCE->cell_type; + new_instance->tac = m2ap_register_MCE->tac; + new_instance->mcc = m2ap_register_MCE->mcc; + new_instance->mnc = m2ap_register_MCE->mnc; + new_instance->mnc_digit_length = m2ap_register_MCE->mnc_digit_length; + new_instance->num_cc = m2ap_register_MCE->num_cc; + + m2ap_id_manager_init(&new_instance->id_manager); + m2ap_timers_init(&new_instance->timers, + m2ap_register_MCE->t_reloc_prep, + m2ap_register_MCE->tm2_reloc_overall); + + for (int i = 0; i< m2ap_register_MCE->num_cc; i++) { + new_instance->eutra_band[i] = m2ap_register_MCE->eutra_band[i]; + new_instance->downlink_frequency[i] = m2ap_register_MCE->downlink_frequency[i]; + new_instance->uplink_frequency_offset[i] = m2ap_register_MCE->uplink_frequency_offset[i]; + new_instance->Nid_cell[i] = m2ap_register_MCE->Nid_cell[i]; + new_instance->N_RB_DL[i] = m2ap_register_MCE->N_RB_DL[i]; + new_instance->frame_type[i] = m2ap_register_MCE->frame_type[i]; + new_instance->fdd_earfcn_DL[i] = m2ap_register_MCE->fdd_earfcn_DL[i]; + new_instance->fdd_earfcn_UL[i] = m2ap_register_MCE->fdd_earfcn_UL[i]; + } + + DevCheck(m2ap_register_MCE->nb_m2 <= M2AP_MAX_NB_MCE_IP_ADDRESS, + M2AP_MAX_NB_MCE_IP_ADDRESS, m2ap_register_MCE->nb_m2, 0); + memcpy(new_instance->target_mce_m2_ip_address, + m2ap_register_MCE->target_mce_m2_ip_address, + m2ap_register_MCE->nb_m2 * sizeof(net_ip_address_t)); + new_instance->nb_m2 = m2ap_register_MCE->nb_m2; + new_instance->mce_m2_ip_address = m2ap_register_MCE->mce_m2_ip_address; + new_instance->sctp_in_streams = m2ap_register_MCE->sctp_in_streams; + new_instance->sctp_out_streams = m2ap_register_MCE->sctp_out_streams; + new_instance->mce_port_for_M2C = m2ap_register_MCE->mce_port_for_M2C; + /* Add the new instance to the list of MCE (meaningfull in virtual mode) */ + m2ap_MCE_insert_new_instance(new_instance); + M2AP_INFO("Registered new MCE[%d] and %s MCE id %u\n", + instance, + m2ap_register_MCE->cell_type == CELL_MACRO_ENB ? "macro" : "home", + m2ap_register_MCE->MCE_id); + + /* initiate the SCTP listener */ + if (m2ap_MCE_init_sctp(new_instance,&m2ap_register_MCE->mce_m2_ip_address,m2ap_register_MCE->mce_port_for_M2C) < 0 ) { + M2AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n"); + return; + } + + M2AP_INFO("MCE[%d] MCE id %u acting as a listner (server)\n", + instance, m2ap_register_MCE->MCE_id); + } +} + +static +void m2ap_MCE_handle_sctp_init_msg_multi_cnf( + instance_t instance_id, + sctp_init_msg_multi_cnf_t *m) { + m2ap_MCE_instance_t *instance; + int index; + DevAssert(m != NULL); + instance = m2ap_MCE_get_instance(instance_id); + DevAssert(instance != NULL); + instance->multi_sd = m->multi_sd; + + /* Exit if CNF message reports failure. + * Failure means multi_sd < 0. + */ + if (instance->multi_sd < 0) { + M2AP_ERROR("Error: be sure to properly configure M2 in your configuration file.\n"); + DevAssert(instance->multi_sd >= 0); + } + + /* Trying to connect to the provided list of MCE ip address */ + + for (index = 0; index < instance->nb_m2; index++) { + M2AP_INFO("MCE[%d] MCE id %u acting as an initiator (client)\n", + instance_id, instance->MCE_id); + m2ap_MCE_register_MCE(instance, + &instance->target_mce_m2_ip_address[index], + &instance->mce_m2_ip_address, + instance->sctp_in_streams, + instance->sctp_out_streams, + instance->mce_port_for_M2C, + instance->multi_sd); + } +} + +//static +//void m2ap_MCE_handle_handover_req(instance_t instance, +// m2ap_handover_req_t *m2ap_handover_req) +//{ +// m2ap_MCE_instance_t *instance_p; +// m2ap_MCE_data_t *target; +// m2ap_id_manager *id_manager; +// int ue_id; +// +// int target_pci = m2ap_handover_req->target_physCellId; +// +// instance_p = m2ap_MCE_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m2ap_is_MCE_pci_in_list(target_pci); +// DevAssert(target != NULL); +// +// /* allocate m2ap ID */ +// id_manager = &instance_p->id_manager; +// ue_id = m2ap_allocate_new_id(id_manager); +// if (ue_id == -1) { +// M2AP_ERROR("could not allocate a new M2AP UE ID\n"); +// /* TODO: cancel handover: send (to be defined) message to RRC */ +// exit(1); +// } +// /* id_source is ue_id, id_target is unknown yet */ +// m2ap_set_ids(id_manager, ue_id, m2ap_handover_req->rnti, ue_id, -1); +// m2ap_id_set_state(id_manager, ue_id, M2ID_STATE_SOURCE_PREPARE); +// m2ap_set_reloc_prep_timer(id_manager, ue_id, +// m2ap_timer_get_tti(&instance_p->timers)); +// m2ap_id_set_target(id_manager, ue_id, target); +// +// m2ap_MCE_generate_m2_handover_request(instance_p, target, m2ap_handover_req, ue_id); +//} + +//static +//void m2ap_MCE_handle_handover_req_ack(instance_t instance, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack) +//{ +// /* TODO: remove this hack (the goal is to find the correct +// * eNodeB structure for the other end) - we need a proper way for RRC +// * and M2AP to identify eNodeBs +// * RRC knows about mod_id and M2AP knows about MCE_id (MCE_ID in +// * the configuration file) +// * as far as I understand.. CROUX +// */ +// m2ap_MCE_instance_t *instance_p; +// m2ap_MCE_data_t *target; +// int source_assoc_id = m2ap_handover_req_ack->source_assoc_id; +// int ue_id; +// int id_source; +// int id_target; +// +// instance_p = m2ap_MCE_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m2ap_get_MCE(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// /* rnti is a new information, save it */ +// ue_id = m2ap_handover_req_ack->m2_id_target; +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// m2ap_set_ids(&instance_p->id_manager, ue_id, m2ap_handover_req_ack->rnti, id_source, id_target); +// +// m2ap_MCE_generate_m2_handover_request_ack(instance_p, target, m2ap_handover_req_ack); +//} +// +//static +//void m2ap_MCE_ue_context_release(instance_t instance, +// m2ap_ue_context_release_t *m2ap_ue_context_release) +//{ +// m2ap_MCE_instance_t *instance_p; +// m2ap_MCE_data_t *target; +// int source_assoc_id = m2ap_ue_context_release->source_assoc_id; +// int ue_id; +// instance_p = m2ap_MCE_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m2ap_get_MCE(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// m2ap_MCE_generate_m2_ue_context_release(instance_p, target, m2ap_ue_context_release); +// +// /* free the M2AP UE ID */ +// ue_id = m2ap_find_id_from_rnti(&instance_p->id_manager, m2ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M2AP_ERROR("could not find UE %x\n", m2ap_ue_context_release->rnti); +// exit(1); +// } +// m2ap_release_id(&instance_p->id_manager, ue_id); +//} + +void MCE_task_send_sctp_init_req(instance_t enb_id, m2ap_mce_sctp_req_t * m2ap_mce_sctp_req) { + // 1. get the itti msg, and retrive the enb_id from the message + // 2. use RC.rrc[enb_id] to fill the sctp_init_t with the ip, port + // 3. creat an itti message to init + + LOG_I(M2AP, "M2AP_SCTP_REQ(create socket)\n"); + MessageDef *message_p = NULL; + + message_p = itti_alloc_new_message (TASK_M2AP_MCE, SCTP_INIT_MSG); + + // if( m2ap_mce_sctp_req == NULL ){ + // message_p->ittiMsg.sctp_init.port = M2AP_PORT_NUMBER; + // message_p->ittiMsg.sctp_init.ppid = M2AP_SCTP_PPID; + // message_p->ittiMsg.sctp_init.ipv4 = 1; + // message_p->ittiMsg.sctp_init.ipv6 = 0; + // message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1; + // //message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr); + // message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr("127.0.0.7"); + // /* + // * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + // * * * * Disable it for now. + // */ + // message_p->ittiMsg.sctp_init.nb_ipv6_addr = 0; + // message_p->ittiMsg.sctp_init.ipv6_address[0] = "0:0:0:0:0:0:0:1"; + // }else{ + message_p->ittiMsg.sctp_init.port = m2ap_mce_sctp_req->mce_port_for_M2C; + message_p->ittiMsg.sctp_init.ppid = M2AP_SCTP_PPID; + message_p->ittiMsg.sctp_init.ipv4 = 1; + message_p->ittiMsg.sctp_init.ipv6 = 0; + message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1; + //message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr); + message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(m2ap_mce_sctp_req->mce_m2_ip_address.ipv4_address); + /* + * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * * * * Disable it for now. + */ + message_p->ittiMsg.sctp_init.nb_ipv6_addr = 0; + message_p->ittiMsg.sctp_init.ipv6_address[0] = "0:0:0:0:0:0:0:1"; + // } + + itti_send_msg_to_task(TASK_SCTP, enb_id, message_p); +} + +void *m2ap_MCE_task(void *arg) { + MessageDef *received_msg = NULL; + int result; + M2AP_DEBUG("Starting M2AP layer\n"); + m2ap_MCE_prepare_internal_data(); + itti_mark_task_ready(TASK_M2AP_MCE); + + //MCE_task_send_sctp_init_req(0,NULL); + + + while (1) { + itti_receive_msg(TASK_M2AP_MCE, &received_msg); + + switch (ITTI_MSG_ID(received_msg)) { + case MESSAGE_TEST: + LOG_W(M2AP,"MCE Received MESSAGE_TEST Message\n"); + //MessageDef * message_p = itti_alloc_new_message(TASK_M2AP_MCE, MESSAGE_TEST); + //itti_send_msg_to_task(TASK_M3AP, 1/*ctxt_pP->module_id*/, message_p); + break; + case TERMINATE_MESSAGE: + M2AP_WARN(" *** Exiting M2AP thread\n"); + itti_exit_task(); + break; + + case M2AP_MCE_SCTP_REQ: + MCE_task_send_sctp_init_req(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MCE_SCTP_REQ(received_msg)); + break; + + case M2AP_SUBFRAME_PROCESS: + m2ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg)); + break; + + case M2AP_REGISTER_MCE_REQ: + LOG_I(M2AP,"MCE Received M2AP_REGISTER_MCE_REQ Message\n"); + m2ap_MCE_handle_register_MCE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_REGISTER_MCE_REQ(received_msg)); + break; + + case M2AP_SETUP_RESP: + LOG_I(M2AP,"MCE Received M2AP_SETUP_RESP Message\n"); + MCE_send_M2_SETUP_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_SETUP_RESP(received_msg)); + break; + + case M2AP_SETUP_FAILURE: + LOG_I(M2AP,"MCE Received M2AP_SETUP_FAILURE Message\n"); + MCE_send_M2_SETUP_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_SETUP_FAILURE(received_msg)); + break; + + case M2AP_MBMS_SCHEDULING_INFORMATION: + LOG_I(M2AP,"MCE Received M2AP_MBMS_SCHEDULING_INFORMATION Message\n"); + MCE_send_MBMS_SCHEDULING_INFORMATION(0, + &M2AP_MBMS_SCHEDULING_INFORMATION(received_msg)); + break; + + case M2AP_MBMS_SESSION_START_REQ: + LOG_I(M2AP,"MCE Received M2AP_MBMS_SESSION_START_REQ Message\n"); + MCE_send_MBMS_SESSION_START_REQUEST(0, + &M2AP_MBMS_SESSION_START_REQ(received_msg)); + break; + + case M2AP_MBMS_SESSION_STOP_REQ: + LOG_I(M2AP,"MCE Received M2AP_MBMS_SESSION_STOP_REQ Message\n"); + MCE_send_MBMS_SESSION_STOP_REQUEST(0, + &M2AP_MBMS_SESSION_STOP_REQ(received_msg)); + break; + + case M2AP_MBMS_SESSION_UPDATE_REQ: + LOG_I(M2AP,"MCE Received M2AP_MBMS_SESSION_UPDATE_REQ Message\n"); + MCE_send_MBMS_SESSION_UPDATE_REQUEST(0, + &M2AP_MBMS_SESSION_UPDATE_REQ(received_msg)); + break; + + case M2AP_RESET: + LOG_I(M2AP,"MCE Received M2AP_RESET Message\n"); + MCE_send_RESET(0, + &M2AP_RESET(received_msg)); + break; + + case M2AP_ENB_CONFIGURATION_UPDATE_ACK: + LOG_I(M2AP,"MCE Received M2AP_ENB_CONFIGURATION_UPDATE_ACK Message\n"); + MCE_send_ENB_CONFIGURATION_UPDATE_ACKNOWLEDGE(0, + &M2AP_ENB_CONFIGURATION_UPDATE_ACK(received_msg)); + break; + + case M2AP_ENB_CONFIGURATION_UPDATE_FAILURE: + LOG_I(M2AP,"MCE Received M2AP_ENB_CONFIGURATION_UPDATE_FAILURE Message\n"); + MCE_send_ENB_CONFIGURATION_UPDATE_FAILURE(0, + &M2AP_ENB_CONFIGURATION_UPDATE_FAILURE(received_msg)); + break; + + + case M2AP_MCE_CONFIGURATION_UPDATE: + LOG_I(M2AP,"MCE Received M2AP_MCE_CONFIGURATION_UPDATE Message\n"); + //MCE_send_MCE_CONFIGURATION_UPDATE(0, + //&M2AP_MCE_CONFIGURATION_UPDATE(received_msg)); + break; + + +// case M2AP_HANDOVER_REQ: +// m2ap_MCE_handle_handover_req(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M2AP_HANDOVER_REQ(received_msg)); +// break; +// +// case M2AP_HANDOVER_REQ_ACK: +// m2ap_MCE_handle_handover_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M2AP_HANDOVER_REQ_ACK(received_msg)); +// break; +// +// case M2AP_UE_CONTEXT_RELEASE: +// m2ap_MCE_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M2AP_UE_CONTEXT_RELEASE(received_msg)); +// break; +// + case SCTP_INIT_MSG_MULTI_CNF: + LOG_D(M2AP,"MCE Received SCTP_INIT_MSG_MULTI_CNF Message\n"); + m2ap_MCE_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_init_msg_multi_cnf); + break; + + case SCTP_NEW_ASSOCIATION_RESP: + LOG_D(M2AP,"MCE Received SCTP_NEW_ASSOCIATION_RESP Message\n"); + m2ap_MCE_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_resp); + break; + + case SCTP_NEW_ASSOCIATION_IND: + LOG_D(M2AP,"MCE Received SCTP_NEW_ASSOCIATION Message\n"); + m2ap_MCE_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_ind); + break; + + case SCTP_DATA_IND: + LOG_D(M2AP,"MCE Received SCTP_DATA_IND Message\n"); + m2ap_MCE_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_data_ind); + break; + + default: + M2AP_ERROR("MCE Received unhandled message: %d:%s\n", + ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + received_msg = NULL; + } + + return NULL; +} + +#include "common/config/config_userapi.h" + +int is_m2ap_MCE_enabled(void) +{ + static volatile int config_loaded = 0; + static volatile int enabled = 0; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + if (pthread_mutex_lock(&mutex)) goto mutex_error; + + if (config_loaded) { + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + return enabled; + } + + char *enable_m2 = NULL; + paramdef_t p[] = { + { "enable_mce_m2", "yes/no", 0, strptr:&enable_m2, defstrval:"", TYPE_STRING, 0 } + }; + + /* TODO: do it per module - we check only first MCE */ + config_get(p, sizeof(p)/sizeof(paramdef_t), "MCEs.[0]"); + if (enable_m2 != NULL && strcmp(enable_m2, "yes") == 0) + enabled = 1; + + config_loaded = 1; + + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + + return enabled; + +mutex_error: + LOG_E(M2AP, "mutex error\n"); + exit(1); +} diff --git a/openair2/M2AP/m2ap_MCE.h b/openair2/M2AP/m2ap_MCE.h new file mode 100644 index 0000000000..563b860883 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE.h @@ -0,0 +1,55 @@ +/* + * 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 m2ap_MCE.h + * \brief m2ap tasks for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include + +/** @defgroup _m2ap_impl_ M2AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef M2AP_MCE_H_ +#define M2AP_MCE_H_ + +#include "m2ap_MCE_defs.h" + + +int m2ap_MCE_init_sctp (m2ap_MCE_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t enb_port_for_M2C); + +void *m2ap_MCE_task(void *arg); + +int is_m2ap_MCE_enabled(void); + +#endif /* M2AP_MCE_H_ */ + +/** + * @} + */ diff --git a/openair2/M2AP/m2ap_MCE_defs.h b/openair2/M2AP/m2ap_MCE_defs.h new file mode 100644 index 0000000000..5267232d69 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_defs.h @@ -0,0 +1,210 @@ +/* + * 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 m2ap_MCE_defs.h + * \brief m2ap struct definitions for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "queue.h" +#include "tree.h" + +#include "sctp_eNB_defs.h" + +#include "m2ap_ids.h" //looks X2AP specific for HO +#include "m2ap_timers.h" + +#ifndef M2AP_MCE_DEFS_H_ +#define M2AP_MCE_DEFS_H_ + +#define M2AP_MCE_NAME_LENGTH_MAX (150) + +typedef enum { + /* Disconnected state: initial state for any association. */ + M2AP_MCE_STATE_DISCONNECTED = 0x0, + + /* State waiting for m2 Setup response message if the target MCE accepts or + * M2 Setup failure if rejects the MCE. + */ + M2AP_MCE_STATE_WAITING = 0x1, + + /* The MCE is successfully connected to another MCE. */ + M2AP_MCE_STATE_CONNECTED = 0x2, + + /* M2AP is ready, and the MCE is successfully connected to another MCE. */ + M2AP_MCE_STATE_READY = 0x3, + + M2AP_MCE_STATE_OVERLOAD = 0x4, + + M2AP_MCE_STATE_RESETTING = 0x5, + + /* Max number of states available */ + M2AP_MCE_STATE_MAX, +} m2ap_MCE_state_t; + +/* Served PLMN identity element */ +/*struct plmn_identity_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + STAILQ_ENTRY(plmn_identity_s) next; +};*/ + +/* Served group id element */ +/*struct served_group_id_s { + uint16_t mce_group_id; + STAILQ_ENTRY(served_group_id_s) next; +};*/ + +/* Served enn code for a particular MCE */ +/*struct mce_code_s { + uint8_t mce_code; + STAILQ_ENTRY(mce_code_s) next; +};*/ + +struct m2ap_MCE_instance_s; + +/* This structure describes association of a MCE to another MCE */ +typedef struct m2ap_MCE_data_s { + /* MCE descriptors tree, ordered by sctp assoc id */ + RB_ENTRY(m2ap_MCE_data_s) entry; + + /* This is the optional name provided by the MME */ + char *MCE_name; + + /* target MCE ID */ + uint32_t MCE_id; + + /* Current MCE load information (if any). */ + //m2ap_load_state_t overload_state; + + /* Current MCE->MCE M2AP association state */ + m2ap_MCE_state_t state; + + /* Next usable stream for UE signalling */ + int32_t nextstream; + + /* Number of input/ouput streams */ + uint16_t in_streams; + uint16_t out_streams; + + /* Connexion id used between SCTP/M2AP */ + uint16_t cnx_id; + + /* SCTP association id */ + int32_t assoc_id; + + /* Nid cells */ + uint32_t Nid_cell[MAX_NUM_CCs]; + int num_cc; + + /* Only meaningfull in virtual mode */ + struct m2ap_MCE_instance_s *m2ap_MCE_instance; +} m2ap_MCE_data_t; + +typedef struct m2ap_MCE_instance_s { + /* used in simulation to store multiple MCE instances*/ + STAILQ_ENTRY(m2ap_MCE_instance_s) m2ap_MCE_entries; + + /* Number of target MCEs requested by MCE (tree size) */ + uint32_t m2_target_mce_nb; + /* Number of target MCEs for which association is pending */ + uint32_t m2_target_mce_pending_nb; + /* Number of target MCE successfully associated to MCE */ + uint32_t m2_target_mce_associated_nb; + /* Tree of M2AP MCE associations ordered by association ID */ + RB_HEAD(m2ap_mce_map, m2ap_MCE_data_s) m2ap_mce_head; + + /* Tree of UE ordered by MCE_ue_m2ap_id's */ + // RB_HEAD(m2ap_ue_map, m2ap_MCE_ue_context_s) m2ap_ue_head; + + /* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */ + instance_t instance; + + /* Displayable name of MCE */ + char *MCE_name; + + /* Unique MCE_id to identify the MCE within EPC. + * In our case the MCE is a macro MCE so the id will be 20 bits long. + * For Home MCE id, this field should be 28 bits long. + */ + uint32_t MCE_id; + /* The type of the cell */ + cell_type_t cell_type; + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + /* CC params */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + net_ip_address_t target_mce_m2_ip_address[M2AP_MAX_NB_MCE_IP_ADDRESS]; + uint8_t nb_m2; + net_ip_address_t mce_m2_ip_address; + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + uint32_t mce_port_for_M2C; + int multi_sd; + + m2ap_id_manager id_manager; + m2ap_timers_t timers; +} m2ap_MCE_instance_t; + +typedef struct { + /* List of served MCEs + * Only used for virtual mode + */ + STAILQ_HEAD(m2ap_MCE_instances_head_s, m2ap_MCE_instance_s) m2ap_MCE_instances_head; + /* Nb of registered MCEs */ + uint8_t nb_registered_MCEs; + + /* Generate a unique connexion id used between M2AP and SCTP */ + uint16_t global_cnx_id; +} m2ap_MCE_internal_data_t; + +int m2ap_MCE_compare_assoc_id(struct m2ap_MCE_data_s *p1, struct m2ap_MCE_data_s *p2); + +/* Generate the tree management functions */ +struct m2ap_MCE_map; +struct m2ap_MCE_data_s; +RB_PROTOTYPE(m2ap_MCE_map, m2ap_MCE_data_s, entry, m2ap_MCE_compare_assoc_id); + + +#endif /* M2AP_MCE_DEFS_H_ */ diff --git a/openair2/M2AP/m2ap_MCE_generate_messages.c b/openair2/M2AP/m2ap_MCE_generate_messages.c new file mode 100644 index 0000000000..a28097cf1a --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_generate_messages.c @@ -0,0 +1,804 @@ +/* + * 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 m2ap_MCE_generate_messages.c + * \brief m2ap procedures for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include "intertask_interface.h" + +//#include "M2AP_LastVisitedCell-Item.h" + +#include "m2ap_common.h" +#include "m2ap_MCE.h" +#include "m2ap_MCE_generate_messages.h" +#include "m2ap_encoder.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +#include "m2ap_itti_messaging.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +int m2ap_MCE_generate_m2_setup_request( + m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p) +{ + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupRequest_t *out; + M2AP_M2SetupRequest_Ies_t *ie; + //M2AP_PLMN_Identity_t *plmn; + //ServedCells__Member *servedCellMember; + //M2AP_GU_Group_ID_t *gu; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + DevAssert(instance_p != NULL); + DevAssert(m2ap_MCE_data_p != NULL); + + m2ap_MCE_data_p->state = M2AP_MCE_STATE_WAITING; + + /* Prepare the M2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_M2SetupRequest; + out = &pdu.choice.initiatingMessage.value.choice.M2SetupRequest; + + /* mandatory */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GlobalMCE_ID; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequest_IEs__value_PR_GlobalMCE_ID; + //MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &ie->value.choice.GlobalMCE_ID.pLMN_Identity); + //ie->value.choice.GlobalMCE_ID.MCE_ID.present = M2AP_MCE_ID_PR_macro_MCE_ID; + //MACRO_MCE_ID_TO_BIT_STRING(instance_p->MCE_id, + // &ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID); + //M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->MCE_id, + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[0], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[1], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[2]); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_ServedCells; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequest_IEs__value_PR_ServedCells; + //{ + // for (int i = 0; inum_cc; i++){ + // servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member)); + // { + // servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i]; + + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &servedCellMember->servedCellInfo.cellId.pLMN_Identity); + // MACRO_MCE_ID_TO_CELL_IDENTITY(instance_p->MCE_id,0, + // &servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier); + + // INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC); + // plmn = (M2AP_PLMN_Identity_t *)calloc(1,sizeof(M2AP_PLMN_Identity_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); + // ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn); + // } + + // if (instance_p->frame_type[i] == FDD) { + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = M2AP_EUTRA_Mode_Info_PR_fDD; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; + // switch (instance_p->N_RB_DL[i]) { + // case 6: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // break; + // case 15: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // break; + // case 25: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // break; + // case 50: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // break; + // case 75: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // break; + // case 100: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // break; + // default: + // AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); + // break; + // } + // } + // else { + // AssertFatal(0,"M2Setuprequest not supported for TDD!"); + // } + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember); + // } + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GUGroupIDList; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequest_IEs__value_PR_GUGroupIDList; + //{ + // gu = (M2AP_GU_Group_ID_t *)calloc(1, sizeof(M2AP_GU_Group_ID_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &gu->pLMN_Identity); + // //@TODO: consider to update this value + // INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID); + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu); + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + M2AP_ERROR("Failed to encode M2 setup request\n"); + return -1; + } + + //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 M2Setup/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); + + m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 0); + + return ret; +} + +int m2ap_MCE_generate_m2_setup_response(m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p) +{ + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupResponse_t *out; + M2AP_M2SetupResponse_Ies_t *ie; + //M2AP_PLMN_Identity_t *plmn; + //ServedCells__Member *servedCellMember; + //M2AP_GU_Group_ID_t *gu; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + DevAssert(instance_p != NULL); + DevAssert(m2ap_MCE_data_p != NULL); + + /* Prepare the M2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_M2SetupResponse; + out = &pdu.choice.successfulOutcome.value.choice.M2SetupResponse; + + /* mandatory */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GlobalMCE_ID; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GlobalMCE_ID; + //MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &ie->value.choice.GlobalMCE_ID.pLMN_Identity); + //ie->value.choice.GlobalMCE_ID.MCE_ID.present = M2AP_MCE_ID_PR_macro_MCE_ID; + //MACRO_MCE_ID_TO_BIT_STRING(instance_p->MCE_id, + // &ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID); + //M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->MCE_id, + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[0], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[1], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[2]); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_ServedCells; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_ServedCells; + //{ + // for (int i = 0; inum_cc; i++){ + // servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member)); + // { + // servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i]; + + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &servedCellMember->servedCellInfo.cellId.pLMN_Identity); + // MACRO_MCE_ID_TO_CELL_IDENTITY(instance_p->MCE_id,0, + // &servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier); + + // INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC); + // plmn = (M2AP_PLMN_Identity_t *)calloc(1,sizeof(M2AP_PLMN_Identity_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); + // ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn); + // } + + // if (instance_p->frame_type[i] == FDD) { + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = M2AP_EUTRA_Mode_Info_PR_fDD; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; + // switch (instance_p->N_RB_DL[i]) { + // case 6: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // break; + // case 15: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // break; + // case 25: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // break; + // case 50: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // break; + // case 75: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // break; + // case 100: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // break; + // default: + // AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); + // break; + // } + // } + // else { + // AssertFatal(0,"M2Setupresponse not supported for TDD!"); + // } + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember); + // } + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GUGroupIDList; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GUGroupIDList; + //{ + // gu = (M2AP_GU_Group_ID_t *)calloc(1, sizeof(M2AP_GU_Group_ID_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &gu->pLMN_Identity); + // //@TODO: consider to update this value + // INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID); + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu); + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + M2AP_ERROR("Failed to encode M2 setup response\n"); + return -1; + } + + m2ap_MCE_data_p->state = M2AP_MCE_STATE_READY; + + //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 M2Setup/successfulOutcome assoc_id %u", m2ap_MCE_data_p->assoc_id); + + m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 0); + + return ret; +} + +int m2ap_MCE_generate_m2_setup_failure(instance_t instance, + uint32_t assoc_id, + M2AP_Cause_PR cause_type, + long cause_value, + long time_to_wait) +{ + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupFailure_t *out; + M2AP_M2SetupFailure_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + /* Prepare the M2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; + pdu.choice.unsuccessfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.unsuccessfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.unsuccessfulOutcome.value.present = M2AP_UnsuccessfulOutcome__value_PR_M2SetupFailure; + out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure; + + /* mandatory */ + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_Cause; + //ie->criticality = M2AP_Criticality_ignore; + //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_Cause; + + //m2ap_MCE_set_cause (&ie->value.choice.Cause, cause_type, cause_value); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional: consider to handle this later */ + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_TimeToWait; + //ie->criticality = M2AP_Criticality_ignore; + //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_TimeToWait; + + //if (time_to_wait > -1) { + // ie->value.choice.TimeToWait = time_to_wait; + //} + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + M2AP_ERROR("Failed to encode M2 setup failure\n"); + return -1; + } + + //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, + // MSC_M2AP_TARGET_MCE, NULL, 0, + // "0 M2Setup/unsuccessfulOutcome assoc_id %u cause %u value %u", + // assoc_id, cause_type, cause_value); + + m2ap_MCE_itti_send_sctp_data_req(instance, assoc_id, buffer, len, 0); + + return ret; +} + +int m2ap_MCE_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value) +{ + + DevAssert (cause_p != NULL); + cause_p->present = cause_type; + + switch (cause_type) { + case M2AP_Cause_PR_radioNetwork: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_transport: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_protocol: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_misc: + cause_p->choice.misc = cause_value; + break; + + default: + return -1; + } + + return 0; +} + +//int m2ap_MCE_generate_m2_handover_request (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequest_t *out; +// M2AP_HandoverRequest_IEs_t *ie; +// M2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs; +// M2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item; +// M2AP_LastVisitedCell_Item_t *lastVisitedCell_Item; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverRequest; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverRequest; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_Cause; +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = M2AP_CauseRadioNetwork_handover_desirable_for_radio_reasons; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargetCell_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_ECGI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.ECGI.pLMN_Identity); +// MACRO_MCE_ID_TO_CELL_IDENTITY(m2ap_MCE_data_p->MCE_id, 0, &ie->value.choice.ECGI.eUTRANcellIdentifier); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_GUMMEI_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_GUMMEI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.GUMMEI.gU_Group_ID.pLMN_Identity); +// //@TODO: consider to update these values +// INT16_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_group_id, &ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID); +// MME_CODE_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_code, &ie->value.choice.GUMMEI.mME_Code); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_ContextInformation; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_ContextInformation; +// //@TODO: consider to update this value +// ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID = m2ap_handover_req->mme_ue_s1ap_id; +// +// KMCE_STAR_TO_BIT_STRING(m2ap_handover_req->kenb,&ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star); +// +// if (m2ap_handover_req->kenb_ncc >=0) { // Check this condition +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = m2ap_handover_req->kenb_ncc; +// } +// else { +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = 1; +// } +// +// ENCRALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.encryption_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms); +// +// INTPROTALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.integrity_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms); +// +// //@TODO: update with proper UEAMPR +// UEAGMAXBITRTD_TO_ASN_PRIMITIVES(3L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink); +// UEAGMAXBITRTU_TO_ASN_PRIMITIVES(6L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateUplink); +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_ToBeSetup_ItemIEs = (M2AP_E_RABs_ToBeSetup_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_ToBeSetup_ItemIEs_t)); +// e_RABS_ToBeSetup_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_ToBeSetup_Item; +// e_RABS_ToBeSetup_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_ToBeSetup_ItemIEs->value.present = M2AP_E_RABs_ToBeSetup_ItemIEs__value_PR_E_RABs_ToBeSetup_Item; +// e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item; +// { +// e_RABs_ToBeSetup_Item->e_RAB_ID = m2ap_handover_req->e_rabs_tobesetup[i].e_rab_id; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI = m2ap_handover_req->e_rab_param[i].qos.qci; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.priority_level; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size = (uint8_t)(m2ap_handover_req->e_rabs_tobesetup[i].MCE_addr.length/8); +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = m2ap_handover_req->e_rabs_tobesetup[i].MCE_addr.length%8; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf = +// calloc(1,e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// memcpy (e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf, +// m2ap_handover_req->e_rabs_tobesetup[i].MCE_addr.buffer, +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// INT32_TO_OCTET_STRING(m2ap_handover_req->e_rabs_tobesetup[i].gtp_teid,&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID); +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list, e_RABS_ToBeSetup_ItemIEs); +// } +// } +// +// OCTET_STRING_fromBuf(&ie->value.choice.UE_ContextInformation.rRC_Context, (char*) m2ap_handover_req->rrc_buffer, m2ap_handover_req->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_HistoryInformation; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_HistoryInformation; +// //@TODO: consider to update this value +// { +// lastVisitedCell_Item = (M2AP_LastVisitedCell_Item_t *)calloc(1, sizeof(M2AP_LastVisitedCell_Item_t)); +// lastVisitedCell_Item->present = M2AP_LastVisitedCell_Item_PR_e_UTRAN_Cell; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.pLMN_Identity); +// MACRO_MCE_ID_TO_CELL_IDENTITY(0, 0, &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.eUTRANcellIdentifier); +// lastVisitedCell_Item->choice.e_UTRAN_Cell.cellType.cell_Size = M2AP_Cell_Size_small; +// lastVisitedCell_Item->choice.e_UTRAN_Cell.time_UE_StayedInCell = 2; +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_HistoryInformation.list, lastVisitedCell_Item); +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover request\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2Handover/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_MCE_generate_m2_handover_request_ack (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequestAcknowledge_t *out; +// M2AP_HandoverRequestAcknowledge_IEs_t *ie; +// M2AP_E_RABs_Admitted_ItemIEs_t *e_RABS_Admitted_ItemIEs; +// M2AP_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// ue_id = m2ap_handover_req_ack->m2_id_target; +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; +// pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge; +// out = &pdu.choice.successfulOutcome.value.choice.HandoverRequestAcknowledge; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_List; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_E_RABs_Admitted_List; +// +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_Admitted_ItemIEs = (M2AP_E_RABs_Admitted_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_Admitted_ItemIEs_t)); +// e_RABS_Admitted_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_Item; +// e_RABS_Admitted_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_Admitted_ItemIEs->value.present = M2AP_E_RABs_Admitted_ItemIEs__value_PR_E_RABs_Admitted_Item; +// e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item; +// { +// e_RABs_Admitted_Item->e_RAB_ID = m2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id; +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs); +// } +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargetMCEtoSource_MCETransparentContainer; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_TargetMCEtoSource_MCETransparentContainer; +// +// OCTET_STRING_fromBuf(&ie->value.choice.TargetMCEtoSource_MCETransparentContainer, (char*) m2ap_handover_req_ack->rrc_buffer, m2ap_handover_req_ack->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover response\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2Handover/successfulOutcome assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_MCE_generate_m2_ue_context_release (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, m2ap_ue_context_release_t *m2ap_ue_context_release) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_UEContextRelease_t *out; +// M2AP_UEContextRelease_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// ue_id = m2ap_find_id_from_rnti(&instance_p->id_manager, m2ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M2AP_ERROR("could not find UE %x\n", m2ap_ue_context_release->rnti); +// exit(1); +// } +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP ue context relase message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_uEContextRelease; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_UEContextRelease; +// out = &pdu.choice.initiatingMessage.value.choice.UEContextRelease; +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 UE Context Release\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2UEContextRelease/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_MCE_generate_m2_handover_cancel (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverCancel_t *out; +// M2AP_HandoverCancel_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// ue_id = m2_ue_id; +// id_source = ue_id; +// id_target = m2ap_id_get_id_target(&instance_p->id_manager, ue_id); +// +// /* Prepare the M2AP handover cancel message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverCancel; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverCancel; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverCancel; +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ +// if (id_target != -1) { +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_Cause; +// switch (cause) { +// case M2AP_T_RELOC_PREP_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_trelocprep_expiry; +// break; +// case M2AP_TX2_RELOC_OVERALL_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_tx2relocoverall_expiry; +// break; +// default: +// /* we can't come here */ +// M2AP_ERROR("unhandled cancel cause\n"); +// exit(1); +// } +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 Handover Cancel\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2HandoverCancel/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} diff --git a/openair2/M2AP/m2ap_MCE_generate_messages.h b/openair2/M2AP/m2ap_MCE_generate_messages.h new file mode 100644 index 0000000000..1632dc807a --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_generate_messages.h @@ -0,0 +1,63 @@ +/* + * 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 m2ap_MCE_generate_messages.h + * \brief m2ap procedures for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_MCE_GENERATE_MESSAGES_H_ +#define M2AP_MCE_GENERATE_MESSAGES_H_ + +#include "m2ap_MCE_defs.h" +#include "m2ap_common.h" + +int m2ap_MCE_generate_m2_setup_request(m2ap_MCE_instance_t *instance_p, + m2ap_MCE_data_t *m2ap_MCE_data_p); + +int m2ap_MCE_generate_m2_setup_response(m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p); + +int m2ap_MCE_generate_m2_setup_failure(instance_t instance, + uint32_t assoc_id, + M2AP_Cause_PR cause_type, + long cause_value, + long time_to_wait); + +int m2ap_MCE_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value); + +//int m2ap_MCE_generate_m2_handover_request (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id); +// +//int m2ap_MCE_generate_m2_handover_request_ack (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack); +// +//int m2ap_MCE_generate_m2_ue_context_release (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_ue_context_release_t *m2ap_ue_context_release); +// +//int m2ap_MCE_generate_m2_handover_cancel (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause); + +#endif /* M2AP_MCE_GENERATE_MESSAGES_H_ */ diff --git a/openair2/M2AP/m2ap_MCE_handler.c b/openair2/M2AP/m2ap_MCE_handler.c new file mode 100644 index 0000000000..85e342f996 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_handler.c @@ -0,0 +1,123 @@ +/* + * 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 m2ap_MCE_handler.c + * \brief m2ap handler procedures for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "intertask_interface.h" + +#include "asn1_conversions.h" + +#include "m2ap_common.h" +#include "m2ap_MCE_defs.h" +#include "m2ap_MCE_handler.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +//#include "m2ap_MCE_management_procedures.h" +#include "m2ap_MCE_generate_messages.h" + +#include "m2ap_MCE_interface_management.h" +//#include "m2ap_eNB_interface_management.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +/* Handlers matrix. Only eNB related procedure present here */ +m2ap_message_decoded_callback m2ap_MCE_messages_callback[][3] = { + { 0, MCE_handle_MBMS_SESSION_START_RESPONSE, 0 }, /* MBMSSessionStart */ + { 0, MCE_handle_MBMS_SESSION_STOP_RESPONSE, 0 }, /* MBMSSessionStop */ + { 0, MCE_handle_MBMS_SCHEDULING_INFORMATION_RESPONSE, 0 }, /* MBMSSchedulingInformation */ + { 0, 0, 0 }, /* Error Indication */ + { 0, 0, 0 }, /* Reset */ + { MCE_handle_M2_SETUP_REQUEST, 0, 0 }, /* M2 Setup */ + { 0, 0, 0 }, /* eNBConfigurationUpdate */ + { 0, 0, 0 }, /* MCEConfigurationUpdate */ + { 0, 0, 0 }, /* privateMessage */ + { 0, 0, 0 }, /* MBMSSessionUpdate */ + { 0, 0, 0 }, /* MBMSServiceCounting */ + { 0, 0, 0 }, /* MBMSServiceCountingResultReport */ + { 0, 0, 0 } /* MBMSOverloadNotification */ +}; + +static char *m2ap_direction2String(int m2ap_dir) { +static char *m2ap_direction_String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; +return(m2ap_direction_String[m2ap_dir]); +} + + +int m2ap_MCE_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length) +{ + M2AP_M2AP_PDU_t pdu; + int ret; + + DevAssert(data != NULL); + + memset(&pdu, 0, sizeof(pdu)); + + if (m2ap_decode_pdu(&pdu, data, data_length) < 0) { + LOG_E(M2AP, "Failed to decode PDU\n"); + return -1; + } + + /* Checking procedure Code and direction of message */ + if (pdu.choice.initiatingMessage.procedureCode > sizeof(m2ap_MCE_messages_callback) / (3 * sizeof( + m2ap_MCE_message_decoded_callback)) + || (pdu.present > M2AP_M2AP_PDU_PR_unsuccessfulOutcome)) { + LOG_E(M2AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return -1; + } + + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (m2ap_MCE_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) { + LOG_E(M2AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, + m2ap_direction2String(pdu.present - 1)); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return -1; + } + + /* Calling the right handler */ + LOG_I(M2AP, "Calling handler with instance %d\n",instance); + ret = (*m2ap_MCE_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1]) + (instance, assoc_id, stream, &pdu); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return ret; +} + + diff --git a/openair2/M2AP/m2ap_MCE_handler.h b/openair2/M2AP/m2ap_MCE_handler.h new file mode 100644 index 0000000000..e9faae8f5d --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_handler.h @@ -0,0 +1,43 @@ +/* + * 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 m2ap_handler.h + * \brief m2ap handler procedures for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_MCE_HANDLERS_H_ +#define M2AP_MCE_HANDLERS_H_ + +#include "m2ap_MCE_defs.h" + +//void m2ap_handle_m2_setup_message(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown); + +int m2ap_MCE_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + +//int m2ap_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + //const uint8_t * const data, const uint32_t data_length); + + +#endif /* M2AP_MCE_HANDLERS_H_ */ diff --git a/openair2/M2AP/m2ap_MCE_interface_management.c b/openair2/M2AP/m2ap_MCE_interface_management.c new file mode 100644 index 0000000000..1bef834179 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_interface_management.c @@ -0,0 +1,1421 @@ +/* + * 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 m2ap_MCE_interface_management.c + * \brief m2ap interface management for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "m2ap_common.h" +#include "m2ap_encoder.h" +#include "m2ap_decoder.h" +#include "m2ap_itti_messaging.h" +#include "m2ap_MCE_interface_management.h" + +#include "conversions.h" + +extern m2ap_setup_req_t *m2ap_mce_data_from_enb; + +/* + * MBMS Session start + */ +int MCE_send_MBMS_SESSION_START_REQUEST(instance_t instance/*, uint32_t assoc_id*/,m2ap_session_start_req_t* m2ap_session_start_req){ + + //AssertFatal(1==0,"Not implemented yet\n"); + + //module_id_t enb_mod_idP=0; + //module_id_t du_mod_idP=0; + + M2AP_M2AP_PDU_t pdu; + M2AP_SessionStartRequest_t *out; + M2AP_SessionStartRequest_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i=0; + //int j=0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_sessionStart; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_SessionStartRequest; + out = &pdu.choice.initiatingMessage.value.choice.SessionStartRequest; + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStartRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStartRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartRequest_Ies__value_PR_MCE_MBMS_M2AP_ID; + //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. TMGI (integrer value) */ + ie = (M2AP_SessionStartRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStartRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_TMGI; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartRequest_Ies__value_PR_TMGI; + MCC_MNC_TO_PLMNID(0,0,3,&ie->value.choice.TMGI.pLMNidentity);/*instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,*/ + uint8_t TMGI[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(&ie->value.choice.TMGI.serviceID,(const char*)&TMGI[2],3); + + //&ie->choice.TMGI.pLMN_Identity); + //INT16_TO_OCTET_STRING(0,&ie->choice.TMGI.serviceId); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c3. MBMS_Session_ID (integrer value) */ //OCTET_STRING + if(0){ + ie = (M2AP_SessionStartRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStartRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MBMS_Session_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartRequest_Ies__value_PR_MBMS_Session_ID; + //INT16_TO_OCTET_STRING(0,&ie->choice.MBMS_Session_ID); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* mandatory */ + /* c5. MBMS_Service_Area (integrer value) */ //OCTET_STRING + ie = (M2AP_SessionStartRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStartRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MBMS_Service_Area; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartRequest_Ies__value_PR_MBMS_Service_Area; + //OCTET_STRING_fromBuf(&ie->value.choice.MBMS_Service_Area, m2ap_setup_resp->MCEname, + //strlen(m2ap_setup_resp->MCEname)); + //INT16_TO_OCTET_STRING(0,&ie->choice.TMGI.serviceId); + ie->value.choice.MBMS_Service_Area.buf = calloc(3,sizeof(uint8_t)); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + /* mandatory */ + /* c6. TNL_Information (integrer value) */ + ie = (M2AP_SessionStartRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStartRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_TNL_Information; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartRequest_Ies__value_PR_TNL_Information; + //ie->value.choice.TNL_Information.iPMCAddress.buf = calloc(4,sizeof(uint8_t)); + //ie->value.choice.TNL_Information.iPSourceAddress.buf = calloc(4,sizeof(uint8_t)); + //TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234,&ie->value.choice.TNL_Information.iPMCAddress); + //TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234,&ie->value.choice.TNL_Information.iPSourceAddress); + + OCTET_STRING_fromBuf(&ie->value.choice.TNL_Information.gTP_TEID, "1204",strlen("1234")); + OCTET_STRING_fromBuf(&ie->value.choice.TNL_Information.iPMCAddress, "1204",strlen("1234")); + OCTET_STRING_fromBuf(&ie->value.choice.TNL_Information.iPSourceAddress, "1204",strlen("1234")); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if(0){ + // /* optional */ + // /* c7. TNL_Information_1 (integrer value) */ + // ie = (M2AP_SessionStartRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStartRequest_Ies_t)); + // ie->id = M2AP_ProtocolIE_ID_id_TNL_Information_1; + // ie->criticality = M2AP_Criticality_reject; + // ie->value.present = M2AP_SessionStartRequest_Ies__value_PR_TNL_Information_1; + // //asn_int642INTEGER(&ie->value.choice.MBMS_Session_ID, f1ap_du_data->MBMS_Session_ID); //? + // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + + /* encode */ + if (m2ap_encode_pdu(&pdu,&buffer,&len) < 0){ + return -1; + } + + //MCE_m2ap_itti_send_sctp_data_req(instance, m2ap_mce_data_from_mce->assoid,buffer,len,0); + m2ap_MCE_itti_send_sctp_data_req(instance,m2ap_mce_data_from_enb->assoc_id,buffer,len,0); + return 0; + +} + +int MCE_handle_MBMS_SESSION_START_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + //AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M2AP, "MCE_handle_MBMS_SESSION_START_RESPONSE\n"); + + AssertFatal(pdu->present == M2AP_M2AP_PDU_PR_successfulOutcome, + "pdu->present != M2AP_M2AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M2AP_ProcedureCode_id_sessionStart, + "pdu->choice.successfulOutcome->procedureCode != M2AP_ProcedureCode_id_sessionStart\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M2AP_Criticality_reject, + "pdu->choice.successfulOutcome->criticality != M2AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M2AP_SuccessfulOutcome__value_PR_SessionStartResponse, + "pdu->choice.successfulOutcome.value.present != M2AP_SuccessfulOutcome__value_PR_SessionStartResponse\n"); + + + M2AP_SessionStartResponse_t *in = &pdu->choice.successfulOutcome.value.choice.SessionStartResponse; + M2AP_SessionStartResponse_Ies_t *ie; + int MCE_MBMS_M2AP_ID=-1; + int ENB_MBMS_M2AP_ID=-1; + + + MessageDef *msg_g = itti_alloc_new_message(TASK_M2AP_MCE,M2AP_MBMS_SESSION_START_RESP); //TODO + + LOG_D(M2AP, "M2AP: SessionStart-Resp: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (int i=0;i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID: + AssertFatal(ie->criticality == M2AP_Criticality_reject, + "ie->criticality != M2AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M2AP_SessionStartResponse_Ies__value_PR_MCE_MBMS_M2AP_ID, + "ie->value.present != M2AP_sessionStartResponse_IEs__value_PR_MCE_MBMS_M2AP_ID\n"); + MCE_MBMS_M2AP_ID=ie->value.choice.MCE_MBMS_M2AP_ID; + LOG_D(M2AP, "M2AP: SessionStart-Resp: MCE_MBMS_M2AP_ID %d\n", + MCE_MBMS_M2AP_ID); + break; + case M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID: + AssertFatal(ie->criticality == M2AP_Criticality_reject, + "ie->criticality != M2AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M2AP_SessionStartResponse_Ies__value_PR_ENB_MBMS_M2AP_ID, + "ie->value.present != M2AP_sessionStartResponse_Ies__value_PR_ENB_MBMS_M2AP_ID\n"); + ENB_MBMS_M2AP_ID=ie->value.choice.ENB_MBMS_M2AP_ID; + LOG_D(M2AP, "M2AP: SessionStart-Resp: ENB_MBMS_M2AP_ID %d\n", + ENB_MBMS_M2AP_ID); + break; + } + } + + AssertFatal(MCE_MBMS_M2AP_ID!=-1,"MCE_MBMS_M2AP_ID was not sent\n"); + AssertFatal(ENB_MBMS_M2AP_ID!=-1,"ENB_MBMS_M2AP_ID was not sent\n"); + //M2AP_SESSION_START_RESP(msg_p). +// MSC_LOG_RX_MESSAGE( +// MSC_M2AP_MCE, +// MSC_M2AP_ENB, + //return 0; +// 0, +// 0, +// MSC_AS_TIME_FMT" MCE_handle_M2_SESSION_START_RESPONSE successfulOutcome assoc_id %d", +// 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +// assoc_id); +// + LOG_D(M2AP, "Sending M2AP_SESSION_START_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", + assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id)); + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g); + return 0; + +} +int MCE_handle_MBMS_SESSION_START_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + +/* + * MBMS Session stop + */ +int MCE_send_MBMS_SESSION_STOP_REQUEST(instance_t instance, m2ap_session_stop_req_t* m2ap_session_stop_req){ + + + // module_id_t enb_mod_idP=0; + //module_id_t du_mod_idP=0; + + M2AP_M2AP_PDU_t pdu; + M2AP_SessionStopRequest_t *out; + M2AP_SessionStopRequest_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i=0; + //int j=0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_sessionStop; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_SessionStopRequest; + out = &pdu.choice.initiatingMessage.value.choice.SessionStopRequest; + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStopRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStopRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStopRequest_Ies__value_PR_MCE_MBMS_M2AP_ID; + ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. ENB_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStopRequest_Ies_t *)calloc(1, sizeof(M2AP_SessionStopRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStopRequest_Ies__value_PR_ENB_MBMS_M2AP_ID; + ie->value.choice.ENB_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + /* encode */ + if (m2ap_encode_pdu(&pdu,&buffer,&len) < 0){ + return -1; + } + + //MCE_m2ap_itti_send_sctp_data_req(instance, m2ap_mce_data_from_mce->assoid,buffer,len,0); + m2ap_MCE_itti_send_sctp_data_req(instance, m2ap_mce_data_from_enb->assoc_id,buffer,len,0); + return 0; + + + +} + +int MCE_handle_MBMS_SESSION_STOP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + //AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M2AP, "MCE_handle_MBMS_SESSION_STOP_RESPONSE\n"); + + AssertFatal(pdu->present == M2AP_M2AP_PDU_PR_successfulOutcome, + "pdu->present != M2AP_M2AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M2AP_ProcedureCode_id_sessionStop, + "pdu->choice.successfulOutcome->procedureCode != M2AP_ProcedureCode_id_sessionStop\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M2AP_Criticality_reject, + "pdu->choice.successfulOutcome->criticality != M2AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M2AP_SuccessfulOutcome__value_PR_SessionStopResponse, + "pdu->choice.successfulOutcome->value.present != M2AP_SuccessfulOutcome__value_PR_SessionStopResponse\n"); + + + M2AP_SessionStopResponse_t *in = &pdu->choice.successfulOutcome.value.choice.SessionStopResponse; + M2AP_SessionStopResponse_Ies_t *ie; + int MCE_MBMS_M2AP_ID=-1; + int ENB_MBMS_M2AP_ID=-1; + + + MessageDef *msg_g = itti_alloc_new_message(TASK_M2AP_MCE,M2AP_MBMS_SESSION_STOP_RESP); //TODO + + LOG_D(M2AP, "M2AP: SessionStop-Resp: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (int i=0;i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID: + AssertFatal(ie->criticality == M2AP_Criticality_reject, + "ie->criticality != M2AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M2AP_SessionStopResponse_Ies__value_PR_MCE_MBMS_M2AP_ID, + "ie->value.present != M2AP_SessionStopResponse_Ies__value_PR_MCE_MBMS_M2AP_ID\n"); + MCE_MBMS_M2AP_ID=ie->value.choice.MCE_MBMS_M2AP_ID; + LOG_D(M2AP, "M2AP: SessionStop-Resp: MCE_MBMS_M2AP_ID %d\n", + MCE_MBMS_M2AP_ID); + break; + case M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID: + AssertFatal(ie->criticality == M2AP_Criticality_reject, + "ie->criticality != M2AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M2AP_SessionStopResponse_Ies__value_PR_ENB_MBMS_M2AP_ID, + "ie->value.present != M2AP_SessionStopResponse_Ies__value_PR_ENB_MBMS_M2AP_ID\n"); + ENB_MBMS_M2AP_ID=ie->value.choice.ENB_MBMS_M2AP_ID; + LOG_D(M2AP, "M2AP: SessionStop-Resp: ENB_MBMS_M2AP_ID %d\n", + ENB_MBMS_M2AP_ID); + break; + } + } + + AssertFatal(MCE_MBMS_M2AP_ID!=-1,"MCE_MBMS_M2AP_ID was not sent\n"); + AssertFatal(ENB_MBMS_M2AP_ID!=-1,"ENB_MBMS_M2AP_ID was not sent\n"); + // M2AP_SESSION_STOP_RESP(msg_p). + // MSC_LOG_RX_MESSAGE( + // MSC_M2AP_MCE, + // MSC_M2AP_ENB, + // 0, + // 0, + // MSC_AS_TIME_FMT" MCE_handle_M2_SESSION_STOP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + // LOG_D(M2AP, "Sending M2AP_SESSION_START_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id)); + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g); + // + return 0; +} + + + +int MCE_handle_MBMS_SESSION_STOP_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + typedef struct M2AP_MBSFN_Area_Configuration{ + M2AP_PMCH_Configuration_List_t PMCH_Configuration_List; + M2AP_MBSFN_Subframe_ConfigurationList_t MBSFN_Subframe_ConfigurationList; + M2AP_Common_Subframe_Allocation_Period_t Common_Subframe_Allocation_Period; + M2AP_MBSFN_Area_ID_t MBSFN_Area_ID; + M2AP_MBMS_Suspension_Notification_List_t MBMS_Suspension_Notification_List; + }M2AP_MBSFN_Area_Configuration_t; + + +/* + * MBMS Scheduling Information + */ + uint8_t m2ap_message[] = {0x00, 0x02, 0x00, 0x3a, 0x00, 0x00, 0x02, 0x00, 0x19, 0x00, 0x01, 0x00, 0x00, + 0x0a, 0x00, 0x2e, 0x00, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x12, 0x10, 0x00, 0x0c, + 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x13, 0x00, 0x00, 0x00, 0xf1, 0x10, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x16, 0x00, 0x07, 0x00, 0x00, 0x17, 0x00, 0x02, 0x00, 0x40, + 0x00, 0x18, 0x00, 0x01, 0x80, 0x00, 0x1d, 0x00, 0x01, 0x01}; + + +int MCE_send_MBMS_SCHEDULING_INFORMATION(instance_t instance, /*uint32_t assoc_id,*/m2ap_mbms_scheduling_information_t * m2ap_mbms_scheduling_information){ + + //module_id_t enb_mod_idP=0; + //module_id_t du_mod_idP=0; + + M2AP_M2AP_PDU_t pdu; + M2AP_MbmsSchedulingInformation_t *out; + M2AP_MbmsSchedulingInformation_Ies_t *ie; + + uint8_t *buffer/*,*buffer2*/; + uint32_t len/*,len2*/; + int i=0; + int j=0; + int k=0; + //int l=0; + //int l=0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_mbmsSchedulingInformation; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_MbmsSchedulingInformation; + out = &pdu.choice.initiatingMessage.value.choice.MbmsSchedulingInformation; + + /* mandatory */ + /* c1. MCCH_Update_Time */ //long + ie=(M2AP_MbmsSchedulingInformation_Ies_t*)calloc(1,sizeof(M2AP_MbmsSchedulingInformation_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCCH_Update_Time; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_MbmsSchedulingInformation_Ies__value_PR_MCCH_Update_Time; + //ie->value.choice.MCCH_Update_Time = ; + ie->value.choice.MCCH_Update_Time = m2ap_mbms_scheduling_information->mcch_update_time; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. MBSFN_Area_Configuration_List */ //long + ie=(M2AP_MbmsSchedulingInformation_Ies_t*)calloc(1,sizeof(M2AP_MbmsSchedulingInformation_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MBSFN_Area_Configuration_List; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_MbmsSchedulingInformation_Ies__value_PR_MBSFN_Area_Configuration_List; + + for(i=0; i < m2ap_mbms_scheduling_information->num_mbms_area_config_list; i++){ + M2AP_MBSFN_Area_Configuration_List_t * m2ap_mbsfn_area_configuration_list = (M2AP_MBSFN_Area_Configuration_List_t*)calloc(1,sizeof(M2AP_MBSFN_Area_Configuration_List_t)); + /*M2AP_MBSFN_Area_Configuration_Item_t*/ + M2AP_MBSFN_Area_Configuration_Item_t *mbsfn_area_configuration_item_ie; + mbsfn_area_configuration_item_ie =(M2AP_MBSFN_Area_Configuration_Item_t*)calloc(1,sizeof(M2AP_MBSFN_Area_Configuration_Item_t)); + mbsfn_area_configuration_item_ie->id = M2AP_ProtocolIE_ID_id_PMCH_Configuration_List; + mbsfn_area_configuration_item_ie->criticality = M2AP_Criticality_reject; + mbsfn_area_configuration_item_ie->value.present = M2AP_MBSFN_Area_Configuration_Item__value_PR_PMCH_Configuration_List; + + for(j=0; j < m2ap_mbms_scheduling_information->mbms_area_config_list[i].num_pmch_config_list; j++){ + + M2AP_PMCH_Configuration_ItemIEs_t * pmch_configuration_item_ies = (M2AP_PMCH_Configuration_ItemIEs_t*)calloc(1,sizeof(M2AP_PMCH_Configuration_ItemIEs_t)); + pmch_configuration_item_ies->id = M2AP_ProtocolIE_ID_id_PMCH_Configuration_Item; + pmch_configuration_item_ies->criticality = M2AP_Criticality_reject; + pmch_configuration_item_ies->value.present = M2AP_PMCH_Configuration_ItemIEs__value_PR_PMCH_Configuration_Item; + + M2AP_PMCH_Configuration_Item_t * pmch_configuration_item;/* = (M2AP_PMCH_Configuration_Item_t*)calloc(1,sizeof(M2AP_PMCH_Configuration_Item_t));*/ + pmch_configuration_item = &pmch_configuration_item_ies->value.choice.PMCH_Configuration_Item; + { + pmch_configuration_item->pmch_Configuration.dataMCS = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].data_mcs; + pmch_configuration_item->pmch_Configuration.mchSchedulingPeriod = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mch_scheduling_period; + pmch_configuration_item->pmch_Configuration.allocatedSubframesEnd = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].allocated_sf_end; + for(k=0; k < m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].num_mbms_session_list; k++){ + MBMSsessionListPerPMCH_Item__Member *member; + member = (MBMSsessionListPerPMCH_Item__Member*)calloc(1,sizeof(MBMSsessionListPerPMCH_Item__Member)); + MCC_MNC_TO_PLMNID( + m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mcc, + m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mnc, + m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mnc_length + ,&member->tmgi.pLMNidentity); + + //INT16_TO_OCTET_STRING(0,&imember->tmgi); + char buf[4]; + INT32_TO_BUFFER(m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id,buf); + //uint8_t TMGI[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(&member->tmgi.serviceID,(const char*)&buf[1],3); + + //LOG_D(M2AP,"%p,%p,%p,%li,%ld,%ld\n",pmch_configuration_item,&pmch_configuration_item->mbms_Session_List.list,member, m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid,sizeof(member->lcid),sizeof(m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid)); + //long kk = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid; + //uint64_t kk=(m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid); + //memcpy(&member->lcid,&m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid,sizeof(member->lcid)); + // member->lcid = 1; + // for( l=2; l < 28;l++) + // LOG_E(M2AP,"%di\n",l); + // if(l == m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid){ + // member->lcid++;//m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id; + // break; + // } + member->lcid = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid; + //member->lcid = (M2AP_LCID_t*)calloc(1,sizeof(M2AP_LCID_t)); + + ASN_SEQUENCE_ADD(&pmch_configuration_item->mbms_Session_List.list,member); + } + + } + /*M2AP_MBSFN_Subframe_ConfigurationList_t*/ + // M2AP_MBSFN_Area_Configuration_Item_t *mbsfn_area_configuration_item_ie2; + //(mbsfn_area_configuration_item_ie+1) =(M2AP_MBSFN_Area_Configuration_Item_t*)calloc(1,sizeof(M2AP_MBSFN_Area_Configuration_Item_t)); + + ASN_SEQUENCE_ADD(&mbsfn_area_configuration_item_ie->value.choice.PMCH_Configuration_List.list,pmch_configuration_item_ies); + + } + + ASN_SEQUENCE_ADD(m2ap_mbsfn_area_configuration_list,mbsfn_area_configuration_item_ie); + + /*M2AP_MBSFN_Area_Configuration_Item_t*/ + M2AP_MBSFN_Area_Configuration_Item_t *mbsfn_area_configuration_item_ie_1; + mbsfn_area_configuration_item_ie_1 =(M2AP_MBSFN_Area_Configuration_Item_t*)calloc(1,sizeof(M2AP_MBSFN_Area_Configuration_Item_t)); + (mbsfn_area_configuration_item_ie_1)->id = M2AP_ProtocolIE_ID_id_MBSFN_Subframe_Configuration_List; + (mbsfn_area_configuration_item_ie_1)->criticality = M2AP_Criticality_reject; + (mbsfn_area_configuration_item_ie_1)->value.present = M2AP_MBSFN_Area_Configuration_Item__value_PR_MBSFN_Subframe_ConfigurationList; + + for(j=0; j < m2ap_mbms_scheduling_information->mbms_area_config_list[i].num_mbms_sf_config_list; j++){ + M2AP_MBSFN_Subframe_ConfigurationItem_t * mbsfn_subframe_configuration_item_ies = (M2AP_MBSFN_Subframe_ConfigurationItem_t*)calloc(1,sizeof(M2AP_MBSFN_Subframe_ConfigurationItem_t)); + mbsfn_subframe_configuration_item_ies->id = M2AP_ProtocolIE_ID_id_MBSFN_Subframe_Configuration_Item; + mbsfn_subframe_configuration_item_ies->criticality = M2AP_Criticality_reject; + mbsfn_subframe_configuration_item_ies->value.present = M2AP_MBSFN_Subframe_ConfigurationItem__value_PR_MBSFN_Subframe_Configuration; + + M2AP_MBSFN_Subframe_Configuration_t * mbsfn_subframe_configuration; /* = (M2AP_MBSFN_Subframe_Configuration_t*)calloc(1,sizeof(M2AP_MBSFN_Subframe_Configuration_t));*/ + mbsfn_subframe_configuration = &mbsfn_subframe_configuration_item_ies->value.choice.MBSFN_Subframe_Configuration; + { + mbsfn_subframe_configuration->radioframeAllocationPeriod = m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].radioframe_allocation_period; + mbsfn_subframe_configuration->radioframeAllocationOffset = m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].radioframe_allocation_offset; + if(m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].is_four_sf){ + mbsfn_subframe_configuration->subframeAllocation.present = M2AP_MBSFN_Subframe_Configuration__subframeAllocation_PR_fourFrames; + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf = MALLOC(3); + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf[2] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation) & 0xFF); + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf[1] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation>>8) & 0xFF); + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf[0] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation>>16) & 0xFF); + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.size =3; + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.bits_unused = 0; + + }else{ + mbsfn_subframe_configuration->subframeAllocation.present = M2AP_MBSFN_Subframe_Configuration__subframeAllocation_PR_oneFrame; + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf = MALLOC(1); + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.size = 1; + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.bits_unused = 2; + //mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf[0] = 0x38<<2; + mbsfn_subframe_configuration->subframeAllocation.choice.oneFrame.buf[0] = (m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation & 0x3F)<<2; + } + + ASN_SEQUENCE_ADD(&(mbsfn_area_configuration_item_ie_1)->value.choice.MBSFN_Subframe_ConfigurationList.list,mbsfn_subframe_configuration_item_ies); + } + } + + ASN_SEQUENCE_ADD(m2ap_mbsfn_area_configuration_list,mbsfn_area_configuration_item_ie_1); + + + /*M2AP_MBSFN_Area_Configuration_Item_t*/ + M2AP_MBSFN_Area_Configuration_Item_t *mbsfn_area_configuration_item_ie_2; + mbsfn_area_configuration_item_ie_2 =(M2AP_MBSFN_Area_Configuration_Item_t*)calloc(1,sizeof(M2AP_MBSFN_Area_Configuration_Item_t)); + (mbsfn_area_configuration_item_ie_2)->id = M2AP_ProtocolIE_ID_id_Common_Subframe_Allocation_Period; + (mbsfn_area_configuration_item_ie_2)->criticality = M2AP_Criticality_reject; + (mbsfn_area_configuration_item_ie_2)->value.present = M2AP_MBSFN_Area_Configuration_Item__value_PR_Common_Subframe_Allocation_Period; + (mbsfn_area_configuration_item_ie_2)->value.choice.Common_Subframe_Allocation_Period=m2ap_mbms_scheduling_information->mbms_area_config_list[i].common_sf_allocation_period; + + ASN_SEQUENCE_ADD(m2ap_mbsfn_area_configuration_list,mbsfn_area_configuration_item_ie_2); + + + /*M2AP_MBSFN_Area_Configuration_Item_t*/ + M2AP_MBSFN_Area_Configuration_Item_t *mbsfn_area_configuration_item_ie_3; + mbsfn_area_configuration_item_ie_3 =(M2AP_MBSFN_Area_Configuration_Item_t*)calloc(1,sizeof(M2AP_MBSFN_Area_Configuration_Item_t)); + (mbsfn_area_configuration_item_ie_3)->id = M2AP_ProtocolIE_ID_id_MBSFN_Area_ID; + (mbsfn_area_configuration_item_ie_3)->criticality = M2AP_Criticality_reject; + (mbsfn_area_configuration_item_ie_3)->value.present = M2AP_MBSFN_Area_Configuration_Item__value_PR_MBSFN_Area_ID; + (mbsfn_area_configuration_item_ie_3)->value.choice.MBSFN_Area_ID = m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_area_id; + + ASN_SEQUENCE_ADD(m2ap_mbsfn_area_configuration_list,mbsfn_area_configuration_item_ie_3); + + +ASN_SET_ADD(&ie->value.choice.MBSFN_Area_Configuration_List,m2ap_mbsfn_area_configuration_list); + +/* xer_fprint(stdout,&asn_DEF_M2AP_MBSFN_Area_Configuration_Item,mbsfn_area_configuration_item_ie); + xer_fprint(stdout,&asn_DEF_M2AP_MBSFN_Area_Configuration_Item,mbsfn_area_configuration_item_ie_1); + xer_fprint(stdout,&asn_DEF_M2AP_MBSFN_Area_Configuration_Item,mbsfn_area_configuration_item_ie_2); + xer_fprint(stdout,&asn_DEF_M2AP_MBSFN_Area_Configuration_Item,mbsfn_area_configuration_item_ie_3); + xer_fprint(stdout,&asn_DEF_M2AP_MBSFN_Area_Configuration_List, &ie->value.choice.MBSFN_Area_Configuration_List);*/ + + } + + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + + /* encode */ + if (m2ap_encode_pdu(&pdu,&buffer,&len) < 0){ + return -1; + } + m2ap_MCE_itti_send_sctp_data_req(instance,m2ap_mce_data_from_enb->assoc_id,buffer,len,0); + return 0; + +} + +int MCE_handle_MBMS_SCHEDULING_INFORMATION_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + + LOG_D(M2AP, "MCE_handle_MBMS_SCHEDULING_INFORMATION_RESPONSE\n"); + + AssertFatal(pdu->present == M2AP_M2AP_PDU_PR_successfulOutcome, + "pdu->present != M2AP_M2AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M2AP_ProcedureCode_id_mbmsSchedulingInformation, + "pdu->choice.successfulOutcome->procedureCode != M2AP_ProcedureCode_id_mbmsSchedulingInformation\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M2AP_Criticality_reject, + "pdu->choice.successfulOutcome->criticality != M2AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M2AP_SuccessfulOutcome__value_PR_MbmsSchedulingInformationResponse, + "pdu->choice.successfulOutcome->value.present != M2AP_SuccessfulOutcome__value_PR_MbmsSchedulingInformationResponse\n"); + + + //M2AP_MbmsSchedulingInformationResponse_t *in = &pdu->choice.successfulOutcome.value.choice.MbmsSchedulingInformationResponse; + //M2AP_MbmsSchedulingInformationResponse_Ies_t *ie; + //int MCE_MBMS_M2AP_ID=-1; + //int ENB_MBMS_M2AP_ID=-1; + + + MessageDef *msg_g = itti_alloc_new_message(TASK_M2AP_MCE,M2AP_MBMS_SCHEDULING_INFORMATION_RESP); //TODO + +// LOG_D(M2AP, "M2AP: SessionStop-Resp: protocolIEs.list.count %d\n", +// in->protocolIEs.list.count); +// for (int i=0;i < in->protocolIEs.list.count; i++) { +// ie = in->protocolIEs.list.array[i]; +// //switch (ie->id) { +// //case M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID: +// // AssertFatal(ie->criticality == M2AP_Criticality_reject, +// // "ie->criticality != M2AP_Criticality_reject\n"); +// // AssertFatal(ie->value.present == M2AP_sessionStopIEs__value_PR_MCE_MBMS_M2AP_ID, +// // "ie->value.present != M2AP_sessionStopIEs__value_PR_MCE_MBMS_M2AP_ID\n"); +// // TransactionId=ie->value.choice.MCE_MBMS_M2AP_ID; +// // LOG_D(M2AP, "M2AP: SessionStop-Resp: MCE_MBMS_M2AP_ID %d\n", +// // MCE_MBMS_M2AP_ID); +// // break; +// // case M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID: +// // AssertFatal(ie->criticality == M2AP_Criticality_reject, +// // "ie->criticality != M2AP_Criticality_reject\n"); +// // AssertFatal(ie->value.present == M2AP_sessionStopIEs__value_PR_ENB_MBMS_M2AP_ID, +// // "ie->value.present != M2AP_sessionStopIEs__value_PR_ENB_MBMS_M2AP_ID\n"); +// // TransactionId=ie->value.choice.ENB_MBMS_M2AP_ID; +// // LOG_D(M2AP, "M2AP: SessionStop-Resp: ENB_MBMS_M2AP_ID %d\n", +// // ENB_MBMS_M2AP_ID); +// // break; +// //} +// } +// +// M2AP_SESSION_STOP_RESP(msg_p). +// MSC_LOG_RX_MESSAGE( +// MSC_M2AP_MCE, +// MSC_M2AP_ENB, +// 0, +// 0, +// MSC_AS_TIME_FMT" MCE_handle_M2_SCHEDULING_INFORMATION_RESPONSE successfulOutcome assoc_id %d", +// 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +// assoc_id); +// +// LOG_D(M2AP, "Sending M2AP_SCHEDULING_INFO_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", +// assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id)); +// itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), msg_g); +// + return 0; + +} + +/* + * Reset + */ + +int MCE_send_RESET(instance_t instance, m2ap_reset_t * m2ap_reset) { + AssertFatal(1==0,"Not implemented yet\n"); + //M2AP_Reset_t Reset; + +} + + +int MCE_handle_RESET_ACKKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) { + AssertFatal(1==0,"Not implemented yet\n"); + +} + +int MCE_handle_RESET(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) { + AssertFatal(1==0,"Not implemented yet\n"); +} + +int MCE_send_RESET_ACKNOWLEDGE(instance_t instance, M2AP_ResetAcknowledge_t *ResetAcknowledge) { + AssertFatal(1==0,"Not implemented yet\n"); +} + +/* + * M2 Setup + */ +int MCE_handle_M2_SETUP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + LOG_D(M2AP, "MCE_handle_M2_SETUP_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + M2AP_M2SetupRequest_t *container; + M2AP_M2SetupRequest_Ies_t *ie; + int i = 0/*,j=0*/; + int num_mbms_available=0; + + DevAssert(pdu != NULL); + + container = &pdu->choice.initiatingMessage.value.choice.M2SetupRequest; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received m2 setup request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message(TASK_MCE_APP, M2AP_SETUP_REQ); + + /* assoc_id */ + M2AP_SETUP_REQ(message_p).assoc_id = assoc_id; + + /* GlobalENB_id */ + // this function exits if the ie is mandatory + M2AP_FIND_PROTOCOLIE_BY_ID(M2AP_M2SetupRequest_Ies_t, ie, container, + M2AP_ProtocolIE_ID_id_GlobalENB_ID, true); + //asn_INTEGER2ulong(&ie->value.choice.GlobalENB_ID.eNB_ID, &M2AP_SETUP_REQ(message_p).GlobalENB_ID); + if(ie!=NULL){ + if(ie->value.choice.GlobalENB_ID.eNB_ID.present == M2AP_ENB_ID_PR_macro_eNB_ID){ + }else if(ie->value.choice.GlobalENB_ID.eNB_ID.present == M2AP_ENB_ID_PR_short_Macro_eNB_ID){ + }else if(ie->value.choice.GlobalENB_ID.eNB_ID.present == M2AP_ENB_ID_PR_long_Macro_eNB_ID){ + } + } + + LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).GlobalENB_ID %lu \n", M2AP_SETUP_REQ(message_p).GlobalENB_ID); + + /* ENB_name */ + M2AP_FIND_PROTOCOLIE_BY_ID(M2AP_M2SetupRequest_Ies_t, ie, container, + M2AP_ProtocolIE_ID_id_ENBname, false); + if(ie!=NULL){ + M2AP_SETUP_REQ(message_p).ENBname = calloc(ie->value.choice.ENBname.size + 1, sizeof(char)); + memcpy(M2AP_SETUP_REQ(message_p).ENBname, ie->value.choice.ENBname.buf, + ie->value.choice.ENBname.size); + + /* Convert the mme name to a printable string */ + M2AP_SETUP_REQ(message_p).ENBname[ie->value.choice.ENBname.size] = '\0'; + LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).gNB_DU_name %s \n", M2AP_SETUP_REQ(message_p).ENBname); + } + /* ENB_MBMS_Configuration_data_List */ + + + M2AP_FIND_PROTOCOLIE_BY_ID(M2AP_M2SetupRequest_Ies_t, ie, container, + M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_List, true); + + if(ie!=NULL){ + M2AP_SETUP_REQ(message_p).num_mbms_available = ie->value.choice.ENB_MBMS_Configuration_data_List.list.count; + LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).num_mbms_available %d \n", + M2AP_SETUP_REQ(message_p).num_mbms_available); + num_mbms_available = M2AP_SETUP_REQ(message_p).num_mbms_available; + for (i=0; ivalue.choice.ENB_MBMS_Configuration_data_List.list.array[i])->value.choice.ENB_MBMS_Configuration_data_Item); + /* eCGI */ + //mbms_configuration_item_p->eCGI ... (M2AP_ECGI_t) + + OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->eCGI.pLMN_Identity),M2AP_SETUP_REQ(message_p).plmn_identity[i]); + //OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->eCGI.eUTRANcellIdentifier),M2AP_SETUP_REQ(message_p).eutran_cell_identifier[i]); + /* mbsfnSynchronisationArea */ + //mbms_configuration_item_p->mbsfnSynchronisationArea ... (M2AP_MBSFN_SynchronisationArea_ID_t) + + M2AP_SETUP_REQ(message_p).mbsfn_synchronization_area[i]=mbms_configuration_item_p->mbsfnSynchronisationArea; + /* mbmsServiceAreaList */ + //mbms_configuration_item_p->mbmsServiceAreaList ... (M2AP_MBMS_Service_Area_ID_List_t) + } + } + +// /* tac */ +// OCTET_STRING_TO_INT16(&(served_celles_item_p->served_Cell_Information.fiveGS_TAC), M2AP_SETUP_REQ(message_p).tac[i]); +// LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).tac[%d] %d \n", +// i, M2AP_SETUP_REQ(message_p).tac[i]); +// +// /* - nRCGI */ +// TBCD_TO_MCC_MNC(&(served_celles_item_p->served_Cell_Information.nRCGI.pLMN_Identity), M2AP_SETUP_REQ(message_p).mcc[i], +// M2AP_SETUP_REQ(message_p).mnc[i], +// M2AP_SETUP_REQ(message_p).mnc_digit_length[i]); +// +// +// // NR cellID +// BIT_STRING_TO_NR_CELL_IDENTITY(&served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity, +// M2AP_SETUP_REQ(message_p).nr_cellid[i]); +// LOG_D(M2AP, "[SCTP %d] Received nRCGI: MCC %d, MNC %d, CELL_ID %llu\n", assoc_id, +// M2AP_SETUP_REQ(message_p).mcc[i], +// M2AP_SETUP_REQ(message_p).mnc[i], +// (long long unsigned int)M2AP_SETUP_REQ(message_p).nr_cellid[i]); +// LOG_D(M2AP, "nr_cellId : %x %x %x %x %x\n", +// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[0], +// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[1], +// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[2], +// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[3], +// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[4]); +// /* - nRPCI */ +// M2AP_SETUP_REQ(message_p).nr_pci[i] = served_celles_item_p->served_Cell_Information.nRPCI; +// LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).nr_pci[%d] %d \n", +// i, M2AP_SETUP_REQ(message_p).nr_pci[i]); +// +// // System Information +// /* mib */ +// M2AP_SETUP_REQ(message_p).mib[i] = calloc(served_celles_item_p->gNB_DU_System_Information->mIB_message.size + 1, sizeof(char)); +// memcpy(M2AP_SETUP_REQ(message_p).mib[i], served_celles_item_p->gNB_DU_System_Information->mIB_message.buf, +// served_celles_item_p->gNB_DU_System_Information->mIB_message.size); +// /* Convert the mme name to a printable string */ +// M2AP_SETUP_REQ(message_p).mib[i][served_celles_item_p->gNB_DU_System_Information->mIB_message.size] = '\0'; +// M2AP_SETUP_REQ(message_p).mib_length[i] = served_celles_item_p->gNB_DU_System_Information->mIB_message.size; +// LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).mib[%d] %s , len = %d \n", +// i, M2AP_SETUP_REQ(message_p).mib[i], M2AP_SETUP_REQ(message_p).mib_length[i]); +// +// /* sib1 */ +// M2AP_SETUP_REQ(message_p).sib1[i] = calloc(served_celles_item_p->gNB_DU_System_Information->sIB1_message.size + 1, sizeof(char)); +// memcpy(M2AP_SETUP_REQ(message_p).sib1[i], served_celles_item_p->gNB_DU_System_Information->sIB1_message.buf, +// served_celles_item_p->gNB_DU_System_Information->sIB1_message.size); +// /* Convert the mme name to a printable string */ +// M2AP_SETUP_REQ(message_p).sib1[i][served_celles_item_p->gNB_DU_System_Information->sIB1_message.size] = '\0'; +// M2AP_SETUP_REQ(message_p).sib1_length[i] = served_celles_item_p->gNB_DU_System_Information->sIB1_message.size; +// LOG_D(M2AP, "M2AP_SETUP_REQ(message_p).sib1[%d] %s , len = %d \n", +// i, M2AP_SETUP_REQ(message_p).sib1[i], M2AP_SETUP_REQ(message_p).sib1_length[i]); +// } + + + //printf("m2ap_mce_data_from_enb->assoc_id %d %d\n",m2ap_mce_data_from_enb->assoc_id,assoc_id); + + *m2ap_mce_data_from_enb = M2AP_SETUP_REQ(message_p); + //printf("m2ap_mce_data_from_enb->assoc_id %d %d\n",m2ap_mce_data_from_enb->assoc_id,assoc_id); + +// MSC_LOG_TX_MESSAGE( +// MSC_M2AP_MCE, +// MSC_RRC_ENB, +// 0, +// 0, +// MSC_AS_TIME_FMT" MCE_handle_M2_SETUP_REQUEST", +// 0,0//MSC_AS_TIME_ARGS(ctxt_pP), +// ); +// + if (num_mbms_available > 0) { + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + } else { + //MCE_send_M2_SETUP_FAILURE(instance); + return -1; + } +// return 0; + //TEST POINT MCE -> eNB +// if(1){ +// printf("instance %d\n",instance); +// //MCE_send_M2_SETUP_RESPONSE(instance,assoc_id,m2ap_mce_data_from_enb->assoc_id); +// //MCE_send_MBMS_SESSION_START_REQUEST(instance,assoc_id); +// //MCE_send_MBMS_SESSION_STOP_REQUEST(instance,assoc_id); +// //MCE_send_MBMS_SCHEDULING_INFORMATION(instance,assoc_id,NULL); //TODO +// } +// else +// MCE_send_M2_SETUP_FAILURE(instance,assoc_id); + + return 0; +} + +int MCE_send_M2_SETUP_RESPONSE(instance_t instance, /*uint32_t assoc_id,*/ + m2ap_setup_resp_t *m2ap_setup_resp) { + + //module_id_t mce_mod_idP; + //module_id_t enb_mod_idP; + + // This should be fixed + //enb_mod_idP = (module_id_t)0; + //mce_mod_idP = (module_id_t)0; + + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupResponse_t *out; + M2AP_M2SetupResponse_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + int i = 0; + //int j = 0; + + AssertFatal(m2ap_setup_resp!=NULL,"m2ap_setup_resp = NULL\n"); + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M2AP_SuccessfulOutcome_t *)calloc(1, sizeof(M2AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_M2SetupResponse; + out = &pdu.choice.successfulOutcome.value.choice.M2SetupResponse; + + /* mandatory */ + /* c1. GlobalMCE ID (integer value)*/ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_GlobalMCE_ID; + ie->criticality = M2AP_Criticality_reject; //? + ie->value.present = M2AP_M2SetupResponse_Ies__value_PR_GlobalMCE_ID; + //ie->value.choice.TransactionID = M2AP_get_next_transaction_identifier(enb_mod_idP, cu_mod_idP); + MCC_MNC_TO_PLMNID(m2ap_setup_resp->mcc, m2ap_setup_resp->mnc, m2ap_setup_resp->mnc_digit_length, + &ie->value.choice.GlobalMCE_ID.pLMN_Identity); + + ie->value.choice.GlobalMCE_ID.mCE_ID.buf =calloc(2, sizeof(uint8_t)); + ie->value.choice.GlobalMCE_ID.mCE_ID.buf[0] = (m2ap_setup_resp->MCE_id) >> 8; + ie->value.choice.GlobalMCE_ID.mCE_ID.buf[1] = ((m2ap_setup_resp->MCE_id) & 0x0ff); + ie->value.choice.GlobalMCE_ID.mCE_ID.size=2; + //ie->value.choice.GlobalMCE_ID.mCE_ID.bits_unused=0; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional */ + /* c2. MCEname */ + if (m2ap_setup_resp->MCE_name != NULL) { + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCEname; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_M2SetupResponse_Ies__value_PR_MCEname; + OCTET_STRING_fromBuf(&ie->value.choice.MCEname, m2ap_setup_resp->MCE_name, + strlen(m2ap_setup_resp->MCE_name)); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* mandatory */ + /* c3. cells to be Activated list */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_M2SetupResponse_Ies__value_PR_MCCHrelatedBCCH_ConfigPerMBSFNArea; + + for( i=0; i < m2ap_setup_resp->num_mcch_config_per_mbsfn; i++) + { + + M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs_t * mcch_related_bcch_config_per_mbsfn_area_item_ies; + mcch_related_bcch_config_per_mbsfn_area_item_ies = (M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs_t*)calloc(1,sizeof(M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs_t)); + mcch_related_bcch_config_per_mbsfn_area_item_ies->id=M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + mcch_related_bcch_config_per_mbsfn_area_item_ies->criticality = M2AP_Criticality_ignore; + mcch_related_bcch_config_per_mbsfn_area_item_ies->value.present=M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs__value_PR_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + + + M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item_t * config_per_mbsfn_area_item; + config_per_mbsfn_area_item = &mcch_related_bcch_config_per_mbsfn_area_item_ies->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + { + config_per_mbsfn_area_item->pdcchLength=m2ap_setup_resp->mcch_config_per_mbsfn[i].pdcch_length;//M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__pdcchLength_s1; + config_per_mbsfn_area_item->offset=m2ap_setup_resp->mcch_config_per_mbsfn[i].offset;//0; + config_per_mbsfn_area_item->repetitionPeriod=m2ap_setup_resp->mcch_config_per_mbsfn[i].repetition_period;//M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__repetitionPeriod_rf32; + config_per_mbsfn_area_item->modificationPeriod=m2ap_setup_resp->mcch_config_per_mbsfn[i].modification_period;//M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__modificationPeriod_rf512; + config_per_mbsfn_area_item->subframeAllocationInfo.buf = MALLOC(1); + config_per_mbsfn_area_item->subframeAllocationInfo.size=1; + /*char * t; + int bits=7; + for( t = m2ap_setup_resp->mcch_config_per_mbsfn[i].subframe_allocation_info; *t != '\0'; t++,bits--){ + if(*t=='1'){ + config_per_mbsfn_area_item->subframeAllocationInfo.buf[0] |= (uint8_t)(0x1<subframeAllocationInfo.buf[0] = (uint8_t)((m2ap_setup_resp->mcch_config_per_mbsfn[i].subframe_allocation_info & 0x3F)<<2); + + //config_per_mbsfn_area_item->subframeAllocationInfo.buf[0]=0x1<<7; + config_per_mbsfn_area_item->subframeAllocationInfo.bits_unused=2; + + //memset(&config_per_mbsfn_area_item->subframeAllocationInfo,0,sizeof(BIT_STRING_t)); + + config_per_mbsfn_area_item->modulationAndCodingScheme = m2ap_setup_resp->mcch_config_per_mbsfn[i].mcs;//M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__modulationAndCodingScheme_n2; + ASN_SEQUENCE_ADD(&ie->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea.list,mcch_related_bcch_config_per_mbsfn_area_item_ies); + } + + } + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 response\n"); + return -1; + } + + m2ap_MCE_itti_send_sctp_data_req(instance,m2ap_mce_data_from_enb->assoc_id,buffer,len,0); + + return 0; +} + +int MCE_send_M2_SETUP_FAILURE(instance_t instance,m2ap_setup_failure_t* m2ap_setup_failure) { + + // module_id_t enb_mod_idP; + //module_id_t mce_mod_idP; + + // This should be fixed + //enb_mod_idP = (module_id_t)0; + //mce_mod_idP = (module_id_t)0; + + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupFailure_t *out; + M2AP_M2SetupFailure_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; + //pdu.choice.unsuccessfulOutcome = (M2AP_UnsuccessfulOutcome_t *)calloc(1, sizeof(M2AP_UnsuccessfulOutcome_t)); + pdu.choice.unsuccessfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.unsuccessfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.unsuccessfulOutcome.value.present = M2AP_UnsuccessfulOutcome__value_PR_M2SetupFailure; + out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure; + + /* mandatory */ + /* c1. Transaction ID (integer value)*/ + // ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + // ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; + // ie->criticality = M2AP_Criticality_reject; + // ie->value.present = M2AP_M2SetupFailure_Ies__value_PR_GlobalENB_ID; + // ie->value.choice.GlobalENB_ID = M2AP_get_next_transaction_identifier(enb_mod_idP, mce_mod_idP); + // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. Cause */ + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_Cause; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_M2SetupFailure_Ies__value_PR_Cause; + ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; + ie->value.choice.Cause.choice.radioNetwork = M2AP_CauseRadioNetwork_unspecified; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional */ + /* c3. TimeToWait */ + if (0) { + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_TimeToWait; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_M2SetupFailure_Ies__value_PR_TimeToWait; + ie->value.choice.TimeToWait = M2AP_TimeToWait_v10s; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* optional */ + /* c4. CriticalityDiagnostics*/ + if (0) { + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_CriticalityDiagnostics; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_M2SetupFailure_Ies__value_PR_CriticalityDiagnostics; + ie->value.choice.CriticalityDiagnostics.procedureCode = (M2AP_ProcedureCode_t *)calloc(1, sizeof(M2AP_ProcedureCode_t)); + *ie->value.choice.CriticalityDiagnostics.procedureCode = M2AP_ProcedureCode_id_m2Setup; + ie->value.choice.CriticalityDiagnostics.triggeringMessage = (M2AP_TriggeringMessage_t *)calloc(1, sizeof(M2AP_TriggeringMessage_t)); + *ie->value.choice.CriticalityDiagnostics.triggeringMessage = M2AP_TriggeringMessage_initiating_message; + ie->value.choice.CriticalityDiagnostics.procedureCriticality = (M2AP_Criticality_t *)calloc(1, sizeof(M2AP_Criticality_t)); + *ie->value.choice.CriticalityDiagnostics.procedureCriticality = M2AP_Criticality_reject; + //ie->value.choice.CriticalityDiagnostics.transactionID = (M2AP_TransactionID_t *)calloc(1, sizeof(M2AP_TransactionID_t)); + //*ie->value.choice.CriticalityDiagnostics.transactionID = 0; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 setup request\n"); + return -1; + } + + //mce_m2ap_itti_send_sctp_data_req(instance, m2ap_mce_data_from_enb->assoc_id, buffer, len, 0); + m2ap_MCE_itti_send_sctp_data_req(instance,m2ap_mce_data_from_enb->assoc_id,buffer,len,0); + + return 0; +} + +/* + * MCE Configuration Update + */ + +int MCE_send_MCE_CONFIGURATION_UPDATE(instance_t instance, module_id_t du_mod_idP){ + AssertFatal(1==0,"Not implemented yet\n"); + + + M2AP_M2AP_PDU_t pdu; + M2AP_MCEConfigurationUpdate_t *out; + M2AP_MCEConfigurationUpdate_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + //int j = 0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_mCEConfigurationUpdate; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_MCEConfigurationUpdate; + out = &pdu.choice.initiatingMessage.value.choice.MCEConfigurationUpdate; + + /* mandatory */ + /* c1. Transaction ID (integer value)*/ + ie = (M2AP_MCEConfigurationUpdate_Ies_t *)calloc(1, sizeof(M2AP_MCEConfigurationUpdate_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_GlobalMCE_ID; + ie->criticality = M2AP_Criticality_reject; //? + ie->value.present = M2AP_MCEConfigurationUpdate_Ies__value_PR_GlobalMCE_ID; + //ie->value.choice.TransactionID = M2AP_get_next_transaction_identifier(enb_mod_idP, cu_mod_idP); + MCC_MNC_TO_PLMNID(0,0,3/*instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,*/ + ,&ie->value.choice.GlobalMCE_ID.pLMN_Identity); + + ie->value.choice.GlobalMCE_ID.mCE_ID.buf =calloc(2, sizeof(uint8_t)); + ie->value.choice.GlobalMCE_ID.mCE_ID.size=2; + //ie->value.choice.GlobalMCE_ID.mCE_ID.bits_unused=6; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional */ + /* c2. MCEname */ + //if (m2ap_setup_resp->MCEname != NULL) { + // ie = (M2AP_MCEConfigurationUpdate_Ies_t *)calloc(1, sizeof(M2AP_MCEConfigurationUpdate_Ies_t)); + // ie->id = M2AP_ProtocolIE_ID_id_MCEname; + // ie->criticality = M2AP_Criticality_ignore; + // ie->value.present = M2AP_MCEConfigurationUpdate_Ies__value_PR_MCEname; + // OCTET_STRING_fromBuf(&ie->value.choice.MCEname, m2ap_setup_resp->MCEname, + // strlen(m2ap_setup_resp->MCEname)); + // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + //} + + /* mandatory */ + /* c3. cells to be Activated list */ + ie = (M2AP_MCEConfigurationUpdate_Ies_t *)calloc(1, sizeof(M2AP_MCEConfigurationUpdate_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_MCEConfigurationUpdate_Ies__value_PR_MCCHrelatedBCCH_ConfigPerMBSFNArea; + + M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs_t * mcch_related_bcch_config_per_mbsfn_area_item_ies; + mcch_related_bcch_config_per_mbsfn_area_item_ies = (M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs_t*)calloc(1,sizeof(M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs_t)); + mcch_related_bcch_config_per_mbsfn_area_item_ies->id=M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + mcch_related_bcch_config_per_mbsfn_area_item_ies->criticality = M2AP_Criticality_ignore; + mcch_related_bcch_config_per_mbsfn_area_item_ies->value.present=M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_ItemIEs__value_PR_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + + M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item_t * config_per_mbsfn_area_item; + config_per_mbsfn_area_item = &mcch_related_bcch_config_per_mbsfn_area_item_ies->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + { + config_per_mbsfn_area_item->pdcchLength=M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__pdcchLength_s1; + config_per_mbsfn_area_item->offset=0; + config_per_mbsfn_area_item->repetitionPeriod=M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__repetitionPeriod_rf32; + config_per_mbsfn_area_item->modificationPeriod=M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__modificationPeriod_rf512; + config_per_mbsfn_area_item->subframeAllocationInfo.buf = MALLOC(1); + config_per_mbsfn_area_item->subframeAllocationInfo.size=1; + //config_per_mbsfn_area_item->subframeAllocationInfo.buf[0]=0x1<<7; + config_per_mbsfn_area_item->subframeAllocationInfo.bits_unused=2; + + //memset(&config_per_mbsfn_area_item->subframeAllocationInfo,0,sizeof(BIT_STRING_t)); + + config_per_mbsfn_area_item->modulationAndCodingScheme = M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item__modulationAndCodingScheme_n2; + ASN_SEQUENCE_ADD(&ie->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea.list,mcch_related_bcch_config_per_mbsfn_area_item_ies); + } + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 response\n"); + return -1; + } + + //MCE_m2ap_itti_send_sctp_data_req(instance, m2ap_mce_data_from_du->assoc_id, buffer, len, 0); + //printf(",m2ap_mce_data_from_enb->assoc_id %d\n",m2ap_mce_data_from_enb->assoc_id); + + m2ap_MCE_itti_send_sctp_data_req(instance,m2ap_mce_data_from_enb->assoc_id,buffer,len,0); + + + + +} + + +int MCE_handle_MCE_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + + LOG_D(M2AP, "MCE_handle_MCE_CONFIGURATION_UPDATE_FAILURE\n"); + + M2AP_MCEConfigurationUpdateFailure_t *in = &pdu->choice.unsuccessfulOutcome.value.choice.MCEConfigurationUpdateFailure; + + + //M2AP_MCEConfigurationUpdateFailure_Ies_t *ie; + + + MessageDef *msg_p = itti_alloc_new_message (TASK_M2AP_MCE, M2AP_MCE_CONFIGURATION_UPDATE_FAILURE); + + LOG_D(M2AP, "M2AP: MCEConfigurationUpdate-Failure: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + // for (int i=0;i < in->protocolIEs.list.count; i++) { + // ie = in->protocolIEs.list.array[i]; + // // switch (ie->id) { + // // case M2AP_ProtocolIE_ID_id_TimeToWait: + // // AssertFatal(ie->criticality == M2AP_Criticality_ignore, + // // "ie->criticality != M2AP_Criticality_ignore\n"); + // // AssertFatal(ie->value.present == M2AP_M2SetupFailure_Ies__value_PR_TimeToWait, + // // "ie->value.present != M2AP_M2SetupFailure_Ies__value_PR_TimeToWait\n"); + // // LOG_D(M2AP, "M2AP: M2Setup-Failure: TimeToWait %d\n");/*, + // // GlobalMCE_ID);*/ + // // break; + // // } + // } + //AssertFatal(GlobalMCE_ID!=-1,"GlobalMCE_ID was not sent\n"); + //AssertFatal(num_cells_to_activate>0,"No cells activated\n"); + //M2AP_SETUP_RESP (msg_p).num_cells_to_activate = num_cells_to_activate; + + //for (int i=0;i 0, "System Information %d is missing",i); + + //MSC_LOG_RX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_CU, + // 0, + // 0, + // MSC_AS_TIME_FMT" eNB_handle_M2_SETUP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + //LOG_D(M2AP, "Sending M2AP_SETUP_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MOeNBLE_ID_TO_INSTANCE(assoc_id)); + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + return 0; + +} + + +int MCE_handle_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M2AP, "MCE_handle_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_MCEConfigurationUpdateAcknowledge_t *container; + //M2AP_MCEConfigurationUpdateAcknowledge_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.MCEConfigurationUpdate; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_MCE, M2AP_MCE_CONFIGURATION_UPDATE_ACK); + + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + return 0; + +} + + +/* + * ENB Configuration Update + */ + + +int MCE_handle_ENB_CONFIGURATION_UPDATE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M2AP, "MCE_handle_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_MCEConfigurationUpdateAcknowledge_t *container; + //M2AP_MCEConfigurationUpdateAcknowledge_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.MCEConfigurationUpdate; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_MCE, M2AP_MCE_CONFIGURATION_UPDATE_ACK); + + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + return 0; + +} + + +int MCE_send_ENB_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + m2ap_enb_configuration_update_failure_t * m2ap_enb_configuration_update_failure){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + +int MCE_send_ENB_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + m2ap_enb_configuration_update_ack_t *m2ap_enb_configuration_update_ack){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + +/* + * Error Indication + */ + +int MCE_handle_ERROR_INDICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) { + AssertFatal(1==0,"Not implemented yet\n"); + + +} + +int MCE_send_ERROR_INDICATION(instance_t instance, M2AP_ErrorIndication_t *ErrorIndication) { + AssertFatal(1==0,"Not implemented yet\n"); +} + + + + +/* + * Session Update Request + */ +int MCE_send_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, m2ap_mbms_session_update_req_t * m2ap_mbms_session_update_req){ + AssertFatal(1==0,"Not implemented yet\n"); + //M2AP_SessionUpdateRequest_t SessionUpdateRequest; +} + + + +int MCE_handle_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + + +int MCE_handle_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + +/* + * Service Counting Request + */ +int MCE_send_MBMS_SERVICE_COUNTING_REQUEST(instance_t instance, module_id_t du_mod_idP){ + AssertFatal(1==0,"Not implemented yet\n"); + //M2AP_MbmsServiceCountingRequest_t MbmsServiceCountingRequest; +} + + + +int MCE_handle_MBMS_SERVICE_COUNTING_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + + + +int MCE_handle_MBMS_SESSION_COUNTING_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + +/* + * Service Counting Results Report + */ + +int MCE_handle_MBMS_SESSION_COUNTING_RESULTS_REPORT(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + +/* + * Overload Notification + */ +int MCE_handle_MBMS_OVERLOAD_NOTIFICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + + + diff --git a/openair2/M2AP/m2ap_MCE_interface_management.h b/openair2/M2AP/m2ap_MCE_interface_management.h new file mode 100644 index 0000000000..6b899e9ea2 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_interface_management.h @@ -0,0 +1,196 @@ +/* + * 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 m2ap_MCE_interface_management.h + * \brief m2ap interface management for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#ifndef M2AP_MCE_INTERFACE_MANAGEMENT_H_ +#define M2AP_MCE_INTERFACE_MANAGEMENT_H_ +/* + * MBMS Session start + */ +int MCE_send_MBMS_SESSION_START_REQUEST(instance_t instance/*, + uint32_t assoc_id*/,m2ap_session_start_req_t* m2ap_session_start_req); +int MCE_handle_MBMS_SESSION_START_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_handle_MBMS_SESSION_START_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +/* + * MBMS Session stop + */ +int MCE_send_MBMS_SESSION_STOP_REQUEST(instance_t instance, + m2ap_session_stop_req_t* m2ap_session_stop_req); + +int MCE_handle_MBMS_SESSION_STOP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * MBMS Scheduling Information + */ +int MCE_send_MBMS_SCHEDULING_INFORMATION(instance_t instance, + /*uint32_t assoc_id,*/ m2ap_mbms_scheduling_information_t * m2ap_mbms_scheduling_information ); + +int MCE_handle_MBMS_SCHEDULING_INFORMATION_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + + + +/* + * Reset + */ +int MCE_send_RESET(instance_t instance, m2ap_reset_t * m2ap_reset); + +int MCE_handle_RESET_ACKKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_handle_RESET(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +int MCE_send_RESET_ACKNOWLEDGE(instance_t instance, M2AP_ResetAcknowledge_t *ResetAcknowledge); + +/* + * M2AP Setup + */ +int MCE_handle_M2_SETUP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_send_M2_SETUP_RESPONSE(instance_t instance,/*uint32_t assoc_id,*/ m2ap_setup_resp_t *m2ap_setup_resp); + +int MCE_send_M2_SETUP_FAILURE(instance_t instance, /*uint32_t assoc_id*/ m2ap_setup_failure_t * m2ap_setup_failure); + + +/* + * MCE Configuration Update + */ + +int MCE_send_MCE_CONFIGURATION_UPDATE(instance_t instance, module_id_t du_mod_idP); + +int MCE_handle_MCE_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_handle_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * ENB Configuration Update + */ + + +int MCE_handle_ENB_CONFIGURATION_UPDATE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_send_ENB_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + m2ap_enb_configuration_update_failure_t *m2ap_enb_configuration_update_failure); + +int MCE_send_ENB_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + m2ap_enb_configuration_update_ack_t *m2ap_enb_configuration_update_ack); +/* + * Error Indication + */ +int MCE_handle_ERROR_INDICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +int MCE_send_ERROR_INDICATION(instance_t instance, M2AP_ErrorIndication_t *ErrorIndication); + + +/* + * Session Update Request + */ +int MCE_send_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, m2ap_mbms_session_update_req_t * m2ap_mbms_session_update_req); + +int MCE_handle_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_handle_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * Service Counting Request + */ +int MCE_send_MBMS_SERVICE_COUNTING_REQUEST(instance_t instance, module_id_t du_mod_idP); + +int MCE_handle_MBMS_SERVICE_COUNTING_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int MCE_handle_MBMS_SESSION_COUNTING_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +/* + * Service Counting Results Report + */ + +int MCE_handle_MBMS_SESSION_COUNTING_RESULTS_REPORT(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * Overload Notification + */ +int MCE_handle_MBMS_OVERLOAD_NOTIFICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + + + + + +#endif /* M2AP_MCE_INTERFACE_MANAGEMENT_H_ */ + + + diff --git a/openair2/M2AP/m2ap_MCE_management_procedures.c b/openair2/M2AP/m2ap_MCE_management_procedures.c new file mode 100644 index 0000000000..3934a57c74 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_management_procedures.c @@ -0,0 +1,257 @@ +/* + * 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 m2ap_MCE_management_procedures.c + * \brief m2ap tasks for MCE + * \author Javier Morgade + * \date 2018 + * \version 1.0 + */ + +#include +#include +#include + +#include "intertask_interface.h" + +#include "assertions.h" +#include "conversions.h" + +#include "m2ap_common.h" +#include "m2ap_MCE_defs.h" +#include "m2ap_MCE.h" + + +#define M2AP_DEBUG_LIST +#ifdef M2AP_DEBUG_LIST +# define M2AP_MCE_LIST_OUT(x, args...) M2AP_DEBUG("[MCE]%*s"x"\n", 4*indent, "", ##args) +#else +# define M2AP_MCE_LIST_OUT(x, args...) +#endif + +static int indent = 0; + + +m2ap_MCE_internal_data_t m2ap_MCE_internal_data; + +RB_GENERATE(m2ap_mce_map, m2ap_MCE_data_s, entry, m2ap_MCE_compare_assoc_id); + +int m2ap_MCE_compare_assoc_id( + struct m2ap_MCE_data_s *p1, struct m2ap_MCE_data_s *p2) +{ + if (p1->assoc_id == -1) { + if (p1->cnx_id < p2->cnx_id) { + return -1; + } + + if (p1->cnx_id > p2->cnx_id) { + return 1; + } + } else { + if (p1->assoc_id < p2->assoc_id) { + return -1; + } + + if (p1->assoc_id > p2->assoc_id) { + return 1; + } + } + + /* Matching reference */ + return 0; +} + +uint16_t m2ap_MCE_fetch_add_global_cnx_id(void) +{ + return ++m2ap_MCE_internal_data.global_cnx_id; +} + +void m2ap_MCE_prepare_internal_data(void) +{ + memset(&m2ap_MCE_internal_data, 0, sizeof(m2ap_MCE_internal_data)); + STAILQ_INIT(&m2ap_MCE_internal_data.m2ap_MCE_instances_head); +} + +void m2ap_MCE_insert_new_instance(m2ap_MCE_instance_t *new_instance_p) +{ + DevAssert(new_instance_p != NULL); + + STAILQ_INSERT_TAIL(&m2ap_MCE_internal_data.m2ap_MCE_instances_head, + new_instance_p, m2ap_MCE_entries); +} + +void dump_mce_tree_m2(m2ap_MCE_data_t *t) +{ + if (t == NULL) return; + printf("-----------------------\n"); + printf("MCE id %d %s\n", t->MCE_id, t->MCE_name); + printf("state %d\n", t->state); + printf("nextstream %d\n", t->nextstream); + printf("in_streams %d out_streams %d\n", t->in_streams, t->out_streams); + printf("cnx_id %d assoc_id %d\n", t->cnx_id, t->assoc_id); + dump_mce_tree_m2(t->entry.rbe_left); + dump_mce_tree_m2(t->entry.rbe_right); +} + +void dump_mce_trees_m2(void) +{ +m2ap_MCE_instance_t *zz; +STAILQ_FOREACH(zz, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, + m2ap_MCE_entries) { +//printf("here comes the tree (instance %d):\n---------------------------------------------\n", zz->instance); +dump_mce_tree_m2(zz->m2ap_mce_head.rbh_root); +//printf("---------------------------------------------\n"); +} +} + +struct m2ap_MCE_data_s *m2ap_get_MCE(m2ap_MCE_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id) +{ + struct m2ap_MCE_data_s temp; + struct m2ap_MCE_data_s *found; + +//printf("m2ap_get_MCE at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id); +//dump_mce_trees_m2(); + + memset(&temp, 0, sizeof(struct m2ap_MCE_data_s)); + + temp.assoc_id = assoc_id; + temp.cnx_id = cnx_id; + + if (instance_p == NULL) { + STAILQ_FOREACH(instance_p, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, + m2ap_MCE_entries) { + found = RB_FIND(m2ap_mce_map, &instance_p->m2ap_mce_head, &temp); + + if (found != NULL) { + return found; + } + } + } else { + return RB_FIND(m2ap_mce_map, &instance_p->m2ap_mce_head, &temp); + } + + return NULL; +} + + +m2ap_MCE_instance_t *m2ap_MCE_get_instance(instance_t instance) +{ + m2ap_MCE_instance_t *temp = NULL; + + STAILQ_FOREACH(temp, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, + m2ap_MCE_entries) { + if (temp->instance == instance) { + /* Matching occurence */ + return temp; + } + } + + return NULL; +} + +/// utility functions + +void m2ap_dump_MCE (m2ap_MCE_data_t * MCE_ref); + +void +m2ap_dump_MCE_list (void) { + m2ap_MCE_instance_t *inst = NULL; + struct m2ap_MCE_data_s *found = NULL; + struct m2ap_MCE_data_s temp; + + memset(&temp, 0, sizeof(struct m2ap_MCE_data_s)); + + STAILQ_FOREACH (inst, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, m2ap_MCE_entries) { + found = RB_FIND(m2ap_mce_map, &inst->m2ap_mce_head, &temp); + m2ap_dump_MCE (found); + } +} + +void m2ap_dump_MCE (m2ap_MCE_data_t * MCE_ref) { + + if (MCE_ref == NULL) { + return; + } + + M2AP_MCE_LIST_OUT (""); + M2AP_MCE_LIST_OUT ("MCE name: %s", MCE_ref->MCE_name == NULL ? "not present" : MCE_ref->MCE_name); + M2AP_MCE_LIST_OUT ("MCE STATE: %07x", MCE_ref->state); + M2AP_MCE_LIST_OUT ("MCE ID: %07x", MCE_ref->MCE_id); + indent++; + M2AP_MCE_LIST_OUT ("SCTP cnx id: %d", MCE_ref->cnx_id); + M2AP_MCE_LIST_OUT ("SCTP assoc id: %d", MCE_ref->assoc_id); + M2AP_MCE_LIST_OUT ("SCTP instreams: %d", MCE_ref->in_streams); + M2AP_MCE_LIST_OUT ("SCTP outstreams: %d", MCE_ref->out_streams); + indent--; +} + +m2ap_MCE_data_t * m2ap_is_MCE_pci_in_list (const uint32_t pci) +{ + m2ap_MCE_instance_t *inst; + struct m2ap_MCE_data_s *elm; + + STAILQ_FOREACH(inst, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, m2ap_MCE_entries) { + RB_FOREACH(elm, m2ap_mce_map, &inst->m2ap_mce_head) { + for (int i = 0; inum_cc; i++) { + if (elm->Nid_cell[i] == pci) { + return elm; + } + } + } + } + return NULL; +} + +m2ap_MCE_data_t * m2ap_is_MCE_id_in_list (const uint32_t MCE_id) +{ + m2ap_MCE_instance_t *inst; + struct m2ap_MCE_data_s *elm; + + STAILQ_FOREACH(inst, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, m2ap_MCE_entries) { + RB_FOREACH(elm, m2ap_mce_map, &inst->m2ap_mce_head) { + if (elm->MCE_id == MCE_id) + return elm; + } + } + return NULL; +} + +m2ap_MCE_data_t * m2ap_is_MCE_assoc_id_in_list (const uint32_t sctp_assoc_id) +{ + m2ap_MCE_instance_t *inst; + struct m2ap_MCE_data_s *found; + struct m2ap_MCE_data_s temp; + + temp.assoc_id = sctp_assoc_id; + temp.cnx_id = -1; + + STAILQ_FOREACH(inst, &m2ap_MCE_internal_data.m2ap_MCE_instances_head, m2ap_MCE_entries) { + found = RB_FIND(m2ap_mce_map, &inst->m2ap_mce_head, &temp); + if (found != NULL){ + if (found->assoc_id == sctp_assoc_id) { + return found; + } + } + } + return NULL; +} diff --git a/openair2/M2AP/m2ap_MCE_management_procedures.h b/openair2/M2AP/m2ap_MCE_management_procedures.h new file mode 100644 index 0000000000..9e13e723c9 --- /dev/null +++ b/openair2/M2AP/m2ap_MCE_management_procedures.h @@ -0,0 +1,54 @@ +/* + * 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 m2ap_eNB_management_procedures.h + * \brief m2ap tasks for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_MCE_MANAGEMENT_PROCEDURES_H_ +#define M2AP_MCE_MANAGEMENT_PROCEDURES_H + +void m2ap_MCE_prepare_internal_data(void); + +void dump_trees_m2(void); + +void m2ap_MCE_insert_new_instance(m2ap_MCE_instance_t *new_instance_p); + +m2ap_MCE_instance_t *m2ap_MCE_get_instance(uint8_t mod_id); + +uint16_t m2ap_MCE_fetch_add_global_cnx_id(void); + +void m2ap_MCE_prepare_internal_data(void); + +m2ap_MCE_data_t* m2ap_is_MCE_id_in_list(uint32_t MCE_id); + +m2ap_MCE_data_t* m2ap_is_MCE_assoc_id_in_list(uint32_t sctp_assoc_id); + +m2ap_MCE_data_t* m2ap_is_MCE_pci_in_list (const uint32_t pci); + +struct m2ap_MCE_data_s *m2ap_get_MCE(m2ap_MCE_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id); + +#endif /* M2AP_MCE_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair2/M2AP/m2ap_common.c b/openair2/M2AP/m2ap_common.c new file mode 100644 index 0000000000..d288a0a114 --- /dev/null +++ b/openair2/M2AP/m2ap_common.c @@ -0,0 +1,124 @@ +/* + * 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 m2ap_common.c + * \brief m2ap procedures for both eNB and MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "m2ap_common.h" +#include "M2AP_M2AP-PDU.h" + +int asn_debug = 0; +int asn1_xer_print = 0; + +#if defined(EMIT_ASN_DEBUG_EXTERN) +inline void ASN_DEBUG(const char *fmt, ...) +{ + if (asn_debug) { + int adi = asn_debug_indent; + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "[ASN1]"); + + while(adi--) fprintf(stderr, " "); + + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + } +} +#endif + +ssize_t m2ap_generate_initiating_message( + uint8_t **buffer, + uint32_t *length, + M2AP_ProcedureCode_t procedureCode, + M2AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + M2AP_M2AP_PDU_t pdu; + ssize_t encoded; + memset(&pdu, 0, sizeof(M2AP_M2AP_PDU_t)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = procedureCode; + pdu.choice.initiatingMessage.criticality = criticality; + ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_M2AP_M2AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + return encoded; +} + + +ssize_t m2ap_generate_unsuccessfull_outcome( + uint8_t **buffer, + uint32_t *length, + M2AP_ProcedureCode_t procedureCode, + M2AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + M2AP_M2AP_PDU_t pdu; + ssize_t encoded; + memset(&pdu, 0, sizeof(M2AP_M2AP_PDU_t)); + pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; + pdu.choice.successfulOutcome.procedureCode = procedureCode; + pdu.choice.successfulOutcome.criticality = criticality; + ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_M2AP_M2AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + return encoded; +} + +void m2ap_handle_criticality(M2AP_Criticality_t criticality) +{ + +} + diff --git a/openair2/M2AP/m2ap_common.h b/openair2/M2AP/m2ap_common.h new file mode 100644 index 0000000000..95da064b4a --- /dev/null +++ b/openair2/M2AP/m2ap_common.h @@ -0,0 +1,173 @@ +/* + * 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 + */ + +#if HAVE_CONFIG_H_ +# include "config.h" +#endif + +#include "M2AP_ProtocolIE-Field.h" +#include "M2AP_M2AP-PDU.h" +#include "M2AP_InitiatingMessage.h" +#include "M2AP_SuccessfulOutcome.h" +#include "M2AP_UnsuccessfulOutcome.h" +#include "M2AP_ProtocolIE-FieldPair.h" +#include "M2AP_ProtocolIE-ContainerPair.h" +#include "M2AP_ProtocolExtensionField.h" +#include "M2AP_ProtocolExtensionContainer.h" +#include "M2AP_PMCH-Configuration-Item.h" +#include "M2AP_asn_constant.h" +#include "intertask_interface.h" + +#include "common/ran_context.h" + +#ifndef M2AP_COMMON_H_ +#define M2AP_COMMON_H_ + +/** @defgroup _m2ap_impl_ M2AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +/* Checking version of ASN1C compiler */ +#if (ASN1C_ENVIRONMENT_VERSION < 923) +# error "You are compiling m2ap with the wrong version of ASN1C" +#endif + +#ifndef M2AP_PORT +# define M2AP_PORT 36423 +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +extern int asn1_xer_print; + +#if defined(ENB_MODE) +# include "common/utils/LOG/log.h" +# include "m2ap_default_values.h" +# define M2AP_INFO(x, args...) LOG_I(M2AP, x, ##args) +# define M2AP_ERROR(x, args...) LOG_E(M2AP, x, ##args) +# define M2AP_WARN(x, args...) LOG_W(M2AP, x, ##args) +# define M2AP_DEBUG(x, args...) LOG_D(M2AP, x, ##args) +#else +# define M2AP_INFO(x, args...) do { fprintf(stdout, "[M2AP][I]"x, ##args); } while(0) +# define M2AP_ERROR(x, args...) do { fprintf(stdout, "[M2AP][E]"x, ##args); } while(0) +# define M2AP_WARN(x, args...) do { fprintf(stdout, "[M2AP][W]"x, ##args); } while(0) +# define M2AP_DEBUG(x, args...) do { fprintf(stdout, "[M2AP][D]"x, ##args); } while(0) +#endif + +#define M2AP_FIND_PROTOCOLIE_BY_ID(IE_TYPE, ie, container, IE_ID, mandatory) \ + do {\ + IE_TYPE **ptr; \ + ie = NULL; \ + for (ptr = container->protocolIEs.list.array; \ + ptr < &container->protocolIEs.list.array[container->protocolIEs.list.count]; \ + ptr++) { \ + if((*ptr)->id == IE_ID) { \ + ie = *ptr; \ + break; \ + } \ + } \ + if (mandatory) DevAssert(ie != NULL); \ + } while(0) + +/** \brief Function callback prototype. + **/ +typedef int (*m2ap_message_decoded_callback)( + instance_t instance, + uint32_t assocId, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +typedef int (*m2ap_MCE_message_decoded_callback)( + instance_t instance, + uint32_t assocId, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +typedef int (*m2ap_eNB_message_decoded_callback)( + instance_t instance, + uint32_t assocId, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + + + +/** \brief Encode a successfull outcome message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t m2ap_generate_successfull_outcome( + uint8_t **buffer, + uint32_t *length, + M2AP_ProcedureCode_t procedureCode, + M2AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Encode an initiating message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t m2ap_generate_initiating_message( + uint8_t **buffer, + uint32_t *length, + M2AP_ProcedureCode_t procedureCode, + M2AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Encode an unsuccessfull outcome message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t m2ap_generate_unsuccessfull_outcome( + uint8_t **buffer, + uint32_t *length, + M2AP_ProcedureCode_t procedureCode, + M2AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Handle criticality + \param criticality Criticality of the IE + @returns void + **/ +void m2ap_handle_criticality(M2AP_Criticality_t criticality); + +#endif /* M2AP_COMMON_H_ */ diff --git a/openair2/M2AP/m2ap_decoder.c b/openair2/M2AP/m2ap_decoder.c new file mode 100644 index 0000000000..1237c4ec8e --- /dev/null +++ b/openair2/M2AP/m2ap_decoder.c @@ -0,0 +1,194 @@ +/* + * 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 m2ap_decoder.c + * \brief m2ap decoder procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "assertions.h" +#include "intertask_interface.h" +#include "m2ap_common.h" +#include "m2ap_decoder.h" + +static int m2ap_decode_initiating_message(M2AP_M2AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + switch(pdu->choice.initiatingMessage.procedureCode) { + case M2AP_ProcedureCode_id_sessionStart: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + case M2AP_ProcedureCode_id_sessionStop: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + case M2AP_ProcedureCode_id_m2Setup: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + case M2AP_ProcedureCode_id_mbmsSchedulingInformation: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + + + +// case M2AP_ProcedureCode_id_handoverPreparation: +// //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); +// M2AP_INFO("m2ap__decode_initiating_message!\n"); +// break; +// +// case M2AP_ProcedureCode_id_uEContextRelease: +// //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); +// M2AP_INFO("m2ap__decode_initiating_message!\n"); +// break; +// +// case M2AP_ProcedureCode_id_handoverCancel: +// //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); +// M2AP_INFO("m2ap__decode_initiating_message!\n"); +// break; +// + default: + M2AP_ERROR("Unknown procedure ID (%d) for initiating message\n", + (int)pdu->choice.initiatingMessage.procedureCode); + AssertFatal( 0, "Unknown procedure ID (%d) for initiating message\n", + (int)pdu->choice.initiatingMessage.procedureCode); + return -1; + } + + return 0; +} + +static int m2ap_decode_successful_outcome(M2AP_M2AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + switch(pdu->choice.successfulOutcome.procedureCode) { + case M2AP_ProcedureCode_id_sessionStart: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_successfuloutcome_message!\n"); + break; + case M2AP_ProcedureCode_id_sessionStop: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_succesfuloutcome_message!\n"); + break; + case M2AP_ProcedureCode_id_m2Setup: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_succesfuloutcome_message!\n"); + break; + case M2AP_ProcedureCode_id_mbmsSchedulingInformation: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_succesfuloutcome_message!\n"); + break; + + +// case M2AP_ProcedureCode_id_handoverPreparation: +// //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); +// M2AP_INFO("m2ap__decode_successfuloutcome_message!\n"); +// break; +// + default: + M2AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n", + (int)pdu->choice.successfulOutcome.procedureCode); + return -1; + } + + return 0; +} + +static int m2ap_decode_unsuccessful_outcome(M2AP_M2AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + switch(pdu->choice.unsuccessfulOutcome.procedureCode) { + case M2AP_ProcedureCode_id_sessionStart: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + case M2AP_ProcedureCode_id_sessionStop: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + case M2AP_ProcedureCode_id_m2Setup: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + case M2AP_ProcedureCode_id_mbmsSchedulingInformation: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M2AP_M2AP_PDU, pdu); + M2AP_INFO("m2ap__decode_initiating_message!\n"); + break; + + + default: + M2AP_ERROR("Unknown procedure ID (%d) for unsuccessfull outcome message\n", + (int)pdu->choice.unsuccessfulOutcome.procedureCode); + return -1; + } + + return 0; +} + +int m2ap_decode_pdu(M2AP_M2AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length) +{ + asn_dec_rval_t dec_ret; + + DevAssert(buffer != NULL); + + dec_ret = aper_decode(NULL, + &asn_DEF_M2AP_M2AP_PDU, + (void **)&pdu, + buffer, + length, + 0, + 0); + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, pdu); + } + + if (dec_ret.code != RC_OK) { + M2AP_ERROR("Failed to decode pdu\n"); + return -1; + } + + switch(pdu->present) { + case M2AP_M2AP_PDU_PR_initiatingMessage: + return m2ap_decode_initiating_message(pdu); + + case M2AP_M2AP_PDU_PR_successfulOutcome: + return m2ap_decode_successful_outcome(pdu); + + case M2AP_M2AP_PDU_PR_unsuccessfulOutcome: + return m2ap_decode_unsuccessful_outcome(pdu); + + default: + M2AP_DEBUG("Unknown presence (%d) or not implemented\n", (int)pdu->present); + break; + } + + + return -1; +} diff --git a/openair2/M2AP/m2ap_decoder.h b/openair2/M2AP/m2ap_decoder.h new file mode 100644 index 0000000000..6ab01fe703 --- /dev/null +++ b/openair2/M2AP/m2ap_decoder.h @@ -0,0 +1,35 @@ +/* + * 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 m2ap_decoder.h + * \brief m2ap decoder procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_DECODER_H_ +#define M2AP_DECODER_H_ + +int m2ap_decode_pdu(M2AP_M2AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length) +__attribute__ ((warn_unused_result)); + +#endif /* M2AP_DECODER_H_ */ diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h b/openair2/M2AP/m2ap_default_values.h similarity index 61% rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h rename to openair2/M2AP/m2ap_default_values.h index 4d2401db83..baae4b963c 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h +++ b/openair2/M2AP/m2ap_default_values.h @@ -19,28 +19,29 @@ * contact@openairinterface.org */ -/*!\file nrLDPC_decoder.h - * \brief Defines the LDPC decoder core prototypes - * \author Sebastian Wagner (TCL Communications) Email: - * \date 27-03-2018 - * \version 1.0 +/*! \file m2ap_default_values.h + * \brief default values for m2ap procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org * \note * \warning */ -#ifndef __NR_LDPC_DECODER__H__ -#define __NR_LDPC_DECODER__H__ +#ifndef M2AP_DEFAULT_VALUES_H_ +#define M2AP_DEFAULT_VALUES_H_ -#include "nrLDPC_types.h" -#include "nrLDPC_init_mem.h" +#define ENB_TAC (1) +#define ENB_MCC (208) +#define ENB_MNC (92) -/** - \brief LDPC decoder - \param p_decParams LDPC decoder parameters - \param p_llr Input LLRs - \param p_llrOut Output vector - \param p_profiler LDPC profiler statistics -*/ -int32_t nrLDPC_decoder(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_llrOut, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler); +#define ENB_NAME "Eurecom ENB" +#define ENB_NAME_FORMAT (ENB_NAME" %u") + +#define M2AP_PORT_NUMBER (36443) +#define M2AP_SCTP_PPID (43) + +#endif /* M2AP_DEFAULT_VALUES_H_ */ -#endif diff --git a/openair2/M2AP/m2ap_eNB.c b/openair2/M2AP/m2ap_eNB.c new file mode 100644 index 0000000000..206b7cf8ca --- /dev/null +++ b/openair2/M2AP/m2ap_eNB.c @@ -0,0 +1,704 @@ +/* + * 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 m2ap_eNB.c + * \brief m2ap tasks for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include +#include +#include +#include + +#include "intertask_interface.h" + +#include "m2ap_eNB.h" +#include "m2ap_eNB_defs.h" +#include "m2ap_eNB_management_procedures.h" +#include "m2ap_eNB_handler.h" +#include "m2ap_eNB_generate_messages.h" +#include "m2ap_common.h" +#include "m2ap_eNB_interface_management.h" +#include "m2ap_ids.h" +#include "m2ap_timers.h" + +#include "queue.h" +#include "assertions.h" +#include "conversions.h" + +struct m2ap_enb_map; +struct m2ap_eNB_data_s; + +m2ap_setup_req_t * m2ap_enb_data_g; + +RB_PROTOTYPE(m2ap_enb_map, m2ap_eNB_data_s, entry, m2ap_eNB_compare_assoc_id); + +static +void m2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind); + +static +void m2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp); + +static +void m2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind); + +static +void m2ap_eNB_handle_register_eNB(instance_t instance, + m2ap_register_enb_req_t *m2ap_register_eNB); +static +void m2ap_eNB_register_eNB(m2ap_eNB_instance_t *instance_p, + net_ip_address_t *target_eNB_ip_addr, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t enb_port_for_M2C, + int multi_sd); + +//static +//void m2ap_eNB_handle_handover_req(instance_t instance, +// m2ap_handover_req_t *m2ap_handover_req); +// +//static +//void m2ap_eNB_handle_handover_req_ack(instance_t instance, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack); +// +//static +//void m2ap_eNB_ue_context_release(instance_t instance, +// m2ap_ue_context_release_t *m2ap_ue_context_release); +// + +static +void m2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) { + int result; + DevAssert(sctp_data_ind != NULL); + m2ap_eNB_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream, + sctp_data_ind->buffer, sctp_data_ind->buffer_length); + result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +} + +static +void m2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { + m2ap_eNB_instance_t *instance_p; + m2ap_eNB_data_t *m2ap_enb_data_p; + DevAssert(sctp_new_association_resp != NULL); + // printf("m2ap_eNB_handle_sctp_association_resp at 1\n"); + // dump_trees_m2(); + instance_p = m2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + /* if the assoc_id is already known, it is certainly because an IND was received + * before. In this case, just update streams and return + */ + if (sctp_new_association_resp->assoc_id != -1) { + m2ap_enb_data_p = m2ap_get_eNB(instance_p, sctp_new_association_resp->assoc_id, + sctp_new_association_resp->ulp_cnx_id); + + if (m2ap_enb_data_p != NULL) { + /* some sanity check - to be refined at some point */ + if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + M2AP_ERROR("m2ap_enb_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n"); + abort(); + } + + m2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams; + m2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams; + return; + } + } + + m2ap_enb_data_p = m2ap_get_eNB(instance_p, -1, + sctp_new_association_resp->ulp_cnx_id); + DevAssert(m2ap_enb_data_p != NULL); + //printf("m2ap_eNB_handle_sctp_association_resp at 2\n"); + //dump_trees_m2(); + + if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + M2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n", + sctp_new_association_resp->sctp_state, + instance, + sctp_new_association_resp->ulp_cnx_id); + //m2ap_handle_m2_setup_message(instance_p, m2ap_enb_data_p, + // sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); + return; + } + + //printf("m2ap_eNB_handle_sctp_association_resp at 3\n"); + //dump_trees_m2(); + /* Update parameters */ + m2ap_enb_data_p->assoc_id = sctp_new_association_resp->assoc_id; + m2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams; + m2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams; + //printf("m2ap_eNB_handle_sctp_association_resp at 4\n"); + //dump_trees_m2(); + + m2ap_enb_data_g->assoc_id = sctp_new_association_resp->assoc_id; + m2ap_enb_data_g->sctp_in_streams = sctp_new_association_resp->in_streams; + m2ap_enb_data_g->sctp_out_streams = sctp_new_association_resp->out_streams; + + /* Prepare new m2 Setup Request */ + //m2ap_eNB_generate_m2_setup_request(instance_p, m2ap_enb_data_p); + eNB_send_M2_SETUP_REQUEST(instance_p, m2ap_enb_data_p); + //eNB_send_M2_SETUP_REQUEST(instance_p, m2ap_enb_data_g); + +} + +static +void m2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind) { + m2ap_eNB_instance_t *instance_p; + m2ap_eNB_data_t *m2ap_enb_data_p; + //printf("m2ap_eNB_handle_sctp_association_ind at 1 (called for instance %d)\n", instance); + //dump_trees_m2(); + DevAssert(sctp_new_association_ind != NULL); + instance_p = m2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + m2ap_enb_data_p = m2ap_get_eNB(instance_p, sctp_new_association_ind->assoc_id, -1); + + if (m2ap_enb_data_p != NULL) abort(); + + // DevAssert(m2ap_enb_data_p != NULL); + if (m2ap_enb_data_p == NULL) { + /* Create new eNB descriptor */ + m2ap_enb_data_p = calloc(1, sizeof(*m2ap_enb_data_p)); + DevAssert(m2ap_enb_data_p != NULL); + m2ap_enb_data_p->cnx_id = m2ap_eNB_fetch_add_global_cnx_id(); + m2ap_enb_data_p->m2ap_eNB_instance = instance_p; + /* Insert the new descriptor in list of known eNB + * but not yet associated. + */ + RB_INSERT(m2ap_enb_map, &instance_p->m2ap_enb_head, m2ap_enb_data_p); + m2ap_enb_data_p->state = M2AP_ENB_STATE_CONNECTED; + instance_p->m2_target_enb_nb++; + + if (instance_p->m2_target_enb_pending_nb > 0) { + instance_p->m2_target_enb_pending_nb--; + } + } else { + M2AP_WARN("m2ap_enb_data_p already exists\n"); + } + + //printf("m2ap_eNB_handle_sctp_association_ind at 2\n"); + //dump_trees_m2(); + /* Update parameters */ + m2ap_enb_data_p->assoc_id = sctp_new_association_ind->assoc_id; + m2ap_enb_data_p->in_streams = sctp_new_association_ind->in_streams; + m2ap_enb_data_p->out_streams = sctp_new_association_ind->out_streams; + //printf("m2ap_eNB_handle_sctp_association_ind at 3\n"); + //dump_trees_m2(); +} + +int m2ap_eNB_init_sctp (m2ap_eNB_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t enb_port_for_M2C) { + // Create and alloc new message + MessageDef *message; + sctp_init_t *sctp_init = NULL; + DevAssert(instance_p != NULL); + DevAssert(local_ip_addr != NULL); + message = itti_alloc_new_message (TASK_M2AP_ENB, SCTP_INIT_MSG_MULTI_REQ); + sctp_init = &message->ittiMsg.sctp_init_multi; + sctp_init->port = enb_port_for_M2C; + sctp_init->ppid = M2AP_SCTP_PPID; + sctp_init->ipv4 = 1; + sctp_init->ipv6 = 0; + sctp_init->nb_ipv4_addr = 1; +#if 0 + memcpy(&sctp_init->ipv4_address, + local_ip_addr, + sizeof(*local_ip_addr)); +#endif + sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address); + /* + * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * * * * Disable it for now. + */ + sctp_init->nb_ipv6_addr = 0; + sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1"; + return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message); +} + +static void m2ap_eNB_register_eNB(m2ap_eNB_instance_t *instance_p, + net_ip_address_t *target_eNB_ip_address, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t enb_port_for_M2C, + int multi_sd) { + MessageDef *message = NULL; + sctp_new_association_req_multi_t *sctp_new_association_req = NULL; + m2ap_eNB_data_t *m2ap_enb_data = NULL; + DevAssert(instance_p != NULL); + DevAssert(target_eNB_ip_address != NULL); + message = itti_alloc_new_message(TASK_M2AP_ENB, SCTP_NEW_ASSOCIATION_REQ_MULTI); + sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi; + sctp_new_association_req->port = enb_port_for_M2C; + sctp_new_association_req->ppid = M2AP_SCTP_PPID; + sctp_new_association_req->in_streams = in_streams; + sctp_new_association_req->out_streams = out_streams; + sctp_new_association_req->multi_sd = multi_sd; + memcpy(&sctp_new_association_req->remote_address, + target_eNB_ip_address, + sizeof(*target_eNB_ip_address)); + memcpy(&sctp_new_association_req->local_address, + local_ip_addr, + sizeof(*local_ip_addr)); + /* Create new eNB descriptor */ + m2ap_enb_data = calloc(1, sizeof(*m2ap_enb_data)); + DevAssert(m2ap_enb_data != NULL); + m2ap_enb_data->cnx_id = m2ap_eNB_fetch_add_global_cnx_id(); + sctp_new_association_req->ulp_cnx_id = m2ap_enb_data->cnx_id; + m2ap_enb_data->assoc_id = -1; + m2ap_enb_data->m2ap_eNB_instance = instance_p; + + + m2ap_enb_data_g = (m2ap_setup_req_t*)calloc(1,sizeof(m2ap_setup_req_t)); + + + // + m2ap_enb_data->eNB_name = "enb_name"; + /* Insert the new descriptor in list of known eNB + * but not yet associated. + */ + RB_INSERT(m2ap_enb_map, &instance_p->m2ap_enb_head, m2ap_enb_data); + m2ap_enb_data->state = M2AP_ENB_STATE_WAITING; + instance_p->m2_target_enb_nb ++; + instance_p->m2_target_enb_pending_nb ++; + itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message); +} + +static +void m2ap_eNB_handle_register_eNB(instance_t instance, + m2ap_register_enb_req_t *m2ap_register_eNB) { + m2ap_eNB_instance_t *new_instance; + DevAssert(m2ap_register_eNB != NULL); + /* Look if the provided instance already exists */ + new_instance = m2ap_eNB_get_instance(instance); + + if (new_instance != NULL) { + /* Checks if it is a retry on the same eNB */ + DevCheck(new_instance->eNB_id == m2ap_register_eNB->eNB_id, new_instance->eNB_id, m2ap_register_eNB->eNB_id, 0); + DevCheck(new_instance->cell_type == m2ap_register_eNB->cell_type, new_instance->cell_type, m2ap_register_eNB->cell_type, 0); + DevCheck(new_instance->tac == m2ap_register_eNB->tac, new_instance->tac, m2ap_register_eNB->tac, 0); + DevCheck(new_instance->mcc == m2ap_register_eNB->mcc, new_instance->mcc, m2ap_register_eNB->mcc, 0); + DevCheck(new_instance->mnc == m2ap_register_eNB->mnc, new_instance->mnc, m2ap_register_eNB->mnc, 0); + M2AP_WARN("eNB[%d] already registered\n", instance); + } else { + new_instance = calloc(1, sizeof(m2ap_eNB_instance_t)); + DevAssert(new_instance != NULL); + RB_INIT(&new_instance->m2ap_enb_head); + /* Copy usefull parameters */ + new_instance->instance = instance; + new_instance->eNB_name = m2ap_register_eNB->eNB_name; + new_instance->eNB_id = m2ap_register_eNB->eNB_id; + new_instance->cell_type = m2ap_register_eNB->cell_type; + new_instance->tac = m2ap_register_eNB->tac; + new_instance->mcc = m2ap_register_eNB->mcc; + new_instance->mnc = m2ap_register_eNB->mnc; + new_instance->mnc_digit_length = m2ap_register_eNB->mnc_digit_length; + new_instance->num_cc = m2ap_register_eNB->num_cc; + + m2ap_id_manager_init(&new_instance->id_manager); + m2ap_timers_init(&new_instance->timers, + m2ap_register_eNB->t_reloc_prep, + m2ap_register_eNB->tm2_reloc_overall); + + for (int i = 0; i< m2ap_register_eNB->num_cc; i++) { + new_instance->eutra_band[i] = m2ap_register_eNB->eutra_band[i]; + new_instance->downlink_frequency[i] = m2ap_register_eNB->downlink_frequency[i]; + new_instance->uplink_frequency_offset[i] = m2ap_register_eNB->uplink_frequency_offset[i]; + new_instance->Nid_cell[i] = m2ap_register_eNB->Nid_cell[i]; + new_instance->N_RB_DL[i] = m2ap_register_eNB->N_RB_DL[i]; + new_instance->frame_type[i] = m2ap_register_eNB->frame_type[i]; + new_instance->fdd_earfcn_DL[i] = m2ap_register_eNB->fdd_earfcn_DL[i]; + new_instance->fdd_earfcn_UL[i] = m2ap_register_eNB->fdd_earfcn_UL[i]; + } + + DevCheck(m2ap_register_eNB->nb_m2 <= M2AP_MAX_NB_ENB_IP_ADDRESS, + M2AP_MAX_NB_ENB_IP_ADDRESS, m2ap_register_eNB->nb_m2, 0); + memcpy(new_instance->target_mce_m2_ip_address, + m2ap_register_eNB->target_mce_m2_ip_address, + m2ap_register_eNB->nb_m2 * sizeof(net_ip_address_t)); + new_instance->nb_m2 = m2ap_register_eNB->nb_m2; + new_instance->enb_m2_ip_address = m2ap_register_eNB->enb_m2_ip_address; + new_instance->sctp_in_streams = m2ap_register_eNB->sctp_in_streams; + new_instance->sctp_out_streams = m2ap_register_eNB->sctp_out_streams; + new_instance->enb_port_for_M2C = m2ap_register_eNB->enb_port_for_M2C; + + + new_instance->num_mbms_configuration_data_list = m2ap_register_eNB->num_mbms_configuration_data_list; + for(int j=0; j < m2ap_register_eNB->num_mbms_configuration_data_list;j++){ + new_instance->mbms_configuration_data_list[j].num_mbms_service_area_list = m2ap_register_eNB->mbms_configuration_data_list[j].num_mbms_service_area_list; + for(int i=0; i < m2ap_register_eNB->mbms_configuration_data_list[j].num_mbms_service_area_list; i++ ){ + //strcpy(&new_instance->mbms_configuration_data_list[j].mbms_service_area_list[i],&m2ap_register_eNB->mbms_configuration_data_list[j].mbms_service_area_list[i]); + new_instance->mbms_configuration_data_list[j].mbms_service_area_list[i]=m2ap_register_eNB->mbms_configuration_data_list[j].mbms_service_area_list[i]; + } + } + + /* Add the new instance to the list of eNB (meaningfull in virtual mode) */ + m2ap_eNB_insert_new_instance(new_instance); + M2AP_INFO("Registered new eNB[%d] and %s eNB id %u\n", + instance, + m2ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home", + m2ap_register_eNB->eNB_id); + + /* initiate the SCTP listener */ + if (m2ap_eNB_init_sctp(new_instance,&m2ap_register_eNB->enb_m2_ip_address,m2ap_register_eNB->enb_port_for_M2C) < 0 ) { + M2AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n"); + return; + } + + M2AP_INFO("eNB[%d] eNB id %u acting as a listner (server)\n", + instance, m2ap_register_eNB->eNB_id); + } +} + +static +void m2ap_eNB_handle_sctp_init_msg_multi_cnf( + instance_t instance_id, + sctp_init_msg_multi_cnf_t *m) { + m2ap_eNB_instance_t *instance; + int index; + DevAssert(m != NULL); + instance = m2ap_eNB_get_instance(instance_id); + DevAssert(instance != NULL); + instance->multi_sd = m->multi_sd; + + /* Exit if CNF message reports failure. + * Failure means multi_sd < 0. + */ + if (instance->multi_sd < 0) { + M2AP_ERROR("Error: be sure to properly configure M2 in your configuration file.\n"); + DevAssert(instance->multi_sd >= 0); + } + + /* Trying to connect to the provided list of eNB ip address */ + + for (index = 0; index < instance->nb_m2; index++) { + M2AP_INFO("eNB[%d] eNB id %u acting as an initiator (client)\n", + instance_id, instance->eNB_id); + m2ap_eNB_register_eNB(instance, + &instance->target_mce_m2_ip_address[index], + &instance->enb_m2_ip_address, + instance->sctp_in_streams, + instance->sctp_out_streams, + instance->enb_port_for_M2C, + instance->multi_sd); + } +} + +//static +//void m2ap_eNB_handle_handover_req(instance_t instance, +// m2ap_handover_req_t *m2ap_handover_req) +//{ +// m2ap_eNB_instance_t *instance_p; +// m2ap_eNB_data_t *target; +// m2ap_id_manager *id_manager; +// int ue_id; +// +// int target_pci = m2ap_handover_req->target_physCellId; +// +// instance_p = m2ap_eNB_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m2ap_is_eNB_pci_in_list(target_pci); +// DevAssert(target != NULL); +// +// /* allocate m2ap ID */ +// id_manager = &instance_p->id_manager; +// ue_id = m2ap_allocate_new_id(id_manager); +// if (ue_id == -1) { +// M2AP_ERROR("could not allocate a new M2AP UE ID\n"); +// /* TODO: cancel handover: send (to be defined) message to RRC */ +// exit(1); +// } +// /* id_source is ue_id, id_target is unknown yet */ +// m2ap_set_ids(id_manager, ue_id, m2ap_handover_req->rnti, ue_id, -1); +// m2ap_id_set_state(id_manager, ue_id, M2ID_STATE_SOURCE_PREPARE); +// m2ap_set_reloc_prep_timer(id_manager, ue_id, +// m2ap_timer_get_tti(&instance_p->timers)); +// m2ap_id_set_target(id_manager, ue_id, target); +// +// m2ap_eNB_generate_m2_handover_request(instance_p, target, m2ap_handover_req, ue_id); +//} + +//static +//void m2ap_eNB_handle_handover_req_ack(instance_t instance, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack) +//{ +// /* TODO: remove this hack (the goal is to find the correct +// * eNodeB structure for the other end) - we need a proper way for RRC +// * and M2AP to identify eNodeBs +// * RRC knows about mod_id and M2AP knows about eNB_id (eNB_ID in +// * the configuration file) +// * as far as I understand.. CROUX +// */ +// m2ap_eNB_instance_t *instance_p; +// m2ap_eNB_data_t *target; +// int source_assoc_id = m2ap_handover_req_ack->source_assoc_id; +// int ue_id; +// int id_source; +// int id_target; +// +// instance_p = m2ap_eNB_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m2ap_get_eNB(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// /* rnti is a new information, save it */ +// ue_id = m2ap_handover_req_ack->m2_id_target; +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// m2ap_set_ids(&instance_p->id_manager, ue_id, m2ap_handover_req_ack->rnti, id_source, id_target); +// +// m2ap_eNB_generate_m2_handover_request_ack(instance_p, target, m2ap_handover_req_ack); +//} +// +//static +//void m2ap_eNB_ue_context_release(instance_t instance, +// m2ap_ue_context_release_t *m2ap_ue_context_release) +//{ +// m2ap_eNB_instance_t *instance_p; +// m2ap_eNB_data_t *target; +// int source_assoc_id = m2ap_ue_context_release->source_assoc_id; +// int ue_id; +// instance_p = m2ap_eNB_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m2ap_get_eNB(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// m2ap_eNB_generate_m2_ue_context_release(instance_p, target, m2ap_ue_context_release); +// +// /* free the M2AP UE ID */ +// ue_id = m2ap_find_id_from_rnti(&instance_p->id_manager, m2ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M2AP_ERROR("could not find UE %x\n", m2ap_ue_context_release->rnti); +// exit(1); +// } +// m2ap_release_id(&instance_p->id_manager, ue_id); +//} + +//void MCE_task_send_sctp_init_req(instance_t enb_id) { +// // 1. get the itti msg, and retrive the enb_id from the message +// // 2. use RC.rrc[enb_id] to fill the sctp_init_t with the ip, port +// // 3. creat an itti message to init +// +// LOG_I(M2AP, "M2AP_SCTP_REQ(create socket)\n"); +// MessageDef *message_p = NULL; +// +// message_p = itti_alloc_new_message (M2AP, SCTP_INIT_MSG); +// message_p->ittiMsg.sctp_init.port = M2AP_PORT_NUMBER; +// message_p->ittiMsg.sctp_init.ppid = M2AP_SCTP_PPID; +// message_p->ittiMsg.sctp_init.ipv4 = 1; +// message_p->ittiMsg.sctp_init.ipv6 = 0; +// message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1; +// //message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr); +// message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr("127.0.0.7"); +// /* +// * SR WARNING: ipv6 multi-homing fails sometimes for localhost. +// * * * * Disable it for now. +// */ +// message_p->ittiMsg.sctp_init.nb_ipv6_addr = 0; +// message_p->ittiMsg.sctp_init.ipv6_address[0] = "0:0:0:0:0:0:0:1"; +// +// itti_send_msg_to_task(TASK_SCTP, enb_id, message_p); +//} +// +void *m2ap_eNB_task(void *arg) { + MessageDef *received_msg = NULL; + int result; + M2AP_DEBUG("Starting M2AP layer\n"); + m2ap_eNB_prepare_internal_data(); + + itti_mark_task_ready(TASK_M2AP_ENB); + + // MCE_task_send_sctp_init_req(0); + + while (1) { + itti_receive_msg(TASK_M2AP_ENB, &received_msg); + + switch (ITTI_MSG_ID(received_msg)) { + case MESSAGE_TEST: + LOG_D(M2AP,"eNB Received MESSAGE_TEST Message %s\n",itti_get_task_name(ITTI_MSG_ORIGIN_ID(received_msg))); + //MessageDef * message_p = itti_alloc_new_message(TASK_M2AP_ENB, MESSAGE_TEST); + //itti_send_msg_to_task(TASK_M3AP, 1/*ctxt_pP->module_id*/, message_p); + break; + case TERMINATE_MESSAGE: + M2AP_WARN(" *** Exiting M2AP thread\n"); + itti_exit_task(); + break; + + case M2AP_SUBFRAME_PROCESS: + m2ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg)); + break; + + case M2AP_REGISTER_ENB_REQ: + LOG_I(M2AP,"eNB Received M2AP_REGISTER_ENB_REQ Message\n"); + m2ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_REGISTER_ENB_REQ(received_msg)); + break; + + + case M2AP_MBMS_SCHEDULING_INFORMATION_RESP: + LOG_I(M2AP,"eNB M2AP_MBMS_SCHEDULING_INFORMATION_RESP Message\n"); + eNB_send_MBMS_SCHEDULING_INFORMATION_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SCHEDULING_INFORMATION_RESP(received_msg)); + break; + case M2AP_MBMS_SESSION_START_RESP: + LOG_I(M2AP,"eNB M2AP_MBMS_SESSION_START_RESP Message\n"); + eNB_send_MBMS_SESSION_START_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SESSION_START_RESP(received_msg)); + break; + case M2AP_MBMS_SESSION_START_FAILURE: + LOG_I(M2AP,"eNB M2AP_MBMS_SESSION_START_FAILURE Message\n"); + eNB_send_MBMS_SESSION_START_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SESSION_START_FAILURE(received_msg)); + break; + case M2AP_MBMS_SESSION_STOP_RESP: + LOG_I(M2AP,"eNB M2AP_MBMS_SESSION_STOP_RESP Message\n"); + eNB_send_MBMS_SESSION_STOP_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SESSION_STOP_RESP(received_msg)); + break; + case M2AP_ENB_CONFIGURATION_UPDATE: + LOG_I(M2AP,"eNB M2AP_ENB_CONFIGURATION_UPDATE Message\n"); + eNB_send_eNB_CONFIGURATION_UPDATE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_ENB_CONFIGURATION_UPDATE(received_msg)); + break; + case M2AP_MCE_CONFIGURATION_UPDATE_ACK: + LOG_I(M2AP,"eNB M2AP_MCE_CONFIGURATION_UPDATE_ACK Message\n"); + //eNB_send_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + // &M2AP_MCE_CONFIGURATION_UPDATE_ACK(received_msg)); + break; + case M2AP_MCE_CONFIGURATION_UPDATE_FAILURE: + LOG_I(M2AP,"eNB M2AP_MCE_CONFIGURATION_UPDATE_FAILURE Message\n"); + //(ITTI_MESSAGE_GET_INSTANCE(received_msg), + //&M2AP_MCE_CONFIGURATION_UPDATE_FAILURE(received_msg)); + break; + case M2AP_MBMS_SESSION_UPDATE_RESP: + LOG_I(M2AP,"eNB M2AP_MBMS_SESSION_UPDATE_RESP Message\n"); + eNB_send_MBMS_SESSION_UPDATE_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SESSION_UPDATE_RESP(received_msg)); + break; + case M2AP_MBMS_SESSION_UPDATE_FAILURE: + LOG_I(M2AP,"eNB M2AP_MBMS_SESSION_UPDATE_FAILURE Message\n"); + eNB_send_MBMS_SESSION_UPDATE_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SESSION_UPDATE_FAILURE(received_msg)); + break; + case M2AP_MBMS_SERVICE_COUNTING_REPORT: + LOG_I(M2AP,"eNB M2AP_MBMS_SERVICE_COUNTING_REPORT Message\n"); + eNB_send_MBMS_SERVICE_COUNTING_REPORT(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SERVICE_COUNTING_REPORT(received_msg)); + break; + case M2AP_MBMS_OVERLOAD_NOTIFICATION: + LOG_I(M2AP,"eNB M2AP_MBMS_OVERLOAD_NOTIFICATION Message\n"); + eNB_send_MBMS_OVERLOAD_NOTIFICATION(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_OVERLOAD_NOTIFICATION(received_msg)); + break; + case M2AP_MBMS_SERVICE_COUNTING_RESP: + LOG_I(M2AP,"eNB M2AP_MBMS_SERVICE_COUNTING_RESP Message\n"); + eNB_send_MBMS_SERVICE_COUNTING_RESP(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SERVICE_COUNTING_RESP(received_msg)); + break; + case M2AP_MBMS_SERVICE_COUNTING_FAILURE: + LOG_I(M2AP,"eNB Message\n"); + eNB_send_MBMS_SERVICE_COUNTING_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M2AP_MBMS_SERVICE_COUNTING_FAILURE(received_msg)); + break; + + + case SCTP_INIT_MSG_MULTI_CNF: + LOG_I(M2AP,"eNB Received SCTP_INIT_MSG_MULTI_CNF Message\n"); + m2ap_eNB_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_init_msg_multi_cnf); + break; + + case SCTP_NEW_ASSOCIATION_RESP: + LOG_I(M2AP,"eNB Received SCTP_NEW_ASSOCIATION_RESP Message\n"); + m2ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_resp); + break; + + case SCTP_NEW_ASSOCIATION_IND: + LOG_I(M2AP,"eNB Received SCTP_NEW_ASSOCIATION Message\n"); + m2ap_eNB_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_ind); + break; + + case SCTP_DATA_IND: + LOG_I(M2AP,"eNB Received SCTP_DATA_IND Message\n"); + m2ap_eNB_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_data_ind); + break; + + default: + M2AP_ERROR("eNB Received unhandled message: %d:%s\n", + ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + received_msg = NULL; + } + + return NULL; +} + +#include "common/config/config_userapi.h" + +int is_m2ap_eNB_enabled(void) +{ + static volatile int config_loaded = 0; + static volatile int enabled = 0; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + if (pthread_mutex_lock(&mutex)) goto mutex_error; + + if (config_loaded) { + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + return enabled; + } + + char *enable_m2 = NULL; + paramdef_t p[] = { + { "enable_enb_m2", "yes/no", 0, strptr:&enable_m2, defstrval:"", TYPE_STRING, 0 } + }; + + /* TODO: do it per module - we check only first eNB */ + config_get(p, sizeof(p)/sizeof(paramdef_t), "eNBs.[0]"); + if (enable_m2 != NULL && strcmp(enable_m2, "yes") == 0) + enabled = 1; + + config_loaded = 1; + + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + + return enabled; + +mutex_error: + LOG_E(M2AP, "mutex error\n"); + exit(1); +} diff --git a/openair2/M2AP/m2ap_eNB.h b/openair2/M2AP/m2ap_eNB.h new file mode 100644 index 0000000000..608da07e7e --- /dev/null +++ b/openair2/M2AP/m2ap_eNB.h @@ -0,0 +1,55 @@ +/* + * 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 m2ap_eNB.h + * \brief m2ap tasks for eNB + * \author Konstantinos Alexandris , Cedric Roux , Navid Nikaein + * \date 2018 + * \version 1.0 + */ + +#include +#include + +/** @defgroup _m2ap_impl_ M2AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef M2AP_ENB_H_ +#define M2AP_ENB_H_ + +#include "m2ap_eNB_defs.h" + + +int m2ap_eNB_init_sctp (m2ap_eNB_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t enb_port_for_M2C); + +void *m2ap_eNB_task(void *arg); + +int is_m2ap_eNB_enabled(void); + +#endif /* M2AP_ENB_H_ */ + +/** + * @} + */ diff --git a/openair2/M2AP/m2ap_eNB_defs.h b/openair2/M2AP/m2ap_eNB_defs.h new file mode 100644 index 0000000000..b8f7e4b3c6 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_defs.h @@ -0,0 +1,221 @@ +/* + * 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 m2ap_eNB_defs.h + * \brief m2ap struct definitions for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "queue.h" +#include "tree.h" + +#include "sctp_eNB_defs.h" + +#include "m2ap_ids.h" //looks X2AP specific for HO +#include "m2ap_timers.h" + +#ifndef M2AP_ENB_DEFS_H_ +#define M2AP_ENB_DEFS_H_ + +#define M2AP_ENB_NAME_LENGTH_MAX (150) + +typedef enum { + /* Disconnected state: initial state for any association. */ + M2AP_ENB_STATE_DISCONNECTED = 0x0, + + /* State waiting for m2 Setup response message if the target eNB accepts or + * M2 Setup failure if rejects the eNB. + */ + M2AP_ENB_STATE_WAITING = 0x1, + + /* The eNB is successfully connected to another eNB. */ + M2AP_ENB_STATE_CONNECTED = 0x2, + + /* M2AP is ready, and the eNB is successfully connected to another eNB. */ + M2AP_ENB_STATE_READY = 0x3, + + M2AP_ENB_STATE_OVERLOAD = 0x4, + + M2AP_ENB_STATE_RESETTING = 0x5, + + /* Max number of states available */ + M2AP_ENB_STATE_MAX, +} m2ap_eNB_state_t; + +/* Served PLMN identity element */ +/*struct plmn_identity_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + STAILQ_ENTRY(plmn_identity_s) next; +};*/ + +/* Served group id element */ +/*struct served_group_id_s { + uint16_t enb_group_id; + STAILQ_ENTRY(served_group_id_s) next; +};*/ + +/* Served enn code for a particular eNB */ +/*struct enb_code_s { + uint8_t enb_code; + STAILQ_ENTRY(enb_code_s) next; +};*/ + +struct m2ap_eNB_instance_s; + +/* This structure describes association of a eNB to another eNB */ +typedef struct m2ap_eNB_data_s { + /* eNB descriptors tree, ordered by sctp assoc id */ + RB_ENTRY(m2ap_eNB_data_s) entry; + + /* This is the optional name provided by the MME */ + char *eNB_name; + + /* target eNB ID */ + uint32_t eNB_id; + + /* Current eNB load information (if any). */ + //m2ap_load_state_t overload_state; + + /* Current eNB->eNB M2AP association state */ + m2ap_eNB_state_t state; + + /* Next usable stream for UE signalling */ + int32_t nextstream; + + /* Number of input/ouput streams */ + uint16_t in_streams; + uint16_t out_streams; + + /* Connexion id used between SCTP/M2AP */ + uint16_t cnx_id; + + /* SCTP association id */ + int32_t assoc_id; + + /* Nid cells */ + uint32_t Nid_cell[MAX_NUM_CCs]; + int num_cc; + + /* Only meaningfull in virtual mode */ + struct m2ap_eNB_instance_s *m2ap_eNB_instance; +} m2ap_eNB_data_t; + +typedef struct m2ap_eNB_instance_s { + /* used in simulation to store multiple eNB instances*/ + STAILQ_ENTRY(m2ap_eNB_instance_s) m2ap_eNB_entries; + + /* Number of target eNBs requested by eNB (tree size) */ + uint32_t m2_target_enb_nb; + /* Number of target eNBs for which association is pending */ + uint32_t m2_target_enb_pending_nb; + /* Number of target eNB successfully associated to eNB */ + uint32_t m2_target_enb_associated_nb; + /* Tree of M2AP eNB associations ordered by association ID */ + RB_HEAD(m2ap_enb_map, m2ap_eNB_data_s) m2ap_enb_head; + + /* Tree of UE ordered by eNB_ue_m2ap_id's */ + // RB_HEAD(m2ap_ue_map, m2ap_eNB_ue_context_s) m2ap_ue_head; + + /* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */ + instance_t instance; + + /* Displayable name of eNB */ + char *eNB_name; + + /* Unique eNB_id to identify the eNB within EPC. + * In our case the eNB is a macro eNB so the id will be 20 bits long. + * For Home eNB id, this field should be 28 bits long. + */ + uint32_t eNB_id; + /* The type of the cell */ + cell_type_t cell_type; + + //uint16_t num_mbms_service_area_list; + //uint16_t mbms_service_area_list[8]; + + struct{ + uint16_t mbsfn_sync_area; + uint16_t mbms_service_area_list[8]; + uint16_t num_mbms_service_area_list; + }mbms_configuration_data_list[8]; + uint8_t num_mbms_configuration_data_list; + + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + /* CC params */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + net_ip_address_t target_mce_m2_ip_address[M2AP_MAX_NB_ENB_IP_ADDRESS]; + uint8_t nb_m2; + net_ip_address_t enb_m2_ip_address; + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + uint32_t enb_port_for_M2C; + int multi_sd; + + m2ap_id_manager id_manager; + m2ap_timers_t timers; +} m2ap_eNB_instance_t; + +typedef struct { + /* List of served eNBs + * Only used for virtual mode + */ + STAILQ_HEAD(m2ap_eNB_instances_head_s, m2ap_eNB_instance_s) m2ap_eNB_instances_head; + /* Nb of registered eNBs */ + uint8_t nb_registered_eNBs; + + /* Generate a unique connexion id used between M2AP and SCTP */ + uint16_t global_cnx_id; +} m2ap_eNB_internal_data_t; + +int m2ap_eNB_compare_assoc_id(struct m2ap_eNB_data_s *p1, struct m2ap_eNB_data_s *p2); + +/* Generate the tree management functions */ +struct m2ap_eNB_map; +struct m2ap_eNB_data_s; +RB_PROTOTYPE(m2ap_eNB_map, m2ap_eNB_data_s, entry, m2ap_eNB_compare_assoc_id); + + +#endif /* M2AP_ENB_DEFS_H_ */ diff --git a/openair2/M2AP/m2ap_eNB_generate_messages.c b/openair2/M2AP/m2ap_eNB_generate_messages.c new file mode 100644 index 0000000000..b6c821e1ce --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_generate_messages.c @@ -0,0 +1,808 @@ +/* + * 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 m2ap_eNB_generate_messages.c + * \brief m2ap procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include "intertask_interface.h" + +//#include "M2AP_LastVisitedCell-Item.h" + +#include "m2ap_common.h" +#include "m2ap_eNB.h" +#include "m2ap_eNB_generate_messages.h" +#include "m2ap_encoder.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +#include "m2ap_itti_messaging.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +//int m2ap_eNB_generate_m2_setup_request( +// m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p) +//{ +// module_id_t enb_mod_idP=0; +// module_id_t du_mod_idP=0; +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_M2SetupRequest_t *out; +// M2AP_M2SetupRequest_Ies_t *ie; +// +// uint8_t *buffer; +// uint32_t len; +// int i = 0; +// int j = 0; +// +// /* Create */ +// /* 0. pdu Type */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_m2Setup; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_M2SetupRequest; +// out = &pdu.choice.initiatingMessage.value.choice.M2SetupRequest; +// +// /* mandatory */ +// /* c1. GlobalENB_ID (integer value) */ +// ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); +// ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_GlobalENB_ID; +// //ie->value.choice.GlobalENB_ID.eNB_ID = 1;//M2AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP); +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.GlobalENB_ID.pLMN_Identity); +// ie->value.choice.GlobalENB_ID.eNB_ID.present = M2AP_ENB_ID_PR_macro_eNB_ID; +// MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id, +// &ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); +// M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, +// ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0], +// ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1], +// ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// ///* mandatory */ +// ///* c2. GNB_eNB_ID (integrer value) */ +// //ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_gNB_eNB_ID; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupRequestIEs__value_PR_GNB_eNB_ID; +// //asn_int642INTEGER(&ie->value.choice.GNB_eNB_ID, f1ap_du_data->gNB_eNB_id); +// //ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ +// /* c3. ENBname */ +// if (m2ap_eNB_data_p->eNB_name != NULL) { +// ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); +// ie->id = M2AP_ProtocolIE_ID_id_ENBname; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_ENBname; +// //OCTET_STRING_fromBuf(&ie->value.choice.ENB_Name, m2ap_eNB_data_p->eNB_name, +// //strlen(m2ap_eNB_data_p->eNB_name)); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* mandatory */ +// /* c4. serverd cells list */ +// ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); +// ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_List; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_ENB_MBMS_Configuration_data_List; +// +// int num_mbms_available = 1;//m2ap_du_data->num_mbms_available; +// LOG_D(M2AP, "num_mbms_available = %d \n", num_mbms_available); +// +// for (i=0; +// iid = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_Item; +// mbms_configuration_data_list_item_ies->criticality = M2AP_Criticality_reject; +// mbms_configuration_data_list_item_ies->value.present = M2AP_ENB_MBMS_Configuration_data_ItemIEs__value_PR_ENB_MBMS_Configuration_data_Item; +// +// M2AP_ENB_MBMS_Configuration_data_Item_t *mbms_configuration_data_item; +// mbms_configuration_data_item = &mbms_configuration_data_list_item_ies->value.choice.ENB_MBMS_Configuration_data_Item; +// { +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &mbms_configuration_data_item->eCGI.pLMN_Identity); +// MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0, +// &mbms_configuration_data_item->eCGI.eUTRANcellIdentifier); +// M2AP_MBMS_Service_Area_t * mbms_service_area; +// mbms_service_area = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); +// ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area); +// +// +// } +// +// +// //M2AP_ENB_MBMS_Configuration_data_Item_t mbms_configuration_data_item; +// //memset((void *)&mbms_configuration_data_item, 0, sizeof(M2AP_ENB_MBMS_Configuration_data_Item_t)); +// +// //M2AP_ECGI_t eCGI; +// //M2AP_PLMN_Identity_t pLMN_Identity; +// //M2AP_EUTRANCellIdentifier_t eUTRANcellIdentifier +// //M2AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea; +// //M2AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList; +// +// +// ASN_SEQUENCE_ADD(&ie->value.choice.ENB_MBMS_Configuration_data_List.list,mbms_configuration_data_list_item_ies); +// +// } +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// LOG_W(M2AP,"m2ap_eNB_data_p->assoc_id %d\n",m2ap_eNB_data_p->assoc_id); +// /* encode */ +// if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// LOG_E(M2AP, "Failed to encode M2 setup request\n"); +// return -1; +// } +// +// +// LOG_W(M2AP,"pdu.present %d\n",pdu.present); +// // MSC_LOG_TX_MESSAGE( +// // MSC_M2AP_eNB, +// // MSC_M2AP_MCE, +// // (const char *)buffer, +// // len, +// // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", +// // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +// // m2ap_eNB_data_p->ENBname); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p, m2ap_eNB_data_p->assoc_id, buffer, len, 0); +// +// return 0; +// +// +//} + +//int m2ap_MCE_generate_m2_setup_response(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_M2SetupResponse_t *out; +// M2AP_M2SetupResponse_Ies_t *ie; +// //M2AP_PLMN_Identity_t *plmn; +// //ServedCells__Member *servedCellMember; +// //M2AP_GU_Group_ID_t *gu; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// /* Prepare the M2AP message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; +// pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; +// pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_M2SetupResponse; +// out = &pdu.choice.successfulOutcome.value.choice.M2SetupResponse; +// +// /* mandatory */ +// ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GlobalENB_ID; +// //MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// // &ie->value.choice.GlobalENB_ID.pLMN_Identity); +// //ie->value.choice.GlobalENB_ID.eNB_ID.present = M2AP_ENB_ID_PR_macro_eNB_ID; +// //MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id, +// // &ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); +// //M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, +// // ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0], +// // ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1], +// // ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_ServedCells; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_ServedCells; +// //{ +// // for (int i = 0; inum_cc; i++){ +// // servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member)); +// // { +// // servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i]; +// +// // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// // &servedCellMember->servedCellInfo.cellId.pLMN_Identity); +// // MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0, +// // &servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier); +// +// // INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC); +// // plmn = (M2AP_PLMN_Identity_t *)calloc(1,sizeof(M2AP_PLMN_Identity_t)); +// // { +// // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); +// // ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn); +// // } +// +// // if (instance_p->frame_type[i] == FDD) { +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = M2AP_EUTRA_Mode_Info_PR_fDD; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; +// // switch (instance_p->N_RB_DL[i]) { +// // case 6: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; +// // break; +// // case 15: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; +// // break; +// // case 25: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; +// // break; +// // case 50: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; +// // break; +// // case 75: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; +// // break; +// // case 100: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; +// // break; +// // default: +// // AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); +// // break; +// // } +// // } +// // else { +// // AssertFatal(0,"M2Setupresponse not supported for TDD!"); +// // } +// // } +// // ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember); +// // } +// //} +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_GUGroupIDList; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GUGroupIDList; +// //{ +// // gu = (M2AP_GU_Group_ID_t *)calloc(1, sizeof(M2AP_GU_Group_ID_t)); +// // { +// // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// // &gu->pLMN_Identity); +// // //@TODO: consider to update this value +// // INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID); +// // } +// // ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu); +// //} +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode M2 setup response\n"); +// return -1; +// } +// +// m2ap_eNB_data_p->state = M2AP_ENB_STATE_READY; +// +// //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 M2Setup/successfulOutcome assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 0); +// +// return ret; +//} + +//int m2ap_MCE_generate_m2_setup_failure(instance_t instance, +// uint32_t assoc_id, +// M2AP_Cause_PR cause_type, +// long cause_value, +// long time_to_wait) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_M2SetupFailure_t *out; +// M2AP_M2SetupFailure_Ies_t *ie; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// /* Prepare the M2AP message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; +// pdu.choice.unsuccessfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; +// pdu.choice.unsuccessfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.unsuccessfulOutcome.value.present = M2AP_UnsuccessfulOutcome__value_PR_M2SetupFailure; +// out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure; +// +// /* mandatory */ +// ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_Cause; +// //ie->criticality = M2AP_Criticality_ignore; +// //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_Cause; +// +// //m2ap_eNB_set_cause (&ie->value.choice.Cause, cause_type, cause_value); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional: consider to handle this later */ +// ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_TimeToWait; +// //ie->criticality = M2AP_Criticality_ignore; +// //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_TimeToWait; +// +// //if (time_to_wait > -1) { +// // ie->value.choice.TimeToWait = time_to_wait; +// //} +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode M2 setup failure\n"); +// return -1; +// } +// +// //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, +// // MSC_M2AP_TARGET_ENB, NULL, 0, +// // "0 M2Setup/unsuccessfulOutcome assoc_id %u cause %u value %u", +// // assoc_id, cause_type, cause_value); +// +// m2ap_eNB_itti_send_sctp_data_req(instance, assoc_id, buffer, len, 0); +// +// return ret; +//} + +int m2ap_eNB_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value) +{ + + DevAssert (cause_p != NULL); + cause_p->present = cause_type; + + switch (cause_type) { + case M2AP_Cause_PR_radioNetwork: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_transport: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_protocol: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_misc: + cause_p->choice.misc = cause_value; + break; + + default: + return -1; + } + + return 0; +} + +//int m2ap_eNB_generate_m2_handover_request (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequest_t *out; +// M2AP_HandoverRequest_IEs_t *ie; +// M2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs; +// M2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item; +// M2AP_LastVisitedCell_Item_t *lastVisitedCell_Item; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverRequest; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverRequest; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_Cause; +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = M2AP_CauseRadioNetwork_handover_desirable_for_radio_reasons; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargetCell_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_ECGI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.ECGI.pLMN_Identity); +// MACRO_ENB_ID_TO_CELL_IDENTITY(m2ap_eNB_data_p->eNB_id, 0, &ie->value.choice.ECGI.eUTRANcellIdentifier); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_GUMMEI_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_GUMMEI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.GUMMEI.gU_Group_ID.pLMN_Identity); +// //@TODO: consider to update these values +// INT16_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_group_id, &ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID); +// MME_CODE_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_code, &ie->value.choice.GUMMEI.mME_Code); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_ContextInformation; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_ContextInformation; +// //@TODO: consider to update this value +// ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID = m2ap_handover_req->mme_ue_s1ap_id; +// +// KENB_STAR_TO_BIT_STRING(m2ap_handover_req->kenb,&ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star); +// +// if (m2ap_handover_req->kenb_ncc >=0) { // Check this condition +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = m2ap_handover_req->kenb_ncc; +// } +// else { +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = 1; +// } +// +// ENCRALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.encryption_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms); +// +// INTPROTALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.integrity_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms); +// +// //@TODO: update with proper UEAMPR +// UEAGMAXBITRTD_TO_ASN_PRIMITIVES(3L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink); +// UEAGMAXBITRTU_TO_ASN_PRIMITIVES(6L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateUplink); +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_ToBeSetup_ItemIEs = (M2AP_E_RABs_ToBeSetup_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_ToBeSetup_ItemIEs_t)); +// e_RABS_ToBeSetup_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_ToBeSetup_Item; +// e_RABS_ToBeSetup_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_ToBeSetup_ItemIEs->value.present = M2AP_E_RABs_ToBeSetup_ItemIEs__value_PR_E_RABs_ToBeSetup_Item; +// e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item; +// { +// e_RABs_ToBeSetup_Item->e_RAB_ID = m2ap_handover_req->e_rabs_tobesetup[i].e_rab_id; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI = m2ap_handover_req->e_rab_param[i].qos.qci; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.priority_level; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size = (uint8_t)(m2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.length/8); +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = m2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.length%8; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf = +// calloc(1,e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// memcpy (e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf, +// m2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.buffer, +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// INT32_TO_OCTET_STRING(m2ap_handover_req->e_rabs_tobesetup[i].gtp_teid,&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID); +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list, e_RABS_ToBeSetup_ItemIEs); +// } +// } +// +// OCTET_STRING_fromBuf(&ie->value.choice.UE_ContextInformation.rRC_Context, (char*) m2ap_handover_req->rrc_buffer, m2ap_handover_req->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_HistoryInformation; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_HistoryInformation; +// //@TODO: consider to update this value +// { +// lastVisitedCell_Item = (M2AP_LastVisitedCell_Item_t *)calloc(1, sizeof(M2AP_LastVisitedCell_Item_t)); +// lastVisitedCell_Item->present = M2AP_LastVisitedCell_Item_PR_e_UTRAN_Cell; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.pLMN_Identity); +// MACRO_ENB_ID_TO_CELL_IDENTITY(0, 0, &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.eUTRANcellIdentifier); +// lastVisitedCell_Item->choice.e_UTRAN_Cell.cellType.cell_Size = M2AP_Cell_Size_small; +// lastVisitedCell_Item->choice.e_UTRAN_Cell.time_UE_StayedInCell = 2; +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_HistoryInformation.list, lastVisitedCell_Item); +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover request\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2Handover/initiatingMessage assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_eNB_generate_m2_handover_request_ack (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequestAcknowledge_t *out; +// M2AP_HandoverRequestAcknowledge_IEs_t *ie; +// M2AP_E_RABs_Admitted_ItemIEs_t *e_RABS_Admitted_ItemIEs; +// M2AP_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// ue_id = m2ap_handover_req_ack->m2_id_target; +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; +// pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge; +// out = &pdu.choice.successfulOutcome.value.choice.HandoverRequestAcknowledge; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_List; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_E_RABs_Admitted_List; +// +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_Admitted_ItemIEs = (M2AP_E_RABs_Admitted_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_Admitted_ItemIEs_t)); +// e_RABS_Admitted_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_Item; +// e_RABS_Admitted_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_Admitted_ItemIEs->value.present = M2AP_E_RABs_Admitted_ItemIEs__value_PR_E_RABs_Admitted_Item; +// e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item; +// { +// e_RABs_Admitted_Item->e_RAB_ID = m2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id; +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs); +// } +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_TargeteNBtoSource_eNBTransparentContainer; +// +// OCTET_STRING_fromBuf(&ie->value.choice.TargeteNBtoSource_eNBTransparentContainer, (char*) m2ap_handover_req_ack->rrc_buffer, m2ap_handover_req_ack->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover response\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2Handover/successfulOutcome assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_eNB_generate_m2_ue_context_release (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, m2ap_ue_context_release_t *m2ap_ue_context_release) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_UEContextRelease_t *out; +// M2AP_UEContextRelease_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// ue_id = m2ap_find_id_from_rnti(&instance_p->id_manager, m2ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M2AP_ERROR("could not find UE %x\n", m2ap_ue_context_release->rnti); +// exit(1); +// } +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP ue context relase message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_uEContextRelease; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_UEContextRelease; +// out = &pdu.choice.initiatingMessage.value.choice.UEContextRelease; +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 UE Context Release\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2UEContextRelease/initiatingMessage assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_eNB_generate_m2_handover_cancel (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverCancel_t *out; +// M2AP_HandoverCancel_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// ue_id = m2_ue_id; +// id_source = ue_id; +// id_target = m2ap_id_get_id_target(&instance_p->id_manager, ue_id); +// +// /* Prepare the M2AP handover cancel message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverCancel; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverCancel; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverCancel; +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ +// if (id_target != -1) { +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_Cause; +// switch (cause) { +// case M2AP_T_RELOC_PREP_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_trelocprep_expiry; +// break; +// case M2AP_TX2_RELOC_OVERALL_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_tx2relocoverall_expiry; +// break; +// default: +// /* we can't come here */ +// M2AP_ERROR("unhandled cancel cause\n"); +// exit(1); +// } +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 Handover Cancel\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2HandoverCancel/initiatingMessage assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} diff --git a/openair2/M2AP/m2ap_eNB_generate_messages.h b/openair2/M2AP/m2ap_eNB_generate_messages.h new file mode 100644 index 0000000000..49247405f7 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_generate_messages.h @@ -0,0 +1,63 @@ +/* + * 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 m2ap_eNB_generate_messages.h + * \brief m2ap procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENB_GENERATE_MESSAGES_H_ +#define M2AP_ENB_GENERATE_MESSAGES_H_ + +#include "m2ap_eNB_defs.h" +#include "m2ap_common.h" + +//int m2ap_eNB_generate_m2_setup_request(m2ap_eNB_instance_t *instance_p, +// m2ap_eNB_data_t *m2ap_eNB_data_p); +// +//int m2ap_MCE_generate_m2_setup_response(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p); +// +/*int m2ap_MCE_generate_m2_setup_failure(instance_t instance, + uint32_t assoc_id, + M2AP_Cause_PR cause_type, + long cause_value, + long time_to_wait);*/ + +int m2ap_eNB_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value); + +//int m2ap_eNB_generate_m2_handover_request (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id); +// +//int m2ap_eNB_generate_m2_handover_request_ack (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack); +// +//int m2ap_eNB_generate_m2_ue_context_release (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_ue_context_release_t *m2ap_ue_context_release); +// +//int m2ap_eNB_generate_m2_handover_cancel (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause); + +#endif /* M2AP_ENB_GENERATE_MESSAGES_H_ */ diff --git a/openair2/M2AP/m2ap_eNB_handler.c b/openair2/M2AP/m2ap_eNB_handler.c new file mode 100644 index 0000000000..fe0059f0a5 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_handler.c @@ -0,0 +1,123 @@ +/* + * 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 m2ap_eNB_handler.c + * \brief m2ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "intertask_interface.h" + +#include "asn1_conversions.h" + +#include "m2ap_common.h" +#include "m2ap_eNB_defs.h" +#include "m2ap_eNB_handler.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +#include "m2ap_eNB_management_procedures.h" +#include "m2ap_eNB_generate_messages.h" + +//#include "m2ap_MCE_interface_management.h" +#include "m2ap_eNB_interface_management.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +/* Handlers matrix. Only eNB related procedure present here */ +m2ap_eNB_message_decoded_callback m2ap_eNB_messages_callback[][3] = { + { eNB_handle_MBMS_SESSION_START_REQUEST, 0, 0 }, /* MBMSSessionStart */ + { eNB_handle_MBMS_SESSION_STOP_REQUEST, 0, 0 }, /* MBMSSessionStop */ + { eNB_handle_MBMS_SCHEDULING_INFORMATION, 0, 0 }, /* MBMSSchedulingInformation */ + { 0, 0, 0 }, /* Error Indication */ + { 0, 0, 0 }, /* Reset */ + { 0,eNB_handle_M2_SETUP_RESPONSE,eNB_handle_M2_SETUP_FAILURE }, /* M2 Setup */ + { 0, 0, 0 }, /* eNBConfigurationUpdate */ + { 0, 0, 0 }, /* MCEConfigurationUpdate */ + { 0, 0, 0 }, /* privateMessage */ + { 0, 0, 0 }, /* MBMSSessionUpdate */ + { 0, 0, 0 }, /* MBMSServiceCounting */ + { 0, 0, 0 }, /* MBMSServiceCountingResultReport */ + { 0, 0, 0 } /* MBMSOverloadNotification */ +}; + +static char *m2ap_direction2String(int m2ap_dir) { +static char *m2ap_direction_String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; +return(m2ap_direction_String[m2ap_dir]); +} + + +int m2ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length) +{ + M2AP_M2AP_PDU_t pdu; + int ret; + + DevAssert(data != NULL); + + memset(&pdu, 0, sizeof(pdu)); + + if (m2ap_decode_pdu(&pdu, data, data_length) < 0) { + LOG_E(M2AP, "Failed to decode PDU\n"); + return -1; + } + + /* Checking procedure Code and direction of message */ + if (pdu.choice.initiatingMessage.procedureCode > sizeof(m2ap_eNB_messages_callback) / (3 * sizeof( + m2ap_message_decoded_callback)) + || (pdu.present > M2AP_M2AP_PDU_PR_unsuccessfulOutcome)) { + LOG_E(M2AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return -1; + } + + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (m2ap_eNB_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) { + LOG_E(M2AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, + m2ap_direction2String(pdu.present - 1)); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return -1; + } + + /* Calling the right handler */ + LOG_I(M2AP, "Calling handler with instance %d\n",instance); + ret = (*m2ap_eNB_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1]) + (instance, assoc_id, stream, &pdu); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return ret; +} + + diff --git a/openair2/M2AP/m2ap_eNB_handler.h b/openair2/M2AP/m2ap_eNB_handler.h new file mode 100644 index 0000000000..ea4231a6e3 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_handler.h @@ -0,0 +1,43 @@ +/* + * 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 m2ap_handler.h + * \brief m2ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENB_HANDLERS_H_ +#define M2AP_ENB_HANDLERS_H_ + +#include "m2ap_eNB_defs.h" + +//void m2ap_handle_m2_setup_message(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown); + +int m2ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + +//int m2ap_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + //const uint8_t * const data, const uint32_t data_length); + + +#endif /* M2AP_ENB_HANDLERS_H_ */ diff --git a/openair2/M2AP/m2ap_eNB_interface_management.c b/openair2/M2AP/m2ap_eNB_interface_management.c new file mode 100644 index 0000000000..95b8372025 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_interface_management.c @@ -0,0 +1,1319 @@ +/* + * 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 m2ap_MCE_interface_management.c + * \brief m2ap interface management for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech, Spain + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "intertask_interface.h" + +#include "m2ap_common.h" +#include "m2ap_eNB.h" +#include "m2ap_eNB_generate_messages.h" +#include "m2ap_encoder.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +#include "m2ap_eNB_interface_management.h" + + +#include "m2ap_itti_messaging.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +#include "M2AP_MBSFN-Area-Configuration-List.h" + +//#include "m2ap_common.h" +//#include "m2ap_encoder.h" +//#include "m2ap_decoder.h" +//#include "m2ap_itti_messaging.h" +//#include "m2ap_eNB_interface_management.h" +//#include "assertions.h" + +extern m2ap_setup_req_t *m2ap_enb_data_g; + + +//extern m2ap_setup_req_t *m2ap_mce_data_from_enb; +int eNB_handle_MBMS_SCHEDULING_INFORMATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + LOG_D(M2AP, "eNB_handle_MBMS_SCHEDULING_INFORMATION assoc_id %d\n",assoc_id); + + MessageDef *message_p/*,*message_p2*/; + M2AP_MbmsSchedulingInformation_t *container; + M2AP_MbmsSchedulingInformation_Ies_t *ie; + int i = 0; + int j = 0; + int k = 0; + //int m = 0; + + DevAssert(pdu != NULL); + + container = &pdu->choice.initiatingMessage.value.choice.MbmsSchedulingInformation; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS scheduling information on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MBMS_SCHEDULING_INFORMATION); + //message_p2 = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MBMS_SCHEDULING_INFORMATION); + + + + + + M2AP_FIND_PROTOCOLIE_BY_ID(M2AP_MbmsSchedulingInformation_Ies_t, ie, container,M2AP_ProtocolIE_ID_id_MCCH_Update_Time ,true); + //printf("id %d\n",ie->id); + + M2AP_FIND_PROTOCOLIE_BY_ID(M2AP_MbmsSchedulingInformation_Ies_t, ie, container,M2AP_ProtocolIE_ID_id_MBSFN_Area_Configuration_List ,true); + + if(ie){ + + //printf("id %d\n",ie->id); + //printf("MBSFN_Area_Configuration_List %p\n",ie->value.choice.MBSFN_Area_Configuration_List.list.array); + /*M2AP_MBSFN_Area_Configuration_Item_t * kk = &ie->value.choice.MBSFN_Area_Configuration_List.list.array[0]; + printf("M2AP_MBSFN_Area_Configuration_Item %p\n",kk); + printf("M2AP_MBSFN_Area_Configuration_Item %d\n",kk->id);*/ + + const asn_anonymous_sequence_ *list = _A_CSEQUENCE_FROM_VOID((void*)&ie->value.choice.MBSFN_Area_Configuration_List); + if(list->count > 0 ){ + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).num_mbms_area_config_list = list->count; + } + for(i=0; i < list->count; i++ ){ + void * memb_ptr = list->array[i]; + //printf("%p %d\n", memb_ptr,list->count); + const asn_anonymous_sequence_ *list1 = _A_CSEQUENCE_FROM_VOID((void*)memb_ptr); + void * memb_ptr1 = list1->array[0]; + //printf("%p %d\n", memb_ptr1,list1->count); + void * memb_ptr2 = list1->array[1]; + void * memb_ptr3 = list1->array[2]; + void * memb_ptr4 = list1->array[3]; + + //printf("%lu\n", ((M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr1)->id); + M2AP_MBSFN_Area_Configuration_Item_t * m2ap_mbsfn_area_configuration_item = (M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr1; + //printf("count %d\n",m2ap_mbsfn_area_configuration_item->value.choice.PMCH_Configuration_List.list.count); + if(m2ap_mbsfn_area_configuration_item->value.choice.PMCH_Configuration_List.list.count > 0){ + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].num_pmch_config_list = m2ap_mbsfn_area_configuration_item->value.choice.PMCH_Configuration_List.list.count; + } + for(j=0; j < m2ap_mbsfn_area_configuration_item->value.choice.PMCH_Configuration_List.list.count; j++){ + M2AP_PMCH_Configuration_Item_t * m2ap_pmchconfiguration_item =&(((M2AP_PMCH_Configuration_ItemIEs_t*)m2ap_mbsfn_area_configuration_item->value.choice.PMCH_Configuration_List.list.array[j])->value.choice.PMCH_Configuration_Item); + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].data_mcs = m2ap_pmchconfiguration_item->pmch_Configuration.dataMCS; + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mch_scheduling_period = m2ap_pmchconfiguration_item->pmch_Configuration.mchSchedulingPeriod; + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].allocated_sf_end = m2ap_pmchconfiguration_item->pmch_Configuration.allocatedSubframesEnd; + //printf("dataMCS %lu\n",m2ap_pmchconfiguration_item->pmch_Configuration.dataMCS); + //printf("allocatedSubframesEnd %lu\n",m2ap_pmchconfiguration_item->pmch_Configuration.allocatedSubframesEnd); + if(m2ap_pmchconfiguration_item->mbms_Session_List.list.count > 0){ + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].num_mbms_session_list = m2ap_pmchconfiguration_item->mbms_Session_List.list.count; + } + for(k=0; k < m2ap_pmchconfiguration_item->mbms_Session_List.list.count; k++){ + //long mnc,mcc,mnc_length; + PLMNID_TO_MCC_MNC(&m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.pLMNidentity, + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mcc, + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mnc, + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mnc_length); + //char buf[4]; + + //BUFFER_TO_INT32(buf,); + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id = ((m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.serviceID.buf[0]<<16) | (m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.serviceID.buf[1]<<8) | (m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.serviceID.buf[2])); // + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid = m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->lcid; //*/ + //LOG_E(M2AP,"buf[0]:%d buf[1]:%d buf[2]:%d\n",m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.serviceID.buf[0],m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.serviceID.buf[1],m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.serviceID.buf[2]); + } + } + + //printf("%lu\n", ((M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr2)->id); + M2AP_MBSFN_Area_Configuration_Item_t * m2ap_mbsfn_area_configuration_item2 = (M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr2; + //printf("count %d\n",m2ap_mbsfn_area_configuration_item2->value.choice.MBSFN_Subframe_ConfigurationList.list.count); + if(m2ap_mbsfn_area_configuration_item2->value.choice.MBSFN_Subframe_ConfigurationList.list.count > 0){ + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].num_mbms_sf_config_list = m2ap_mbsfn_area_configuration_item2->value.choice.MBSFN_Subframe_ConfigurationList.list.count; + } + for(j=0; j < m2ap_mbsfn_area_configuration_item2->value.choice.MBSFN_Subframe_ConfigurationList.list.count; j++){ + M2AP_MBSFN_Subframe_Configuration_t * m2ap_mbsfn_sf_configuration = &(((M2AP_MBSFN_Subframe_ConfigurationItem_t*)m2ap_mbsfn_area_configuration_item2->value.choice.MBSFN_Subframe_ConfigurationList.list.array[j])->value.choice.MBSFN_Subframe_Configuration); + //printf("radioframe_allocation_period %lu\n",m2ap_mbsfn_sf_configuration->radioframeAllocationPeriod); + //printf("radioframe_allocation_offset %lu\n",m2ap_mbsfn_sf_configuration->radioframeAllocationOffset); + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].mbms_sf_config_list[j].radioframe_allocation_period = m2ap_mbsfn_sf_configuration->radioframeAllocationPeriod; + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].mbms_sf_config_list[j].radioframe_allocation_offset = m2ap_mbsfn_sf_configuration->radioframeAllocationOffset; + if( m2ap_mbsfn_sf_configuration->subframeAllocation.present == M2AP_MBSFN_Subframe_Configuration__subframeAllocation_PR_fourFrames ) { + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation = m2ap_mbsfn_sf_configuration->subframeAllocation.choice.oneFrame.buf[0] | (m2ap_mbsfn_sf_configuration->subframeAllocation.choice.oneFrame.buf[1]<<8) | (m2ap_mbsfn_sf_configuration->subframeAllocation.choice.oneFrame.buf[0]<<16); + }else{ + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation = (m2ap_mbsfn_sf_configuration->subframeAllocation.choice.oneFrame.buf[0] >> 2) & 0x3F; + } + } + + + //printf("%lu\n", ((M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr3)->id); + M2AP_MBSFN_Area_Configuration_Item_t * m2ap_mbsfn_area_configuration_item3 = (M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr3; + //printf("count %d\n",m2ap_mbsfn_area_configuration_item2->value.choice.MBSFN_Subframe_ConfigurationList.list.count); + //printf("Common_Subframe_Allocation_Period %lu\n",m2ap_mbsfn_area_configuration_item3->value.choice.Common_Subframe_Allocation_Period); + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].common_sf_allocation_period = m2ap_mbsfn_area_configuration_item3->value.choice.Common_Subframe_Allocation_Period; + + //printf("%lu\n", ((M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr4)->id); + M2AP_MBSFN_Area_Configuration_Item_t * m2ap_mbsfn_area_configuration_item4 = (M2AP_MBSFN_Area_Configuration_Item_t*)memb_ptr4; + //printf("MBMS_Area_ID %lu\n",m2ap_mbsfn_area_configuration_item4->value.choice.MBSFN_Area_ID); + M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].mbms_area_id = m2ap_mbsfn_area_configuration_item4->value.choice.MBSFN_Area_ID; + } + + + //const asn_anonymous_sequence_ *list3 = _A_CSEQUENCE_FROM_VOID((void*)memb_ptr2); + //void * memb_ptr3 = list3->array[0]; + //printf("%p\n", memb_ptr3); + + + + + //xer_fprint(stdout, &asn_DEF_M2AP_MBSFN_Area_Configuration_List, &ie->value.choice.MBSFN_Area_Configuration_List); + + } + + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + return 0; + +} +int eNB_send_MBMS_SCHEDULING_INFORMATION_RESPONSE(instance_t instance, m2ap_mbms_scheduling_information_resp_t * m2ap_mbms_scheduling_information_resp){ +// module_id_t mce_mod_idP; + //module_id_t enb_mod_idP; + + // This should be fixed + // enb_mod_idP = (module_id_t)0; + // mce_mod_idP = (module_id_t)0; + + M2AP_M2AP_PDU_t pdu; + //M2AP_MbmsSchedulingInformationResponse_t *out; + //M2AP_MbmsSchedulingInformationResponse_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M2AP_SuccessfulOutcome_t *)calloc(1, sizeof(M2AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_mbmsSchedulingInformation; + pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_MbmsSchedulingInformationResponse; + //out = &pdu.choice.successfulOutcome.value.choice.MbmsSchedulingInformationResponse; + + +// /* mandatory */ +// /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long +// ie = (M2AP_MbmsSchedulingInformationResponse_Ies_t *)calloc(1, sizeof(M2AP_MbmsSchedulingInformationResponse_Ies_t)); +// ie->id = M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_MbmsSchedulingInformationResponse_Ies__value_PR_MCE_MBMS_M2AP_ID; +// //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long +// ie = (M2AP_SessionStartResponse_Ies_t *)calloc(1, sizeof(M2AP_SessionStartResponse_Ies_t)); +// ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_MbmsSchedulingInformationResponse_Ies__value_PR_ENB_MBMS_M2AP_ID; +// //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 SessionStart Response\n"); + return -1; + } + + + LOG_D(M2AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m2ap_eNB_data_p->ENBname); + + m2ap_eNB_itti_send_sctp_data_req(instance, m2ap_enb_data_g->assoc_id, buffer, len, 0); + return 0; +} + + + + +int eNB_handle_MBMS_SESSION_START_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + LOG_D(M2AP, "eNB_handle_MBMS_SESSION_START_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_SessionStartRequest_t *container; + //M2AP_SessionStartRequest_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.SessionStartRequest; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MBMS_SESSION_START_REQ); + + + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + +// if(1){ +// eNB_send_MBMS_SESSION_START_RESPONSE(instance,NULL); +// }else +// eNB_send_MBMS_SESSION_START_FAILURE(instance,NULL); + return 0; + +} + +int eNB_send_MBMS_SESSION_START_RESPONSE(instance_t instance, m2ap_session_start_resp_t * m2ap_session_start_resp){ +// module_id_t mce_mod_idP; +// module_id_t enb_mod_idP; + + // This should be fixed +// enb_mod_idP = (module_id_t)0; +// mce_mod_idP = (module_id_t)0; + + M2AP_M2AP_PDU_t pdu; + M2AP_SessionStartResponse_t *out; + M2AP_SessionStartResponse_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M2AP_SuccessfulOutcome_t *)calloc(1, sizeof(M2AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_sessionStart; + pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_SessionStartResponse; + out = &pdu.choice.successfulOutcome.value.choice.SessionStartResponse; + + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStartResponse_Ies_t *)calloc(1, sizeof(M2AP_SessionStartResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartResponse_Ies__value_PR_MCE_MBMS_M2AP_ID; + //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStartResponse_Ies_t *)calloc(1, sizeof(M2AP_SessionStartResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartResponse_Ies__value_PR_ENB_MBMS_M2AP_ID; + //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 SessionStart Response\n"); + return -1; + } + + + LOG_D(M2AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m2ap_eNB_data_p->ENBname); + + m2ap_eNB_itti_send_sctp_data_req(instance, m2ap_enb_data_g->assoc_id, buffer, len, 0); + return 0; +} + + +int eNB_send_MBMS_SESSION_START_FAILURE(instance_t instance, m2ap_session_start_failure_t * m2ap_session_start_failure){ + //module_id_t enb_mod_idP; + //module_id_t mce_mod_idP; + + // This should be fixed + //enb_mod_idP = (module_id_t)0; + // mce_mod_idP = (module_id_t)0; + + M2AP_M2AP_PDU_t pdu; + M2AP_SessionStartFailure_t *out; + M2AP_SessionStartFailure_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; + //pdu.choice.unsuccessfulOutcome = (M2AP_UnsuccessfulOutcome_t *)calloc(1, sizeof(M2AP_UnsuccessfulOutcome_t)); + pdu.choice.unsuccessfulOutcome.procedureCode = M2AP_ProcedureCode_id_sessionStart; + pdu.choice.unsuccessfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.unsuccessfulOutcome.value.present = M2AP_UnsuccessfulOutcome__value_PR_SessionStartFailure; + out = &pdu.choice.unsuccessfulOutcome.value.choice.SessionStartFailure; + + /* mandatory */ + /* c1. Transaction ID (integer value)*/ + // ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + // ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; + // ie->criticality = M2AP_Criticality_reject; + // ie->value.present = M2AP_M2SetupFailure_Ies__value_PR_GlobalENB_ID; + // ie->value.choice.GlobalENB_ID = M2AP_get_next_transaction_identifier(enb_mod_idP, mce_mod_idP); + // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStartFailure_Ies_t *)calloc(1, sizeof(M2AP_SessionStartFailure_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStartFailure_Ies__value_PR_MCE_MBMS_M2AP_ID; + //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + + /* mandatory */ + /* c2. Cause */ + ie = (M2AP_SessionStartFailure_Ies_t *)calloc(1, sizeof(M2AP_SessionStartFailure_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_Cause; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_SessionStartFailure_Ies__value_PR_Cause; + ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; + ie->value.choice.Cause.choice.radioNetwork = M2AP_CauseRadioNetwork_unspecified; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 setup request\n"); + return -1; + } + + //mce_m2ap_itti_send_sctp_data_req(instance, m2ap_mce_data_from_enb->assoc_id, buffer, len, 0); + m2ap_eNB_itti_send_sctp_data_req(instance,m2ap_enb_data_g->assoc_id,buffer,len,0); + + + return 0; +} + +int eNB_handle_MBMS_SESSION_STOP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu){ + LOG_D(M2AP, "eNB_handle_MBMS_SESSION_STOP_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_SessionStopRequest_t *container; + //M2AP_SessionStopRequest_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.SessionStopRequest; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MBMS_SESSION_STOP_REQ); + + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + + +// if(1){ +// eNB_send_MBMS_SESSION_STOP_RESPONSE(instance,NULL); +// }else +// eNB_send_MBMS_SESSION_STOP_FAILURE(instance,NULL); + return 0; + +} +int eNB_send_MBMS_SESSION_STOP_RESPONSE(instance_t instance, m2ap_session_stop_resp_t * m2ap_session_stop_resp){ + //module_id_t mce_mod_idP; + //module_id_t enb_mod_idP; + + // This should be fixed + //enb_mod_idP = (module_id_t)0; + //mce_mod_idP = (module_id_t)0; + + M2AP_M2AP_PDU_t pdu; + M2AP_SessionStopResponse_t *out; + M2AP_SessionStopResponse_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M2AP_SuccessfulOutcome_t *)calloc(1, sizeof(M2AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_sessionStop; + pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_SessionStopResponse; + out = &pdu.choice.successfulOutcome.value.choice.SessionStopResponse; + + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStopResponse_Ies_t *)calloc(1, sizeof(M2AP_SessionStopResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_MCE_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStopResponse_Ies__value_PR_MCE_MBMS_M2AP_ID; + //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c1. MCE_MBMS_M2AP_ID (integer value) */ //long + ie = (M2AP_SessionStopResponse_Ies_t *)calloc(1, sizeof(M2AP_SessionStopResponse_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_M2AP_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_SessionStopResponse_Ies__value_PR_ENB_MBMS_M2AP_ID; + //ie->value.choice.MCE_MBMS_M2AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 SessionStop Response\n"); + return -1; + } + + + LOG_D(M2AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m2ap_eNB_data_p->ENBname); + + m2ap_eNB_itti_send_sctp_data_req(instance, m2ap_enb_data_g->assoc_id, buffer, len, 0); + return 0; +} + + uint8_t bytes [] = {0x00, 0x05, /* .....+.. */ +0x00, 0x24, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x00, /* .$...... */ +0x08, 0x00, 0x02, 0xf8, 0x39, 0x00, 0x00, 0xe0, /* ....9... */ +0x00, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x00, 0x10, /* ........ */ +0x00, 0x0c, 0x00, 0x02, 0xf8, 0x39, 0x00, 0xe0, /* .....9.. */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + +/* + M2 Setup +*/ + +// SETUP REQUEST +int eNB_send_M2_SETUP_REQUEST(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t* m2ap_eNB_data_p) { + // module_id_t enb_mod_idP=0; + // module_id_t du_mod_idP=0; + + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupRequest_t *out; + M2AP_M2SetupRequest_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + int i = 0; + int j = 0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_M2SetupRequest; + out = &pdu.choice.initiatingMessage.value.choice.M2SetupRequest; + + /* mandatory */ + /* c1. GlobalENB_ID (integer value) */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_GlobalENB_ID; + //ie->value.choice.GlobalENB_ID.eNB_ID = 1;//M2AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP); + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &ie->value.choice.GlobalENB_ID.pLMN_Identity); + ie->value.choice.GlobalENB_ID.eNB_ID.present = M2AP_ENB_ID_PR_macro_eNB_ID; + MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id, + &ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); + M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0], + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1], + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ///* mandatory */ + ///* c2. GNB_eNB_ID (integrer value) */ + //ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_gNB_eNB_ID; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequestIEs__value_PR_GNB_eNB_ID; + //asn_int642INTEGER(&ie->value.choice.GNB_eNB_ID, f1ap_du_data->gNB_eNB_id); + //ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional */ + /* c3. ENBname */ + if (m2ap_eNB_data_p->eNB_name != NULL) { + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENBname; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_ENBname; + OCTET_STRING_fromBuf(&ie->value.choice.ENBname, m2ap_eNB_data_p->eNB_name, + strlen(m2ap_eNB_data_p->eNB_name)); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* mandatory */ + /* c4. serverd cells list */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_List; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_ENB_MBMS_Configuration_data_List; + + int num_mbms_available = instance_p->num_mbms_configuration_data_list; + LOG_D(M2AP, "num_mbms_available = %d \n", num_mbms_available); + + for (i=0; + iid = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_Item; + mbms_configuration_data_list_item_ies->criticality = M2AP_Criticality_reject; + mbms_configuration_data_list_item_ies->value.present = M2AP_ENB_MBMS_Configuration_data_ItemIEs__value_PR_ENB_MBMS_Configuration_data_Item; + + M2AP_ENB_MBMS_Configuration_data_Item_t *mbms_configuration_data_item; + mbms_configuration_data_item = &mbms_configuration_data_list_item_ies->value.choice.ENB_MBMS_Configuration_data_Item; + { + /* M2AP_ECGI_t eCGI */ + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &mbms_configuration_data_item->eCGI.pLMN_Identity); + MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0, + &mbms_configuration_data_item->eCGI.eUTRANcellIdentifier); + /* M2AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea */ + mbms_configuration_data_item->mbsfnSynchronisationArea=instance_p->mbms_configuration_data_list[i].mbsfn_sync_area; //? long + /* M2AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList */ + for(j=0;jmbms_configuration_data_list[i].num_mbms_service_area_list;j++){ + M2AP_MBMS_Service_Area_t * mbms_service_area = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); + + char buf[2]; + INT16_TO_BUFFER(instance_p->mbms_configuration_data_list[i].mbms_service_area_list[j],buf); + OCTET_STRING_fromBuf(mbms_service_area,buf,2); + //LOG_D(M2AP,"%s\n",instance_p->mbms_configuration_data_list[i].mbms_service_area_list[j]); + //OCTET_STRING_fromBuf(mbms_service_area,"03",2); + ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area); + } + /*M2AP_MBMS_Service_Area_t * mbms_service_area,*mbms_service_area2; + mbms_service_area = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); + mbms_service_area2 = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); + //memset(mbms_service_area,0,sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(mbms_service_area,"01",2); + ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area); + OCTET_STRING_fromBuf(mbms_service_area2,"02",2); + ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area2);*/ + + + } + + + //M2AP_ENB_MBMS_Configuration_data_Item_t mbms_configuration_data_item; + //memset((void *)&mbms_configuration_data_item, 0, sizeof(M2AP_ENB_MBMS_Configuration_data_Item_t)); + + //M2AP_ECGI_t eCGI; + //M2AP_PLMN_Identity_t pLMN_Identity; + //M2AP_EUTRANCellIdentifier_t eUTRANcellIdentifier + //M2AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea; + //M2AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList; + + + ASN_SEQUENCE_ADD(&ie->value.choice.ENB_MBMS_Configuration_data_List.list,mbms_configuration_data_list_item_ies); + + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + LOG_D(M2AP,"m2ap_eNB_data_p->assoc_id %d\n",m2ap_eNB_data_p->assoc_id); + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 setup request\n"); + return -1; + } + + + LOG_D(M2AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m2ap_eNB_data_p->ENBname); + + +// buffer = &bytes[0]; +// len = 40; +// +// for(int i=0; i < len; i++ ) +// printf("%02X",buffer[i]); +// printf("\n"); +// + m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 0); + + return 0; +} + + +int eNB_handle_M2_SETUP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + + LOG_D(M2AP, "eNB_handle_M2_SETUP_RESPONSE\n"); + + AssertFatal(pdu->present == M2AP_M2AP_PDU_PR_successfulOutcome, + "pdu->present != M2AP_M2AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M2AP_ProcedureCode_id_m2Setup, + "pdu->choice.successfulOutcome.procedureCode != M2AP_ProcedureCode_id_M2Setup\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M2AP_Criticality_reject, + "pdu->choice.successfulOutcome.criticality != M2AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M2AP_SuccessfulOutcome__value_PR_M2SetupResponse, + "pdu->choice.successfulOutcome.value.present != M2AP_SuccessfulOutcome__value_PR_M2SetupResponse\n"); + + M2AP_M2SetupResponse_t *in = &pdu->choice.successfulOutcome.value.choice.M2SetupResponse; + + + M2AP_M2SetupResponse_Ies_t *ie; + //int GlobalMCE_ID = -1; + int num_cells_to_activate = 0; + //M2AP_Cells_to_be_Activated_List_Item_t *cell; + int i,j; + + MessageDef *msg_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_SETUP_RESP); + //MessageDef *msg_p2 = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_SETUP_RESP); + + LOG_D(M2AP, "M2AP: M2Setup-Resp: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (j=0;j < in->protocolIEs.list.count; j++) { + ie = in->protocolIEs.list.array[j]; + switch (ie->id) { + case M2AP_ProtocolIE_ID_id_GlobalMCE_ID: + AssertFatal(ie->criticality == M2AP_Criticality_reject, + "ie->criticality != M2AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M2AP_M2SetupResponse_Ies__value_PR_GlobalMCE_ID, + "ie->value.present != M2AP_M2SetupResponse_Ies__value_PR_GlobalMCE_ID\n"); + LOG_D(M2AP, "M2AP: M2Setup-Resp: GlobalMCE_ID \n");/*, + GlobalMCE_ID);*/ + /*PLMNID_TO_MCC_MNC(&m2ap_pmchconfiguration_item->mbms_Session_List.list.array[k]->tmgi.pLMNidentity, + &M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mcc, + &M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mnc, + &M2AP_MBMS_SCHEDULING_INFORMATION(message_p).mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].mnc_length);*/ + + + break; + case M2AP_ProtocolIE_ID_id_MCEname: + AssertFatal(ie->criticality == M2AP_Criticality_ignore, + "ie->criticality != M2AP_Criticality_ignore\n"); + AssertFatal(ie->value.present == M2AP_M2SetupResponse_Ies__value_PR_MCEname, + "ie->value.present != M2AP_M2SetupResponse_Ies__value_PR_MCEname\n"); + //M2AP_SETUP_RESP (msg_p).MCE_name = malloc(ie->value.choice.size+1); + //memcpy(M2AP_SETUP_RESP (msg_p).gNB_CU_name,ie->value.choice.GNB_CU_Name.buf,ie->value.choice.GNB_CU_Name.size); + //M2AP_SETUP_RESP (msg_p).gNB_CU_name[ie->value.choice.GNB_CU_Name.size]='\0'; + //LOG_D(M2AP, "M2AP: M2Setup-Resp: gNB_CU_name %s\n", + //M2AP_SETUP_RESP (msg_p).gNB_CU_name); + break; + case M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea: + AssertFatal(ie->criticality == M2AP_Criticality_reject, + "ie->criticality != M2AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M2AP_M2SetupResponse_Ies__value_PR_MCCHrelatedBCCH_ConfigPerMBSFNArea, + "ie->value.present != M2AP_M2SetupResponse_Ies__value_PR_MCCHrelatedBCCH_ConfigPerMBSFNArea\n"); + num_cells_to_activate = ie->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea.list.count; + if(ie->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea.list.count > 0 ){ + M2AP_SETUP_RESP(msg_p).num_mcch_config_per_mbsfn = ie->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea.list.count; + } + //LOG_D(M2AP, "M2AP: Activating %d cells\n",num_cells_to_activate); + for (i=0;ivalue.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea.list.array[i]; + AssertFatal(mcch_related_bcch_config_per_mbms_area_ies->id == M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item, + " mcch_related_bcch_config_per_mbms_area_ies->id != M2AP_ProtocolIE_ID_id_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item "); + M2AP_MCCHrelatedBCCH_ConfigPerMBSFNArea_Item_t * config_per_mbsfn_area_item = &mcch_related_bcch_config_per_mbms_area_ies->value.choice.MCCHrelatedBCCH_ConfigPerMBSFNArea_Item; + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[i].pdcch_length = (uint8_t)config_per_mbsfn_area_item->pdcchLength; + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[i].offset = (uint8_t)config_per_mbsfn_area_item->offset; + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[i].modification_period = (uint8_t)config_per_mbsfn_area_item->modificationPeriod; + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[i].mcs = (uint8_t)config_per_mbsfn_area_item->modulationAndCodingScheme; + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[i].repetition_period = (uint8_t)config_per_mbsfn_area_item->repetitionPeriod; + + //LOG_E(M2AP,"mcs %lu\n",config_per_mbsfn_area_item->modulationAndCodingScheme); + //LOG_E(M2AP,"pdcch_length %lu\n",config_per_mbsfn_area_item->pdcchLength); + //LOG_E(M2AP,"modification_period %lu\n",config_per_mbsfn_area_item->modificationPeriod); + //LOG_E(M2AP,"repetition_period %lu\n",config_per_mbsfn_area_item->repetitionPeriod); + //LOG_E(M2AP,"offset %lu\n",config_per_mbsfn_area_item->offset); + //LOG_E(M2AP,"subframe_allocation_info %lu\n", config_per_mbsfn_area_item->subframeAllocationInfo.size); + + + if(config_per_mbsfn_area_item->subframeAllocationInfo.size == 1){ + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[i].subframe_allocation_info = config_per_mbsfn_area_item->subframeAllocationInfo.buf[0]>>2; + LOG_D(M2AP,"subframe_allocation_info %d\n", config_per_mbsfn_area_item->subframeAllocationInfo.buf[0]); + } + } + break; + } + } + //AssertFatal(GlobalMCE_ID!=-1,"GlobalMCE_ID was not sent\n"); + //AssertFatal(num_cells_to_activate>0,"No cells activated\n"); + //M2AP_SETUP_RESP (msg_p).num_cells_to_activate = num_cells_to_activate; + + //for (int i=0;i 0, "System Information %d is missing",i); + + //MSC_LOG_RX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_CU, + // 0, + // 0, + // MSC_AS_TIME_FMT" eNB_handle_M2_SETUP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + //LOG_D(M2AP, "Sending M2AP_SETUP_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MOeNBLE_ID_TO_INSTANCE(assoc_id)); + //itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p2); + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + return 0; +} + +// SETUP FAILURE +int eNB_handle_M2_SETUP_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) { + LOG_D(M2AP, "eNB_handle_M2_SETUP_FAILURE\n"); + + M2AP_M2SetupFailure_t *in = &pdu->choice.unsuccessfulOutcome.value.choice.M2SetupFailure; + + + M2AP_M2SetupFailure_Ies_t *ie; + + + MessageDef *msg_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_SETUP_FAILURE); + + LOG_D(M2AP, "M2AP: M2Setup-Failure: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (int i=0;i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case M2AP_ProtocolIE_ID_id_TimeToWait: + AssertFatal(ie->criticality == M2AP_Criticality_ignore, + "ie->criticality != M2AP_Criticality_ignore\n"); + AssertFatal(ie->value.present == M2AP_M2SetupFailure_Ies__value_PR_TimeToWait, + "ie->value.present != M2AP_M2SetupFailure_Ies__value_PR_TimeToWait\n"); + LOG_D(M2AP, "M2AP: M2Setup-Failure: TimeToWait \n");/*, + GlobalMCE_ID);*/ + break; + } + } + //AssertFatal(GlobalMCE_ID!=-1,"GlobalMCE_ID was not sent\n"); + //AssertFatal(num_cells_to_activate>0,"No cells activated\n"); + //M2AP_SETUP_RESP (msg_p).num_cells_to_activate = num_cells_to_activate; + + //for (int i=0;i 0, "System Information %d is missing",i); + + //MSC_LOG_RX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_CU, + // 0, + // 0, + // MSC_AS_TIME_FMT" eNB_handle_M2_SETUP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + //LOG_D(M2AP, "Sending M2AP_SETUP_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MOeNBLE_ID_TO_INSTANCE(assoc_id)); + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + return 0; +} + +/* + * eNB Configuration Update + */ +int eNB_send_eNB_CONFIGURATION_UPDATE(instance_t instance, m2ap_enb_configuration_update_t * m2ap_enb_configuration_update) +{ + + AssertFatal(1==0,"Not implemented yet\n"); + + M2AP_M2AP_PDU_t pdu; + M2AP_ENBConfigurationUpdate_t *out; + M2AP_ENBConfigurationUpdate_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + int i = 0; + //int j = 0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_eNBConfigurationUpdate; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_ENBConfigurationUpdate; + out = &pdu.choice.initiatingMessage.value.choice.ENBConfigurationUpdate; + + /* mandatory */ + /* c1. GlobalENB_ID (integer value) */ + ie = (M2AP_ENBConfigurationUpdate_Ies_t *)calloc(1, sizeof(M2AP_ENBConfigurationUpdate_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_ENBConfigurationUpdate_Ies__value_PR_GlobalENB_ID; + //ie->value.choice.GlobalENB_ID.eNB_ID = 1;//M2AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP); + MCC_MNC_TO_PLMNID(0, 0, 3, + &ie->value.choice.GlobalENB_ID.pLMN_Identity); + ie->value.choice.GlobalENB_ID.eNB_ID.present = M2AP_ENB_ID_PR_macro_eNB_ID; + MACRO_ENB_ID_TO_BIT_STRING(10, + &ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); + M2AP_INFO("%d -> %02x%02x%02x\n", 10, + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0], + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1], + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional */ + /* c3. ENBname */ + if (0) { + ie = (M2AP_ENBConfigurationUpdate_Ies_t *)calloc(1, sizeof(M2AP_ENBConfigurationUpdate_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENBname; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_ENBConfigurationUpdate_Ies__value_PR_ENBname; + //OCTET_STRING_fromBuf(&ie->value.choice.ENBname, m2ap_eNB_data_p->eNB_name, + //strlen(m2ap_eNB_data_p->eNB_name)); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* mandatory */ + /* c4. serverd cells list */ + ie = (M2AP_ENBConfigurationUpdate_Ies_t *)calloc(1, sizeof(M2AP_ENBConfigurationUpdate_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_List_ConfigUpdate; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_ENBConfigurationUpdate_Ies__value_PR_ENB_MBMS_Configuration_data_List_ConfigUpdate; + + int num_mbms_available = 1;//m2ap_du_data->num_mbms_available; + LOG_D(M2AP, "num_mbms_available = %d \n", num_mbms_available); + + for (i=0; + iid = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_Item; + mbms_configuration_data_list_item_ies->criticality = M2AP_Criticality_reject; + mbms_configuration_data_list_item_ies->value.present = M2AP_ENB_MBMS_Configuration_data_ItemIEs__value_PR_ENB_MBMS_Configuration_data_Item; + + M2AP_ENB_MBMS_Configuration_data_Item_t *mbms_configuration_data_item; + mbms_configuration_data_item = &mbms_configuration_data_list_item_ies->value.choice.ENB_MBMS_Configuration_data_Item; + { + /* M2AP_ECGI_t eCGI */ + MCC_MNC_TO_PLMNID(0, 0, 3, + &mbms_configuration_data_item->eCGI.pLMN_Identity); + MACRO_ENB_ID_TO_CELL_IDENTITY(10,0, + &mbms_configuration_data_item->eCGI.eUTRANcellIdentifier); + /* M2AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea */ + mbms_configuration_data_item->mbsfnSynchronisationArea=10000; //? long + /* M2AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList */ + M2AP_MBMS_Service_Area_t * mbms_service_area,*mbms_service_area2; + mbms_service_area = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); + mbms_service_area2 = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); + //memset(mbms_service_area,0,sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(mbms_service_area,"01",2); + ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area); + OCTET_STRING_fromBuf(mbms_service_area2,"02",2); + ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area2); + + + } + + + //M2AP_ENB_MBMS_Configuration_data_Item_t mbms_configuration_data_item; + //memset((void *)&mbms_configuration_data_item, 0, sizeof(M2AP_ENB_MBMS_Configuration_data_Item_t)); + + //M2AP_ECGI_t eCGI; + //M2AP_PLMN_Identity_t pLMN_Identity; + //M2AP_EUTRANCellIdentifier_t eUTRANcellIdentifier + //M2AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea; + //M2AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList; + + + ASN_SEQUENCE_ADD(&ie->value.choice.ENB_MBMS_Configuration_data_List_ConfigUpdate.list,mbms_configuration_data_list_item_ies); + + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + //LOG_D(M2AP,"m2ap_eNB_data_p->assoc_id %d\n",m2ap_eNB_data_p->assoc_id); + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 setup request\n"); + return -1; + } + + + LOG_D(M2AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m2ap_eNB_data_p->ENBname); + + +// buffer = &bytes[0]; +// len = 40; +// +// for(int i=0; i < len; i++ ) +// printf("%02X",buffer[i]); +// printf("\n"); +// + m2ap_eNB_itti_send_sctp_data_req(instance, m2ap_enb_data_g->assoc_id, buffer, len, 0); + + return 0; +} + +int eNB_handle_eNB_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + + AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M2AP, "eNB_handle_eNB_CONFIGURATION_UPDATE_FAILURE\n"); + + M2AP_ENBConfigurationUpdateFailure_t *in = &pdu->choice.unsuccessfulOutcome.value.choice.ENBConfigurationUpdateFailure; + + + //M2AP_ENBConfigurationUpdateFailure_Ies_t *ie; + + + MessageDef *msg_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_ENB_CONFIGURATION_UPDATE_FAILURE); + + LOG_D(M2AP, "M2AP: ENBConfigurationUpdate-Failure: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + //for (int i=0;i < in->protocolIEs.list.count; i++) { + // ie = in->protocolIEs.list.array[i]; + // // switch (ie->id) { + // // case M2AP_ProtocolIE_ID_id_TimeToWait: + // // AssertFatal(ie->criticality == M2AP_Criticality_ignore, + // // "ie->criticality != M2AP_Criticality_ignore\n"); + // // AssertFatal(ie->value.present == M2AP_M2SetupFailure_Ies__value_PR_TimeToWait, + // // "ie->value.present != M2AP_M2SetupFailure_Ies__value_PR_TimeToWait\n"); + // // LOG_D(M2AP, "M2AP: M2Setup-Failure: TimeToWait %d\n");/*, + // // GlobalMCE_ID);*/ + // // break; + // // } + //} + //AssertFatal(GlobalMCE_ID!=-1,"GlobalMCE_ID was not sent\n"); + //AssertFatal(num_cells_to_activate>0,"No cells activated\n"); + //M2AP_SETUP_RESP (msg_p).num_cells_to_activate = num_cells_to_activate; + + //for (int i=0;i 0, "System Information %d is missing",i); + + //MSC_LOG_RX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_CU, + // 0, + // 0, + // MSC_AS_TIME_FMT" eNB_handle_M2_SETUP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + //LOG_D(M2AP, "Sending M2AP_SETUP_RESP ITTI message to ENB_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MOeNBLE_ID_TO_INSTANCE(assoc_id)); + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + return 0; +} + + + +int eNB_handle_eNB_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + LOG_D(M2AP, "eNB_handle_eNB_CONFIGURATION_UPDATE_ACKNOWLEDGE assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_ENBConfigurationUpdateAcknowledge_t *container; + //M2AP_ENBConfigurationUpdateAcknowledge_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.ENBConfigurationUpdate; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_ENB_CONFIGURATION_UPDATE_ACK); + + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + return 0; +} + + +/* + * MCE Configuration Update + */ +int eNB_handle_MCE_CONFIGURATION_UPDATE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + LOG_D(M2AP, "eNB_handle_MCE_CONFIGURATION_UPDATE assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_MCEConfigurationUpdate_t *container; + //M2AP_MCEConfigurationUpdate_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.MCEConfigurationUpdate; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MCE_CONFIGURATION_UPDATE); + + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + return 0; +} + +int eNB_send_MCE_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + M2AP_MCEConfigurationUpdateFailure_t *MCEConfigurationUpdateFailure) +{ + + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + + +int eNB_send_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + M2AP_MCEConfigurationUpdateAcknowledge_t *MCEConfigurationUpdateAcknowledge) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + + +/* + * Error Indication + */ +int eNB_send_ERROR_INDICATION(instance_t instance, m2ap_error_indication_t * m2ap_error_indication) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + +int eNB_handle_ERROR_INDICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + + + +/* + * Session Update Request + */ +int eNB_handle_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + LOG_D(M2AP, "eNB_handle_MBMS_SESSION_STOP_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_SessionUpdateRequest_t *container; + //M2AP_SessionUpdateRequest_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.SessionUpdateRequest; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MBMS_SESSION_UPDATE_REQ); + + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + + return 0; +} + + +int eNB_send_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, m2ap_mbms_session_update_resp_t * m2ap_mbms_session_update_resp) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + + +int eNB_send_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, m2ap_mbms_session_update_failure_t * m2ap_mbms_session_update_failure) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + +/* + * Service Counting + */ + +int eNB_handle_MBMS_SERVICE_COUNTING_REQ(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu) +{ + LOG_D(M2AP, "eNB_handle_MBMS_SERVICE_COUNTING_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M2AP_MbmsServiceCountingRequest_t *container; + //M2AP_MbmsServiceCountingRequest_Ies_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + // container = &pdu->choice.initiatingMessage.value.choice.MbmsServiceCountingRequest; + + /* M2 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M2AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + message_p = itti_alloc_new_message (TASK_M2AP_ENB, M2AP_MBMS_SERVICE_COUNTING_REQ); + + + itti_send_msg_to_task(TASK_ENB_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + + + return 0; +} +int eNB_send_MBMS_SERVICE_COUNTING_REPORT(instance_t instance, m2ap_mbms_service_counting_report_t * m2ap_mbms_service_counting_report) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} +int eNB_send_MBMS_SERVICE_COUNTING_RESP(instance_t instance, m2ap_mbms_service_counting_resp_t * m2ap_mbms_service_counting_resp) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} +int eNB_send_MBMS_SERVICE_COUNTING_FAILURE(instance_t instance, m2ap_mbms_service_counting_failure_t * m2ap_mbms_service_counting_failure) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + +/* + * Overload Notification + */ +int eNB_send_MBMS_OVERLOAD_NOTIFICATION(instance_t instance, m2ap_mbms_overload_notification_t * m2ap_mbms_overload_notification) +{ + AssertFatal(1==0,"Not implemented yet\n"); + return 0; +} + + + + diff --git a/openair2/M2AP/m2ap_eNB_interface_management.h b/openair2/M2AP/m2ap_eNB_interface_management.h new file mode 100644 index 0000000000..09bab1f125 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_interface_management.h @@ -0,0 +1,173 @@ +/* + * 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 m2ap_eNB_interface_management.h + * \brief m2ap interface management for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#ifndef M2AP_ENB_INTERFACE_MANAGEMENT_H_ +#define M2AP_ENB_INTERFACE_MANAGEMENT_H_ + +/* + * Session Start + */ + +int eNB_handle_MBMS_SESSION_START_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int eNB_send_MBMS_SESSION_START_RESPONSE(instance_t instance, m2ap_session_start_resp_t * m2ap_session_start_resp); +int eNB_send_MBMS_SESSION_START_FAILURE(instance_t instance, m2ap_session_start_failure_t * m2ap_session_start_failure ); + +/* + * Session Stop + */ + +int eNB_handle_MBMS_SESSION_STOP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +int eNB_send_MBMS_SESSION_STOP_RESPONSE(instance_t instance, m2ap_session_stop_resp_t * m2ap_session_stop_resp); + + +/* + * MBMS Scheduling Information + */ + +int eNB_handle_MBMS_SCHEDULING_INFORMATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int eNB_send_MBMS_SCHEDULING_INFORMATION_RESPONSE(instance_t instance, m2ap_mbms_scheduling_information_resp_t * m2ap_mbms_scheduling_information_resp); + + +/* + * Reset + */ +int eNB_handle_RESET(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +int eNB_send_RESET_ACKKNOWLEDGE(instance_t instance, M2AP_ResetAcknowledge_t *ResetAcknowledge); +int eNB_send_RESET(instance_t instance, M2AP_Reset_t *Reset); +int eNB_handle_RESET_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * M2AP Setup + */ +int eNB_send_M2_SETUP_REQUEST( m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p); + +int eNB_handle_M2_SETUP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int eNB_handle_M2_SETUP_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * eNB Configuration Update + */ +int eNB_send_eNB_CONFIGURATION_UPDATE(instance_t instance, m2ap_enb_configuration_update_t * m2ap_enb_configuration_update); + +int eNB_handle_eNB_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int eNB_handle_eNB_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +/* + * MCE Configuration Update + */ +int eNB_handle_MCE_CONFIGURATION_UPDATE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int eNB_send_MCE_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + M2AP_MCEConfigurationUpdateFailure_t *MCEConfigurationUpdateFailure); + +int eNB_send_MCE_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + M2AP_MCEConfigurationUpdateAcknowledge_t *MCEConfigurationUpdateAcknowledge); + +/* + * Error Indication + */ +int eNB_send_ERROR_INDICATION(instance_t instance, m2ap_error_indication_t * m2ap_error_indication); +int eNB_handle_ERROR_INDICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + + +/* + * Session Update Request + */ +int eNB_handle_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); + +int eNB_send_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, m2ap_mbms_session_update_resp_t * m2ap_mbms_session_update_resp); //?? + +int eNB_send_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, m2ap_mbms_session_update_failure_t * m2ap_mbms_session_update_failure); + +/* + * Service Counting + */ + +int eNB_handle_MBMS_SERVICE_COUNTING_REQ(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M2AP_M2AP_PDU_t *pdu); +int eNB_send_MBMS_SERVICE_COUNTING_REPORT(instance_t instance, m2ap_mbms_service_counting_report_t * m2ap_mbms_service_counting_report); +int eNB_send_MBMS_SERVICE_COUNTING_RESP(instance_t instance, m2ap_mbms_service_counting_resp_t * m2ap_mbms_service_counting_resp); +int eNB_send_MBMS_SERVICE_COUNTING_FAILURE(instance_t instance, m2ap_mbms_service_counting_failure_t * m2ap_mbms_service_counting_failure); + + +/* + * Overload Notification + */ +int eNB_send_MBMS_OVERLOAD_NOTIFICATION(instance_t instance, m2ap_mbms_overload_notification_t * m2ap_mbms_overload_notification); + + +#endif /* M2AP_ENB_INTERFACE_MANAGEMENT_H_ */ + + + diff --git a/openair2/M2AP/m2ap_eNB_management_procedures.c b/openair2/M2AP/m2ap_eNB_management_procedures.c new file mode 100644 index 0000000000..b3ada92fa8 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_management_procedures.c @@ -0,0 +1,257 @@ +/* + * 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 m2ap_eNB_management_procedures.c + * \brief m2ap tasks for eNB + * \author Javier Morgade + * \date 2018 + * \version 1.0 + */ + +#include +#include +#include + +#include "intertask_interface.h" + +#include "assertions.h" +#include "conversions.h" + +#include "m2ap_common.h" +#include "m2ap_eNB_defs.h" +#include "m2ap_eNB.h" + + +#define M2AP_DEBUG_LIST +#ifdef M2AP_DEBUG_LIST +# define M2AP_eNB_LIST_OUT(x, args...) M2AP_DEBUG("[eNB]%*s"x"\n", 4*indent, "", ##args) +#else +# define M2AP_eNB_LIST_OUT(x, args...) +#endif + +static int indent = 0; + + +m2ap_eNB_internal_data_t m2ap_eNB_internal_data; + +RB_GENERATE(m2ap_enb_map, m2ap_eNB_data_s, entry, m2ap_eNB_compare_assoc_id); + +int m2ap_eNB_compare_assoc_id( + struct m2ap_eNB_data_s *p1, struct m2ap_eNB_data_s *p2) +{ + if (p1->assoc_id == -1) { + if (p1->cnx_id < p2->cnx_id) { + return -1; + } + + if (p1->cnx_id > p2->cnx_id) { + return 1; + } + } else { + if (p1->assoc_id < p2->assoc_id) { + return -1; + } + + if (p1->assoc_id > p2->assoc_id) { + return 1; + } + } + + /* Matching reference */ + return 0; +} + +uint16_t m2ap_eNB_fetch_add_global_cnx_id(void) +{ + return ++m2ap_eNB_internal_data.global_cnx_id; +} + +void m2ap_eNB_prepare_internal_data(void) +{ + memset(&m2ap_eNB_internal_data, 0, sizeof(m2ap_eNB_internal_data)); + STAILQ_INIT(&m2ap_eNB_internal_data.m2ap_eNB_instances_head); +} + +void m2ap_eNB_insert_new_instance(m2ap_eNB_instance_t *new_instance_p) +{ + DevAssert(new_instance_p != NULL); + + STAILQ_INSERT_TAIL(&m2ap_eNB_internal_data.m2ap_eNB_instances_head, + new_instance_p, m2ap_eNB_entries); +} + +void dump_tree_m2(m2ap_eNB_data_t *t) +{ + if (t == NULL) return; + printf("-----------------------\n"); + printf("eNB id %d %s\n", t->eNB_id, t->eNB_name); + printf("state %d\n", t->state); + printf("nextstream %d\n", t->nextstream); + printf("in_streams %d out_streams %d\n", t->in_streams, t->out_streams); + printf("cnx_id %d assoc_id %d\n", t->cnx_id, t->assoc_id); + dump_tree_m2(t->entry.rbe_left); + dump_tree_m2(t->entry.rbe_right); +} + +void dump_trees_m2(void) +{ +m2ap_eNB_instance_t *zz; +STAILQ_FOREACH(zz, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, + m2ap_eNB_entries) { +printf("here comes the tree (instance %d):\n---------------------------------------------\n", zz->instance); +dump_tree_m2(zz->m2ap_enb_head.rbh_root); +printf("---------------------------------------------\n"); +} +} + +struct m2ap_eNB_data_s *m2ap_get_eNB(m2ap_eNB_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id) +{ + struct m2ap_eNB_data_s temp; + struct m2ap_eNB_data_s *found; + +printf("m2ap_get_eNB at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id); +dump_trees_m2(); + + memset(&temp, 0, sizeof(struct m2ap_eNB_data_s)); + + temp.assoc_id = assoc_id; + temp.cnx_id = cnx_id; + + if (instance_p == NULL) { + STAILQ_FOREACH(instance_p, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, + m2ap_eNB_entries) { + found = RB_FIND(m2ap_enb_map, &instance_p->m2ap_enb_head, &temp); + + if (found != NULL) { + return found; + } + } + } else { + return RB_FIND(m2ap_enb_map, &instance_p->m2ap_enb_head, &temp); + } + + return NULL; +} + + +m2ap_eNB_instance_t *m2ap_eNB_get_instance(instance_t instance) +{ + m2ap_eNB_instance_t *temp = NULL; + + STAILQ_FOREACH(temp, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, + m2ap_eNB_entries) { + if (temp->instance == instance) { + /* Matching occurence */ + return temp; + } + } + + return NULL; +} + +/// utility functions + +void m2ap_dump_eNB (m2ap_eNB_data_t * eNB_ref); + +void +m2ap_dump_eNB_list (void) { + m2ap_eNB_instance_t *inst = NULL; + struct m2ap_eNB_data_s *found = NULL; + struct m2ap_eNB_data_s temp; + + memset(&temp, 0, sizeof(struct m2ap_eNB_data_s)); + + STAILQ_FOREACH (inst, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, m2ap_eNB_entries) { + found = RB_FIND(m2ap_enb_map, &inst->m2ap_enb_head, &temp); + m2ap_dump_eNB (found); + } +} + +void m2ap_dump_eNB (m2ap_eNB_data_t * eNB_ref) { + + if (eNB_ref == NULL) { + return; + } + + M2AP_eNB_LIST_OUT (""); + M2AP_eNB_LIST_OUT ("eNB name: %s", eNB_ref->eNB_name == NULL ? "not present" : eNB_ref->eNB_name); + M2AP_eNB_LIST_OUT ("eNB STATE: %07x", eNB_ref->state); + M2AP_eNB_LIST_OUT ("eNB ID: %07x", eNB_ref->eNB_id); + indent++; + M2AP_eNB_LIST_OUT ("SCTP cnx id: %d", eNB_ref->cnx_id); + M2AP_eNB_LIST_OUT ("SCTP assoc id: %d", eNB_ref->assoc_id); + M2AP_eNB_LIST_OUT ("SCTP instreams: %d", eNB_ref->in_streams); + M2AP_eNB_LIST_OUT ("SCTP outstreams: %d", eNB_ref->out_streams); + indent--; +} + +m2ap_eNB_data_t * m2ap_is_eNB_pci_in_list (const uint32_t pci) +{ + m2ap_eNB_instance_t *inst; + struct m2ap_eNB_data_s *elm; + + STAILQ_FOREACH(inst, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, m2ap_eNB_entries) { + RB_FOREACH(elm, m2ap_enb_map, &inst->m2ap_enb_head) { + for (int i = 0; inum_cc; i++) { + if (elm->Nid_cell[i] == pci) { + return elm; + } + } + } + } + return NULL; +} + +m2ap_eNB_data_t * m2ap_is_eNB_id_in_list (const uint32_t eNB_id) +{ + m2ap_eNB_instance_t *inst; + struct m2ap_eNB_data_s *elm; + + STAILQ_FOREACH(inst, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, m2ap_eNB_entries) { + RB_FOREACH(elm, m2ap_enb_map, &inst->m2ap_enb_head) { + if (elm->eNB_id == eNB_id) + return elm; + } + } + return NULL; +} + +m2ap_eNB_data_t * m2ap_is_eNB_assoc_id_in_list (const uint32_t sctp_assoc_id) +{ + m2ap_eNB_instance_t *inst; + struct m2ap_eNB_data_s *found; + struct m2ap_eNB_data_s temp; + + temp.assoc_id = sctp_assoc_id; + temp.cnx_id = -1; + + STAILQ_FOREACH(inst, &m2ap_eNB_internal_data.m2ap_eNB_instances_head, m2ap_eNB_entries) { + found = RB_FIND(m2ap_enb_map, &inst->m2ap_enb_head, &temp); + if (found != NULL){ + if (found->assoc_id == sctp_assoc_id) { + return found; + } + } + } + return NULL; +} diff --git a/openair2/M2AP/m2ap_eNB_management_procedures.h b/openair2/M2AP/m2ap_eNB_management_procedures.h new file mode 100644 index 0000000000..fbc49d0169 --- /dev/null +++ b/openair2/M2AP/m2ap_eNB_management_procedures.h @@ -0,0 +1,54 @@ +/* + * 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 m2ap_eNB_management_procedures.h + * \brief m2ap tasks for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENB_MANAGEMENT_PROCEDURES_H_ +#define M2AP_ENB_MANAGEMENT_PROCEDURES_H + +void m2ap_eNB_prepare_internal_data(void); + +void dump_trees_m2(void); + +void m2ap_eNB_insert_new_instance(m2ap_eNB_instance_t *new_instance_p); + +m2ap_eNB_instance_t *m2ap_eNB_get_instance(uint8_t mod_id); + +uint16_t m2ap_eNB_fetch_add_global_cnx_id(void); + +//void m2ap_eNB_prepare_internal_data(void); + +m2ap_eNB_data_t* m2ap_is_eNB_id_in_list(uint32_t eNB_id); + +m2ap_eNB_data_t* m2ap_is_eNB_assoc_id_in_list(uint32_t sctp_assoc_id); + +m2ap_eNB_data_t* m2ap_is_eNB_pci_in_list (const uint32_t pci); + +struct m2ap_eNB_data_s *m2ap_get_eNB(m2ap_eNB_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id); + +#endif /* M2AP_ENB_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair2/M2AP/m2ap_encoder.c b/openair2/M2AP/m2ap_encoder.c new file mode 100644 index 0000000000..8f798ff55c --- /dev/null +++ b/openair2/M2AP/m2ap_encoder.c @@ -0,0 +1,61 @@ +/* + * 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 m2ap_encoder.c + * \brief m2ap encoder procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include +#include + +#include "assertions.h" +#include "conversions.h" +#include "intertask_interface.h" +#include "m2ap_common.h" +#include "m2ap_encoder.h" + +int m2ap_encode_pdu(M2AP_M2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) +{ + ssize_t encoded; + + DevAssert(pdu != NULL); + DevAssert(buffer != NULL); + DevAssert(len != NULL); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)pdu); + } + + encoded = aper_encode_to_new_buffer(&asn_DEF_M2AP_M2AP_PDU, 0, pdu, (void **)buffer); + + if (encoded < 0) { + return -1; + } + + *len = encoded; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, pdu); + return encoded; +} diff --git a/openair2/M2AP/m2ap_encoder.h b/openair2/M2AP/m2ap_encoder.h new file mode 100644 index 0000000000..cf844f2983 --- /dev/null +++ b/openair2/M2AP/m2ap_encoder.h @@ -0,0 +1,35 @@ +/* + * 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 m2ap_encoder.h + * \brief m2ap encoder procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENCODER_H_ +#define M2AP_ENCODER_H_ + +int m2ap_encode_pdu(M2AP_M2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) +__attribute__ ((warn_unused_result)); + +#endif /* M2AP_ENCODER_H_ */ diff --git a/openair2/M2AP/m2ap_handler.c b/openair2/M2AP/m2ap_handler.c new file mode 100644 index 0000000000..1221bcedb5 --- /dev/null +++ b/openair2/M2AP/m2ap_handler.c @@ -0,0 +1,123 @@ +/* + * 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 m2ap_eNB_handler.c + * \brief m2ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "intertask_interface.h" + +#include "asn1_conversions.h" + +#include "m2ap_common.h" +#include "m2ap_eNB_defs.h" +//#include "m2ap_handler.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +//#include "m2ap_eNB_management_procedures.h" +#include "m2ap_eNB_generate_messages.h" + +#include "m2ap_MCE_interface_management.h" +#include "m2ap_eNB_interface_management.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +/* Handlers matrix. Only eNB related procedure present here */ +m2ap_message_decoded_callback m2ap_messages_callback[][3] = { + { eNB_handle_MBMS_SESSION_START_REQUEST, MCE_handle_MBMS_SESSION_START_RESPONSE, 0 }, /* MBMSSessionStart */ + { eNB_handle_MBMS_SESSION_STOP_REQUEST, MCE_handle_MBMS_SESSION_STOP_RESPONSE, 0 }, /* MBMSSessionStop */ + { eNB_handle_MBMS_SCHEDULING_INFORMATION, MCE_handle_MBMS_SCHEDULING_INFORMATION_RESPONSE, 0 }, /* MBMSSchedulingInformation */ + { 0, 0, 0 }, /* Error Indication */ + { 0, 0, 0 }, /* Reset */ + { MCE_handle_M2_SETUP_REQUEST,eNB_handle_M2_SETUP_RESPONSE,eNB_handle_M2_SETUP_FAILURE }, /* M2 Setup */ + { 0, 0, 0 }, /* eNBConfigurationUpdate */ + { 0, 0, 0 }, /* MCEConfigurationUpdate */ + { 0, 0, 0 }, /* privateMessage */ + { 0, 0, 0 }, /* MBMSSessionUpdate */ + { 0, 0, 0 }, /* MBMSServiceCounting */ + { 0, 0, 0 }, /* MBMSServiceCountingResultReport */ + { 0, 0, 0 } /* MBMSOverloadNotification */ +}; + +static char *m2ap_direction2String(int m2ap_dir) { +static char *m2ap_direction_String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; +return(m2ap_direction_String[m2ap_dir]); +} + + +int m2ap_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length) +{ + M2AP_M2AP_PDU_t pdu; + int ret; + + DevAssert(data != NULL); + + memset(&pdu, 0, sizeof(pdu)); + + if (m2ap_decode_pdu(&pdu, data, data_length) < 0) { + LOG_E(M2AP, "Failed to decode PDU\n"); + return -1; + } + + /* Checking procedure Code and direction of message */ + if (pdu.choice.initiatingMessage.procedureCode > sizeof(m2ap_messages_callback) / (3 * sizeof( + m2ap_message_decoded_callback)) + || (pdu.present > M2AP_M2AP_PDU_PR_unsuccessfulOutcome)) { + LOG_E(M2AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return -1; + } + + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (m2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) { + LOG_E(M2AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, + m2ap_direction2String(pdu.present - 1)); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return -1; + } + + /* Calling the right handler */ + LOG_I(M2AP, "Calling handler with instance %d\n",instance); + ret = (*m2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1]) + (instance, assoc_id, stream, &pdu); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M2AP_M2AP_PDU, &pdu); + return ret; +} + + diff --git a/openair2/M2AP/m2ap_handler.h b/openair2/M2AP/m2ap_handler.h new file mode 100644 index 0000000000..88fb26bc3e --- /dev/null +++ b/openair2/M2AP/m2ap_handler.h @@ -0,0 +1,43 @@ +/* + * 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 m2ap_handler.h + * \brief m2ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENB_OLD_HANDLERS_H_ +#define M2AP_ENB_OLD_HANDLERS_H_ + +#include "m2ap_eNB_defs.h" + +void m2ap_handle_m2_setup_message(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown); + +int m2ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + +int m2ap_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + + +#endif /* M2AP_ENB_OLD_HANDLERS_H_ */ diff --git a/openair2/M2AP/m2ap_ids.c b/openair2/M2AP/m2ap_ids.c new file mode 100644 index 0000000000..347ba36d82 --- /dev/null +++ b/openair2/M2AP/m2ap_ids.c @@ -0,0 +1,128 @@ +/* + * 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 "m2ap_ids.h" + +#include + +void m2ap_id_manager_init(m2ap_id_manager *m) +{ + int i; + memset(m, 0, sizeof(m2ap_id_manager)); + for (i = 0; i < M2AP_MAX_IDS; i++) + m->ids[i].rnti = -1; +} + +int m2ap_allocate_new_id(m2ap_id_manager *m) +{ + int i; + for (i = 0; i < M2AP_MAX_IDS; i++) + if (m->ids[i].rnti == -1) { + m->ids[i].rnti = 0; + m->ids[i].id_source = -1; + m->ids[i].id_target = -1; + return i; + } + return -1; +} + +void m2ap_release_id(m2ap_id_manager *m, int id) +{ + m->ids[id].rnti = -1; +} + +int m2ap_find_id(m2ap_id_manager *m, int id_source, int id_target) +{ + int i; + for (i = 0; i < M2AP_MAX_IDS; i++) + if (m->ids[i].rnti != -1 && + m->ids[i].id_source == id_source && + m->ids[i].id_target == id_target) + return i; + return -1; +} + +int m2ap_find_id_from_id_source(m2ap_id_manager *m, int id_source) +{ + int i; + for (i = 0; i < M2AP_MAX_IDS; i++) + if (m->ids[i].rnti != -1 && + m->ids[i].id_source == id_source) + return i; + return -1; +} + +int m2ap_find_id_from_rnti(m2ap_id_manager *m, int rnti) +{ + int i; + for (i = 0; i < M2AP_MAX_IDS; i++) + if (m->ids[i].rnti == rnti) + return i; + return -1; +} + +void m2ap_set_ids(m2ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target) +{ + m->ids[ue_id].rnti = rnti; + m->ids[ue_id].id_source = id_source; + m->ids[ue_id].id_target = id_target; +} + +/* real type of target is m2ap_eNB_data_t * */ +void m2ap_id_set_target(m2ap_id_manager *m, int ue_id, void *target) +{ + m->ids[ue_id].target = target; +} + +void m2ap_id_set_state(m2ap_id_manager *m, int ue_id, m2id_state_t state) +{ + m->ids[ue_id].state = state; +} + +void m2ap_set_reloc_prep_timer(m2ap_id_manager *m, int ue_id, uint64_t time) +{ + m->ids[ue_id].t_reloc_prep_start = time; +} + +void m2ap_set_reloc_overall_timer(m2ap_id_manager *m, int ue_id, uint64_t time) +{ + m->ids[ue_id].tm2_reloc_overall_start = time; +} + +int m2ap_id_get_id_source(m2ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].id_source; +} + +int m2ap_id_get_id_target(m2ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].id_target; +} + +int m2ap_id_get_rnti(m2ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].rnti; +} + +void *m2ap_id_get_target(m2ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].target; +} diff --git a/openair2/M2AP/m2ap_ids.h b/openair2/M2AP/m2ap_ids.h new file mode 100644 index 0000000000..8603d67788 --- /dev/null +++ b/openair2/M2AP/m2ap_ids.h @@ -0,0 +1,80 @@ +/* + * 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 + */ + +#ifndef M2AP_IDS_H_ +#define M2AP_IDS_H_ + +#include + +/* maximum number of simultaneous handovers, do not set too high */ +#define M2AP_MAX_IDS 16 + +/* + * state: + * - when starting handover in source, UE is in state M2ID_STATE_SOURCE_PREPARE + * - after receiving HO_ack in source, UE is in state M2ID_STATE_SOURCE_OVERALL + * - in target, UE is in state X2ID_STATE_TARGET + * The state is used to check timers. + */ +typedef enum { + M2ID_STATE_SOURCE_PREPARE, + M2ID_STATE_SOURCE_OVERALL, + M2ID_STATE_TARGET +} m2id_state_t; + +typedef struct { + int rnti; /* -1 when free */ + int id_source; + int id_target; + + /* the target eNB. Real type is m2ap_eNB_data_t * */ + void *target; + + /* state: needed to check timers */ + m2id_state_t state; + + /* timers */ + uint64_t t_reloc_prep_start; + uint64_t tm2_reloc_overall_start; +} m2ap_id; + +typedef struct { + m2ap_id ids[M2AP_MAX_IDS]; +} m2ap_id_manager; + +void m2ap_id_manager_init(m2ap_id_manager *m); +int m2ap_allocate_new_id(m2ap_id_manager *m); +void m2ap_release_id(m2ap_id_manager *m, int id); +int m2ap_find_id(m2ap_id_manager *, int id_source, int id_target); +int m2ap_find_id_from_id_source(m2ap_id_manager *, int id_source); +int m2ap_find_id_from_rnti(m2ap_id_manager *, int rnti); +void m2ap_set_ids(m2ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target); +void m2ap_id_set_state(m2ap_id_manager *m, int ue_id, m2id_state_t state); +/* real type of target is m2ap_eNB_data_t * */ +void m2ap_id_set_target(m2ap_id_manager *m, int ue_id, void *target); +void m2ap_set_reloc_prep_timer(m2ap_id_manager *m, int ue_id, uint64_t time); +void m2ap_set_reloc_overall_timer(m2ap_id_manager *m, int ue_id, uint64_t time); +int m2ap_id_get_id_source(m2ap_id_manager *m, int ue_id); +int m2ap_id_get_id_target(m2ap_id_manager *m, int ue_id); +int m2ap_id_get_rnti(m2ap_id_manager *m, int ue_id); +void *m2ap_id_get_target(m2ap_id_manager *m, int ue_id); + +#endif /* M2AP_IDS_H_ */ diff --git a/openair2/M2AP/m2ap_itti_messaging.c b/openair2/M2AP/m2ap_itti_messaging.c new file mode 100644 index 0000000000..b9cfd32901 --- /dev/null +++ b/openair2/M2AP/m2ap_itti_messaging.c @@ -0,0 +1,96 @@ +/* + * 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 m2ap_eNB_itti_messaging.c + * \brief m2ap tasks for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include "intertask_interface.h" + +#include "m2ap_itti_messaging.h" + +void m2ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream) +{ + MessageDef *message_p; + sctp_data_req_t *sctp_data_req; + + message_p = itti_alloc_new_message(TASK_M2AP_ENB, SCTP_DATA_REQ); + + sctp_data_req = &message_p->ittiMsg.sctp_data_req; + + sctp_data_req->assoc_id = assoc_id; + sctp_data_req->buffer = buffer; + sctp_data_req->buffer_length = buffer_length; + sctp_data_req->stream = stream; + + //LOG_W(M2AP,"assoc_id %d, stream %d\n",assoc_id,stream); + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} + + +void m2ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id) +{ + MessageDef *message_p = NULL; + sctp_close_association_t *sctp_close_association_p = NULL; + + message_p = itti_alloc_new_message(TASK_M2AP_ENB, SCTP_CLOSE_ASSOCIATION); + sctp_close_association_p = &message_p->ittiMsg.sctp_close_association; + sctp_close_association_p->assoc_id = assoc_id; + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} + + +void m2ap_MCE_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream) +{ + MessageDef *message_p; + sctp_data_req_t *sctp_data_req; + + message_p = itti_alloc_new_message(TASK_M2AP_MCE, SCTP_DATA_REQ); + + sctp_data_req = &message_p->ittiMsg.sctp_data_req; + + sctp_data_req->assoc_id = assoc_id; + sctp_data_req->buffer = buffer; + sctp_data_req->buffer_length = buffer_length; + sctp_data_req->stream = stream; + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} + + +void m2ap_MCE_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id) +{ + MessageDef *message_p = NULL; + sctp_close_association_t *sctp_close_association_p = NULL; + + message_p = itti_alloc_new_message(TASK_M2AP_MCE, SCTP_CLOSE_ASSOCIATION); + sctp_close_association_p = &message_p->ittiMsg.sctp_close_association; + sctp_close_association_p->assoc_id = assoc_id; + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} diff --git a/openair2/M2AP/m2ap_itti_messaging.h b/openair2/M2AP/m2ap_itti_messaging.h new file mode 100644 index 0000000000..bdc416bca7 --- /dev/null +++ b/openair2/M2AP/m2ap_itti_messaging.h @@ -0,0 +1,48 @@ +/* + * 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 m2ap_itti_messaging.h + * \brief m2ap tasks for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENB_ITTI_MESSAGING_H_ +#define M2AP_ENB_ITTI_MESSAGING_H_ + +void m2ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream); + + +void m2ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id); + + +void m2ap_MCE_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream); + + +void m2ap_MCE_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id); + + + + +#endif /* M2AP_ENB_ITTI_MESSAGING_H_ */ diff --git a/openair2/M2AP/m2ap_timers.c b/openair2/M2AP/m2ap_timers.c new file mode 100644 index 0000000000..13ec6423ac --- /dev/null +++ b/openair2/M2AP/m2ap_timers.c @@ -0,0 +1,105 @@ +/* + * 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 "m2ap_timers.h" +#include "assertions.h" +#include "PHY/defs_common.h" /* TODO: try to not include this */ +#include "m2ap_messages_types.h" +#include "m2ap_eNB_defs.h" +#include "m2ap_ids.h" +#include "m2ap_eNB_management_procedures.h" +#include "m2ap_eNB_generate_messages.h" + +void m2ap_timers_init(m2ap_timers_t *t, int t_reloc_prep, int tm2_reloc_overall) +{ + t->tti = 0; + t->t_reloc_prep = t_reloc_prep; + t->tm2_reloc_overall = tm2_reloc_overall; +} + +void m2ap_check_timers(instance_t instance) +{ + //m2ap_eNB_instance_t *instance_p; + //m2ap_timers_t *t; + //m2ap_id_manager *m; + //int i; + //m2ap_handover_cancel_cause_t cause; + //void *target; + //MessageDef *msg; + //int m2_ongoing; + + //instance_p = m2ap_eNB_get_instance(instance); + //DevAssert(instance_p != NULL); + + //t = &instance_p->timers; + //m = &instance_p->id_manager; + + ///* increment subframe count */ + //t->tti++; + + //m2_ongoing = 0; + + //for (i = 0; i < M2AP_MAX_IDS; i++) { + // if (m->ids[i].rnti == -1) continue; + // m2_ongoing++; + + // if (m->ids[i].state == M2ID_STATE_SOURCE_PREPARE && + // t->tti > m->ids[i].t_reloc_prep_start + t->t_reloc_prep) { + // LOG_I(M2AP, "M2 timeout reloc prep\n"); + // /* t_reloc_prep timed out */ + // cause = M2AP_T_RELOC_PREP_TIMEOUT; + // goto timeout; + // } + + // if (m->ids[i].state == M2ID_STATE_SOURCE_OVERALL && + // t->tti > m->ids[i].tm2_reloc_overall_start + t->tm2_reloc_overall) { + // LOG_I(M2AP, "M2 timeout reloc overall\n"); + // /* tm2_reloc_overall timed out */ + // cause = M2AP_TM2_RELOC_OVERALL_TIMEOUT; + // goto timeout; + // } + + // /* no timeout -> check next UE */ + // continue; + + // timeout: + // /* inform target about timeout */ + // target = m2ap_id_get_target(m, i); + // m2ap_eNB_generate_m2_handover_cancel(instance_p, target, i, cause); + + // /* inform RRC of cancellation */ + // msg = itti_alloc_new_message(TASK_M2AP, M2AP_HANDOVER_CANCEL); + // M2AP_HANDOVER_CANCEL(msg).rnti = m2ap_id_get_rnti(m, i); + // M2AP_HANDOVER_CANCEL(msg).cause = cause; + // itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg); + + // /* remove UE from M2AP */ + // m2ap_release_id(m, i); + //} + + //if (m2_ongoing && t->tti % 1000 == 0) + // LOG_I(M2AP, "M2 has %d process ongoing\n", m2_ongoing); +} + +uint64_t m2ap_timer_get_tti(m2ap_timers_t *t) +{ + return t->tti; +} diff --git a/openair2/M2AP/m2ap_timers.h b/openair2/M2AP/m2ap_timers.h new file mode 100644 index 0000000000..d2875d92af --- /dev/null +++ b/openair2/M2AP/m2ap_timers.h @@ -0,0 +1,45 @@ +/* + * 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 + */ + +#ifndef M2AP_TIMERS_H_ +#define M2AP_TIMERS_H_ + +#include +#include "platform_types.h" + +typedef struct { + /* incremented every TTI (every millisecond when in realtime). + * Used to check timers. + * 64 bits gives us more than 500 million years of (realtime) processing. + * It should be enough. + */ + uint64_t tti; + + /* timer values (unit: TTI, ie. millisecond when in realtime) */ + int t_reloc_prep; + int tm2_reloc_overall; +} m2ap_timers_t; + +void m2ap_timers_init(m2ap_timers_t *t, int t_reloc_prep, int tm2_reloc_overall); +void m2ap_check_timers(instance_t instance); +uint64_t m2ap_timer_get_tti(m2ap_timers_t *t); + +#endif /* M2AP_TIMERS_H_ */ diff --git a/openair2/MCE_APP/mce_app.c b/openair2/MCE_APP/mce_app.c new file mode 100644 index 0000000000..32dfa5cc42 --- /dev/null +++ b/openair2/MCE_APP/mce_app.c @@ -0,0 +1,754 @@ +/* + * 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 + */ + +/* + mce_app.c + ------------------- + AUTHOR : Javier Morgade + COMPANY : VICOMTECH Spain + EMAIL : javier.morgade@ieee.org +*/ + +#include +#include + +#include "mce_app.h" +#include "mce_config.h" +#include "assertions.h" +#include "common/ran_context.h" +#include "targets/RT/USER/lte-softmodem.h" + +#include "common/utils/LOG/log.h" + +# include "intertask_interface.h" +# include "s1ap_eNB.h" +# include "sctp_eNB_task.h" +# include "gtpv1u_eNB_task.h" +# include "flexran_agent.h" + +# include "x2ap_eNB.h" +# include "x2ap_messages_types.h" +# include "m2ap_eNB.h" +# include "m2ap_MCE.h" +# include "m2ap_messages_types.h" +# include "m3ap_MCE.h" +# include "m3ap_messages_types.h" +# define X2AP_ENB_REGISTER_RETRY_DELAY 10 + +#include "openair1/PHY/INIT/phy_init.h" +extern unsigned char NB_MCE_INST; + +extern RAN_CONTEXT_t RC; + +# define MCE_REGISTER_RETRY_DELAY 10 + +#include "targets/RT/USER/lte-softmodem.h" + +static m2ap_mbms_scheduling_information_t * m2ap_mbms_scheduling_information_local = NULL; +static m2ap_setup_resp_t * m2ap_setup_resp_local = NULL; +static m2ap_setup_req_t * m2ap_setup_req_local = NULL; + + +/*------------------------------------------------------------------------------*/ + +static uint32_t MCE_app_register(ngran_node_t node_type,uint32_t mce_id_start, uint32_t mce_id_end) { + uint32_t mce_id; + MessageDef *msg_p; + uint32_t register_mce_pending = 0; + + for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { + { + // M3AP registration + /* note: there is an implicit relationship between the data structure and the message name */ + msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_REGISTER_MCE_REQ); + //RCconfig_S1(msg_p, mce_id); + + //if (mce_id == 0) + //RCconfig_gtpu(); + + //LOG_I(MCE_APP,"default drx %d\n",((M3AP_REGISTER_MCE_REQ(msg_p)).default_drx)); + + LOG_I(ENB_APP,"[MCE %d] MCE_app_register via M3AP for instance %d\n", mce_id, ENB_MODULE_ID_TO_INSTANCE(mce_id)); + itti_send_msg_to_task (TASK_M3AP, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); + + //if (NODE_IS_DU(node_type)) { // F1AP registration + // // configure F1AP here for F1C + // LOG_I(ENB_APP,"ngran_eNB_DU: Allocating ITTI message for F1AP_SETUP_REQ\n"); + // msg_p = itti_alloc_new_message (TASK_ENB_APP, F1AP_SETUP_REQ); + // RCconfig_DU_F1(msg_p, enb_id); + + // LOG_I(ENB_APP,"[eNB %d] eNB_app_register via F1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id)); + // itti_send_msg_to_task (TASK_DU_F1, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + // // configure GTPu here for F1U + //} + //else { // S1AP registration + // /* note: there is an implicit relationship between the data structure and the message name */ + // msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ); + // RCconfig_S1(msg_p, enb_id); + + // if (enb_id == 0) RCconfig_gtpu(); + + // LOG_I(ENB_APP,"default drx %d\n",((S1AP_REGISTER_ENB_REQ(msg_p)).default_drx)); + + // LOG_I(ENB_APP,"[eNB %d] eNB_app_register via S1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id)); + // itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + //} + + register_mce_pending++; + } + } + + return register_mce_pending; +} + + +/*------------------------------------------------------------------------------*/ +//static uint32_t MCE_app_register_x2(uint32_t mce_id_start, uint32_t mce_id_end) { +// uint32_t mce_id; +// MessageDef *msg_p; +// uint32_t register_mce_m2_pending = 0; +// +// for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { +// { +// msg_p = itti_alloc_new_message (TASK_ENB_APP, X2AP_REGISTER_ENB_REQ); +// RCconfig_X2(msg_p, mce_id); +// itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); +// register_mce_x2_pending++; +// } +// } +// +// return register_mce_x2_pending; +//} + +/*------------------------------------------------------------------------------*/ +//static uint32_t MCE_app_register_m2(uint32_t mce_id_start, uint32_t mce_id_end) { +// uint32_t mce_id; +// MessageDef *msg_p; +// uint32_t register_mce_m2_pending = 0; +// +// LOG_W(MCE_APP,"Register ..."); +// for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { +// { +// // LOG_W(MCE_APP,"Register commes inside ...\n"); +// msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_REGISTER_MCE_REQ); +// //RCconfig_M2_MCE(msg_p, mce_id); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); +// // LOG_W(MCE_APP,"Register sent ...\n"); +// register_mce_m2_pending++; +// } +// } +// +// return register_mce_m2_pending; +//} +// +/*------------------------------------------------------------------------------*/ +static uint32_t MCE_app_register_m3(uint32_t mce_id_start, uint32_t mce_id_end) { + uint32_t mce_id; + MessageDef *msg_p; + uint32_t register_mce_m3_pending = 0; + + LOG_D(MCE_APP,"Register ...\n"); + for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { + { + // LOG_W(MCE_APP,"Register commes inside ...\n"); + msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_REGISTER_MCE_REQ); + RCconfig_M3(msg_p, mce_id); + itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); + LOG_D(MCE_APP,"Register sent ...\n"); + register_mce_m3_pending++; + } + } + + return register_mce_m3_pending; +} + +/*************************** M3AP MCE handle **********************************/ +//static uint32_t MCE_app_handle_m3ap_mbms_session_start_req(instance_t instance){ +// //uint32_t mce_id=0; +// // MessageDef *msg_p; +// // msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_START_RESP); +// // itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// +// return 0; +//} + +static uint32_t MCE_app_handle_m3ap_mbms_session_stop_req(instance_t instance){ + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_STOP_RESP); + itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} + +static uint32_t MCE_app_handle_m3ap_mbms_session_update_req(instance_t instance){ + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_UPDATE_RESP); + itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} +//// end M3AP MCE handle **********************************/ + + +/*************************** M2AP MCE handle **********************************/ +static uint32_t MCE_app_handle_m2ap_setup_req(instance_t instance){ + + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_SETUP_RESP); + if(m2ap_setup_resp_local) + memcpy(&M2AP_SETUP_RESP(msg_p),m2ap_setup_resp_local,sizeof(m2ap_setup_resp_t)); + else + RCconfig_M2_MCCH(msg_p,0); + + + itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} + +static uint32_t MCE_app_handle_m2ap_mbms_session_start_resp(instance_t instance){ + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_START_RESP); + itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + return 0; +} + +//// end M2AP MCE handle **********************************/ + + +/*************************** M2AP MCE send **********************************/ +static uint32_t MCE_app_send_m2ap_mbms_scheduling_information(instance_t instance){ + + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MBMS_SCHEDULING_INFORMATION); + if(m2ap_mbms_scheduling_information_local) + memcpy(&M2AP_MBMS_SCHEDULING_INFORMATION(msg_p),m2ap_mbms_scheduling_information_local,sizeof(m2ap_mbms_scheduling_information_t)); + else + RCconfig_M2_SCHEDULING(msg_p,0); + itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} + +static uint32_t MCE_app_send_m2ap_session_start_req(instance_t instance){ + + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MBMS_SESSION_START_REQ); + itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} +//static uint32_t MCE_app_send_m2ap_session_stop_req(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MBMS_SESSION_STOP_REQ); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} +//static uint32_t MCE_app_send_m2ap_mce_configuration_update(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MCE_CONFIGURATION_UPDATE); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} +//static uint32_t MCE_app_send_m2ap_enb_configuration_update_ack(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_ENB_CONFIGURATION_UPDATE_ACK); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} +//static uint32_t MCE_app_send_m2ap_enb_configuration_update_failure(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_ENB_CONFIGURATION_UPDATE_FAILURE); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} //// end M2AP MCE send **********************************/ + +//static uint32_t MCE_app_send_MME_APP(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MCE_APP, MESSAGE_TEST); +// itti_send_msg_to_task (TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} + +//static uint32_t MCE_app_send_MME_APP2(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MCE_APP, MESSAGE_TEST); +// itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} + +/*------------------------------------------------------------------------------*/ +void *MCE_app_task(void *args_p) { + uint32_t mce_nb = 1;//RC.nb_inst; + uint32_t mce_id_start = 0; + uint32_t mce_id_end = mce_id_start + mce_nb; + uint32_t register_mce_pending=0; + uint32_t registered_mce=0; + //long mce_register_retry_timer_id; + long mce_scheduling_info_timer_id; + //uint32_t m3_register_mce_pending = 0; + // uint32_t x2_registered_mce = 0; + // long x2_mce_register_retry_timer_id; + // uint32_t m2_register_mce_pending = 0; + // uint32_t m2_registered_mce = 0; + // long m2_mce_register_retry_timer_id; + MessageDef *msg_p = NULL; + instance_t instance; + int result; + /* for no gcc warnings */ + (void)instance; + itti_mark_task_ready (TASK_MCE_APP); + + /* Try to register each MCE */ + // This assumes that node_type of all RRC instances is the same + if (EPC_MODE_ENABLED) { + register_mce_pending = MCE_app_register(RC.rrc[0]->node_type, mce_id_start, mce_id_end); + } + + /* Try to register each MCE with each other */ + // if (is_x2ap_enabled() && !NODE_IS_DU(RC.rrc[0]->node_type)) { + // x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end); + // } + // MCE_app_send_MME_APP2(0); + + + if (is_m2ap_MCE_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) { + RCconfig_MCE(); + + if(!m2ap_mbms_scheduling_information_local) + m2ap_mbms_scheduling_information_local = (m2ap_mbms_scheduling_information_t*)calloc(1,sizeof(m2ap_mbms_scheduling_information_t)); + if(m2ap_mbms_scheduling_information_local) + RCconfig_m2_scheduling(m2ap_mbms_scheduling_information_local,0); + + if(!m2ap_setup_resp_local) + m2ap_setup_resp_local = (m2ap_setup_resp_t*)calloc(1,sizeof(m2ap_setup_resp_t)); + if(m2ap_setup_resp_local) + RCconfig_m2_mcch(m2ap_setup_resp_local,0); + } + + // /* Try to register each MCE with MCE each other */ + if (is_m3ap_MCE_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) { + ///*m3_register_mce_pending =*/ MCE_app_register_m3 (mce_id_start, mce_id_end); + } + + do { + // Wait for a message + itti_receive_msg (TASK_MCE_APP, &msg_p); + instance = ITTI_MSG_INSTANCE (msg_p); + + switch (ITTI_MSG_ID(msg_p)) { + case TERMINATE_MESSAGE: + LOG_W(MCE_APP, " *** Exiting MCE_APP thread\n"); + itti_exit_task (); + break; + + case MESSAGE_TEST: + LOG_I(MCE_APP, "Received %s\n", ITTI_MSG_NAME(msg_p)); + break; + + case SOFT_RESTART_MESSAGE: + //handle_reconfiguration(instance); + break; + + case M3AP_REGISTER_MCE_CNF: + //AssertFatal(!NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received S1AP_REGISTER_ENB_CNF\n"); + LOG_I(MCE_APP, "[MCE %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p), + M3AP_REGISTER_MCE_CNF(msg_p).nb_mme); + DevAssert(register_mce_pending > 0); + register_mce_pending--; + + /* Check if at least MCE is registered with one MME */ + if (M3AP_REGISTER_MCE_CNF(msg_p).nb_mme > 0) { + registered_mce++; + } + + /* Check if all register MCE requests have been processed */ + if (register_mce_pending == 0) { + if (registered_mce == mce_nb) { + /* If all MCE are registered, start L2L1 task */ + // MessageDef *msg_init_p; + // msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE); + // itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); + } else { + LOG_W(MCE_APP, " %d MCE not associated with a MME, retrying registration in %d seconds ...\n", + mce_nb - registered_mce, MCE_REGISTER_RETRY_DELAY); + + // /* Restart the MCE registration process in MCE_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (MCE_REGISTER_RETRY_DELAY, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + // NULL, &mce_register_retry_timer_id) < 0) { + // LOG_E(MCE_APP, " Can not start MCE register retry timer, use \"sleep\" instead!\n"); + // sleep(MCE_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // registered_mce = 0; + // register_mce_pending = MCE_app_register (RC.rrc[0]->node_type,mce_id_start, mce_id_end); + // } + } + } + + break; + + case M3AP_MBMS_SESSION_START_REQ: + LOG_I(MCE_APP, "Received M3AP_MBMS_SESSION_START_REQ message %s\n", ITTI_MSG_NAME (msg_p)); + //MCE_app_handle_m3ap_mbms_session_start_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + if(m2ap_setup_req_local) + if (timer_setup (2, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + NULL, &mce_scheduling_info_timer_id) < 0) { + } + + + break; + + case M3AP_MBMS_SESSION_STOP_REQ: + LOG_I(MCE_APP, "Received M3AP_MBMS_SESSION_STOP_REQ message %s\n", ITTI_MSG_NAME (msg_p)); + MCE_app_handle_m3ap_mbms_session_stop_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + break; + + case M3AP_MBMS_SESSION_UPDATE_REQ: + LOG_I(MCE_APP, "Received M3AP_MBMS_SESSION_UPDATE_REQ message %s\n", ITTI_MSG_NAME (msg_p)); + MCE_app_handle_m3ap_mbms_session_update_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + break; + + + + case M3AP_SETUP_RESP: + LOG_I(MCE_APP, "Received M3AP_SETUP_RESP message %s\n", ITTI_MSG_NAME (msg_p)); + // //AssertFatal(NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received F1AP_REGISTER_ENB_CNF in CU/MCE\n"); + + // //LOG_I(MCE_APP, "Received %s: associated ngran_MCE_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p), + // //F1AP_SETUP_RESP(msg_p).gNB_CU_name,F1AP_SETUP_RESP(msg_p).num_cells_to_activate); + // + // //handle_f1ap_setup_resp(&F1AP_SETUP_RESP(msg_p)); + // handle_m3ap_setup_resp(&M3AP_SETUP_RESP(msg_p)); + + // DevAssert(register_mce_pending > 0); + // register_mce_pending--; + + // /* Check if at least MCE is registered with one MME */ + // //if (M3AP_SETUP_RESP(msg_p).num_cells_to_activate > 0) { + // // registered_enb++; + // //} + + // /* Check if all register MCE requests have been processed */ + // if (register_mce_pending == 0) { + // if (registered_mce == mce_nb) { + // /* If all MCE cells are registered, start L2L1 task */ + // MessageDef *msg_init_p; + + // //msg_init_p = itti_alloc_new_message (TASK_MCE_APP, INITIALIZE_MESSAGE); + // //itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); + + // } else { + // LOG_W(MCE_APP, " %d MCE not associated with a MME, retrying registration in %d seconds ...\n", + // mce_nb - registered_mce, MCE_REGISTER_RETRY_DELAY); + + // /* Restart the MCE registration process in MCE_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (MCE_REGISTER_RETRY_DELAY, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + // NULL, &mce_register_retry_timer_id) < 0) { + // LOG_E(ENB_APP, " Can not start MCE register retry timer, use \"sleep\" instead!\n"); + + // sleep(MCE_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // registered_mce = 0; + // register_mce_pending = MCE_app_register (RC.rrc[0]->node_type,mce_id_start, mce_id_end);//, enb_properties_p); + // } + // } + // } + + break; + + case M3AP_DEREGISTERED_MCE_IND: + if (EPC_MODE_ENABLED) { + LOG_W(MCE_APP, "[MCE %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p), + M3AP_DEREGISTERED_MCE_IND(msg_p).nb_mme); + /* TODO handle recovering of registration */ + } + + break; + + case TIMER_HAS_EXPIRED: + LOG_I(MCE_APP, " Received %s: timer_id %ld\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id); + + if (TIMER_HAS_EXPIRED (msg_p).timer_id == mce_scheduling_info_timer_id/*mce_register_retry_timer_id*/) { + /* Restart the registration process */ + //registered_mce = 0; + //register_mce_pending = MCE_app_register (RC.rrc[0]->node_type, mce_id_start, mce_id_end); + MCE_app_send_m2ap_mbms_scheduling_information(0); + } + + //if (TIMER_HAS_EXPIRED (msg_p).timer_id == x2_mce_register_retry_timer_id) { + // /* Restart the registration process */ + // x2_registered_mce = 0; + // x2_register_mce_pending = MCE_app_register_x2 (mce_id_start, mce_id_end); + //} + + break; + + // case X2AP_DEREGISTERED_ENB_IND: + // LOG_W(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // X2AP_DEREGISTERED_ENB_IND(msg_p).nb_x2); + // /* TODO handle recovering of registration */ + // break; + + // case X2AP_REGISTER_ENB_CNF: + // LOG_I(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // X2AP_REGISTER_ENB_CNF(msg_p).nb_x2); + // DevAssert(x2_register_enb_pending > 0); + // x2_register_enb_pending--; + + // /* Check if at least MCE is registered with one target MCE */ + // if (X2AP_REGISTER_ENB_CNF(msg_p).nb_x2 > 0) { + // x2_registered_enb++; + // } + + // /* Check if all register MCE requests have been processed */ + // if (x2_register_enb_pending == 0) { + // if (x2_registered_enb == enb_nb) { + // /* If all MCE are registered, start RRC HO task */ + // } else { + // uint32_t x2_not_associated = enb_nb - x2_registered_enb; + // LOG_W(ENB_APP, " %d MCE %s not associated with the target\n", + // x2_not_associated, x2_not_associated > 1 ? "are" : "is"); + + // // timer to retry + // /* Restart the MCE registration process in ENB_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, + // INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL, + // &x2_enb_register_retry_timer_id) < 0) { + // LOG_E(ENB_APP, " Can not start MCE X2AP register: retry timer, use \"sleep\" instead!\n"); + // sleep(X2AP_ENB_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // x2_registered_enb = 0; + // x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end); + // } + // } + // } + + // break; + + // case M2AP_DEREGISTERED_ENB_IND: + // LOG_W(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // M2AP_DEREGISTERED_ENB_IND(msg_p).nb_m2); + // /* TODO handle recovering of registration */ + // break; + + // case M2AP_REGISTER_ENB_CNF: + // LOG_I(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // M2AP_REGISTER_ENB_CNF(msg_p).nb_m2); + // DevAssert(m2_register_enb_pending > 0); + // m2_register_enb_pending--; + + // /* Check if at least MCE is registered with one target MCE */ + // if (M2AP_REGISTER_ENB_CNF(msg_p).nb_m2 > 0) { + // m2_registered_enb++; + // } + + // /* Check if all register MCE requests have been processed */ + // if (m2_register_enb_pending == 0) { + // if (m2_registered_enb == enb_nb) { + // /* If all MCE are registered, start RRC HO task */ + // } else { + // uint32_t m2_not_associated = enb_nb - m2_registered_enb; + // LOG_W(ENB_APP, " %d MCE %s not associated with the target\n", + // m2_not_associated, m2_not_associated > 1 ? "are" : "is"); + + // // timer to retry + // /* Restart the MCE registration process in ENB_REGISTER_RETRY_DELAY seconds */ + // //if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, + // // INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL, + // // &x2_enb_register_retry_timer_id) < 0) { + // // LOG_E(ENB_APP, " Can not start MCE X2AP register: retry timer, use \"sleep\" instead!\n"); + // // sleep(X2AP_ENB_REGISTER_RETRY_DELAY); + // // /* Restart the registration process */ + // // x2_registered_enb = 0; + // // x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end); + // //} + // } + // } + + // break; + case M2AP_RESET: + LOG_I(MCE_APP, "Received M2AP_RESET message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_SETUP_REQ: + LOG_I(MCE_APP, "Received M2AP_SETUP_REQ message %s\n", ITTI_MSG_NAME (msg_p)); + if(!m2ap_setup_req_local) + m2ap_setup_req_local = (m2ap_setup_req_t*)calloc(1,sizeof(m2ap_setup_req_t)); + if(m2ap_setup_req_local) + memcpy(m2ap_setup_req_local,&M2AP_SETUP_REQ(msg_p),sizeof(m2ap_setup_req_t)); + MCE_app_handle_m2ap_setup_req(ITTI_MESSAGE_GET_INSTANCE(msg_p)); + //MCE_app_send_m2ap_mbms_scheduling_information(0); + //if (timer_setup (2, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + // NULL, &mce_scheduling_info_timer_id) < 0) { + //} + + + /*m3_register_mce_pending =*/ MCE_app_register_m3 (mce_id_start, mce_id_end); + + //MCE_app_send_m2ap_session_start_req(0); + break; + + case M2AP_MBMS_SESSION_START_RESP: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_START_RESP message %s\n", ITTI_MSG_NAME (msg_p)); + //MCE_app_send_m2ap_session_stop_req(0); + MCE_app_handle_m2ap_mbms_session_start_resp(0); + break; + + case M2AP_MBMS_SESSION_STOP_RESP: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_STOP_RESP message %s\n", ITTI_MSG_NAME (msg_p)); + //MCE_app_send_m2ap_session_start_req(0); + //MCE_app_handle_m2ap_mbms_session_start_resp(0); + //MCE_app_send_MME_APP(0); + break; + + case M2AP_MBMS_SCHEDULING_INFORMATION_RESP: + LOG_I(MCE_APP, "Received M2AP_MBMS_SCHEDULING_INFORMATION_RESP message %s\n", ITTI_MSG_NAME (msg_p)); + MCE_app_send_m2ap_session_start_req(0); + break; + + case M2AP_ENB_CONFIGURATION_UPDATE: + LOG_I(MCE_APP, "Received M2AP_ENB_CONFIGURATION_UPDATE message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_ERROR_INDICATION: + LOG_I(MCE_APP, "Received M2AP_ERROR_INDICATION message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MBMS_SESSION_UPDATE_RESP: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_RESP message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MBMS_SESSION_UPDATE_FAILURE: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_FAILURE message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MBMS_SERVICE_COUNTING_REPORT: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_REPORT message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MBMS_OVERLOAD_NOTIFICATION: + LOG_I(MCE_APP, "Received M2AP_MBMS_OVERLOAD_NOTIFICATION message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MBMS_SERVICE_COUNTING_RESP: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_RESP message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MBMS_SERVICE_COUNTING_FAILURE: + LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_FAILURE message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + case M2AP_MCE_CONFIGURATION_UPDATE_ACK: + LOG_I(MCE_APP, "Received M2AP_MCE_CONFIGURATION_UPDATE_ACK message %s\n", ITTI_MSG_NAME (msg_p)); + break; + case M2AP_MCE_CONFIGURATION_UPDATE_FAILURE: + LOG_I(MCE_APP, "Received M2AP_MCE_CONFIGURATION_UPDATE_FAILURE message %s\n", ITTI_MSG_NAME (msg_p)); + break; + + default: + LOG_E(MCE_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while (1); + + return NULL; +} + +//void handle_reconfiguration(module_id_t mod_id) { +// struct timespec start, end; +// clock_gettime(CLOCK_MONOTONIC, &start); +// flexran_agent_info_t *flexran = RC.flexran[mod_id]; +// LOG_I(ENB_APP, "lte-softmodem soft-restart requested\n"); +// +// if (ENB_WAIT == flexran->node_ctrl_state) { +// /* this is already waiting, just release */ +// pthread_mutex_lock(&flexran->mutex_node_ctrl); +// flexran->node_ctrl_state = ENB_NORMAL_OPERATION; +// pthread_mutex_unlock(&flexran->mutex_node_ctrl); +// pthread_cond_signal(&flexran->cond_node_ctrl); +// return; +// } +// +// if (stop_L1L2(mod_id) < 0) { +// LOG_E(ENB_APP, "can not stop lte-softmodem, aborting restart\n"); +// return; +// } +// +// /* node_ctrl_state should have value ENB_MAKE_WAIT only if this method is not +// * executed by the FlexRAN thread */ +// if (ENB_MAKE_WAIT == flexran->node_ctrl_state) { +// LOG_I(ENB_APP, " * MCE %d: Waiting for FlexRAN RTController command *\n", mod_id); +// pthread_mutex_lock(&flexran->mutex_node_ctrl); +// flexran->node_ctrl_state = ENB_WAIT; +// +// while (ENB_NORMAL_OPERATION != flexran->node_ctrl_state) +// pthread_cond_wait(&flexran->cond_node_ctrl, &flexran->mutex_node_ctrl); +// +// pthread_mutex_unlock(&flexran->mutex_node_ctrl); +// } +// +// if (restart_L1L2(mod_id) < 0) { +// LOG_E(ENB_APP, "can not restart, killing lte-softmodem\n"); +// exit_fun("can not restart L1L2, killing lte-softmodem"); +// return; +// } +// +// clock_gettime(CLOCK_MONOTONIC, &end); +// end.tv_sec -= start.tv_sec; +// +// if (end.tv_nsec >= start.tv_nsec) { +// end.tv_nsec -= start.tv_nsec; +// } else { +// end.tv_sec -= 1; +// end.tv_nsec = end.tv_nsec - start.tv_nsec + 1000000000; +// } +// +// LOG_I(ENB_APP, "lte-softmodem restart succeeded in %ld.%ld s\n", end.tv_sec, end.tv_nsec / 1000000); +//} + + diff --git a/openair2/MCE_APP/mce_app.h b/openair2/MCE_APP/mce_app.h new file mode 100644 index 0000000000..59146b9d0d --- /dev/null +++ b/openair2/MCE_APP/mce_app.h @@ -0,0 +1,41 @@ +/* + * 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 + */ + +/* + mce_app.h + ------------------- + AUTHOR : Javier Morgade + COMPANY : VICOMTECH Spain + EMAIL : javier.morgade@ieee.org +*/ + +#ifndef MCE_APP_H_ +#define MCE_APP_H_ + +#include +#include "platform_types.h" + + +void *MCE_app_task(void *args_p); + +//void handle_reconfiguration(module_id_t mod_id); + +#endif /* ENB_APP_H_ */ diff --git a/openair2/MCE_APP/mce_config.c b/openair2/MCE_APP/mce_config.c new file mode 100644 index 0000000000..975f524ebd --- /dev/null +++ b/openair2/MCE_APP/mce_config.c @@ -0,0 +1,512 @@ +/* + * 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 + */ + +/* + mce_config.c + ------------------- + AUTHOR : Javier Morgade + COMPANY : Vicomtech, Spain + EMAIL : javier.morgade@ieee.org +*/ + +#include +#include + +#include "common/utils/LOG/log.h" +#include "assertions.h" +#include "enb_config.h" +#include "UTIL/OTG/otg.h" +#include "UTIL/OTG/otg_externs.h" +#include "intertask_interface.h" +#include "s1ap_eNB.h" +#include "sctp_eNB_task.h" +#include "common/ran_context.h" +#include "sctp_default_values.h" +#include "LTE_SystemInformationBlockType2.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" +#include "PHY/phy_extern.h" +#include "PHY/INIT/phy_init.h" +#include "targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" +#include "nfapi_vnf.h" +#include "nfapi_pnf.h" + +#include "L1_paramdef.h" +#include "MACRLC_paramdef.h" +#include "common/config/config_userapi.h" +#include "RRC_config_tools.h" +#include "enb_paramdef.h" +#include "proto_agent.h" + +#include "m3ap_MCE.h" + + + +int RCconfig_MCE(void ) { + //int num_enbs = 0; + //char *enb_interface_name_for_S1U = NULL; + char *mce_interface_name_for_m2_enb = NULL; + char *mce_interface_name_for_m3_mme = NULL; + //char *enb_ipv4_address_for_S1U = NULL; + char *mce_ipv4_address_for_m2c = NULL; + char *mce_ipv4_address_for_m3c = NULL; + //uint32_t enb_port_for_S1U = 0; + uint32_t mce_port_for_m2c = 0; + uint32_t mce_port_for_m3c = 0; + char *address = NULL; + char *cidr = NULL; + //char gtpupath[MAX_OPTNAME_SIZE*2 + 8]; + char mcepath[MAX_OPTNAME_SIZE*2 + 8]; + //paramdef_t ENBSParams[] = ENBSPARAMS_DESC; + //paramdef_t GTPUParams[] = GTPUPARAMS_DESC; + + paramdef_t MCEParams[] = MCE_NETPARAMS_DESC; + + ///* get number of active eNodeBs */ + //config_get( ENBSParams,sizeof(ENBSParams)/sizeof(paramdef_t),NULL); + //num_enbs = ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt; + //AssertFatal (num_enbs >0, + // "Failed to parse config file no active eNodeBs in %s \n", ENB_CONFIG_STRING_ACTIVE_ENBS); + //sprintf(gtpupath,"%s.[%i].%s",ENB_CONFIG_STRING_ENB_LIST,0,ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + //config_get( GTPUParams,sizeof(GTPUParams)/sizeof(paramdef_t),gtpupath); + config_get(MCEParams,sizeof(MCEParams)/sizeof(paramdef_t),mcepath); + //cidr = enb_ipv4_address_for_S1U; + cidr = mce_ipv4_address_for_m2c; + address = strtok(cidr, "/"); + + //LOG_W(MCE_APP,"cidr %s\n",cidr); + //LOG_W(MCE_APP,"address %s\n",address); + //LOG_W(MCE_APP,"mce_interface_name_for_m2_enb %s\n",mce_interface_name_for_m2_enb); + //LOG_W(MCE_APP,"mce_ipv4_address_for_m2c %s\n",mce_ipv4_address_for_m2c); + //LOG_W(MCE_APP,"mce_ipv4_address_for_m2c %s\n",*(MCEParams[1/*MCE_IPV4_ADDRESS_FOR_M2C_IDX*/].strptr)); + //LOG_W(MCE_APP,"mce_port_for_m2c %d\n",mce_port_for_m2c); + //LOG_W(MCE_APP,"mce_interface_name_for_m3_mme %s\n",mce_interface_name_for_m3_mme); + //LOG_W(MCE_APP,"mce_ipv4_address_for_m3c %s\n",mce_ipv4_address_for_m3c); + //LOG_W(MCE_APP,"mce_port_for_m3c %d\n",mce_port_for_m3c); + +// strcpy(X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4_address,*(X2ParamList.paramarray[l][ENB_X2_IPV4_ADDRESS_IDX].strptr)); + + + if (address) { + MessageDef *message; + AssertFatal((message = itti_alloc_new_message(TASK_MCE_APP, M2AP_MCE_SCTP_REQ))!=NULL,""); + //IPV4_STR_ADDR_TO_INT_NWBO ( address, M2AP_MCE_SCTP_REQ(message).mce_m2_ip_address, "BAD IP ADDRESS FORMAT FOR MCE M2_C !\n" ); + M2AP_MCE_SCTP_REQ (message).mce_m2_ip_address.ipv6 = 0; + M2AP_MCE_SCTP_REQ (message).mce_m2_ip_address.ipv4 = 1; + strcpy( M2AP_MCE_SCTP_REQ (message).mce_m2_ip_address.ipv4_address, address); + //LOG_I(MCE_APP,"Configuring M2_C address : %s -> %x\n",address,M2AP_MCE_SCTP_REQ(message).mce_m2_ip_address); + M2AP_MCE_SCTP_REQ(message).mce_port_for_M2C = mce_port_for_m2c; + itti_send_msg_to_task (TASK_M2AP_MCE, 0, message); // data model is wrong: gtpu doesn't have enb_id (or module_id) + } else + LOG_E(MCE_APP,"invalid address for M2AP\n"); + + return 0; +} + + +int RCconfig_M3(MessageDef *msg_p, uint32_t i) { + int l; + //int num_enbs = 0; + //char *enb_interface_name_for_S1U = NULL; + char *mce_interface_name_for_m2_enb = NULL; + char *mce_interface_name_for_m3_mme = NULL; + //char *enb_ipv4_address_for_S1U = NULL; + char *mce_ipv4_address_for_m2c = NULL; + char *mce_ipv4_address_for_m3c = NULL; + //uint32_t enb_port_for_S1U = 0; + uint32_t mce_port_for_m2c = 0; + uint32_t mce_port_for_m3c = 0; + char *address = NULL; + char *cidr = NULL; + + + char mcepath[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MCEParams[] = MCE_NETPARAMS_DESC; + paramdef_t M3Params[] = M3PARAMS_DESC; + paramdef_t MCCHParams[] = MCCH_PARAMS_DESC; + + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + config_get(MCEParams,sizeof(MCEParams)/sizeof(paramdef_t),mcepath); + + paramlist_def_t M3ParamList = {MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS,NULL,0}; + paramlist_def_t MCCHParamList = {MCE_CONFIG_STRING_MCCH_CONFIG_PER_MBSFN_AREA,NULL,0}; + + char aprefix[MAX_OPTNAME_SIZE*80 + 8]; + sprintf(aprefix,"%s.[%i]","MCEs",0); + /* Some default/random parameters */ + M3AP_REGISTER_MCE_REQ (msg_p).MCE_id = i; + //M3AP_REGISTER_MCE_REQ (msg_p).MME_name = "kk"; + sprintf(aprefix,"%s.[%i]","MCEs",0); + config_getlist( &M3ParamList,M3Params,sizeof(M3Params)/sizeof(paramdef_t),aprefix); + //printf("M3ParamList.numelt %d\n",M3ParamList.numelt); + M3AP_REGISTER_MCE_REQ (msg_p).nb_m3 = 0; + for (l = 0; l < M3ParamList.numelt; l++) { + M3AP_REGISTER_MCE_REQ (msg_p).nb_m3 += 1; + M3AP_REGISTER_MCE_REQ (msg_p).MCE_name = strdup(*(M3ParamList.paramarray[l][MCE_MCE_NAME_IDX].strptr)); + + strcpy(M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv4_address,*(M3ParamList.paramarray[l][MCE2_M3_IPV4_ADDRESS_IDX].strptr)); + strcpy(M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv6_address,*(M3ParamList.paramarray[l][MCE2_M3_IPV6_ADDRESS_IDX].strptr)); + + if (strcmp(*(M3ParamList.paramarray[l][MCE2_M3_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) { + M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv4 = 1; + M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv6 = 0; + } else if (strcmp(*(M3ParamList.paramarray[l][MCE2_M3_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) { + M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv4 = 0; + M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv6 = 1; + } else if (strcmp(*(M3ParamList.paramarray[l][MCE2_M3_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) { + M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv4 = 1; + M3AP_REGISTER_MCE_REQ (msg_p).target_mme_m3_ip_address[l].ipv6 = 1; + } + M3AP_REGISTER_MCE_REQ (msg_p).sctp_out_streams = 2; + M3AP_REGISTER_MCE_REQ (msg_p).sctp_in_streams = 2; + } + + sprintf(aprefix,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + config_get( MCEParams,sizeof(MCEParams)/sizeof(paramdef_t),aprefix); + M3AP_REGISTER_MCE_REQ (msg_p).mme_port_for_M3C = (uint32_t)*(MCEParams[MCE2_PORT_FOR_M3C_IDX].uptr); + + if ((MCEParams[MCE2_IPV4_ADDR_FOR_M3C_IDX].strptr == NULL) || (M3AP_REGISTER_MCE_REQ (msg_p).mme_port_for_M3C == 0)) { + LOG_E(RRC,"Add eNB IPv4 address and/or port for M3C in the CONF file!\n"); + exit(1); + } + + cidr = *(MCEParams[MCE2_IPV4_ADDR_FOR_M3C_IDX].strptr); + address = strtok(cidr, "/"); + M3AP_REGISTER_MCE_REQ (msg_p).mme_m3_ip_address.ipv6 = 0; + M3AP_REGISTER_MCE_REQ (msg_p).mme_m3_ip_address.ipv4 = 1; + strcpy(M3AP_REGISTER_MCE_REQ (msg_p).mme_m3_ip_address.ipv4_address, address); + + sprintf(aprefix,"%s.[%i]","MCEs",0); + config_getlist( &MCCHParamList,MCCHParams,sizeof(MCCHParams)/sizeof(paramdef_t),aprefix); + //printf("MCCHParamList.numelt %d\n",MCCHParamList.numelt); + for (l = 0; l < MCCHParamList.numelt; l++) { + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].mbsfn_area = *(MCCHParamList.paramarray[l][MCCH_MBSFN_AREA_IDX].uptr); + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].pdcch_length = *(MCCHParamList.paramarray[l][MCCH_PDCCH_LENGTH_IDX].uptr); + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].repetition_period = *(MCCHParamList.paramarray[l][MCCH_REPETITION_PERIOD_IDX].uptr); + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].offset = *(MCCHParamList.paramarray[l][MCCH_OFFSET_IDX].uptr); + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].modification_period = *(MCCHParamList.paramarray[l][MCCH_MODIFICATION_PERIOD_IDX].uptr); + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].subframe_allocation_info = *(MCCHParamList.paramarray[l][MCCH_SF_ALLOCATION_INFO_IDX].uptr); + //M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].mcs = strdup(*(MCCHParamList.paramarray[l][MCCH_MCS_IDX].strptr)); + } + + + + + + return 0; +} +int RCconfig_m2_mcch(m2ap_setup_resp_t * m2ap_setup_resp, uint32_t i) { + int l; + + char mcepath[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MCCHParams[] = MCCH_PARAMS_DESC; + paramdef_t MCEParams[] = MCE_PARAMS_DESC; + paramdef_t PLNMParams[] = MCE_PLMN_PARAMS_DESC; + paramlist_def_t MCCHParamList = {MCE_CONFIG_STRING_MCCH_CONFIG_PER_MBSFN_AREA,NULL,0}; + char aprefix[MAX_OPTNAME_SIZE*80 + 8]; + sprintf(mcepath,"%s.[%i]","MCEs",0); + config_get(MCEParams,sizeof(MCEParams)/sizeof(paramdef_t),mcepath); + m2ap_setup_resp->MCE_id = *(MCEParams[MCE_MCE_ID_IDX].uptr); + m2ap_setup_resp->MCE_name = strdup(*(MCEParams[MCE_MCE_NAME_IDX].strptr));; + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_PLMN); + config_get(PLNMParams,sizeof(PLNMParams)/sizeof(paramdef_t),mcepath); + m2ap_setup_resp->mcc = *(PLNMParams[MCE_CONFIG_STRING_MCC_IDX].uptr); + m2ap_setup_resp->mnc = *(PLNMParams[MCE_CONFIG_STRING_MNC_IDX].uptr); + m2ap_setup_resp->mnc_digit_length = *(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr); + //LOG_E(MCE_APP,"PLNM %d\n",*(PLNMParams[MCE_CONFIG_STRING_MCC_IDX].uptr)); + //LOG_E(MCE_APP,"PLNM %d\n",*(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr)); + + + sprintf(aprefix,"%s.[%i]","MCEs",0); + config_getlist( &MCCHParamList,MCCHParams,sizeof(MCCHParams)/sizeof(paramdef_t),aprefix); + //printf("MCCHParamList.numelt %d\n",MCCHParamList.numelt); + AssertFatal(MCCHParamList.numelt <= 8, "File wrong parsed\n"); + for (l = 0; l < MCCHParamList.numelt; l++) { + m2ap_setup_resp->mcch_config_per_mbsfn[l].mbsfn_area = *(MCCHParamList.paramarray[l][MCCH_MBSFN_AREA_IDX].uptr); + m2ap_setup_resp->mcch_config_per_mbsfn[l].pdcch_length = *(MCCHParamList.paramarray[l][MCCH_PDCCH_LENGTH_IDX].uptr); + m2ap_setup_resp->mcch_config_per_mbsfn[l].repetition_period = *(MCCHParamList.paramarray[l][MCCH_REPETITION_PERIOD_IDX].uptr); + m2ap_setup_resp->mcch_config_per_mbsfn[l].offset = *(MCCHParamList.paramarray[l][MCCH_OFFSET_IDX].uptr); + m2ap_setup_resp->mcch_config_per_mbsfn[l].modification_period = *(MCCHParamList.paramarray[l][MCCH_MODIFICATION_PERIOD_IDX].uptr); + m2ap_setup_resp->mcch_config_per_mbsfn[l].subframe_allocation_info = *(MCCHParamList.paramarray[l][MCCH_SF_ALLOCATION_INFO_IDX].uptr); + m2ap_setup_resp->mcch_config_per_mbsfn[l].mcs = *(MCCHParamList.paramarray[l][MCCH_MCS_IDX].uptr); + } + m2ap_setup_resp->num_mcch_config_per_mbsfn = MCCHParamList.numelt; + return 0; +} +int RCconfig_M2_MCCH(MessageDef *msg_p, uint32_t i) { + int l; + + char mcepath[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MCCHParams[] = MCCH_PARAMS_DESC; + paramdef_t MCEParams[] = MCE_PARAMS_DESC; + paramdef_t PLNMParams[] = MCE_PLMN_PARAMS_DESC; + paramlist_def_t MCCHParamList = {MCE_CONFIG_STRING_MCCH_CONFIG_PER_MBSFN_AREA,NULL,0}; + char aprefix[MAX_OPTNAME_SIZE*80 + 8]; + sprintf(mcepath,"%s.[%i]","MCEs",0); + config_get(MCEParams,sizeof(MCEParams)/sizeof(paramdef_t),mcepath); + M2AP_SETUP_RESP (msg_p).MCE_id = *(MCEParams[MCE_MCE_ID_IDX].uptr); + M2AP_SETUP_RESP (msg_p).MCE_name = strdup(*(MCEParams[MCE_MCE_NAME_IDX].strptr));; + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_PLMN); + config_get(PLNMParams,sizeof(PLNMParams)/sizeof(paramdef_t),mcepath); + M2AP_SETUP_RESP (msg_p).mcc = *(PLNMParams[MCE_CONFIG_STRING_MCC_IDX].uptr); + M2AP_SETUP_RESP (msg_p).mnc = *(PLNMParams[MCE_CONFIG_STRING_MNC_IDX].uptr); + M2AP_SETUP_RESP (msg_p).mnc_digit_length = *(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr); + //LOG_E(MCE_APP,"PLNM %d\n",*(PLNMParams[MCE_CONFIG_STRING_MCC_IDX].uptr)); + //LOG_E(MCE_APP,"PLNM %d\n",*(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr)); + + + sprintf(aprefix,"%s.[%i]","MCEs",0); + config_getlist( &MCCHParamList,MCCHParams,sizeof(MCCHParams)/sizeof(paramdef_t),aprefix); + //printf("MCCHParamList.numelt %d\n",MCCHParamList.numelt); + AssertFatal(MCCHParamList.numelt <= 8, "File wrong parsed\n"); + for (l = 0; l < MCCHParamList.numelt; l++) { + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].mbsfn_area = *(MCCHParamList.paramarray[l][MCCH_MBSFN_AREA_IDX].uptr); + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].pdcch_length = *(MCCHParamList.paramarray[l][MCCH_PDCCH_LENGTH_IDX].uptr); + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].repetition_period = *(MCCHParamList.paramarray[l][MCCH_REPETITION_PERIOD_IDX].uptr); + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].offset = *(MCCHParamList.paramarray[l][MCCH_OFFSET_IDX].uptr); + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].modification_period = *(MCCHParamList.paramarray[l][MCCH_MODIFICATION_PERIOD_IDX].uptr); + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].subframe_allocation_info = *(MCCHParamList.paramarray[l][MCCH_SF_ALLOCATION_INFO_IDX].uptr); + M2AP_SETUP_RESP(msg_p).mcch_config_per_mbsfn[l].mcs = *(MCCHParamList.paramarray[l][MCCH_MCS_IDX].uptr); + } + M2AP_SETUP_RESP(msg_p).num_mcch_config_per_mbsfn = MCCHParamList.numelt; + + + return 0; +} +int RCconfig_m2_scheduling( m2ap_mbms_scheduling_information_t * m2ap_mbms_scheduling_information, uint32_t i) { + int l,j,k/*,m*/; + char mcepath[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MBMS_SCHE_Params[] = MCE_MBMS_SCHEDULING_INFO_PARAMS_DESC; + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO); + //LOG_E(MCE_APP,"%s\n",mcepath); + config_get(MBMS_SCHE_Params,sizeof(MBMS_SCHE_Params)/sizeof(paramdef_t),mcepath); + //LOG_E(MCE_APP,"%s %d\n",mcepath, *(MBMS_SCHE_Params[MCE_CONFIG_STRING_MCCH_UPDATE_TIME_IDX].uptr)); + m2ap_mbms_scheduling_information->mcch_update_time=*(MBMS_SCHE_Params[MCE_CONFIG_STRING_MCCH_UPDATE_TIME_IDX].uptr); + + paramdef_t MBMS_CONFIGURATION_Params[] = MCE_MBMS_AREA_CONFIGURATION_LIST_PARAMS_DESC; + paramlist_def_t MBMS_AREA_CONFIGURATION_ParamList = {MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,NULL,0}; + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO); + config_getlist(&MBMS_AREA_CONFIGURATION_ParamList,MBMS_CONFIGURATION_Params,sizeof(MBMS_CONFIGURATION_Params)/sizeof(paramdef_t),mcepath); + AssertFatal(MBMS_AREA_CONFIGURATION_ParamList.numelt <= 8, "File wrong parsed\n"); + //LOG_E(MCE_APP,"%s\n",mcepath); + //LOG_E(MCE_APP,"MBMS_AREA_CONFIGURATION_ParamList.numelt %d\n",MBMS_AREA_CONFIGURATION_ParamList.numelt); + + m2ap_mbms_scheduling_information->num_mbms_area_config_list = MBMS_AREA_CONFIGURATION_ParamList.numelt; + for (l = 0; l < MBMS_AREA_CONFIGURATION_ParamList.numelt; l++) { + m2ap_mbms_scheduling_information->mbms_area_config_list[l].common_sf_allocation_period = *(MBMS_AREA_CONFIGURATION_ParamList.paramarray[l][MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].mbms_area_id=*(MBMS_AREA_CONFIGURATION_ParamList.paramarray[l][MCE_CONFIG_STRING_MBMS_AREA_ID_IDX].uptr); + char mcepath2[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t PMCH_Params[] = MCE_MBMS_PMCH_CONFIGURATION_LIST_PARAMS_DESC; + paramlist_def_t PMCH_ParamList = {MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,NULL,0}; + sprintf(mcepath2,"%s.[%i].%s.%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l); + //LOG_E(MCE_APP,"%s\n",mcepath2); + config_getlist(&PMCH_ParamList,PMCH_Params,sizeof(PMCH_Params)/sizeof(paramdef_t),mcepath2); + AssertFatal(PMCH_ParamList.numelt <= 8, "File wrong parsed\n"); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].num_pmch_config_list=PMCH_ParamList.numelt; + for(j = 0; j < PMCH_ParamList.numelt; j++){ + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].allocated_sf_end = *(PMCH_ParamList.paramarray[j][MCE_CONFIG_STRING_ALLOCATED_SF_END_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].data_mcs = *(PMCH_ParamList.paramarray[j][MCE_CONFIG_STRING_DATA_MCS_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mch_scheduling_period= *(PMCH_ParamList.paramarray[j][MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD_IDX].uptr); + char mcepath3[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MBMS_SESSION_LIST_Params[] = MCE_MBMS_MBMS_SESSION_LIST_DESC; + paramlist_def_t MBMS_SESSION_LIST_ParamList = {MCE_CONFIG_STRING_MBMS_SESSION_LIST,NULL,0}; + sprintf(mcepath3,"%s.[%i].%s.%s.[%i].%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l,MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,j); + config_getlist(&MBMS_SESSION_LIST_ParamList,MBMS_SESSION_LIST_Params,sizeof(MBMS_SESSION_LIST_Params)/sizeof(paramdef_t),mcepath3); + //LOG_E(MCE_APP,"%s ---- %d\n",mcepath3, MBMS_SESSION_LIST_ParamList.numelt); + AssertFatal(MBMS_SESSION_LIST_ParamList.numelt <= 8, "File wrong parsed\n"); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].num_mbms_session_list = MBMS_SESSION_LIST_ParamList.numelt; + for(k = 0; k < MBMS_SESSION_LIST_ParamList.numelt; k++ ){ + + //char mcepath4[MAX_OPTNAME_SIZE*8 + 8]; + //paramdef_t MBMS_SESSION_LIST_PER_PMCH_Params[] = MCE_MBMS_MBMS_SESSION_LIST_PER_PMCH_PARAMS_DESC; + //paramlist_def_t MBMS_SESSION_LIST_PER_PMCH_ParamList = {MCE_CONFIG_STRING_MBMS_SESSION_LIST_PER_PMCH,NULL,0}; + //sprintf(mcepath4,"%s.[%i].%s.%s.[%i].%s.[%i].%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l,MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,j,MCE_CONFIG_STRING_MBMS_SESSION_LIST,k); + //LOG_E(MCE_APP,"%s\n",mcepath4); + //config_getlist(&MBMS_SESSION_LIST_PER_PMCH_ParamList,MBMS_SESSION_LIST_PER_PMCH_Params,sizeof(MBMS_SESSION_LIST_PER_PMCH_Params)/sizeof(paramdef_t),mcepath4); + //m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].num_mbms_session_per_pmch = MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt; + //for(m = 0; m < MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt; m++){ + + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].service_id = + *(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_SERVICE_ID_IDX].uptr); + uint32_t lcid =*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_LCID_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].lcid =lcid; + //uint32_t service_id2=*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_LCID_IDX].uptr); + //m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].service_id2 =service_id2; + //LOG_E(MCE_APP,"lcid %ld\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_LCID_IDX].uptr)); + //LOG_E(MCE_APP,"service_id %d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_SERVICE_ID_IDX].uptr)); + + char mcepath5[MAX_OPTNAME_SIZE*8 + 8]; + paramdef_t PLNMParams[] = MCE_PLMN_PARAMS_DESC; + sprintf(mcepath5,"%s.[%i].%s.%s.[%i].%s.[%i].%s.[%i].%s","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l,MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,j,MCE_CONFIG_STRING_MBMS_SESSION_LIST,k,MCE_CONFIG_STRING_PLMN); + config_get(PLNMParams,sizeof(PLNMParams)/sizeof(paramdef_t),mcepath5); + //LOG_E(MCE_APP,"PLNM %d\n",*(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr)); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].mcc = *(PLNMParams[MCE_CONFIG_STRING_MCC_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].mnc = *(PLNMParams[MCE_CONFIG_STRING_MNC_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].mnc_length = *(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr); + + //} + //LOG_E(MCE_APP,"MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt %d\n",MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt); + //AssertFatal(MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt <= 8, "File wrong parsed\n"); + + //printf("%d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_PLNM_IDENTITY_IDX].uptr)); + //printf("%d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_SERVICE_ID_IDX].uptr)); + //printf("%d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_LCID_IDX].uptr)); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + } + } + paramdef_t MBSFN_SF_Params[] = MCE_MBMS_MBMS_SF_CONFIGURATION_LIST_PARAMS_DESC; + paramlist_def_t MBSFN_SF_ParamList = {MCE_CONFIG_STRING_MBMS_SF_CONFIGURATION_LIST,NULL,0}; + sprintf(mcepath2,"%s.[%i].%s.%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l); + //LOG_E(MCE_APP,"%s\n",mcepath2); + config_getlist(&MBSFN_SF_ParamList,MBSFN_SF_Params,sizeof(MBSFN_SF_Params)/sizeof(paramdef_t),mcepath2); + AssertFatal(MBSFN_SF_ParamList.numelt <= 8, "File wrong parsed\n"); + + m2ap_mbms_scheduling_information->mbms_area_config_list[l].num_mbms_sf_config_list=MBSFN_SF_ParamList.numelt; + for(j = 0; j < MBSFN_SF_ParamList.numelt; j++){ + m2ap_mbms_scheduling_information->mbms_area_config_list[l].mbms_sf_config_list[j].radioframe_allocation_period=*(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD_IDX].uptr); + m2ap_mbms_scheduling_information->mbms_area_config_list[l].mbms_sf_config_list[j].radioframe_allocation_offset = *(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET_IDX].uptr); + if(strcmp(*(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_NUM_FRAME_IDX].strptr),"oneFrame")==0){ + m2ap_mbms_scheduling_information->mbms_area_config_list[l].mbms_sf_config_list[j].is_four_sf = 0; + }else{ + m2ap_mbms_scheduling_information->mbms_area_config_list[l].mbms_sf_config_list[j].is_four_sf = 1; + } + m2ap_mbms_scheduling_information->mbms_area_config_list[l].mbms_sf_config_list[j].subframe_allocation = *(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_SUBFRAME_ALLOCATION_IDX].uptr); + } + + + } + return 0; +} +int RCconfig_M2_SCHEDULING(MessageDef *msg_p, uint32_t i) { + int l,j,k/*,m*/; + char mcepath[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MBMS_SCHE_Params[] = MCE_MBMS_SCHEDULING_INFO_PARAMS_DESC; + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO); + //LOG_E(MCE_APP,"%s\n",mcepath); + config_get(MBMS_SCHE_Params,sizeof(MBMS_SCHE_Params)/sizeof(paramdef_t),mcepath); + //LOG_E(MCE_APP,"%s %d\n",mcepath, *(MBMS_SCHE_Params[MCE_CONFIG_STRING_MCCH_UPDATE_TIME_IDX].uptr)); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mcch_update_time=*(MBMS_SCHE_Params[MCE_CONFIG_STRING_MCCH_UPDATE_TIME_IDX].uptr); + + paramdef_t MBMS_CONFIGURATION_Params[] = MCE_MBMS_AREA_CONFIGURATION_LIST_PARAMS_DESC; + paramlist_def_t MBMS_AREA_CONFIGURATION_ParamList = {MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,NULL,0}; + sprintf(mcepath,"%s.[%i].%s","MCEs",0,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO); + config_getlist(&MBMS_AREA_CONFIGURATION_ParamList,MBMS_CONFIGURATION_Params,sizeof(MBMS_CONFIGURATION_Params)/sizeof(paramdef_t),mcepath); + AssertFatal(MBMS_AREA_CONFIGURATION_ParamList.numelt <= 8, "File wrong parsed\n"); + //LOG_E(MCE_APP,"%s\n",mcepath); + //LOG_E(MCE_APP,"MBMS_AREA_CONFIGURATION_ParamList.numelt %d\n",MBMS_AREA_CONFIGURATION_ParamList.numelt); + + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).num_mbms_area_config_list = MBMS_AREA_CONFIGURATION_ParamList.numelt; + for (l = 0; l < MBMS_AREA_CONFIGURATION_ParamList.numelt; l++) { + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].common_sf_allocation_period = *(MBMS_AREA_CONFIGURATION_ParamList.paramarray[l][MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].mbms_area_id=*(MBMS_AREA_CONFIGURATION_ParamList.paramarray[l][MCE_CONFIG_STRING_MBMS_AREA_ID_IDX].uptr); + char mcepath2[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t PMCH_Params[] = MCE_MBMS_PMCH_CONFIGURATION_LIST_PARAMS_DESC; + paramlist_def_t PMCH_ParamList = {MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,NULL,0}; + sprintf(mcepath2,"%s.[%i].%s.%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l); + //LOG_E(MCE_APP,"%s\n",mcepath2); + config_getlist(&PMCH_ParamList,PMCH_Params,sizeof(PMCH_Params)/sizeof(paramdef_t),mcepath2); + AssertFatal(PMCH_ParamList.numelt <= 8, "File wrong parsed\n"); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].num_pmch_config_list=PMCH_ParamList.numelt; + for(j = 0; j < PMCH_ParamList.numelt; j++){ + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].allocated_sf_end = *(PMCH_ParamList.paramarray[j][MCE_CONFIG_STRING_ALLOCATED_SF_END_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].data_mcs = *(PMCH_ParamList.paramarray[j][MCE_CONFIG_STRING_DATA_MCS_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mch_scheduling_period= *(PMCH_ParamList.paramarray[j][MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD_IDX].uptr); + char mcepath3[MAX_OPTNAME_SIZE*2 + 8]; + paramdef_t MBMS_SESSION_LIST_Params[] = MCE_MBMS_MBMS_SESSION_LIST_DESC; + paramlist_def_t MBMS_SESSION_LIST_ParamList = {MCE_CONFIG_STRING_MBMS_SESSION_LIST,NULL,0}; + sprintf(mcepath3,"%s.[%i].%s.%s.[%i].%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l,MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,j); + config_getlist(&MBMS_SESSION_LIST_ParamList,MBMS_SESSION_LIST_Params,sizeof(MBMS_SESSION_LIST_Params)/sizeof(paramdef_t),mcepath3); + //LOG_E(MCE_APP,"%s ---- %d\n",mcepath3, MBMS_SESSION_LIST_ParamList.numelt); + AssertFatal(MBMS_SESSION_LIST_ParamList.numelt <= 8, "File wrong parsed\n"); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].num_mbms_session_list = MBMS_SESSION_LIST_ParamList.numelt; + for(k = 0; k < MBMS_SESSION_LIST_ParamList.numelt; k++ ){ + + //char mcepath4[MAX_OPTNAME_SIZE*8 + 8]; + //paramdef_t MBMS_SESSION_LIST_PER_PMCH_Params[] = MCE_MBMS_MBMS_SESSION_LIST_PER_PMCH_PARAMS_DESC; + //paramlist_def_t MBMS_SESSION_LIST_PER_PMCH_ParamList = {MCE_CONFIG_STRING_MBMS_SESSION_LIST_PER_PMCH,NULL,0}; + //sprintf(mcepath4,"%s.[%i].%s.%s.[%i].%s.[%i].%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l,MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,j,MCE_CONFIG_STRING_MBMS_SESSION_LIST,k); + //LOG_E(MCE_APP,"%s\n",mcepath4); + //config_getlist(&MBMS_SESSION_LIST_PER_PMCH_ParamList,MBMS_SESSION_LIST_PER_PMCH_Params,sizeof(MBMS_SESSION_LIST_PER_PMCH_Params)/sizeof(paramdef_t),mcepath4); + //M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].num_mbms_session_per_pmch = MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt; + //for(m = 0; m < MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt; m++){ + + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].service_id = + *(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_SERVICE_ID_IDX].uptr); + uint32_t lcid =*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_LCID_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].lcid =lcid; + //uint32_t service_id2=*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_LCID_IDX].uptr); + //M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].service_id2 =service_id2; + //LOG_E(MCE_APP,"lcid %ld\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_LCID_IDX].uptr)); + //LOG_E(MCE_APP,"service_id %d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_MBMS_SERVICE_ID_IDX].uptr)); + + char mcepath5[MAX_OPTNAME_SIZE*8 + 8]; + paramdef_t PLNMParams[] = MCE_PLMN_PARAMS_DESC; + sprintf(mcepath5,"%s.[%i].%s.%s.[%i].%s.[%i].%s.[%i].%s","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l,MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST,j,MCE_CONFIG_STRING_MBMS_SESSION_LIST,k,MCE_CONFIG_STRING_PLMN); + config_get(PLNMParams,sizeof(PLNMParams)/sizeof(paramdef_t),mcepath5); + //LOG_E(MCE_APP,"PLNM %d\n",*(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr)); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].mcc = *(PLNMParams[MCE_CONFIG_STRING_MCC_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].mnc = *(PLNMParams[MCE_CONFIG_STRING_MNC_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].pmch_config_list[j].mbms_session_list[k].mnc_length = *(PLNMParams[MCE_CONFIG_STRING_MNC_LENGTH_IDX].uptr); + + //} + //LOG_E(MCE_APP,"MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt %d\n",MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt); + //AssertFatal(MBMS_SESSION_LIST_PER_PMCH_ParamList.numelt <= 8, "File wrong parsed\n"); + + //printf("%d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_PLNM_IDENTITY_IDX].uptr)); + //printf("%d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_SERVICE_ID_IDX].uptr)); + //printf("%d\n",*(MBMS_SESSION_LIST_ParamList.paramarray[k][MCE_CONFIG_STRING_LCID_IDX].uptr)); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + //*((MBMS_SESSION_LIST_ParamList[k][].uptr); + } + } + paramdef_t MBSFN_SF_Params[] = MCE_MBMS_MBMS_SF_CONFIGURATION_LIST_PARAMS_DESC; + paramlist_def_t MBSFN_SF_ParamList = {MCE_CONFIG_STRING_MBMS_SF_CONFIGURATION_LIST,NULL,0}; + sprintf(mcepath2,"%s.[%i].%s.%s.[%i]","MCEs",i,MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO,MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST,l); + //LOG_E(MCE_APP,"%s\n",mcepath2); + config_getlist(&MBSFN_SF_ParamList,MBSFN_SF_Params,sizeof(MBSFN_SF_Params)/sizeof(paramdef_t),mcepath2); + AssertFatal(MBSFN_SF_ParamList.numelt <= 8, "File wrong parsed\n"); + + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].num_mbms_sf_config_list=MBSFN_SF_ParamList.numelt; + for(j = 0; j < MBSFN_SF_ParamList.numelt; j++){ + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].mbms_sf_config_list[j].radioframe_allocation_period=*(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD_IDX].uptr); + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].mbms_sf_config_list[j].radioframe_allocation_offset = *(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET_IDX].uptr); + if(strcmp(*(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_NUM_FRAME_IDX].strptr),"oneFrame")==0){ + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].mbms_sf_config_list[j].is_four_sf = 0; + }else{ + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].mbms_sf_config_list[j].is_four_sf = 1; + } + M2AP_MBMS_SCHEDULING_INFORMATION(msg_p).mbms_area_config_list[l].mbms_sf_config_list[j].subframe_allocation = *(MBSFN_SF_ParamList.paramarray[j][MCE_CONFIG_STRING_SUBFRAME_ALLOCATION_IDX].uptr); + } + + + } + + return 0; +} + diff --git a/openair2/MCE_APP/mce_config.h b/openair2/MCE_APP/mce_config.h new file mode 100644 index 0000000000..3078b64e49 --- /dev/null +++ b/openair2/MCE_APP/mce_config.h @@ -0,0 +1,71 @@ +/* + * 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 + */ + +/* + mce_config.h + ------------------- + AUTHOR : Javier Morgade + COMPANY : VICOMTECH, Spain + EMAIL : javier.morgade@ieee.org +*/ + +#ifndef MCE_CONFIG_H_ +#define MCE_CONFIG_H_ +#include +#include +#include +#include + +#include "commonDef.h" +#include "platform_types.h" +#include "platform_constants.h" +#include "PHY/impl_defs_top.h" +#include "PHY/defs_eNB.h" +#include "s1ap_messages_types.h" +#include "f1ap_messages_types.h" +#include "LTE_SystemInformationBlockType2.h" +#include "rrc_messages_types.h" +#include "RRC/LTE/rrc_defs.h" +#include +#include "enb_paramdef.h" + +#define IPV4_STR_ADDR_TO_INT_NWBO(AdDr_StR,NwBo,MeSsAgE ) do {\ + struct in_addr inp;\ + if ( inet_aton(AdDr_StR, &inp ) < 0 ) {\ + AssertFatal (0, MeSsAgE);\ + } else {\ + NwBo = inp.s_addr;\ + }\ + } while (0); + + +void read_config_and_init(void); + +int RCconfig_MCE(void); +int RCconfig_M3(MessageDef *msg_p, uint32_t i); +int RCconfig_M2_MCCH(MessageDef *msg_p, uint32_t i); +int RCconfig_m2_mcch(m2ap_setup_resp_t * m2ap_setup_resp, uint32_t i); +int RCconfig_M2_SCHEDULING(MessageDef *msg_p, uint32_t i); +int RCconfig_m2_scheduling(m2ap_mbms_scheduling_information_t *m2ap_mbms_scheduling_information, uint32_t i); + + +#endif /* MCE_CONFIG_H_ */ +/** @} */ diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 2825a2ee40..91c75ac67f 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -34,7 +34,7 @@ #include "openair1/PHY/phy_extern.h" #include "openair1/SCHED_NR/fapi_nr_l1.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/MAC/mac_proto.h" #include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "common/ran_context.h" @@ -51,6 +51,7 @@ extern int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind); extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind); extern uint8_t nfapi_mode; extern uint16_t sf_ahead; +extern uint16_t sl_ahead; void handle_nr_rach(NR_UL_IND_t *UL_info) { if (UL_info->rach_ind.rach_indication_body.number_of_preambles>0) { @@ -163,7 +164,7 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) { UL_info->rx_ind.rx_indication_body.number_of_pdus = 0; } } else { - + if (UL_info->rx_ind.rx_indication_body.number_of_pdus>0 && UL_info->crc_ind.crc_indication_body.number_of_crcs>0) { for (int i=0; irx_ind.rx_indication_body.number_of_pdus; i++) { for (int j=0; jcrc_ind.crc_indication_body.number_of_crcs; j++) { @@ -177,33 +178,29 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) { if (UL_info->crc_ind.crc_indication_body.crc_pdu_list[j].crc_indication_rel8.crc_flag == 1) { // CRC error indication LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC error) \n",UL_info->frame,UL_info->slot); - /* - rx_sdu(UL_info->module_id, - UL_info->CC_id, - NFAPI_SFNSF2SFN(UL_info->rx_ind.sfn_sf), //UL_info->frame, - NFAPI_SFNSF2SF(UL_info->rx_ind.sfn_sf), //UL_info->slot, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti, - (uint8_t *)NULL, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi); - */ - } - else { - LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->slot); - /* - rx_sdu(UL_info->module_id, - UL_info->CC_id, - NFAPI_SFNSF2SFN(UL_info->rx_ind.sfn_sf), //UL_info->frame, - NFAPI_SFNSF2SF(UL_info->rx_ind.sfn_sf), //UL_info->slot, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].data, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance, - UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi); - */ - } + nr_rx_sdu(UL_info->module_id, + UL_info->CC_id, + NFAPI_SFNSF2SFN(UL_info->rx_ind.sfn_sf), //UL_info->frame, + NFAPI_SFNSF2SF(UL_info->rx_ind.sfn_sf), //UL_info->slot, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti, + (uint8_t *)NULL, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi); + } else { + LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->slot); + nr_rx_sdu(UL_info->module_id, + UL_info->CC_id, + NFAPI_SFNSF2SFN(UL_info->rx_ind.sfn_sf), //UL_info->frame, + NFAPI_SFNSF2SF(UL_info->rx_ind.sfn_sf), //UL_info->slot, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].data, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi); + } + //printf("rx_indication_rel8.timing_advance %d\n", UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance); break; } //if (UL_info->crc_ind.crc_pdu_list[j].rx_ue_information.rnti == @@ -265,22 +262,22 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) { if (ifi->CC_mask == ((1<frame+((UL_info->slot>(9-sf_ahead))?1:0)) % 1024, - (UL_info->slot+sf_ahead)%10); + (UL_info->frame+((UL_info->slot>(9-sl_ahead))?1:0)) % 1024, + (UL_info->slot+sl_ahead)%10); */ nfapi_nr_config_request_scf_t *cfg = &mac->config[CC_id]; int spf = get_spf(cfg); gNB_dlsch_ulsch_scheduler(module_id, UL_info->frame, UL_info->slot, - (UL_info->frame+((UL_info->slot>(spf-1-sf_ahead))?1:0)) % 1024, - (UL_info->slot+sf_ahead)%spf); + (UL_info->frame+((UL_info->slot>(spf-1-sl_ahead))?1:0)) % 1024, + (UL_info->slot+sl_ahead)%spf); ifi->CC_mask = 0; sched_info->module_id = module_id; sched_info->CC_id = CC_id; - sched_info->frame = (UL_info->frame + ((UL_info->slot>(spf-1-sf_ahead)) ? 1 : 0)) % 1024; - sched_info->slot = (UL_info->slot+sf_ahead)%spf; + sched_info->frame = (UL_info->frame + ((UL_info->slot>(spf-1-sl_ahead)) ? 1 : 0)) % 1024; + sched_info->slot = (UL_info->slot+sl_ahead)%spf; sched_info->DL_req = &mac->DL_req[CC_id]; sched_info->UL_dci_req = &mac->UL_dci_req[CC_id]; diff --git a/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c b/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c index 7736252a07..5d2cf18974 100644 --- a/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c +++ b/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c @@ -8,8 +8,9 @@ int main ( int argc, char** argv) { nfapi_nr_cell_param_t nfapi_nr_cell_param_test; - nfapi_nr_param_tlv_t* tlvs_to_report_list; - nfapi_nr_cell_param_test.config_tlvs_to_report_list = tlvs_to_report_list; + nfapi_nr_param_tlv_t tlvs_to_report_list; + + nfapi_nr_cell_param_test.config_tlvs_to_report_list = &tlvs_to_report_list; nfapi_nr_cell_param_test.phy_state = 0; nfapi_nr_cell_param_test.release_capability = 0; nfapi_nr_cell_param_test.skip_blank_dl_config = 0; diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 234714a3b5..64a814bcdb 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -30,12 +30,13 @@ * \warning */ +#include "PHY/defs_nr_UE.h" #include "NR_IF_Module.h" #include "mac_proto.h" #include "assertions.h" #include "LAYER2/NR_MAC_UE/mac_extern.h" #include "SCHED_NR_UE/fapi_nr_ue_l1.h" -#include "executables/nr-softmodem.h" +#include "executables/softmodem-common.h" #include @@ -70,22 +71,25 @@ int handle_dci(module_id_t module_id, int cc_id, unsigned int gNB_index, fapi_nr } // L2 Abstraction Layer -int8_t handle_dlsch (module_id_t module_id, int cc_id, uint8_t gNB_index, fapi_nr_dci_indication_t *dci_ind, uint8_t *pduP, uint32_t pdu_len, frame_t frame, int slot){ +int8_t handle_dlsch (module_id_t module_id, int cc_id, uint8_t gNB_index, fapi_nr_dci_indication_t *dci_ind, uint8_t *pduP, uint32_t pdu_len, frame_t frame, int slot, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){ -LOG_D(MAC, "handle_dlsch at MAC layer \n"); -if (IS_SOFTMODEM_NOS1) - nr_ue_send_sdu(module_id, 0, frame, slot, - pduP, - pdu_len, - 0); -return 0; + LOG_D(MAC, "handle_dlsch at MAC layer \n"); + //if (IS_SOFTMODEM_NOS1 || IS_SOFTMODEM_RFSIM) + // sdu should be processed even when is S1 mode because data and timing advance updates are transmitted by the UE + nr_ue_send_sdu(module_id, cc_id, frame, slot, + pduP, + pdu_len, + gNB_index, + ul_time_alignment); + + return 0; /* - return nr_ue_process_dlsch( module_id, - cc_id, - gNB_index, - dci_ind, - pduP, - pdu_len); + return nr_ue_process_dlsch(module_id, + cc_id, + gNB_index, + dci_ind, + pduP, + pdu_len); */ } @@ -129,7 +133,7 @@ int nr_ue_ul_indication(nr_uplink_indication_t *ul_info){ return 0; } -int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){ +int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){ int32_t i; uint32_t ret_mask = 0x0; @@ -156,9 +160,9 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){ // fapi_nr_dci_pdu_rel15_t *dci = &dl_info->dci_ind->dci_list[i].dci; ret_mask |= (handle_dci(dl_info->module_id, - dl_info->cc_id, - dl_info->gNB_index, - dl_info->dci_ind->dci_list+i)<< FAPI_NR_DCI_IND); + dl_info->cc_id, + dl_info->gNB_index, + dl_info->dci_ind->dci_list+i)<< FAPI_NR_DCI_IND); AssertFatal( nr_ue_if_module_inst[module_id] != NULL, "IF module is void!\n" ); nr_ue_if_module_inst[module_id]->scheduled_response(&mac->scheduled_response); @@ -204,10 +208,6 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){ }*/ //(dl_info->dci_list+i)->rnti - - - - } } @@ -240,7 +240,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){ // ret_mask |= (0) << FAPI_NR_RX_PDU_TYPE_DLSCH; ret_mask |= (handle_dlsch(dl_info->module_id, dl_info->cc_id, dl_info->gNB_index, dl_info->dci_ind, (dl_info->rx_ind->rx_indication_body+i)->pdsch_pdu.pdu, - (dl_info->rx_ind->rx_indication_body+i)->pdsch_pdu.pdu_length, dl_info->frame, dl_info->slot)) << FAPI_NR_RX_PDU_TYPE_DLSCH; + (dl_info->rx_ind->rx_indication_body+i)->pdsch_pdu.pdu_length, dl_info->frame, dl_info->slot, ul_time_alignment)) << FAPI_NR_RX_PDU_TYPE_DLSCH; LOG_D(MAC,"[L2][IF MODULE][DL INDICATION][RX_IND], DLSCH case Number of PDUs: %d \n", dl_info->rx_ind->number_pdus); diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h index 4fca5819e0..0784e71584 100755 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h @@ -37,7 +37,7 @@ #include #include "fapi_nr_ue_interface.h" - +typedef struct NR_UL_TIME_ALIGNMENT NR_UL_TIME_ALIGNMENT_t; typedef struct { /// module id @@ -106,8 +106,6 @@ typedef struct { int CC_id; /// frame frame_t frame; - /// subframe - sub_frame_t subframe; /// slot int slot; @@ -163,7 +161,7 @@ typedef int8_t (nr_ue_phy_config_request_f)(nr_phy_config_t *phy_config); * -1: Failed to consume bytes. Abort the mission. * Non-negative return values indicate success, and ignored. */ -typedef int (nr_ue_dl_indication_f)(nr_downlink_indication_t *dl_info); +typedef int (nr_ue_dl_indication_f)(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment); /* * Generic type of an application-defined callback to return various @@ -202,7 +200,7 @@ int nr_ue_if_module_kill(uint32_t module_id); /**\brief interface between L1/L2, indicating the downlink related information, like dci_ind and rx_req \param dl_info including dci_ind and rx_request messages*/ -int nr_ue_dl_indication(nr_downlink_indication_t *dl_info); +int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment); int nr_ue_ul_indication(nr_uplink_indication_t *ul_info); diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h index ff264f921e..f260222097 100644 --- a/openair2/PHY_INTERFACE/IF_Module.h +++ b/openair2/PHY_INTERFACE/IF_Module.h @@ -140,6 +140,8 @@ typedef struct IF_Module_s { void (*UL_indication)(UL_IND_t *UL_INFO); void (*schedule_response)(Sched_Rsp_t *Sched_INFO); void (*PHY_config_req)(PHY_Config_t *config_INFO); + void (*PHY_config_update_sib2_req)(PHY_Config_t* config_INFO); + void (*PHY_config_update_sib13_req)(PHY_Config_t* config_INFO); uint32_t CC_mask; uint16_t current_frame; uint8_t current_subframe; diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c index 930387c742..bf2bbf7429 100644 --- a/openair2/PHY_INTERFACE/phy_stub_UE.c +++ b/openair2/PHY_INTERFACE/phy_stub_UE.c @@ -1,14 +1,29 @@ +/* + * 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 "openair1/PHY/defs.h" -//#include "openair2/PHY_INTERFACE/IF_Module.h" -//#include "openair1/PHY/extern.h" #include "openair2/LAYER2/MAC/mac_extern.h" #include "openair2/LAYER2/MAC/mac.h" #include "openair2/LAYER2/MAC/mac_proto.h" -//#include "openair2/LAYER2/MAC/vars.h" #include "openair1/SCHED_UE/sched_UE.h" #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" -//#include "common/ran_context.h" #include "openair2/PHY_INTERFACE/phy_stub_UE.h" #include "openair2/ENB_APP/L1_paramdef.h" #include "openair2/ENB_APP/enb_paramdef.h" @@ -16,14 +31,12 @@ #include "common/config/config_load_configmodule.h" #include "common/config/config_userapi.h" -//#define DEADLINE_SCHEDULER 1 - - -extern int oai_nfapi_crc_indication(nfapi_crc_indication_t *crc_ind); -extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind); extern int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); -void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port); - +void configure_nfapi_pnf(char *vnf_ip_addr, + int vnf_p5_port, + char *pnf_ip_addr, + int pnf_p7_port, + int vnf_p7_port); UL_IND_t *UL_INFO = NULL; nfapi_tx_request_pdu_t* tx_request_pdu_list = NULL; @@ -31,8 +44,6 @@ nfapi_dl_config_request_t* dl_config_req = NULL; nfapi_ul_config_request_t* ul_config_req = NULL; nfapi_hi_dci0_request_t* hi_dci0_req = NULL; -//extern uint8_t nfapi_pnf; -//UL_IND_t *UL_INFO; extern nfapi_tx_request_pdu_t* tx_request_pdu[1023][10][10]; //extern int timer_subframe; //extern int timer_frame; @@ -42,1025 +53,1079 @@ extern uint16_t sf_ahead; void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); +void fill_rx_indication_UE_MAC(module_id_t Mod_id, + int frame, + int subframe, + UL_IND_t *UL_INFO, + uint8_t *ulsch_buffer, + uint16_t buflen, + uint16_t rnti, + int index) { + nfapi_rx_indication_pdu_t *pdu; + int timing_advance_update; + pthread_mutex_lock(&fill_ul_mutex.rx_mutex); -void fill_rx_indication_UE_MAC(module_id_t Mod_id,int frame,int subframe, UL_IND_t* UL_INFO, uint8_t *ulsch_buffer, uint16_t buflen, uint16_t rnti, int index) -{ - nfapi_rx_indication_pdu_t *pdu; + UL_INFO->rx_ind.sfn_sf = frame << 4 | subframe; + UL_INFO->rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + UL_INFO->rx_ind.vendor_extension = ul_config_req->vendor_extension; - int timing_advance_update; + pdu = &UL_INFO->rx_ind.rx_indication_body + .rx_pdu_list[UL_INFO->rx_ind.rx_indication_body.number_of_pdus]; + // pdu = &UL_INFO->rx_ind.rx_indication_body.rx_pdu_list[index]; + // pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = rnti; + pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; + pdu->rx_indication_rel8.length = buflen; + pdu->rx_indication_rel8.offset = 1; + pdu->rx_indication_rel9.tl.tag = NFAPI_RX_INDICATION_REL9_TAG; + pdu->rx_indication_rel9.timing_advance_r9 = 0; - // pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); - // change for mutiple UE's simulation. - pthread_mutex_lock(&fill_ul_mutex.rx_mutex); + // ulsch_buffer is necessary to keep its value. + pdu->data = malloc(buflen); + memcpy(pdu->data, ulsch_buffer, buflen); + // estimate timing advance for MAC + timing_advance_update = 0; // Don't know what to put here + pdu->rx_indication_rel8.timing_advance = timing_advance_update; + int SNRtimes10 = 640; - UL_INFO->rx_ind.sfn_sf = frame<<4| subframe; - UL_INFO->rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; - UL_INFO->rx_ind.vendor_extension = ul_config_req->vendor_extension; - - - pdu = &UL_INFO->rx_ind.rx_indication_body.rx_pdu_list[UL_INFO->rx_ind.rx_indication_body.number_of_pdus]; - //pdu = &UL_INFO->rx_ind.rx_indication_body.rx_pdu_list[index]; - - // pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle; - pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - pdu->rx_ue_information.rnti = rnti; - pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; - //pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; - pdu->rx_indication_rel8.length = buflen; - pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation - - // ulsch_buffer is necessary to keep its value. - //pdu->data = ulsch_buffer; - pdu->data = malloc(buflen); - memcpy(pdu->data,ulsch_buffer,buflen); - // estimate timing advance for MAC - //sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); - timing_advance_update = 0; // Don't know what to put here - pdu->rx_indication_rel8.timing_advance = timing_advance_update; - - int SNRtimes10 = 640; - - if (SNRtimes10 < -640) pdu->rx_indication_rel8.ul_cqi=0; - else if (SNRtimes10 > 635) pdu->rx_indication_rel8.ul_cqi=255; - else pdu->rx_indication_rel8.ul_cqi=(640+SNRtimes10)/5; - - - UL_INFO->rx_ind.rx_indication_body.number_of_pdus++; - UL_INFO->rx_ind.sfn_sf = frame<<4 | subframe; - // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); - // change for mutiple UE's simulation. - pthread_mutex_unlock(&fill_ul_mutex.rx_mutex); - + if (SNRtimes10 < -640) + pdu->rx_indication_rel8.ul_cqi = 0; + else if (SNRtimes10 > 635) + pdu->rx_indication_rel8.ul_cqi = 255; + else + pdu->rx_indication_rel8.ul_cqi = (640 + SNRtimes10) / 5; + UL_INFO->rx_ind.rx_indication_body.number_of_pdus++; + UL_INFO->rx_ind.sfn_sf = frame << 4 | subframe; + pthread_mutex_unlock(&fill_ul_mutex.rx_mutex); } -void fill_sr_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_INFO, uint16_t rnti) { - - - // change for mutiple UE's simulation. - //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); +void fill_sr_indication_UE_MAC(int Mod_id, + int frame, + int subframe, + UL_IND_t *UL_INFO, + uint16_t rnti) { pthread_mutex_lock(&fill_ul_mutex.sr_mutex); - nfapi_sr_indication_t *sr_ind = &UL_INFO->sr_ind; - nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body; - nfapi_sr_indication_pdu_t *pdu = &sr_ind_body->sr_pdu_list[sr_ind_body->number_of_srs]; - UL_INFO->sr_ind.vendor_extension = ul_config_req->vendor_extension; + nfapi_sr_indication_t *sr_ind = &UL_INFO->sr_ind; + nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body; + nfapi_sr_indication_pdu_t *pdu = &sr_ind_body->sr_pdu_list[sr_ind_body->number_of_srs]; + UL_INFO->sr_ind.vendor_extension = ul_config_req->vendor_extension; - //nfapi_sr_indication_pdu_t *pdu = &UL_INFO->sr_ind.sr_indication_body.sr_pdu_list[UL_INFO->rx_ind.rx_indication_body.number_of_pdus]; - - sr_ind->sfn_sf = frame<<4|subframe; + sr_ind->sfn_sf = frame << 4 | subframe; sr_ind->header.message_id = NFAPI_RX_SR_INDICATION; sr_ind_body->tl.tag = NFAPI_SR_INDICATION_BODY_TAG; - pdu->instance_length = 0; // don't know what to do with this + pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; - pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - pdu->rx_ue_information.rnti = rnti; //UE_mac_inst[Mod_id].crnti - - - // dependency from PHY not sure how to substitute this. Should we hardcode it? - //int SNRtimes10 = dB_fixed_times10(stat) - 200;//(10*eNB->measurements.n0_power_dB[0]); - int SNRtimes10 = 640; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = rnti; // UE_mac_inst[Mod_id].crnti pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; - - - if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0; - else if (SNRtimes10 > 635) pdu->ul_cqi_information.ul_cqi=255; - else pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5; pdu->ul_cqi_information.channel = 0; - //UL_INFO->rx_ind.rx_indication_body.number_of_pdus++; + int SNRtimes10 = 640; + if (SNRtimes10 < -640) + pdu->ul_cqi_information.ul_cqi = 0; + else if (SNRtimes10 > 635) + pdu->ul_cqi_information.ul_cqi = 255; + else + pdu->ul_cqi_information.ul_cqi = (640 + SNRtimes10) / 5; + + // UL_INFO->rx_ind.rx_indication_body.number_of_pdus++; sr_ind_body->number_of_srs++; - // change for mutiple UE's simulation. - // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); pthread_mutex_unlock(&fill_ul_mutex.sr_mutex); } - -void fill_crc_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_INFO, uint8_t crc_flag, int index, uint16_t rnti) { - - // change for mutiple UE's simulation. - //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); +void fill_crc_indication_UE_MAC(int Mod_id, + int frame, + int subframe, + UL_IND_t *UL_INFO, + uint8_t crc_flag, + int index, + uint16_t rnti) { pthread_mutex_lock(&fill_ul_mutex.crc_mutex); - // REMEMBER HAVE EXCHANGED THE FOLLOWING TWO LINES HERE! - nfapi_crc_indication_pdu_t *pdu = &UL_INFO->crc_ind.crc_indication_body.crc_pdu_list[UL_INFO->crc_ind.crc_indication_body.number_of_crcs]; + nfapi_crc_indication_pdu_t *pdu = + &UL_INFO->crc_ind.crc_indication_body + .crc_pdu_list[UL_INFO->crc_ind.crc_indication_body.number_of_crcs]; - UL_INFO->crc_ind.sfn_sf = frame<<4| subframe; - UL_INFO->crc_ind.vendor_extension = ul_config_req->vendor_extension; - UL_INFO->crc_ind.header.message_id = NFAPI_CRC_INDICATION; + UL_INFO->crc_ind.sfn_sf = frame << 4 | subframe; + UL_INFO->crc_ind.vendor_extension = ul_config_req->vendor_extension; + UL_INFO->crc_ind.header.message_id = NFAPI_CRC_INDICATION; UL_INFO->crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG; - pdu->instance_length = 0; // don't know what to do with this - // pdu->rx_ue_information.handle = handle; - pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->instance_length = 0; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - //pdu->rx_ue_information.rnti = UE_mac_inst[Mod_id].crnti; - pdu->rx_ue_information.rnti = rnti; - pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; - pdu->crc_indication_rel8.crc_flag = crc_flag; + pdu->rx_ue_information.rnti = rnti; + pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; + pdu->crc_indication_rel8.crc_flag = crc_flag; UL_INFO->crc_ind.crc_indication_body.number_of_crcs++; - LOG_D(PHY, "%s() rnti:%04x pdus:%d\n", __FUNCTION__, pdu->rx_ue_information.rnti, UL_INFO->crc_ind.crc_indication_body.number_of_crcs); + LOG_D(PHY, + "%s() rnti:%04x pdus:%d\n", + __FUNCTION__, + pdu->rx_ue_information.rnti, + UL_INFO->crc_ind.crc_indication_body.number_of_crcs); - // change for mutiple UE's simulation. - // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); pthread_mutex_unlock(&fill_ul_mutex.crc_mutex); } -void fill_rach_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_INFO, uint8_t ra_PreambleIndex, uint16_t ra_RNTI) { +void fill_rach_indication_UE_MAC(int Mod_id, + int frame, + int subframe, + UL_IND_t *UL_INFO, + uint8_t ra_PreambleIndex, + uint16_t ra_RNTI) { + LOG_D(MAC, "fill_rach_indication_UE_MAC 1 \n"); - LOG_D(MAC, "fill_rach_indication_UE_MAC 1 \n"); + pthread_mutex_lock(&fill_ul_mutex.rach_mutex); - // change for mutiple UE's simulation. - // pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); - pthread_mutex_lock(&fill_ul_mutex.rach_mutex); + UL_INFO->rach_ind.rach_indication_body.number_of_preambles = 1; - // memory allocation and free memory of UL_INFO are done in UE_phy_stub_single_thread_rxn_txnp4. - // UL_INFO = (UL_IND_t*)malloc(sizeof(UL_IND_t)); + UL_INFO->rach_ind.header.message_id = NFAPI_RACH_INDICATION; + UL_INFO->rach_ind.sfn_sf = frame << 4 | subframe; + UL_INFO->rach_ind.vendor_extension = NULL; - UL_INFO->rach_ind.rach_indication_body.number_of_preambles = 1; + UL_INFO->rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; - //eNB->UL_INFO.rach_ind.preamble_list = &eNB->preamble_list[0]; - UL_INFO->rach_ind.header.message_id = NFAPI_RACH_INDICATION; - UL_INFO->rach_ind.sfn_sf = frame<<4 | subframe; - UL_INFO->rach_ind.vendor_extension = NULL; + const int np = UL_INFO->rach_ind.rach_indication_body.number_of_preambles; + UL_INFO->rach_ind.rach_indication_body.preamble_list = + calloc(np, sizeof(nfapi_preamble_pdu_t)); + UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.tl.tag = + NFAPI_PREAMBLE_REL8_TAG; + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel8.timing_advance = 0; // Not sure about that - UL_INFO->rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; + // The two following should get extracted from the call to + // get_prach_resources(). + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel8.preamble = ra_PreambleIndex; + UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.rnti = + ra_RNTI; + // UL_INFO->rach_ind.rach_indication_body.number_of_preambles++; + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel13.rach_resource_type = 0; + UL_INFO->rach_ind.rach_indication_body.preamble_list[0].instance_length = 0; - UL_INFO->rach_ind.rach_indication_body.preamble_list = (nfapi_preamble_pdu_t*)malloc(UL_INFO->rach_ind.rach_indication_body.number_of_preambles*sizeof(nfapi_preamble_pdu_t)); - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.timing_advance = 0; // Not sure about that + LOG_I(PHY, + "UE Filling NFAPI indication for RACH : TA %d, Preamble %d, rnti %x, " + "rach_resource_type %d\n", + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel8.timing_advance, + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel8.preamble, + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel8.rnti, + UL_INFO->rach_ind.rach_indication_body.preamble_list[0] + .preamble_rel13.rach_resource_type); - //The two following should get extracted from the call to get_prach_resources(). - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.preamble = ra_PreambleIndex; - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.rnti = ra_RNTI; - //UL_INFO->rach_ind.rach_indication_body.number_of_preambles++; - - - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel13.rach_resource_type = 0; - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].instance_length = 0; - - - LOG_E(PHY,"\n\n\n\nDJP - this needs to be sent to VNF **********************************************\n\n\n\n"); - LOG_E(PHY,"UE Filling NFAPI indication for RACH : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.timing_advance, - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.preamble, - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.rnti, - UL_INFO->rach_ind.rach_indication_body.preamble_list[0].preamble_rel13.rach_resource_type); - - // This function is currently defined only in the nfapi-RU-RAU-split so we should call it when we merge - // with that branch. - oai_nfapi_rach_ind(&UL_INFO->rach_ind); - free(UL_INFO->rach_ind.rach_indication_body.preamble_list); - - // memory allocation and free memory of UL_INFO are done in UE_phy_stub_single_thread_rxn_txnp4. - //free(UL_INFO); - - //} - // change for mutiple UE's simulation. - // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); - pthread_mutex_unlock(&fill_ul_mutex.rach_mutex); + // This function is currently defined only in the nfapi-RU-RAU-split so we + // should call it when we merge with that branch. + oai_nfapi_rach_ind(&UL_INFO->rach_ind); + free(UL_INFO->rach_ind.rach_indication_body.preamble_list); + pthread_mutex_unlock(&fill_ul_mutex.rach_mutex); } -void fill_ulsch_cqi_indication_UE_MAC(int Mod_id, uint16_t frame,uint8_t subframe, UL_IND_t *UL_INFO, uint16_t rnti) { +void fill_ulsch_cqi_indication_UE_MAC(int Mod_id, + uint16_t frame, + uint8_t subframe, + UL_IND_t *UL_INFO, + uint16_t rnti) { + pthread_mutex_lock(&fill_ul_mutex.cqi_mutex); + nfapi_cqi_indication_pdu_t *pdu = + &UL_INFO->cqi_ind.cqi_indication_body + .cqi_pdu_list[UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis]; + nfapi_cqi_indication_raw_pdu_t *raw_pdu = + &UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list + [UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis]; - // change for mutiple UE's simulation. - //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); - pthread_mutex_lock(&fill_ul_mutex.cqi_mutex); - nfapi_cqi_indication_pdu_t *pdu = &UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list[UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis]; - nfapi_cqi_indication_raw_pdu_t *raw_pdu = &UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list[UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis]; + UL_INFO->cqi_ind.sfn_sf = frame << 4 | subframe; + // because of nfapi_vnf.c:733, set message id to 0, not + // NFAPI_RX_CQI_INDICATION; + UL_INFO->cqi_ind.header.message_id = 0; + UL_INFO->cqi_ind.cqi_indication_body.tl.tag = NFAPI_CQI_INDICATION_BODY_TAG; - pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - pdu->rx_ue_information.rnti = rnti; - // Since we assume that CRC flag is always 0 (ACK) I guess that data_offset should always be 0. - pdu->cqi_indication_rel9.data_offset = 0; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = rnti; + // Since we assume that CRC flag is always 0 (ACK) I guess that data_offset + // should always be 0. + pdu->cqi_indication_rel8.data_offset = 0; - // by default set O to rank 1 value - //pdu->cqi_indication_rel9.length = (ulsch_harq->Or1>>3) + ((ulsch_harq->Or1&7) > 0 ? 1 : 0); - // Not useful field for our case - pdu->cqi_indication_rel9.tl.tag = NFAPI_CQI_INDICATION_REL9_TAG; - pdu->cqi_indication_rel9.length = 0; - pdu->cqi_indication_rel9.ri[0] = 0; + pdu->cqi_indication_rel8.tl.tag = NFAPI_CQI_INDICATION_REL8_TAG; + pdu->cqi_indication_rel8.length = 1; + pdu->cqi_indication_rel8.ri = 0; - - pdu->cqi_indication_rel9.timing_advance = 0; - pdu->cqi_indication_rel9.number_of_cc_reported = 1; + pdu->cqi_indication_rel8.timing_advance = 0; + // pdu->cqi_indication_rel8.number_of_cc_reported = 1; + pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; pdu->ul_cqi_information.channel = 1; // PUSCH - // Not sure how to substitute this. This should be the actual CQI value? So can - // we hardcode it to a specific value? - //memcpy((void*)raw_pdu->pdu,ulsch_harq->o,pdu->cqi_indication_rel9.length); - raw_pdu->pdu[0] = 7; - - + // eNB_scheduler_primitives.c:4839: the upper four bits seem to be the CQI + const int cqi = 15; + raw_pdu->pdu[0] = cqi << 4; UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis++; - // change for mutiple UE's simulation. - //pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); pthread_mutex_unlock(&fill_ul_mutex.cqi_mutex); } -void fill_ulsch_harq_indication_UE_MAC(int Mod_id, int frame,int subframe, UL_IND_t *UL_INFO, nfapi_ul_config_ulsch_harq_information *harq_information, uint16_t rnti) -{ - - // change for mutiple UE's simulation. - //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); +void fill_ulsch_harq_indication_UE_MAC( + int Mod_id, + int frame, + int subframe, + UL_IND_t *UL_INFO, + nfapi_ul_config_ulsch_harq_information *harq_information, + uint16_t rnti) { pthread_mutex_lock(&fill_ul_mutex.harq_mutex); - nfapi_harq_indication_pdu_t *pdu = &UL_INFO->harq_ind.harq_indication_body.harq_pdu_list[UL_INFO->harq_ind.harq_indication_body.number_of_harqs]; - int i; + nfapi_harq_indication_pdu_t *pdu = + &UL_INFO->harq_ind.harq_indication_body.harq_pdu_list + [UL_INFO->harq_ind.harq_indication_body.number_of_harqs]; UL_INFO->harq_ind.header.message_id = NFAPI_HARQ_INDICATION; - UL_INFO->harq_ind.sfn_sf = frame<<4|subframe; - UL_INFO->harq_ind.vendor_extension = ul_config_req->vendor_extension; + UL_INFO->harq_ind.sfn_sf = frame << 4 | subframe; + UL_INFO->harq_ind.vendor_extension = ul_config_req->vendor_extension; - UL_INFO->harq_ind.harq_indication_body.tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; + UL_INFO->harq_ind.harq_indication_body.tl.tag = + NFAPI_HARQ_INDICATION_BODY_TAG; - pdu->instance_length = 0; // don't know what to do with this + pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; - pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - pdu->rx_ue_information.rnti = rnti; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = rnti; // For now we consider only FDD - //if (eNB->frame_parms.frame_type == FDD) { - pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; - pdu->harq_indication_fdd_rel13.mode = 0; - pdu->harq_indication_fdd_rel13.number_of_ack_nack = harq_information->harq_information_rel10.harq_size; + // if (eNB->frame_parms.frame_type == FDD) { + pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; + pdu->harq_indication_fdd_rel13.mode = 0; + pdu->harq_indication_fdd_rel13.number_of_ack_nack = + harq_information->harq_information_rel10.harq_size; - // Could this be wrong? Is the number_of_ack_nack field equivalent to O_ACK? - //pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; + // Could this be wrong? Is the number_of_ack_nack field equivalent to O_ACK? + // pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; - for (i=0;iharq_information_rel10.harq_size;i++) { - - pdu->harq_indication_fdd_rel13.harq_tb_n[i] = 1; // Assuming always an ACK (No NACK or DTX) - - } + for (int i = 0; i < harq_information->harq_information_rel10.harq_size; i++) { + pdu->harq_indication_fdd_rel13.harq_tb_n[i] = 1; // Assume always ACK (No NACK or DTX) + } UL_INFO->harq_ind.harq_indication_body.number_of_harqs++; - // change for mutiple UE's simulation. - //pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); - pthread_mutex_unlock(&fill_ul_mutex.harq_mutex);} - + pthread_mutex_unlock(&fill_ul_mutex.harq_mutex); +} void fill_uci_harq_indication_UE_MAC(int Mod_id, int frame, int subframe, UL_IND_t *UL_INFO, nfapi_ul_config_harq_information *harq_information, - uint16_t rnti - /*uint8_t tdd_mapping_mode, - uint16_t tdd_multiplexing_mask*/) { - - - // change for mutiple UE's simulation. - //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex); + uint16_t rnti) { pthread_mutex_lock(&fill_ul_mutex.harq_mutex); - nfapi_harq_indication_t *ind = &UL_INFO->harq_ind; + nfapi_harq_indication_t *ind = &UL_INFO->harq_ind; nfapi_harq_indication_body_t *body = &ind->harq_indication_body; - nfapi_harq_indication_pdu_t *pdu = &body->harq_pdu_list[UL_INFO->harq_ind.harq_indication_body.number_of_harqs]; + nfapi_harq_indication_pdu_t *pdu = + &body->harq_pdu_list[UL_INFO->harq_ind.harq_indication_body + .number_of_harqs]; - UL_INFO->harq_ind.vendor_extension = ul_config_req->vendor_extension; + UL_INFO->harq_ind.vendor_extension = ul_config_req->vendor_extension; - ind->sfn_sf = frame<<4|subframe; + ind->sfn_sf = frame << 4 | subframe; ind->header.message_id = NFAPI_HARQ_INDICATION; body->tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; - pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; - pdu->instance_length = 0; // don't know what to do with this - // pdu->rx_ue_information.handle = handle; - pdu->rx_ue_information.rnti = rnti; + pdu->instance_length = 0; // don't know what to do with this + pdu->rx_ue_information.rnti = rnti; pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; int SNRtimes10 = 640; - - if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0; - else if (SNRtimes10 > 635) pdu->ul_cqi_information.ul_cqi=255; - else pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5; + if (SNRtimes10 < -640) + pdu->ul_cqi_information.ul_cqi = 0; + else if (SNRtimes10 > 635) + pdu->ul_cqi_information.ul_cqi = 255; + else + pdu->ul_cqi_information.ul_cqi = (640 + SNRtimes10) / 5; pdu->ul_cqi_information.channel = 0; - if(harq_information->harq_information_rel9_fdd.tl.tag == NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG){ - if ((harq_information->harq_information_rel9_fdd.ack_nack_mode == 0) && - (harq_information->harq_information_rel9_fdd.harq_size == 1)) { - - pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; + if (harq_information->harq_information_rel9_fdd.tl.tag + == NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG) { + if ((harq_information->harq_information_rel9_fdd.ack_nack_mode == 0) + && (harq_information->harq_information_rel9_fdd.harq_size == 1)) { + pdu->harq_indication_fdd_rel13.tl.tag = + NFAPI_HARQ_INDICATION_FDD_REL13_TAG; pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = 1; - //AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); - pdu->harq_indication_fdd_rel13.harq_tb_n[0] = 1; // Assuming always an ACK (No NACK or DTX) + // AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, + // "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); + pdu->harq_indication_fdd_rel13.harq_tb_n[0] = + 1; // Assuming always an ACK (No NACK or DTX) - - } - else if ((harq_information->harq_information_rel9_fdd.ack_nack_mode == 0) && - (harq_information->harq_information_rel9_fdd.harq_size == 2)) { - pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; + } else if ((harq_information->harq_information_rel9_fdd.ack_nack_mode == 0) + && (harq_information->harq_information_rel9_fdd.harq_size + == 2)) { + pdu->harq_indication_fdd_rel13.tl.tag = + NFAPI_HARQ_INDICATION_FDD_REL13_TAG; pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = 2; - pdu->harq_indication_fdd_rel13.harq_tb_n[0] = 1; // Assuming always an ACK (No NACK or DTX) - pdu->harq_indication_fdd_rel13.harq_tb_n[1] = 1; // Assuming always an ACK (No NACK or DTX) - + pdu->harq_indication_fdd_rel13.harq_tb_n[0] = + 1; // Assuming always an ACK (No NACK or DTX) + pdu->harq_indication_fdd_rel13.harq_tb_n[1] = + 1; // Assuming always an ACK (No NACK or DTX) } - }else if(harq_information->harq_information_rel10_tdd.tl.tag == NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG ){ - if ((harq_information->harq_information_rel10_tdd.ack_nack_mode == 0) && - (harq_information->harq_information_rel10_tdd.harq_size == 1)) { - pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; - pdu->harq_indication_tdd_rel13.mode = 0; - pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; - pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1; - - } else if ((harq_information->harq_information_rel10_tdd.ack_nack_mode == 1) && - (harq_information->harq_information_rel10_tdd.harq_size == 2)) { - pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; - pdu->harq_indication_tdd_rel13.mode = 0; - pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; - pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1; - pdu->harq_indication_tdd_rel13.harq_data[1].bundling.value_0 = 1; - - } - } else AssertFatal(1==0,"only format 1a/b for now, received \n"); + } else if (harq_information->harq_information_rel10_tdd.tl.tag + == NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG) { + if ((harq_information->harq_information_rel10_tdd.ack_nack_mode == 0) + && (harq_information->harq_information_rel10_tdd.harq_size == 1)) { + pdu->harq_indication_tdd_rel13.tl.tag = + NFAPI_HARQ_INDICATION_TDD_REL13_TAG; + pdu->harq_indication_tdd_rel13.mode = 0; + pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; + pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1; + } else if ((harq_information->harq_information_rel10_tdd.ack_nack_mode == 1) + && (harq_information->harq_information_rel10_tdd.harq_size + == 2)) { + pdu->harq_indication_tdd_rel13.tl.tag = + NFAPI_HARQ_INDICATION_TDD_REL13_TAG; + pdu->harq_indication_tdd_rel13.mode = 0; + pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; + pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1; + pdu->harq_indication_tdd_rel13.harq_data[1].bundling.value_0 = 1; + } + } else + AssertFatal(1 == 0, "only format 1a/b for now, received \n"); UL_INFO->harq_ind.harq_indication_body.number_of_harqs++; - LOG_D(PHY,"Incremented eNB->UL_INFO.harq_ind.number_of_harqs:%d\n", UL_INFO->harq_ind.harq_indication_body.number_of_harqs); - // change for mutiple UE's simulation. - //pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex); + LOG_D(PHY, + "Incremented eNB->UL_INFO.harq_ind.number_of_harqs:%d\n", + UL_INFO->harq_ind.harq_indication_body.number_of_harqs); pthread_mutex_unlock(&fill_ul_mutex.harq_mutex); - } - void handle_nfapi_ul_pdu_UE_MAC(module_id_t Mod_id, - nfapi_ul_config_request_pdu_t *ul_config_pdu, - uint16_t frame,uint8_t subframe,uint8_t srs_present, int index) -{ - + nfapi_ul_config_request_pdu_t *ul_config_pdu, + uint16_t frame, + uint8_t subframe, + uint8_t srs_present, + int index) { if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) { - LOG_D(PHY,"Applying UL config for UE, rnti %x for frame %d, subframe %d\n", - (ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8).rnti,frame,subframe); - uint8_t ulsch_buffer[5477] __attribute__ ((aligned(32))); + LOG_D(PHY, + "Applying UL config for UE, rnti %x for frame %d, subframe %d\n", + (ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8).rnti, + frame, + subframe); + uint8_t ulsch_buffer[5477] __attribute__((aligned(32))); uint16_t buflen = ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size; uint16_t rnti = ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti; - uint8_t access_mode=SCHEDULED_ACCESS; - if(buflen>0){ - if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case - LOG_D(MAC, "handle_nfapi_ul_pdu_UE_MAC 2.2, Mod_id:%d, SFN/SF: %d/%d \n", Mod_id, frame, subframe); - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti, index); - Msg3_transmitted(Mod_id, 0, frame, 0); - // Modification - UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; - UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + uint8_t access_mode = SCHEDULED_ACCESS; + if (buflen > 0) { + if (UE_mac_inst[Mod_id].first_ULSCH_Tx == 1) { // Msg3 case + LOG_D(MAC, + "handle_nfapi_ul_pdu_UE_MAC 2.2, Mod_id:%d, SFN/SF: %d/%d \n", + Mod_id, + frame, + subframe); + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + UE_mac_inst[Mod_id].RA_prach_resources.Msg3, + buflen, + rnti, + index); + Msg3_transmitted(Mod_id, 0, frame, 0); + // Modification + UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; + UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - // This should be done after the reception of the respective hi_dci0 - //UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - } - else { - ue_get_sdu( Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_buffer,buflen, rnti, index); - } + // This should be done after the reception of the respective hi_dci0 + // UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + } else { + ue_get_sdu(Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + ulsch_buffer, + buflen, + rnti, + index); + } } } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) { + // AssertFatal((UE_id = + // find_ulsch(ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0, + // "No available UE ULSCH for rnti + // %x\n",ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti); + uint8_t ulsch_buffer[5477] __attribute__((aligned(32))); + uint16_t buflen = + ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.size; + nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = + &ul_config_pdu->ulsch_harq_pdu.harq_information; + uint16_t rnti = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti; + uint8_t access_mode = SCHEDULED_ACCESS; + if (buflen > 0) { + if (UE_mac_inst[Mod_id].first_ULSCH_Tx == 1) { // Msg3 case + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + UE_mac_inst[Mod_id].RA_prach_resources.Msg3, + buflen, + rnti, + index); + Msg3_transmitted(Mod_id, 0, frame, 0); + // UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + // Modification + UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; + UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + } else { + ue_get_sdu(Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + ulsch_buffer, + buflen, + rnti, + index); + } + } + if (ulsch_harq_information != NULL) + fill_ulsch_harq_indication_UE_MAC( + Mod_id, frame, subframe, UL_INFO, ulsch_harq_information, rnti); - //AssertFatal((UE_id = find_ulsch(ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0, - // "No available UE ULSCH for rnti %x\n",ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti); - uint8_t ulsch_buffer[5477] __attribute__ ((aligned(32))); - uint16_t buflen = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.size; - nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = &ul_config_pdu->ulsch_harq_pdu.harq_information; - uint16_t rnti = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti; - uint8_t access_mode=SCHEDULED_ACCESS; - if(buflen>0){ - if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti, index); - Msg3_transmitted(Mod_id, 0, frame, 0); - //UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - // Modification - UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; - UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - } - else { - ue_get_sdu( Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_buffer,buflen, rnti, index); - } + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) { + uint8_t ulsch_buffer[5477] __attribute__((aligned(32))); + uint16_t buflen = ul_config_pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.size; - } - if(ulsch_harq_information!=NULL) - fill_ulsch_harq_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_harq_information, rnti); + uint16_t rnti = ul_config_pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti; + uint8_t access_mode = SCHEDULED_ACCESS; + if (buflen > 0) { + if (UE_mac_inst[Mod_id].first_ULSCH_Tx == 1) { // Msg3 case + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + UE_mac_inst[Mod_id].RA_prach_resources.Msg3, + buflen, + rnti, + index); + Msg3_transmitted(Mod_id, 0, frame, 0); + // UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + // Modification + UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; + UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + } else { + ue_get_sdu(Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + ulsch_buffer, + buflen, + rnti, + index); + } + } + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE) { + uint8_t ulsch_buffer[5477] __attribute__((aligned(32))); + uint16_t buflen = ul_config_pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.size; + nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = + &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; + uint16_t rnti = ul_config_pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti; + uint8_t access_mode = SCHEDULED_ACCESS; + if (buflen > 0) { + if (UE_mac_inst[Mod_id].first_ULSCH_Tx == 1) { // Msg3 case + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + UE_mac_inst[Mod_id].RA_prach_resources.Msg3, + buflen, + rnti, + index); + Msg3_transmitted(Mod_id, 0, frame, 0); + // UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + // Modification + UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; + UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + } else { + ue_get_sdu(Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); + fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); + fill_rx_indication_UE_MAC(Mod_id, + frame, + subframe, + UL_INFO, + ulsch_buffer, + buflen, + rnti, + index); + } + } + + if (ulsch_harq_information != NULL) + fill_ulsch_harq_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_harq_information, rnti); + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) { + uint16_t rnti = ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti; + + nfapi_ul_config_harq_information *ulsch_harq_information = &ul_config_pdu->uci_harq_pdu.harq_information; + if (ulsch_harq_information != NULL) + fill_uci_harq_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_harq_information, rnti); + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE) { + AssertFatal(1 == 0, "NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE not handled yet\n"); + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE) { + AssertFatal(1 == 0, + "NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE not handled yet\n"); + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE) { + AssertFatal(1 == 0, + "NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE not handled yet\n"); + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE) { + uint16_t rnti = + ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti; + + if (ue_get_SR(Mod_id, 0, frame, 0, rnti, subframe)) + fill_sr_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, rnti); + + } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE) { + // AssertFatal((UE_id = + // find_uci(rel8->rnti,proc->frame_tx,proc->subframe_tx,eNB,SEARCH_EXIST_OR_FREE))>=0, + // "No available UE UCI for rnti + // %x\n",ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti); + + uint16_t rnti = + ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti; + + // We fill the sr_indication only if ue_get_sr() would normally instruct PHY + // to send a SR. + if (ue_get_SR(Mod_id, 0, frame, 0, rnti, subframe)) + fill_sr_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, rnti); + + nfapi_ul_config_harq_information *ulsch_harq_information = + &ul_config_pdu->uci_sr_harq_pdu.harq_information; + if (ulsch_harq_information != NULL) + fill_uci_harq_indication_UE_MAC( + Mod_id, frame, subframe, UL_INFO, ulsch_harq_information, rnti); } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) { - uint8_t ulsch_buffer[5477] __attribute__ ((aligned(32))); - uint16_t buflen = ul_config_pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.size; - - uint16_t rnti = ul_config_pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti; - uint8_t access_mode=SCHEDULED_ACCESS; - if(buflen>0){ - if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti, index); - Msg3_transmitted(Mod_id, 0, frame, 0); - //UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - // Modification - UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; - UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - } - else { - ue_get_sdu( Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_buffer,buflen, rnti, index); - } - } - fill_ulsch_cqi_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, rnti); - - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE) { - - uint8_t ulsch_buffer[5477] __attribute__ ((aligned(32))); - uint16_t buflen = ul_config_pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.size; - nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; - - uint16_t rnti = ul_config_pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti; - uint8_t access_mode=SCHEDULED_ACCESS; - if(buflen>0){ - if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti, index); - Msg3_transmitted(Mod_id, 0, frame, 0); - //UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - // Modification - UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; - UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; - } - else { - ue_get_sdu( Mod_id, 0, frame, subframe, 0, ulsch_buffer, buflen, &access_mode); - fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0, index, rnti); - fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_buffer,buflen, rnti, index); - } - } - - if(ulsch_harq_information!=NULL) - fill_ulsch_harq_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, ulsch_harq_information, rnti); - fill_ulsch_cqi_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, rnti); - - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) { - - uint16_t rnti = ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti; - - nfapi_ul_config_harq_information *ulsch_harq_information = &ul_config_pdu->uci_harq_pdu.harq_information; - if(ulsch_harq_information != NULL) - fill_uci_harq_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO,ulsch_harq_information, rnti); - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE) { - AssertFatal(1==0,"NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE not handled yet\n"); - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE) { - AssertFatal(1==0,"NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE not handled yet\n"); - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE) { - AssertFatal(1==0,"NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE not handled yet\n"); - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE) { - - uint16_t rnti = ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti; - - if (ue_get_SR(Mod_id ,0,frame, 0, rnti, subframe)) - fill_sr_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, rnti); - - } - else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE) { - //AssertFatal((UE_id = find_uci(rel8->rnti,proc->frame_tx,proc->subframe_tx,eNB,SEARCH_EXIST_OR_FREE))>=0, - // "No available UE UCI for rnti %x\n",ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti); - - uint16_t rnti = ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti; - - // We fill the sr_indication only if ue_get_sr() would normally instruct PHY to send a SR. - if (ue_get_SR(Mod_id ,0,frame, 0, rnti, subframe)) - fill_sr_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO,rnti); - - nfapi_ul_config_harq_information *ulsch_harq_information = &ul_config_pdu->uci_sr_harq_pdu.harq_information; - if (ulsch_harq_information != NULL) - fill_uci_harq_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO,ulsch_harq_information, rnti); - - } - } - - - - - -int ul_config_req_UE_MAC(nfapi_ul_config_request_t* req, int timer_frame, int timer_subframe, module_id_t Mod_id) -{ - //if (req!=NULL){ // && req->ul_config_request_body.ul_config_pdu_list !=NULL){ - LOG_D(PHY,"[PNF] UL_CONFIG_REQ %s() sfn_sf:%d pdu:%d rach_prach_frequency_resources:%d srs_present:%u\n", - __FUNCTION__, - NFAPI_SFNSF2DEC(req->sfn_sf), - req->ul_config_request_body.number_of_pdus, - req->ul_config_request_body.rach_prach_frequency_resources, - req->ul_config_request_body.srs_present - ); +int ul_config_req_UE_MAC(nfapi_ul_config_request_t *req, + int timer_frame, + int timer_subframe, + module_id_t Mod_id) { + LOG_D(PHY, + "[PNF] UL_CONFIG_REQ %s() sfn_sf:%d pdu:%d " + "rach_prach_frequency_resources:%d srs_present:%u\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(req->sfn_sf), + req->ul_config_request_body.number_of_pdus, + req->ul_config_request_body.rach_prach_frequency_resources, + req->ul_config_request_body.srs_present); int sfn = NFAPI_SFNSF2SFN(req->sfn_sf); int sf = NFAPI_SFNSF2SF(req->sfn_sf); + LOG_D(MAC, + "ul_config_req_UE_MAC() TOTAL NUMBER OF UL_CONFIG PDUs: %d, SFN/SF: " + "%d/%d \n", + req->ul_config_request_body.number_of_pdus, + timer_frame, + timer_subframe); - LOG_D(MAC, "ul_config_req_UE_MAC() TOTAL NUMBER OF UL_CONFIG PDUs: %d, SFN/SF: %d/%d \n", req->ul_config_request_body.number_of_pdus, timer_frame, timer_subframe); - - - - for (int i=0;iul_config_request_body.number_of_pdus;i++) - { - - if ( - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_mac_inst[Mod_id].crnti) || - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == UE_mac_inst[Mod_id].crnti) || - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == UE_mac_inst[Mod_id].crnti) || - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == UE_mac_inst[Mod_id].crnti) || - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == UE_mac_inst[Mod_id].crnti) || - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].uci_sr_pdu.ue_information.ue_information_rel8.rnti == UE_mac_inst[Mod_id].crnti) || - (req->ul_config_request_body.ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE && req->ul_config_request_body.ul_config_pdu_list[i].uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == UE_mac_inst[Mod_id].crnti) - ) - { - - handle_nfapi_ul_pdu_UE_MAC(Mod_id,&req->ul_config_request_body.ul_config_pdu_list[i],sfn,sf,req->ul_config_request_body.srs_present, i); - - } - else - { - //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() PDU:%i UNKNOWN type :%d\n", __FUNCTION__, i, ul_config_pdu_list[i].pdu_type); + const rnti_t rnti = UE_mac_inst[Mod_id].crnti; + for (int i = 0; i < req->ul_config_request_body.number_of_pdus; i++) { + nfapi_ul_config_request_pdu_t* pdu = &req->ul_config_request_body.ul_config_pdu_list[i]; + const int pdu_type = pdu->pdu_type; + if ( (pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE + && pdu->ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) + || (pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE + && pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) + || (pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE + && pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) + || (pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE + && pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) + || (pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE + && pdu->uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == rnti) + || (pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE + && pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti == rnti) + || (pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE + && pdu->uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) { + handle_nfapi_ul_pdu_UE_MAC( + Mod_id, pdu, sfn, sf, req->ul_config_request_body.srs_present, i); + } else { + // NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() PDU:%i UNKNOWN type :%d\n", + // __FUNCTION__, i, ul_config_pdu_list[i].pdu_type); } } -// } - return 0; } +int tx_req_UE_MAC(nfapi_tx_request_t *req) { + LOG_D(PHY, + "%s() SFN/SF:%d/%d PDUs:%d\n", + __FUNCTION__, + NFAPI_SFNSF2SFN(req->sfn_sf), + NFAPI_SFNSF2SF(req->sfn_sf), + req->tx_request_body.number_of_pdus); - -int tx_req_UE_MAC(nfapi_tx_request_t* req) -{ - - LOG_D(PHY,"%s() SFN/SF:%d/%d PDUs:%d\n", __FUNCTION__, NFAPI_SFNSF2SFN(req->sfn_sf), NFAPI_SFNSF2SF(req->sfn_sf), req->tx_request_body.number_of_pdus); - - - for (int i=0; itx_request_body.number_of_pdus; i++) - { - LOG_D(PHY,"%s() SFN/SF:%d/%d number_of_pdus:%d [PDU:%d] pdu_length:%d pdu_index:%d num_segments:%d\n", + for (int i = 0; i < req->tx_request_body.number_of_pdus; i++) { + LOG_D(PHY, + "%s() SFN/SF:%d/%d number_of_pdus:%d [PDU:%d] pdu_length:%d " + "pdu_index:%d num_segments:%d\n", __FUNCTION__, - NFAPI_SFNSF2SFN(req->sfn_sf), NFAPI_SFNSF2SF(req->sfn_sf), + NFAPI_SFNSF2SFN(req->sfn_sf), + NFAPI_SFNSF2SF(req->sfn_sf), req->tx_request_body.number_of_pdus, i, req->tx_request_body.tx_pdu_list[i].pdu_length, req->tx_request_body.tx_pdu_list[i].pdu_index, - req->tx_request_body.tx_pdu_list[i].num_segments - ); - - } + req->tx_request_body.tx_pdu_list[i].num_segments); + } return 0; } - -int dl_config_req_UE_MAC(nfapi_dl_config_request_t* req, module_id_t Mod_id) //, nfapi_tx_request_pdu_t* tx_request_pdu_list) -{ - //if (req!=NULL && tx_request_pdu_list!=NULL){ +int dl_config_req_UE_MAC(nfapi_dl_config_request_t* req, module_id_t Mod_id) { int sfn = NFAPI_SFNSF2SFN(req->sfn_sf); int sf = NFAPI_SFNSF2SF(req->sfn_sf); - //Mod_id = 0; // Currently static (only for one UE) but this should change. - /*struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; - L1_rxtx_proc_t *proc = &eNB->proc.L1_proc;*/ nfapi_dl_config_request_pdu_t* dl_config_pdu_list = req->dl_config_request_body.dl_config_pdu_list; - nfapi_dl_config_request_pdu_t *dl_config_pdu_tmp; - //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() TX:%d/%d RX:%d/%d sfn_sf:%d DCI:%d PDU:%d\n", __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->frame_rx, proc->subframe_rx, NFAPI_SFNSF2DEC(req->sfn_sf), req->dl_config_request_body.number_dci, req->dl_config_request_body.number_pdu); - - - - //LOG_D(PHY,"NFAPI: Sched_INFO:SFN/SF:%d%d dl_pdu:%d tx_req:%d hi_dci0:%d ul_cfg:%d num_pdcch_symbols:%d\n", - // frame,subframe,number_dl_pdu,TX_req->tx_request_body.number_of_pdus,number_hi_dci0_pdu,number_ul_pdu, eNB->pdcch_vars[subframe&1].num_pdcch_symbols); - - for (int i=0;idl_config_request_body.number_pdu;i++) - { - //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sfn/sf:%d PDU[%d] size:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size); - //LOG_E(MAC, "dl_config_req_UE_MAC 2 Received real ones: sfn/sf:%d.%d PDU[%d] size:%d\n", sfn, sf, i, dl_config_pdu_list[i].pdu_size); - - if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - { - if (dl_config_pdu_list[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 1) { - // C-RNTI (Normal DLSCH case) - dl_config_pdu_tmp = &dl_config_pdu_list[i+1]; - if (dl_config_pdu_tmp->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE && UE_mac_inst[Mod_id].crnti == dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti){ - - /*nfapi_tx_request_pdu_t *ptr = tx_request_pdu_list; - ptr += dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index*(sizeof(nfapi_tx_request_pdu_t)); - nfapi_tx_request_pdu_t temp; - memset(&temp, 0, sizeof(nfapi_tx_request_pdu_t)); - //if (!memcmp(&temp, ptr, sizeof(temp)) ... - if( *(char*)ptr != 0){ - //if(tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data!= NULL && tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_length >0){ - */ - - // to avoid unexpected error , add check pdu_index is more than 0. - if((dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index >= 0) &&(dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index <= tx_req_num_elems -1)){ - //if(tx_request_pdu_list + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index!= NULL){ - - LOG_E(MAC, "dl_config_req_UE_MAC 2 Received data: sfn/sf:%d PDU[%d] size:%d, TX_PDU index: %d, tx_req_num_elems: %d \n", NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size, dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index, tx_req_num_elems); - - ue_send_sdu(Mod_id, 0, sfn, sf, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_length, - 0); - i++; - } - else{ - LOG_E(MAC,"dl_config_req_UE_MAC 2: Problem with receiving data: sfn/sf:%d PDU[%d] size:%d, TX_PDU index: %d\n", NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size, dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index); - i++; - } - } - else { - LOG_E(MAC,"[UE %d] Frame %d, subframe %d : DLSCH PDU from NFAPI not for this UE \n",Mod_id, sfn,sf); - i++; - } - } - else if (dl_config_pdu_list[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 2) { - dl_config_pdu_tmp = &dl_config_pdu_list[i+1]; - if(dl_config_pdu_tmp->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE && dl_config_pdu_list[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti == 0xFFFF && UE_mac_inst[Mod_id].UE_mode[0] != NOT_SYNCHED){ //&& UE_mac_inst[Mod_id].UE_mode[0] != NOT_SYNCHED - - if(dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index <= tx_req_num_elems -1){ - //if(tx_request_pdu_list + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index!= NULL){ - ue_decode_si(Mod_id, 0, sfn, 0, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_length); - i++; - } - else{ - LOG_E(MAC,"dl_config_req_UE_MAC 3: Problem with receiving SI: sfn/sf:%d PDU[%d] size:%d, TX_PDU index: %d\n", NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size, dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index); - i++; - } - } - else if(dl_config_pdu_tmp->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE && dl_config_pdu_list[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti == 0xFFFE){ - // P_RNTI case - //pdu = Tx_req->tx_request_body.tx_pdu_list[dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data; - - if (dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index <= tx_req_num_elems -1){ - //if(tx_request_pdu_list + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index!= NULL){ - ue_decode_p(Mod_id, 0, sfn, 0, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_length); - i++; - } - else{ - LOG_E(MAC,"dl_config_req_UE_MAC: Problem with receiving Paging: sfn/sf:%d PDU[%d] size:%d, TX_PDU index: %d\n", NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size, dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index); - i++; - } - } - else if(dl_config_pdu_tmp->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) { - // RA-RNTI case - LOG_E(MAC,"dl_config_req_UE_MAC 4 Received RAR? \n"); - // RNTI parameter not actually used. Provided only to comply with existing function definition. - // Not sure about parameters to fill the preamble index. - //rnti_t c_rnti = UE_mac_inst[Mod_id].crnti; - rnti_t ra_rnti = UE_mac_inst[Mod_id].RA_prach_resources.ra_RNTI; - if ((UE_mac_inst[Mod_id].UE_mode[0] != PUSCH) && - (UE_mac_inst[Mod_id].RA_prach_resources.Msg3!=NULL) && (ra_rnti== dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti) && - //(tx_request_pdu_list + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index!= NULL)) { - (dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index <= tx_req_num_elems -1)) { - LOG_E(MAC,"dl_config_req_UE_MAC 5 Received RAR, PreambleIndex: %d \n", UE_mac_inst[Mod_id].RA_prach_resources.ra_PreambleIndex); - ue_process_rar(Mod_id, 0, sfn, - ra_rnti, //RA-RNTI - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data, - &dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti, //t-crnti - UE_mac_inst[Mod_id].RA_prach_resources.ra_PreambleIndex, - tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data); - UE_mac_inst[Mod_id].UE_mode[0] = RA_RESPONSE; - UE_mac_inst[Mod_id].first_ULSCH_Tx = 1; //Expecting an UL_CONFIG_ULSCH_PDU to enable Msg3 Txon (first ULSCH Txon for the UE) - } - i++; - } - else { - LOG_E(MAC,"[UE %d] Frame %d, subframe %d : Cannot extract DLSCH PDU from NFAPI 2\n",Mod_id, sfn, sf); - i++; - } - - } - } - else if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_BCH_PDU_TYPE) - { - // BCH case - // Last parameter is 1 if first time synchronization and zero otherwise. Not sure which value to put - // for our case. - //LOG_E(MAC,"dl_config_req_UE_MAC 4 Received MIB: sfn/sf: %d.%d \n", sfn, sf); - if(UE_mac_inst[Mod_id].UE_mode[0] == NOT_SYNCHED){ - dl_phy_sync_success(Mod_id,sfn,0, 1); - LOG_E(MAC,"dl_config_req_UE_MAC 5 Received MIB: UE_mode: %d, sfn/sf: %d.%d\n", UE_mac_inst[Mod_id].UE_mode[0], sfn, sf); - UE_mac_inst[Mod_id].UE_mode[0]=PRACH; - } - else - dl_phy_sync_success(Mod_id,sfn,0, 0); - - } - - else - { - //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() UNKNOWN:%d\n", __FUNCTION__, dl_config_pdu_list[i].pdu_type); - } - } - - return 0; - -} - - -int hi_dci0_req_UE_MAC(nfapi_hi_dci0_request_t* req, module_id_t Mod_id) -{ - if (req!=NULL && req->hi_dci0_request_body.hi_dci0_pdu_list!=NULL){ - LOG_D(PHY,"[UE-PHY_STUB] hi dci0 request sfn_sf:%d number_of_dci:%d number_of_hi:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), req->hi_dci0_request_body.number_of_dci, req->hi_dci0_request_body.number_of_hi); - - - - for (int i=0; ihi_dci0_request_body.number_of_dci + req->hi_dci0_request_body.number_of_hi; i++) - { - LOG_D(PHY,"[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d]\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); - - if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) - { - LOG_D(PHY,"[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_DCI_PDU_TYPE not used \n", NFAPI_SFNSF2DEC(req->sfn_sf), i); - - } - else if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type == NFAPI_HI_DCI0_HI_PDU_TYPE) - { - //LOG_I(MAC,"[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_HI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); - - nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu = &req->hi_dci0_request_body.hi_dci0_pdu_list[i]; - - // This is meaningful only after ACKnowledging the first ULSCH Txon (i.e. Msg3) - if(hi_dci0_req_pdu->hi_pdu.hi_pdu_rel8.hi_value == 1 && UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ - //LOG_I(MAC,"[UE-PHY_STUB] HI_DCI0_REQ 2 sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_HI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); - //UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; - //UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + for (int i = 0; i < req->dl_config_request_body.number_pdu; i++) { + if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) { + const rnti_t rnti = dl_config_pdu_list[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti; + const int rnti_type = dl_config_pdu_list[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type; + /* We assume the DCI DL PDU is followed by the DLSCH (the standard is + * more free), so advance by one more and directly process the + * following DLSCH PDU */ + i++; + AssertFatal(i < req->dl_config_request_body.number_pdu, + "Need PDU following DCI at index %d, but not found\n", + i); + nfapi_dl_config_request_pdu_t *dl_config_pdu_tmp = &dl_config_pdu_list[i]; + if (dl_config_pdu_tmp->pdu_type != NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) { + LOG_E(MAC, "expected DLSCH PDU at index %d\n", i); + continue; } + if (rnti != dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti) { + LOG_I(MAC, + "%s(): sfn/sf %d DLSCH PDU RNTI %x does not match DCI RNTI %x\n", + __func__, + NFAPI_SFNSF2DEC(req->sfn_sf), + rnti, + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti); + continue; + } + const int pdu_index = dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index; + if (pdu_index < 0 && pdu_index >= tx_req_num_elems) { + LOG_E(MAC, + "dl_config_req_UE_MAC 2: Problem with receiving data: " + "sfn/sf:%d PDU[%d] size:%d, TX_PDU index: %d\n", + NFAPI_SFNSF2DEC(req->sfn_sf), + i, + dl_config_pdu_list[i].pdu_size, + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index); + continue; + } + if (rnti_type == 1) { + // C-RNTI (Normal DLSCH case) + if (UE_mac_inst[Mod_id].crnti != rnti) { + LOG_D(MAC, + "sfn/sf %d/%d DCI not for UE %d/RNTI %x but for RNTI %x, " + "skipping\n", + sfn, sf, Mod_id, UE_mac_inst[Mod_id].crnti, rnti); + continue; + } - } - else - { - LOG_E(PHY,"[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d] - unknown pdu type:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), i, req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type); + LOG_D(MAC, + "%s() Received data: sfn/sf:%d PDU[%d] " + "size:%d, TX_PDU index: %d, tx_req_num_elems: %d \n", + __func__, + NFAPI_SFNSF2DEC(req->sfn_sf), + i, + dl_config_pdu_list[i].pdu_size, + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index, + tx_req_num_elems); + ue_send_sdu(Mod_id, 0, sfn, sf, + tx_request_pdu_list[pdu_index].segments[0].segment_data, + tx_request_pdu_list[pdu_index].segments[0].segment_length, + 0); + } else if (rnti_type == 2) { + if (rnti == 0xFFFF) { /* SI-RNTI */ + if (UE_mac_inst[Mod_id].UE_mode[0] == NOT_SYNCHED) { + /* this check is in the code before refactoring, but I don't know + * why. Leave it in here for the moment */ + continue; + } + + ue_decode_si(Mod_id, 0, sfn, 0, + tx_request_pdu_list[pdu_index].segments[0].segment_data, + tx_request_pdu_list[pdu_index].segments[0].segment_length); + } else if (rnti == 0xFFFE) { /* PI-RNTI */ + LOG_I(MAC, "%s() Received paging message: sfn/sf:%d PDU[%d]\n", + __func__, NFAPI_SFNSF2DEC(req->sfn_sf), i); + ue_decode_p(Mod_id, 0, sfn, 0, + tx_request_pdu_list[pdu_index].segments[0].segment_data, + tx_request_pdu_list[pdu_index].segments[0].segment_length); + } else if (rnti == 0x0002) { /* RA-RNTI */ + LOG_E(MAC, "%s(): Received RAR?\n", __func__); + // RNTI parameter not actually used. Provided only to comply with + // existing function definition. Not sure about parameters to fill + // the preamble index. + const rnti_t ra_rnti = UE_mac_inst[Mod_id].RA_prach_resources.ra_RNTI; + DevAssert(ra_rnti == 0x0002); + if (UE_mac_inst[Mod_id].UE_mode[0] != PUSCH + && UE_mac_inst[Mod_id].RA_prach_resources.Msg3 != NULL + && ra_rnti == dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti) { + LOG_E(MAC, + "dl_config_req_UE_MAC 5 Received RAR, PreambleIndex: %d \n", + UE_mac_inst[Mod_id].RA_prach_resources.ra_PreambleIndex); + ue_process_rar(Mod_id, 0, sfn, + ra_rnti, //RA-RNTI + tx_request_pdu_list[pdu_index].segments[0].segment_data, + &dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.rnti, //t-crnti + UE_mac_inst[Mod_id].RA_prach_resources.ra_PreambleIndex, + tx_request_pdu_list[pdu_index].segments[0].segment_data); + UE_mac_inst[Mod_id].UE_mode[0] = RA_RESPONSE; + // Expecting an UL_CONFIG_ULSCH_PDU to enable Msg3 Txon (first + // ULSCH Txon for the UE) + UE_mac_inst[Mod_id].first_ULSCH_Tx = 1; + } + } else { + LOG_W(MAC, "can not handle special RNTI %x\n", rnti); + } + } + } else if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_BCH_PDU_TYPE) { + // BCH case: Last parameter is 1 if first time synchronization and zero + // otherwise. Not sure which value to put for our case. + if (UE_mac_inst[Mod_id].UE_mode[0] == NOT_SYNCHED){ + dl_phy_sync_success(Mod_id, sfn, 0, 1); + LOG_E(MAC, + "%s(): Received MIB: UE_mode: %d, sfn/sf: %d.%d\n", + __func__, + UE_mac_inst[Mod_id].UE_mode[0], + sfn, + sf); + UE_mac_inst[Mod_id].UE_mode[0] = PRACH; + } else { + dl_phy_sync_success(Mod_id, sfn, 0, 0); + } } } + return 0; +} +int hi_dci0_req_UE_MAC(nfapi_hi_dci0_request_t *req, module_id_t Mod_id) { + if (req != NULL && req->hi_dci0_request_body.hi_dci0_pdu_list != NULL) { + LOG_D(PHY, + "[UE-PHY_STUB] hi dci0 request sfn_sf:%d number_of_dci:%d " + "number_of_hi:%d\n", + NFAPI_SFNSF2DEC(req->sfn_sf), + req->hi_dci0_request_body.number_of_dci, + req->hi_dci0_request_body.number_of_hi); + + for (int i = 0; i < req->hi_dci0_request_body.number_of_dci + + req->hi_dci0_request_body.number_of_hi; + i++) { + LOG_D(PHY, + "[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d]\n", + NFAPI_SFNSF2DEC(req->sfn_sf), + i); + + if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type + == NFAPI_HI_DCI0_DCI_PDU_TYPE) { + LOG_D(PHY, + "[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d] - " + "NFAPI_HI_DCI0_DCI_PDU_TYPE\n", + NFAPI_SFNSF2DEC(req->sfn_sf), + i); + const nfapi_hi_dci0_dci_pdu_rel8_t *dci = + &req->hi_dci0_request_body.hi_dci0_pdu_list[i].dci_pdu.dci_pdu_rel8; + if (dci->rnti != UE_mac_inst[Mod_id].crnti) + continue; + const int sfn = NFAPI_SFNSF2SFN(req->sfn_sf); + const int sf = NFAPI_SFNSF2SF(req->sfn_sf); + if (dci->cqi_csi_request) + fill_ulsch_cqi_indication_UE_MAC(Mod_id, sfn, sf, UL_INFO, dci->rnti); + } else if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type + == NFAPI_HI_DCI0_HI_PDU_TYPE) { + nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu = + &req->hi_dci0_request_body.hi_dci0_pdu_list[i]; + + // This is meaningful only after ACKnowledging the first ULSCH Txon + // (i.e. Msg3) + if (hi_dci0_req_pdu->hi_pdu.hi_pdu_rel8.hi_value == 1 + && UE_mac_inst[Mod_id].first_ULSCH_Tx == 1) { + // LOG_I(MAC,"[UE-PHY_STUB] HI_DCI0_REQ 2 sfn_sf:%d PDU[%d] - + // NFAPI_HI_DCI0_HI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); + // UE_mac_inst[Mod_id].UE_mode[0] = PUSCH; + // UE_mac_inst[Mod_id].first_ULSCH_Tx = 0; + } + + } else { + LOG_E(PHY, + "[UE-PHY_STUB] HI_DCI0_REQ sfn_sf:%d PDU[%d] - unknown pdu " + "type:%d\n", + NFAPI_SFNSF2DEC(req->sfn_sf), + i, + req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type); + } + } } - return 0; } +// The following set of memcpy functions should be getting called as callback +// functions from pnf_p7_subframe_ind. +int memcpy_dl_config_req(nfapi_pnf_p7_config_t *pnf_p7, + nfapi_dl_config_request_t *req) { + dl_config_req = (nfapi_dl_config_request_t *)malloc(sizeof(nfapi_dl_config_request_t)); + // UE_mac_inst[Mod_id].dl_config_req->header = req->header; + dl_config_req->sfn_sf = req->sfn_sf; + dl_config_req->vendor_extension = req->vendor_extension; + dl_config_req->dl_config_request_body.number_dci = req->dl_config_request_body.number_dci; + dl_config_req->dl_config_request_body.number_pdcch_ofdm_symbols = req->dl_config_request_body.number_pdcch_ofdm_symbols; + dl_config_req->dl_config_request_body.number_pdsch_rnti = req->dl_config_request_body.number_pdsch_rnti; + dl_config_req->dl_config_request_body.number_pdu = req->dl_config_request_body.number_pdu; -// The following set of memcpy functions should be getting called as callback functions from -// pnf_p7_subframe_ind. -int memcpy_dl_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req) -{ + dl_config_req->dl_config_request_body.tl.tag = req->dl_config_request_body.tl.tag; + dl_config_req->dl_config_request_body.tl.length = req->dl_config_request_body.tl.length; - //for (Mod_id=0; Mod_idheader = req->header; - dl_config_req->sfn_sf = req->sfn_sf; - - dl_config_req->vendor_extension = req->vendor_extension; - - dl_config_req->dl_config_request_body.number_dci = req->dl_config_request_body.number_dci; - dl_config_req->dl_config_request_body.number_pdcch_ofdm_symbols = req->dl_config_request_body.number_pdcch_ofdm_symbols; - dl_config_req->dl_config_request_body.number_pdsch_rnti = req->dl_config_request_body.number_pdsch_rnti; - dl_config_req->dl_config_request_body.number_pdu = req->dl_config_request_body.number_pdu; - - dl_config_req->dl_config_request_body.tl.tag = req->dl_config_request_body.tl.tag; - dl_config_req->dl_config_request_body.tl.length = req->dl_config_request_body.tl.length; - - dl_config_req->dl_config_request_body.dl_config_pdu_list = (nfapi_dl_config_request_pdu_t*) calloc(req->dl_config_request_body.number_pdu, sizeof(nfapi_dl_config_request_pdu_t)); - for(int i=0; idl_config_request_body.number_pdu; i++) { - dl_config_req->dl_config_request_body.dl_config_pdu_list[i] = req->dl_config_request_body.dl_config_pdu_list[i]; - } - - //} - - return 0; + dl_config_req->dl_config_request_body.dl_config_pdu_list = + calloc(req->dl_config_request_body.number_pdu, + sizeof(nfapi_dl_config_request_pdu_t)); + for (int i = 0; i < dl_config_req->dl_config_request_body.number_pdu; i++) { + dl_config_req->dl_config_request_body.dl_config_pdu_list[i] = + req->dl_config_request_body.dl_config_pdu_list[i]; + } + return 0; } -int memcpy_ul_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req) -{ +int memcpy_ul_config_req(nfapi_pnf_p7_config_t *pnf_p7, + nfapi_ul_config_request_t *req) { + ul_config_req = malloc(sizeof(nfapi_ul_config_request_t)); - //for (Mod_id=0; Mod_idsfn_sf = req->sfn_sf; + ul_config_req->vendor_extension = req->vendor_extension; - ul_config_req = (nfapi_ul_config_request_t*)malloc(sizeof(nfapi_ul_config_request_t)); + ul_config_req->ul_config_request_body.number_of_pdus = req->ul_config_request_body.number_of_pdus; + ul_config_req->ul_config_request_body.rach_prach_frequency_resources = req->ul_config_request_body.rach_prach_frequency_resources; + ul_config_req->ul_config_request_body.srs_present = req->ul_config_request_body.srs_present; - ul_config_req->sfn_sf = req->sfn_sf; - ul_config_req->vendor_extension = req->vendor_extension; + ul_config_req->ul_config_request_body.tl.tag = req->ul_config_request_body.tl.tag; + ul_config_req->ul_config_request_body.tl.length = req->ul_config_request_body.tl.length; + ul_config_req->ul_config_request_body.ul_config_pdu_list = + calloc(req->ul_config_request_body.number_of_pdus, + sizeof(nfapi_ul_config_request_pdu_t)); + for (int i = 0; i < ul_config_req->ul_config_request_body.number_of_pdus; i++) { + ul_config_req->ul_config_request_body.ul_config_pdu_list[i] = + req->ul_config_request_body.ul_config_pdu_list[i]; + } - ul_config_req->ul_config_request_body.number_of_pdus = req->ul_config_request_body.number_of_pdus; - ul_config_req->ul_config_request_body.rach_prach_frequency_resources = req->ul_config_request_body.rach_prach_frequency_resources; - ul_config_req->ul_config_request_body.srs_present = req->ul_config_request_body.srs_present; - - ul_config_req->ul_config_request_body.tl.tag = req->ul_config_request_body.tl.tag; - ul_config_req->ul_config_request_body.tl.length = req->ul_config_request_body.tl.length; - - //LOG_D(MAC, "memcpy_ul_config_req 1 #ofULPDUs: %d \n", UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.number_of_pdus); //req->ul_config_request_body.number_of_pdus); - ul_config_req->ul_config_request_body.ul_config_pdu_list = (nfapi_ul_config_request_pdu_t*) malloc(req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); - for(int i=0; iul_config_request_body.number_of_pdus; i++) { - ul_config_req->ul_config_request_body.ul_config_pdu_list[i] = req->ul_config_request_body.ul_config_pdu_list[i]; - } - //} - - return 0; + return 0; } +int memcpy_tx_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_tx_request_t *req) { + tx_req_num_elems = req->tx_request_body.number_of_pdus; + tx_request_pdu_list = calloc(tx_req_num_elems, sizeof(nfapi_tx_request_pdu_t)); + for (int i = 0; i < tx_req_num_elems; i++) { + tx_request_pdu_list[i].num_segments = req->tx_request_body.tx_pdu_list[i].num_segments; + tx_request_pdu_list[i].pdu_index = req->tx_request_body.tx_pdu_list[i].pdu_index; + tx_request_pdu_list[i].pdu_length = req->tx_request_body.tx_pdu_list[i].pdu_length; + for (int j = 0; j < req->tx_request_body.tx_pdu_list[i].num_segments; j++) { + tx_request_pdu_list[i].segments[j].segment_length = req->tx_request_body.tx_pdu_list[i].segments[j].segment_length; + if (tx_request_pdu_list[i].segments[j].segment_length > 0) { + tx_request_pdu_list[i].segments[j].segment_data = calloc( + tx_request_pdu_list[i].segments[j].segment_length, sizeof(uint8_t)); + memcpy(tx_request_pdu_list[i].segments[j].segment_data, + req->tx_request_body.tx_pdu_list[i].segments[j].segment_data, + tx_request_pdu_list[i].segments[j].segment_length); + } + } + } - - -int memcpy_tx_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req) -{ - - tx_req_num_elems = req->tx_request_body.number_of_pdus; - tx_request_pdu_list = (nfapi_tx_request_pdu_t*) calloc(tx_req_num_elems, sizeof(nfapi_tx_request_pdu_t)); - for (int i=0; itx_request_body.tx_pdu_list[i].num_segments; - tx_request_pdu_list[i].pdu_index = req->tx_request_body.tx_pdu_list[i].pdu_index; - tx_request_pdu_list[i].pdu_length = req->tx_request_body.tx_pdu_list[i].pdu_length; - for (int j=0; jtx_request_body.tx_pdu_list[i].num_segments; j++){ - //*tx_request_pdu_list[i].segments[j].segment_data = *req->tx_request_body.tx_pdu_list[i].segments[j].segment_data; - tx_request_pdu_list[i].segments[j].segment_length = req->tx_request_body.tx_pdu_list[i].segments[j].segment_length; - if(tx_request_pdu_list[i].segments[j].segment_length > 0){ - tx_request_pdu_list[i].segments[j].segment_data = (uint8_t*)malloc(tx_request_pdu_list[i].segments[j].segment_length*sizeof (uint8_t)); - memcpy(tx_request_pdu_list[i].segments[j].segment_data, req->tx_request_body.tx_pdu_list[i].segments[j].segment_data, tx_request_pdu_list[i].segments[j].segment_length); - } - } - - } - - return 0; + return 0; } -int memcpy_hi_dci0_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req) -{ +int memcpy_hi_dci0_req(nfapi_pnf_p7_config_t *pnf_p7, + nfapi_hi_dci0_request_t *req) { + hi_dci0_req = (nfapi_hi_dci0_request_t *)malloc(sizeof(nfapi_hi_dci0_request_t)); - //if(req!=0){ + hi_dci0_req->sfn_sf = req->sfn_sf; + hi_dci0_req->vendor_extension = req->vendor_extension; - //for (Mod_id=0; Mod_idhi_dci0_request_body.number_of_dci = req->hi_dci0_request_body.number_of_dci; + hi_dci0_req->hi_dci0_request_body.number_of_hi = req->hi_dci0_request_body.number_of_hi; + hi_dci0_req->hi_dci0_request_body.sfnsf = req->hi_dci0_request_body.sfnsf; - hi_dci0_req->sfn_sf = req->sfn_sf; - hi_dci0_req->vendor_extension = req->vendor_extension; + // UE_mac_inst[Mod_id].hi_dci0_req->hi_dci0_request_body.tl = + // req->hi_dci0_request_body.tl; + hi_dci0_req->hi_dci0_request_body.tl.tag = req->hi_dci0_request_body.tl.tag; + hi_dci0_req->hi_dci0_request_body.tl.length = req->hi_dci0_request_body.tl.length; - hi_dci0_req->hi_dci0_request_body.number_of_dci = req->hi_dci0_request_body.number_of_dci; - hi_dci0_req->hi_dci0_request_body.number_of_hi = req->hi_dci0_request_body.number_of_hi; - hi_dci0_req->hi_dci0_request_body.sfnsf = req->hi_dci0_request_body.sfnsf; + int total_pdus = hi_dci0_req->hi_dci0_request_body.number_of_dci + + hi_dci0_req->hi_dci0_request_body.number_of_hi; - //UE_mac_inst[Mod_id].hi_dci0_req->hi_dci0_request_body.tl = req->hi_dci0_request_body.tl; - hi_dci0_req->hi_dci0_request_body.tl.tag = req->hi_dci0_request_body.tl.tag; - hi_dci0_req->hi_dci0_request_body.tl.length = req->hi_dci0_request_body.tl.length; + hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list = + calloc(total_pdus, sizeof(nfapi_hi_dci0_request_pdu_t)); - int total_pdus = hi_dci0_req->hi_dci0_request_body.number_of_dci + hi_dci0_req->hi_dci0_request_body.number_of_hi; - - hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list = (nfapi_hi_dci0_request_pdu_t*) malloc(total_pdus*sizeof(nfapi_hi_dci0_request_pdu_t)); - - for(int i=0; ihi_dci0_request_body.hi_dci0_pdu_list[i] = req->hi_dci0_request_body.hi_dci0_pdu_list[i]; - //LOG_I(MAC, "Original hi_dci0 req. type:%d, Copy type: %d \n",req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type, UE_mac_inst[Mod_id].hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type); - } - - //} - return 0; + for (int i = 0; i < total_pdus; i++) { + hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list[i] = req->hi_dci0_request_body.hi_dci0_pdu_list[i]; + // LOG_I(MAC, "Original hi_dci0 req. type:%d, Copy type: %d + // \n",req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type, + // UE_mac_inst[Mod_id].hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type); + } + return 0; } - - void UE_config_stub_pnf(void) { - int j; + int j; paramdef_t L1_Params[] = L1PARAMS_DESC; - paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST,NULL,0}; + paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST, NULL, 0}; - config_getlist( &L1_ParamList,L1_Params,sizeof(L1_Params)/sizeof(paramdef_t), NULL); + config_getlist(&L1_ParamList, L1_Params, sizeof(L1_Params) / sizeof(paramdef_t), NULL); if (L1_ParamList.numelt > 0) { - for (j=0; jcarrier[0]; mib = &carrier->mib; - if(Srb_id == BCCH_SI_MBMS) { + if((Srb_id & RAB_OFFSET) == BCCH_SI_MBMS){ if (frameP%4 == 0) { memcpy(&buffer_pP[0], RC.rrc[Mod_idP]->carrier[CC_id].SIB1_MBMS, @@ -206,7 +204,7 @@ mac_rrc_data_req( RC.rrc[Mod_idP]->carrier[CC_id].sizeof_MCCH_MESSAGE[mbsfn_sync_area]); if (LOG_DEBUGFLAG(DEBUG_RRC)) { - LOG_D(RRC,"[eNB %d] Frame %d : MCCH request => MCCH_MESSAGE \n",Mod_idP,frameP); + LOG_W(RRC,"[eNB %d] Frame %d : MCCH request => MCCH_MESSAGE \n",Mod_idP,frameP); for (int i=0; icarrier[CC_id].sizeof_MCCH_MESSAGE[mbsfn_sync_area]; i++) { LOG_T(RRC,"%x.",buffer_pP[i]); @@ -299,10 +297,9 @@ mac_rrc_data_ind( if (ue_context_p->ue_context.Status != RRC_RECONFIGURED) { LOG_E(RRC,"[eNB %d] Received C-RNTI ,but UE %x status(%d) not RRC_RECONFIGURED\n",module_idP,rntiP,ue_context_p->ue_context.Status); return (-1); - } else { - rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt,ue_context_p,0); - ue_context_p->ue_context.Status = RRC_RECONFIGURED; - } + } + rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt,ue_context_p,0); + ue_context_p->ue_context.Status = RRC_RECONFIGURED; } } diff --git a/openair2/RRC/LTE/L2_interface_common.c b/openair2/RRC/LTE/L2_interface_common.c index 20df462938..fa332b5be1 100644 --- a/openair2/RRC/LTE/L2_interface_common.c +++ b/openair2/RRC/LTE/L2_interface_common.c @@ -37,9 +37,7 @@ #include "msc.h" #include "common/ran_context.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" //#define RRC_DATA_REQ_DEBUG //#define DEBUG_RRC 1 @@ -135,7 +133,6 @@ rrc_data_ind( ctxt_pP->rnti); } -#if defined(ENABLE_ITTI) { MessageDef *message_p; // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). @@ -152,11 +149,4 @@ rrc_data_ind( RRC_DCCH_DATA_IND (message_p).eNB_index = ctxt_pP->eNB_index; itti_send_msg_to_task (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, ctxt_pP->instance, message_p); } -#else - rrc_eNB_decode_dcch( - ctxt_pP, - DCCH_index, - buffer_pP, - sdu_sizeP); -#endif } diff --git a/openair2/RRC/LTE/L2_interface_ue.c b/openair2/RRC/LTE/L2_interface_ue.c index c9d4e61d0a..61ab63955d 100644 --- a/openair2/RRC/LTE/L2_interface_ue.c +++ b/openair2/RRC/LTE/L2_interface_ue.c @@ -37,9 +37,7 @@ #include "msc.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" //#define RRC_DATA_REQ_DEBUG @@ -76,7 +74,6 @@ mac_rrc_data_req_ue( LOG_D(RRC,"[UE %d] Frame %d buffer_pP status %d,\n",Mod_idP,frameP, UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); if( (UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size > 0) ) { -#if defined(ENABLE_ITTI) { MessageDef *message_p; int ccch_size = UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size; @@ -96,7 +93,6 @@ mac_rrc_data_req_ue( itti_send_msg_to_task (TASK_MAC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); } -#endif memcpy(&buffer_pP[0],&UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.Payload[0],UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); uint8_t Ret_size=UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size; // UE_rrc_inst[Mod_id].Srb0[eNB_index].Tx_buffer.payload_size=0; @@ -138,7 +134,6 @@ mac_rrc_data_ind_ue( if(srb_idP == BCCH_SI_MBMS) { LOG_D(RRC,"[UE %d] Received SDU for BCCH on MBMS SRB %ld from eNB %d\n",module_idP,srb_idP,eNB_indexP); -#if defined(ENABLE_ITTI) { MessageDef *message_p; int msg_sdu_size = sizeof(RRC_MAC_BCCH_MBMS_DATA_IND (message_p).sdu); @@ -161,14 +156,10 @@ mac_rrc_data_ind_ue( RRC_MAC_BCCH_MBMS_DATA_IND (message_p).rsrp = 45 /* TODO change phy to report rspp */; itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); } -#else - decode_BCCH_MBMS_DLSCH_Message(&ctxt,eNB_indexP,(uint8_t *)sduP,sdu_lenP, 0, 0); -#endif } if(srb_idP == BCCH) { LOG_D(RRC,"[UE %d] Received SDU for BCCH on SRB %ld from eNB %d\n",module_idP,srb_idP,eNB_indexP); -#if defined(ENABLE_ITTI) { MessageDef *message_p; int msg_sdu_size = sizeof(RRC_MAC_BCCH_DATA_IND (message_p).sdu); @@ -191,9 +182,6 @@ mac_rrc_data_ind_ue( RRC_MAC_BCCH_DATA_IND (message_p).rsrp = 45 /* TODO change phy to report rspp */; itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); } -#else - decode_BCCH_DLSCH_Message(&ctxt,eNB_indexP,(uint8_t *)sduP,sdu_lenP, 0, 0); -#endif } if(srb_idP == PCCH) { @@ -204,7 +192,6 @@ mac_rrc_data_ind_ue( if((srb_idP & RAB_OFFSET) == CCCH) { if (sdu_lenP>0) { LOG_T(RRC,"[UE %d] Received SDU for CCCH on SRB %ld from eNB %d\n",module_idP,srb_idP & RAB_OFFSET,eNB_indexP); -#if defined(ENABLE_ITTI) { MessageDef *message_p; int msg_sdu_size = CCCH_SDU_SIZE; @@ -226,20 +213,12 @@ mac_rrc_data_ind_ue( RRC_MAC_CCCH_DATA_IND (message_p).rnti = rntiP; itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); } -#else - SRB_INFO *Srb_info; - Srb_info = &UE_rrc_inst[module_idP].Srb0[eNB_indexP]; - memcpy(Srb_info->Rx_buffer.Payload,sduP,sdu_lenP); - Srb_info->Rx_buffer.payload_size = sdu_lenP; - rrc_ue_decode_ccch(&ctxt, Srb_info, eNB_indexP); -#endif } } if ((srb_idP & RAB_OFFSET) == MCCH) { LOG_T(RRC,"[UE %d] Frame %d: Received SDU on MBSFN sync area %d for MCCH on SRB %ld from eNB %d\n", module_idP,frameP, mbsfn_sync_areaP, srb_idP & RAB_OFFSET,eNB_indexP); -#if defined(ENABLE_ITTI) { MessageDef *message_p; int msg_sdu_size = sizeof(RRC_MAC_MCCH_DATA_IND (message_p).sdu); @@ -259,9 +238,6 @@ mac_rrc_data_ind_ue( RRC_MAC_MCCH_DATA_IND (message_p).mbsfn_sync_area = mbsfn_sync_areaP; itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); } -#else - decode_MCCH_Message(&ctxt, eNB_indexP, sduP, sdu_lenP, mbsfn_sync_areaP); -#endif } //TTN (for D2D) @@ -297,7 +273,6 @@ rrc_data_req_ue( ctxt_pP->rnti, muiP, sdu_sizeP); -#if defined(ENABLE_ITTI) { MessageDef *message_p; // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). @@ -325,18 +300,6 @@ rrc_data_req_ue( message_p); return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } -#else - return pdcp_data_req ( - ctxt_pP, - SRB_FLAG_YES, - rb_idP, - muiP, - confirmP, - sdu_sizeP, - buffer_pP, - modeP,NULL, NULL - ); -#endif } //------------------------------------------------------------------------------ @@ -352,7 +315,6 @@ rrc_data_ind_ue( rb_id_t DCCH_index = Srb_id; LOG_I(RRC, "[UE %x] Frame %d: received a DCCH %ld message on SRB %ld with Size %d from eNB %d\n", ctxt_pP->module_id, ctxt_pP->frame, DCCH_index,Srb_id,sdu_sizeP, ctxt_pP->eNB_index); -#if defined(ENABLE_ITTI) { MessageDef *message_p; // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). @@ -369,20 +331,11 @@ rrc_data_ind_ue( RRC_DCCH_DATA_IND (message_p).eNB_index = ctxt_pP->eNB_index; itti_send_msg_to_task (TASK_RRC_UE, ctxt_pP->instance, message_p); } -#else - //#warning "LG put 0 to arg4 that is eNB index" - rrc_ue_decode_dcch( - ctxt_pP, - DCCH_index, - buffer_pP, - 0); -#endif } //-------------------------------------------------------------------------------------------// void rrc_in_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) { //-------------------------------------------------------------------------------------------// -#if defined(ENABLE_ITTI) { MessageDef *message_p; //LOG_I(RRC,"sending a message to task_mac_ue\n"); @@ -391,14 +344,6 @@ void rrc_in_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) { RRC_MAC_IN_SYNC_IND (message_p).enb_index = eNB_index; itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); } -#else - UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt=0; - - if (UE_rrc_inst[Mod_idP].Info[eNB_index].T310_active==1) { - UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt++; - } - -#endif } //-------------------------------------------------------------------------------------------// @@ -412,7 +357,6 @@ void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt, UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt); -#if defined(ENABLE_ITTI) { MessageDef *message_p; message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_OUT_OF_SYNC_IND); @@ -420,9 +364,6 @@ void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index RRC_MAC_OUT_OF_SYNC_IND (message_p).enb_index = eNB_index; itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); } -#else - UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt++; -#endif } //------------------------------------------------------------------------------ @@ -442,16 +383,11 @@ mac_UE_get_rrc_status( //-------------------------------------------------------------------------------------------// int mac_ue_ccch_success_ind(module_id_t Mod_idP, uint8_t eNB_index) { //-------------------------------------------------------------------------------------------// -#if defined(ENABLE_ITTI) { MessageDef *message_p; message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_CCCH_DATA_CNF); RRC_MAC_CCCH_DATA_CNF (message_p).enb_index = eNB_index; itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); } -#else - // reset the tx buffer to indicate RRC that ccch was successfully transmitted (for example if contention resolution succeeds) - UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size=0; -#endif return 0; } diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.c b/openair2/RRC/LTE/MESSAGES/asn1_msg.c index 48cc432a06..583e10da94 100644 --- a/openair2/RRC/LTE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.c @@ -89,9 +89,9 @@ #include "LTE_MeasIdToAddModList.h" #include "enb_config.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif + +#include "intertask_interface.h" + #include "common/ran_context.h" #include "secu_defs.h" @@ -231,7 +231,7 @@ uint8_t do_MIB_FeMBMS(rrc_eNB_carrier_data_t *carrier, uint32_t N_RB_DL, uint32_ mib_fembms->message.spare.bits_unused = 6; // This makes a spare of 10 bits //TODO additionalNonBMSFNSubframes-r14 INTEGER (0..3) ? //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_LTE_BCCH_BCH_Message_MBMS, (void *)mib_fembms); + //xer_fprint(stdout, &asn_DEF_LTE_BCCH_BCH_Message_MBMS, (void *)mib_fembms); //} enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_BCCH_BCH_Message_MBMS, NULL, @@ -381,17 +381,12 @@ uint8_t do_MIB_SL(const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, } uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, - int Mod_id,int CC_id -#if defined(ENABLE_ITTI) - , RrcConfigurationReq *configuration -#endif + int Mod_id,int CC_id, + RrcConfigurationReq *configuration ) { // SystemInformation_t systemInformation; -#if defined(ENABLE_ITTI) int num_plmn = configuration->num_plmn; -#else - int num_plmn = 1; -#endif + LTE_PLMN_IdentityInfo_t *PLMN_identity_info; LTE_MCC_MNC_Digit_t *dummy_mcc_0; LTE_MCC_MNC_Digit_t *dummy_mcc_1; @@ -438,16 +433,10 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, if (dummy_mcc_0 == NULL || dummy_mcc_1 == NULL || dummy_mcc_2 == NULL) exit(1); - -#if defined(ENABLE_ITTI) *dummy_mcc_0 = (configuration->mcc[i] / 100) % 10; *dummy_mcc_1 = (configuration->mcc[i] / 10) % 10; *dummy_mcc_2 = (configuration->mcc[i] / 1) % 10; -#else - *dummy_mcc_0 = 0; - *dummy_mcc_1 = 0; - *dummy_mcc_2 = 1; -#endif + ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mcc->list, dummy_mcc_0); ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mcc->list, dummy_mcc_1); ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mcc->list, dummy_mcc_2); @@ -460,8 +449,6 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, if (dummy_mnc_0 == NULL || dummy_mnc_1 == NULL || dummy_mnc_2 == NULL) exit(1); -#if defined(ENABLE_ITTI) - if (configuration->mnc[i] >= 100) { *dummy_mnc_0 = (configuration->mnc[i] / 100) % 10; *dummy_mnc_1 = (configuration->mnc[i] / 10) % 10; @@ -478,11 +465,6 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, } } -#else - *dummy_mnc[i][0] = 0; - *dummy_mnc[i][1] = 1; - *dummy_mnc[i][2] = 0xf; -#endif ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mnc.list, dummy_mnc_0); ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mnc.list, dummy_mnc_1); @@ -499,36 +481,20 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, // 16 bits (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf = MALLOC(2); -#if defined(ENABLE_ITTI) (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf[0] = (configuration->tac >> 8) & 0xff; (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf[1] = (configuration->tac >> 0) & 0xff; -#else - (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf[0] = 0x00; - (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf[1] = 0x01; -#endif (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.size=2; (*sib1_MBMS)->cellAccessRelatedInfo_r14.trackingAreaCode_r14.bits_unused=0; // 28 bits (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf = MALLOC(8); -#if defined(ENABLE_ITTI) (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[0] = (configuration->cell_identity >> 20) & 0xff; (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[1] = (configuration->cell_identity >> 12) & 0xff; (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[2] = (configuration->cell_identity >> 4) & 0xff; (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[3] = (configuration->cell_identity << 4) & 0xf0; -#else - (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[0] = 0x00; - (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[1] = 0x00; - (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[2] = 0x00; - (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[3] = 0x10; -#endif (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.size=4; (*sib1_MBMS)->cellAccessRelatedInfo_r14.cellIdentity_r14.bits_unused=4; - (*sib1_MBMS)->freqBandIndicator_r14 = -#if defined(ENABLE_ITTI) - configuration->eutra_band[CC_id]; -#else - 7; -#endif + (*sib1_MBMS)->freqBandIndicator_r14 = configuration->eutra_band[CC_id]; + schedulingInfo->si_Periodicity_r14=LTE_SchedulingInfo__si_Periodicity_rf16; *sib_type = LTE_SIB_Type_MBMS_r14_sibType13_v920; ASN_SEQUENCE_ADD(&schedulingInfo->sib_MappingInfo_r14.list, sib_type); @@ -586,7 +552,7 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, } //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS, (void *)bcch_message); + //xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS, (void *)bcch_message); //} enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS, NULL, @@ -603,37 +569,123 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier, return((enc_rval.encoded+7)/8); } + //----------------------------------------------------------------------------- /* * Generate the configuration structure for CDRX feature */ -LTE_DRX_Config_t *do_DrxConfig(uint8_t Mod_id, - int CC_id, - RrcConfigurationReq *configuration, +LTE_DRX_Config_t *do_DrxConfig(int CC_id, + RrcConfigurationReq *configuration, LTE_UE_EUTRA_Capability_t *UEcap) //----------------------------------------------------------------------------- { + /* Check CC id */ + if (CC_id >= MAX_NUM_CCs) { + LOG_E(RRC, "[do_DrxConfig] Invalid CC_id for DRX configuration\n"); + return NULL; + } + + /* No CDRX configuration */ + if (configuration->radioresourceconfig[CC_id].drx_Config_present == LTE_DRX_Config_PR_NOTHING) { + return NULL; + } + + /* CDRX not implemented for TDD */ + if (configuration->frame_type[CC_id] == 1) { + LOG_E(RRC, "[do_DrxConfig] CDRX not implemented for TDD\n"); + return NULL; + } + + /* Need UE capabilities */ + if (!UEcap) { + LOG_E(RRC,"[do_DrxConfig] No UEcap pointer\n"); + return NULL; + } + + /* Check the UE capabilities, CDRX not implemented for Coverage Extension */ + LTE_UE_EUTRA_Capability_v920_IEs_t *cap_920 = NULL; + LTE_UE_EUTRA_Capability_v940_IEs_t *cap_940 = NULL; + LTE_UE_EUTRA_Capability_v1020_IEs_t *cap_1020 = NULL; + LTE_UE_EUTRA_Capability_v1060_IEs_t *cap_1060 = NULL; + LTE_UE_EUTRA_Capability_v1090_IEs_t *cap_1090 = NULL; + LTE_UE_EUTRA_Capability_v1130_IEs_t *cap_1130 = NULL; + LTE_UE_EUTRA_Capability_v1170_IEs_t *cap_1170 = NULL; + LTE_UE_EUTRA_Capability_v1180_IEs_t *cap_1180 = NULL; + LTE_UE_EUTRA_Capability_v11a0_IEs_t *cap_11a0 = NULL; + LTE_UE_EUTRA_Capability_v1250_IEs_t *cap_1250 = NULL; + LTE_UE_EUTRA_Capability_v1260_IEs_t *cap_1260 = NULL; + LTE_UE_EUTRA_Capability_v1270_IEs_t *cap_1270 = NULL; + LTE_UE_EUTRA_Capability_v1280_IEs_t *cap_1280 = NULL; + LTE_UE_EUTRA_Capability_v1310_IEs_t *cap_1310 = NULL; + LTE_CE_Parameters_r13_t *CE_param = NULL; + long *ce_a_param = NULL; + + cap_920 = UEcap->nonCriticalExtension; + if (cap_920) { + cap_940 = cap_920->nonCriticalExtension; + if (cap_940) { + cap_1020 = cap_940->nonCriticalExtension; + if (cap_1020) { + cap_1060 = cap_1020->nonCriticalExtension; + if (cap_1060) { + cap_1090 = cap_1060->nonCriticalExtension; + if (cap_1090) { + cap_1130 = cap_1090->nonCriticalExtension; + if (cap_1130) { + cap_1170 = cap_1130->nonCriticalExtension; + if (cap_1170) { + cap_1180 = cap_1170->nonCriticalExtension; + if (cap_1180) { + cap_11a0 = cap_1180->nonCriticalExtension; + if (cap_11a0) { + cap_1250 = cap_11a0->nonCriticalExtension; + if (cap_1250) { + cap_1260 = cap_1250->nonCriticalExtension; + if (cap_1260) { + cap_1270 = cap_1260->nonCriticalExtension; + if (cap_1270) { + cap_1280 = cap_1270->nonCriticalExtension; + if (cap_1280) { + cap_1310 = cap_1280->nonCriticalExtension; + if (cap_1310) { + CE_param = cap_1310->ce_Parameters_r13; + if (CE_param) { + ce_a_param = CE_param->ce_ModeA_r13; + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + + if (ce_a_param) { + LOG_E(RRC,"[do_DrxConfig] Coverage Extension not supported by CDRX\n"); + return NULL; + } + LTE_DRX_Config_t *drxConfig = NULL; BIT_STRING_t *featureGroupIndicators = NULL; bool ueSupportCdrxShortFlag = false; bool ueSupportCdrxLongFlag = false; /* Check the UE capabilities for short and long CDRX cycles support */ - if (UEcap) { - featureGroupIndicators = UEcap->featureGroupIndicators; - - if (featureGroupIndicators) { - if (featureGroupIndicators->size > 1 || (featureGroupIndicators->size == 1 && featureGroupIndicators->bits_unused < 4)) { - ueSupportCdrxShortFlag = ((featureGroupIndicators->buf[0] & (uint8_t) 0x10) > 0); - ueSupportCdrxLongFlag = ((featureGroupIndicators->buf[0] & (uint8_t) 0x08) > 0); - LOG_I(RRC,"[do_DrxConfig] featureGroupIndicators->buf[0]: %x\n", featureGroupIndicators->buf[0]); - } else LOG_W(RRC,"[do_DrxConfig] Not enough featureGroupIndicators bits\n"); - } else LOG_W(RRC,"[do_DrxConfig] No featureGroupIndicators pointer\n"); - } else LOG_W(RRC,"[do_DrxConfig] No UEcap pointer\n"); - - if (configuration->radioresourceconfig[CC_id].drx_Config_present == LTE_DRX_Config_PR_NOTHING) { - return NULL; - } + featureGroupIndicators = UEcap->featureGroupIndicators; + if (featureGroupIndicators) { + if (featureGroupIndicators->size > 1 || (featureGroupIndicators->size == 1 && featureGroupIndicators->bits_unused < 4)) { + ueSupportCdrxShortFlag = ((featureGroupIndicators->buf[0] & (uint8_t) 0x10) > 0); + ueSupportCdrxLongFlag = ((featureGroupIndicators->buf[0] & (uint8_t) 0x08) > 0); + LOG_D(RRC,"[do_DrxConfig] featureGroupIndicators->buf[0]: %x\n", featureGroupIndicators->buf[0]); + } else LOG_W(RRC,"[do_DrxConfig] Not enough featureGroupIndicators bits\n"); + } else LOG_W(RRC,"[do_DrxConfig] No featureGroupIndicators pointer\n"); drxConfig = (LTE_DRX_Config_t *) malloc(sizeof(LTE_DRX_Config_t)); @@ -651,74 +703,75 @@ LTE_DRX_Config_t *do_DrxConfig(uint8_t Mod_id, if (drxConfig->present == LTE_DRX_Config_PR_release) { drxConfig->choice.release = (NULL_t) 0; } else { - drxConfig->choice.setup.onDurationTimer = configuration->radioresourceconfig[CC_id].drx_onDurationTimer; - drxConfig->choice.setup.drx_InactivityTimer = configuration->radioresourceconfig[CC_id].drx_InactivityTimer; - drxConfig->choice.setup.drx_RetransmissionTimer = configuration->radioresourceconfig[CC_id].drx_RetransmissionTimer; - drxConfig->choice.setup.longDRX_CycleStartOffset.present = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset_present; + struct LTE_DRX_Config__setup *choiceSetup = &drxConfig->choice.setup; + choiceSetup->onDurationTimer = configuration->radioresourceconfig[CC_id].drx_onDurationTimer; + choiceSetup->drx_InactivityTimer = configuration->radioresourceconfig[CC_id].drx_InactivityTimer; + choiceSetup->drx_RetransmissionTimer = configuration->radioresourceconfig[CC_id].drx_RetransmissionTimer; + choiceSetup->longDRX_CycleStartOffset.present = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset_present; - switch (drxConfig->choice.setup.longDRX_CycleStartOffset.present) { - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf10: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf10 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + switch (choiceSetup->longDRX_CycleStartOffset.present) { + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf10: + choiceSetup->longDRX_CycleStartOffset.choice.sf10 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf20: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf20 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf20: + choiceSetup->longDRX_CycleStartOffset.choice.sf20 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf32: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf32 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf32: + choiceSetup->longDRX_CycleStartOffset.choice.sf32 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf40: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf40 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf40: + choiceSetup->longDRX_CycleStartOffset.choice.sf40 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf64: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf64 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf64: + choiceSetup->longDRX_CycleStartOffset.choice.sf64 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf80: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf80 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf80: + choiceSetup->longDRX_CycleStartOffset.choice.sf80 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf128: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf128 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf128: + choiceSetup->longDRX_CycleStartOffset.choice.sf128 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf160: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf160 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf160: + choiceSetup->longDRX_CycleStartOffset.choice.sf160 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf256: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf256 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf256: + choiceSetup->longDRX_CycleStartOffset.choice.sf256 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf320: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf320 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf320: + choiceSetup->longDRX_CycleStartOffset.choice.sf320 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf512: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf512 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf512: + choiceSetup->longDRX_CycleStartOffset.choice.sf512 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf640: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf640 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf640: + choiceSetup->longDRX_CycleStartOffset.choice.sf640 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf1024: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf1024 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf1024: + choiceSetup->longDRX_CycleStartOffset.choice.sf1024 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf1280: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf1280 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf1280: + choiceSetup->longDRX_CycleStartOffset.choice.sf1280 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf2048: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf2048 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf2048: + choiceSetup->longDRX_CycleStartOffset.choice.sf2048 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; - case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf2560: - drxConfig->choice.setup.longDRX_CycleStartOffset.choice.sf2560 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; + case LTE_DRX_Config__setup__longDRX_CycleStartOffset_PR_sf2560: + choiceSetup->longDRX_CycleStartOffset.choice.sf2560 = configuration->radioresourceconfig[CC_id].drx_longDrx_CycleStartOffset; break; default: @@ -727,12 +780,12 @@ LTE_DRX_Config_t *do_DrxConfig(uint8_t Mod_id, /* Short DRX cycle configuration */ if (!ueSupportCdrxShortFlag || configuration->radioresourceconfig[CC_id].drx_shortDrx_ShortCycleTimer == 0) { - drxConfig->choice.setup.shortDRX = NULL; + choiceSetup->shortDRX = NULL; } else { - drxConfig->choice.setup.shortDRX = MALLOC(sizeof(struct LTE_DRX_Config__setup__shortDRX)); - memset(drxConfig->choice.setup.shortDRX, 0, sizeof(struct LTE_DRX_Config__setup__shortDRX)); - drxConfig->choice.setup.shortDRX->shortDRX_Cycle = configuration->radioresourceconfig[CC_id].drx_shortDrx_Cycle; - drxConfig->choice.setup.shortDRX->drxShortCycleTimer = configuration->radioresourceconfig[CC_id].drx_shortDrx_ShortCycleTimer; + choiceSetup->shortDRX = MALLOC(sizeof(struct LTE_DRX_Config__setup__shortDRX)); + memset(choiceSetup->shortDRX, 0, sizeof(struct LTE_DRX_Config__setup__shortDRX)); + choiceSetup->shortDRX->shortDRX_Cycle = configuration->radioresourceconfig[CC_id].drx_shortDrx_Cycle; + choiceSetup->shortDRX->drxShortCycleTimer = configuration->radioresourceconfig[CC_id].drx_shortDrx_ShortCycleTimer; } } @@ -740,17 +793,11 @@ LTE_DRX_Config_t *do_DrxConfig(uint8_t Mod_id, } uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, - int Mod_id,int CC_id, BOOLEAN_t brOption -#if defined(ENABLE_ITTI) - , RrcConfigurationReq *configuration -#endif + int Mod_id,int CC_id, BOOLEAN_t brOption, + RrcConfigurationReq *configuration ) { // SystemInformation_t systemInformation; -#if defined(ENABLE_ITTI) int num_plmn = configuration->num_plmn; -#else - int num_plmn = 1; -#endif LTE_PLMN_IdentityInfo_t *PLMN_identity_info; LTE_MCC_MNC_Digit_t *dummy_mcc_0; LTE_MCC_MNC_Digit_t *dummy_mcc_1; @@ -759,8 +806,8 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, LTE_MCC_MNC_Digit_t *dummy_mnc_1; LTE_MCC_MNC_Digit_t *dummy_mnc_2; asn_enc_rval_t enc_rval; - LTE_SchedulingInfo_t *schedulingInfo; - LTE_SIB_Type_t *sib_type; + LTE_SchedulingInfo_t schedulingInfo,schedulingInfo2; + LTE_SIB_Type_t sib_type,sib_type2; uint8_t *buffer; LTE_BCCH_DL_SCH_Message_t *bcch_message; LTE_SystemInformationBlockType1_t **sib1; @@ -785,15 +832,13 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, if (PLMN_identity_info == NULL) exit(1); - schedulingInfo = CALLOC(1, sizeof(LTE_SchedulingInfo_t)); - - if (schedulingInfo == NULL) - exit(1); - - sib_type = CALLOC(1, sizeof(LTE_SIB_Type_t)); - - if (sib_type == NULL) - exit(1); + memset(PLMN_identity_info,0,num_plmn * sizeof(LTE_PLMN_IdentityInfo_t)); + memset(&schedulingInfo,0,sizeof(LTE_SchedulingInfo_t)); + memset(&sib_type,0,sizeof(LTE_SIB_Type_t)); + if(configuration->eMBMS_M2_configured){ + memset(&schedulingInfo2,0,sizeof(LTE_SchedulingInfo_t)); + memset(&sib_type2,0,sizeof(LTE_SIB_Type_t)); + } /* as per TS 36.311, up to 6 PLMN_identity_info are allowed in list -> add one by one */ for (int i = 0; i < num_plmn; ++i) { @@ -807,15 +852,10 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, if (dummy_mcc_0 == NULL || dummy_mcc_1 == NULL || dummy_mcc_2 == NULL) exit(1); -#if defined(ENABLE_ITTI) + *dummy_mcc_0 = (configuration->mcc[i] / 100) % 10; *dummy_mcc_1 = (configuration->mcc[i] / 10) % 10; *dummy_mcc_2 = (configuration->mcc[i] / 1) % 10; -#else - *dummy_mcc_0 = 0; - *dummy_mcc_1 = 0; - *dummy_mcc_2 = 1; -#endif ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mcc->list, dummy_mcc_0); ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mcc->list, dummy_mcc_1); ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mcc->list, dummy_mcc_2); @@ -828,7 +868,6 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, if (dummy_mnc_0 == NULL || dummy_mnc_1 == NULL || dummy_mnc_2 == NULL) exit(1); -#if defined(ENABLE_ITTI) if (configuration->mnc[i] >= 100) { *dummy_mnc_0 = (configuration->mnc[i] / 100) % 10; @@ -845,12 +884,6 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, *dummy_mnc_2 = (configuration->mnc[i] / 1) % 10; } } - -#else - *dummy_mnc_0 = 0; - *dummy_mnc_1 = 1; - *dummy_mnc_2 = 0xf; -#endif ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mnc.list, dummy_mnc_0); ASN_SEQUENCE_ADD(&PLMN_identity_info[i].plmn_Identity.mnc.list, dummy_mnc_1); @@ -867,28 +900,16 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, // 16 bits (*sib1)->cellAccessRelatedInfo.trackingAreaCode.buf = MALLOC(2); -#if defined(ENABLE_ITTI) (*sib1)->cellAccessRelatedInfo.trackingAreaCode.buf[0] = (configuration->tac >> 8) & 0xff; (*sib1)->cellAccessRelatedInfo.trackingAreaCode.buf[1] = (configuration->tac >> 0) & 0xff; -#else - (*sib1)->cellAccessRelatedInfo.trackingAreaCode.buf[0] = 0x00; - (*sib1)->cellAccessRelatedInfo.trackingAreaCode.buf[1] = 0x01; -#endif (*sib1)->cellAccessRelatedInfo.trackingAreaCode.size = 2; (*sib1)->cellAccessRelatedInfo.trackingAreaCode.bits_unused = 0; // 28 bits (*sib1)->cellAccessRelatedInfo.cellIdentity.buf = MALLOC(8); -#if defined(ENABLE_ITTI) (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[0] = (configuration->cell_identity >> 20) & 0xff; (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[1] = (configuration->cell_identity >> 12) & 0xff; (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[2] = (configuration->cell_identity >> 4) & 0xff; (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[3] = (configuration->cell_identity << 4) & 0xf0; -#else - (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[0] = 0x00; - (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[1] = 0x00; - (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[2] = 0x00; - (*sib1)->cellAccessRelatedInfo.cellIdentity.buf[3] = 0x10; -#endif (*sib1)->cellAccessRelatedInfo.cellIdentity.size=4; (*sib1)->cellAccessRelatedInfo.cellIdentity.bits_unused=4; // assign_enum(&(*sib1)->cellAccessRelatedInfo.cellBarred,SystemInformationBlockType1__cellAccessRelatedInfo__cellBarred_notBarred); @@ -900,36 +921,27 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, (*sib1)->cellSelectionInfo.q_RxLevMinOffset=NULL; //(*sib1)->p_Max = CALLOC(1, sizeof(P_Max_t)); // *((*sib1)->p_Max) = 23; - (*sib1)->freqBandIndicator = -#if defined(ENABLE_ITTI) - configuration->eutra_band[CC_id]; -#else - 7; -#endif - schedulingInfo->si_Periodicity=LTE_SchedulingInfo__si_Periodicity_rf8; + (*sib1)->freqBandIndicator = configuration->eutra_band[CC_id]; + schedulingInfo.si_Periodicity=LTE_SchedulingInfo__si_Periodicity_rf8; + if(configuration->eMBMS_M2_configured){ + schedulingInfo2.si_Periodicity=LTE_SchedulingInfo__si_Periodicity_rf8; + } // This is for SIB2/3 - *sib_type = LTE_SIB_Type_sibType3; - ASN_SEQUENCE_ADD(&schedulingInfo->sib_MappingInfo.list, sib_type); - ASN_SEQUENCE_ADD(&(*sib1)->schedulingInfoList.list, schedulingInfo); + sib_type=LTE_SIB_Type_sibType3; + ASN_SEQUENCE_ADD(&schedulingInfo.sib_MappingInfo.list,&sib_type); + ASN_SEQUENCE_ADD(&(*sib1)->schedulingInfoList.list,&schedulingInfo); + if(configuration->eMBMS_M2_configured){ + sib_type2=LTE_SIB_Type_sibType13_v920; + ASN_SEQUENCE_ADD(&schedulingInfo2.sib_MappingInfo.list,&sib_type2); + ASN_SEQUENCE_ADD(&(*sib1)->schedulingInfoList.list,&schedulingInfo2); + } // ASN_SEQUENCE_ADD(&schedulingInfo.sib_MappingInfo.list,NULL); -#if defined(ENABLE_ITTI) if (configuration->frame_type[CC_id] == TDD) -#endif { (*sib1)->tdd_Config = CALLOC(1,sizeof(struct LTE_TDD_Config)); - (*sib1)->tdd_Config->subframeAssignment = -#if defined(ENABLE_ITTI) - configuration->tdd_config[CC_id]; -#else - 3; // +kogo this was frame_parms->tdd_config -#endif - (*sib1)->tdd_Config->specialSubframePatterns = -#if defined(ENABLE_ITTI) - configuration->tdd_config_s[CC_id]; -#else - 0; -#endif + (*sib1)->tdd_Config->subframeAssignment = configuration->tdd_config[CC_id]; + (*sib1)->tdd_Config->specialSubframePatterns = configuration->tdd_config_s[CC_id]; } (*sib1)->si_WindowLength = LTE_SystemInformationBlockType1__si_WindowLength_ms20; @@ -957,8 +969,6 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, sib1_1250->freqBandIndicatorPriority_r12 = 0; // long* // FIXME sib1_1250->nonCriticalExtension = NULL; ////Rel1310 -#if defined(ENABLE_ITTI) - if ((configuration->schedulingInfoSIB1_BR_r13[CC_id] != 0) && (brOption==TRUE)) { sib1_1250->nonCriticalExtension = calloc(1, sizeof(LTE_SystemInformationBlockType1_v1310_IEs_t)); @@ -1152,89 +1162,6 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, sib1_1320->nonCriticalExtension = NULL; } -#else - sib1_1250->nonCriticalExtension = calloc(1, sizeof(LTE_SystemInformationBlockType1_v1310_IEs_t)); - memset(sib1_1250->nonCriticalExtension, 0, sizeof(LTE_SystemInformationBlockType1_v1310_IEs_t)); - SystemInformationBlockType1_v1310_IEs_t *sib1_1310 = sib1_1250->nonCriticalExtension; - sib1_1310->hyperSFN_r13 = calloc(1, sizeof(BIT_STRING_t)); // type - memset(sib1_1310->hyperSFN_r13, 0, sizeof(BIT_STRING_t)); - sib1_1310->hyperSFN_r13->buf = calloc(2, sizeof(uint8_t)); - memset(sib1_1310->hyperSFN_r13->buf, 0, 2*sizeof(uint8_t)); - sib1_1310->hyperSFN_r13->size = 2; - sib1_1310->hyperSFN_r13->bits_unused = 6; - sib1_1310->eDRX_Allowed_r13 = NULL; // long* - sib1_1310->cellSelectionInfoCE_r13 = calloc(1, sizeof(LTE_CellSelectionInfoCE_r13_t)); - memset(sib1_1310->cellSelectionInfoCE_r13, 0, sizeof(LTE_CellSelectionInfoCE_r13_t)); - sib1_1310->cellSelectionInfoCE_r13->q_RxLevMinCE_r13 = -70; // (Q_RxLevMin_t) long - sib1_1310->cellSelectionInfoCE_r13->q_QualMinRSRQ_CE_r13 = NULL; // (Q_RxLevMin_t) *long - sib1_1310->bandwidthReducedAccessRelatedInfo_r13 - = calloc(1, sizeof(struct LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13)); - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13 - = LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms20; // 0 - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->si_RepetitionPattern_r13 - = LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_everyRF; // 0 - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13 = calloc(1, sizeof(LTE_SchedulingInfoList_BR_r13_t)); - SchedulingInfo_BR_r13_t *schedulinginfo_br_13 = calloc(1, sizeof(LTE_SchedulingInfo_BR_r13_t)); - memset(schedulinginfo_br_13, 0, sizeof(LTE_SchedulingInfo_BR_r13_t)); - schedulinginfo_br_13->si_Narrowband_r13 = 1; - schedulinginfo_br_13->si_TBS_r13 = LTE_SchedulingInfo_BR_r13__si_TBS_r13_b152; - ASN_SEQUENCE_ADD(&sib1_1310->bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13->list, schedulinginfo_br_13); - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13 - = calloc(1, sizeof(struct LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__fdd_DownlinkOrTddSubframeBitmapBR_r13)); - memset(sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13, 0, - sizeof(struct LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__fdd_DownlinkOrTddSubframeBitmapBR_r13)); - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13->present - = LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__fdd_DownlinkOrTddSubframeBitmapBR_r13_PR_subframePattern10_r13; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13->choice.subframePattern10_r13.buf = calloc(2, sizeof(uint8_t)); - memset(sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13->choice.subframePattern10_r13.buf, 0, 2 * sizeof(uint8_t)); - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13->choice.subframePattern10_r13.size = 2; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_DownlinkOrTddSubframeBitmapBR_r13->choice.subframePattern10_r13.bits_unused = 6; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_UplinkSubframeBitmapBR_r13 = calloc(1, sizeof(BIT_STRING_t)); - memset(sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_UplinkSubframeBitmapBR_r13, 0, sizeof(BIT_STRING_t)); - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_UplinkSubframeBitmapBR_r13->buf = calloc(2, sizeof(uint8_t)); - memset(sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_UplinkSubframeBitmapBR_r13->buf, 0, - 2 * sizeof(uint8_t)); - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_UplinkSubframeBitmapBR_r13->size = 2; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->fdd_UplinkSubframeBitmapBR_r13->bits_unused = 6; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13 = 1; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->si_HoppingConfigCommon_r13 - = LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_HoppingConfigCommon_r13_on; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->si_ValidityTime_r13 = calloc(1, sizeof(long)); - memset(sib1_1310->bandwidthReducedAccessRelatedInfo_r13->si_ValidityTime_r13, 0, sizeof(long)); - *sib1_1310->bandwidthReducedAccessRelatedInfo_r13->si_ValidityTime_r13 - = LTE_SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_ValidityTime_r13_true; - sib1_1310->bandwidthReducedAccessRelatedInfo_r13->systemInfoValueTagList_r13 = calloc(1, sizeof(LTE_SystemInfoValueTagList_r13_t)); - LTE_SystemInfoValueTagSI_r13_t *systemInfoValueTagSi_r13 = CALLOC(1, sizeof(LTE_SystemInfoValueTagSI_r13_t)); - *systemInfoValueTagSi_r13 = 0; - ASN_SEQUENCE_ADD(&sib1_1310->bandwidthReducedAccessRelatedInfo_r13->systemInfoValueTagList_r13->list, systemInfoValueTagSi_r13); - sib1_1310->nonCriticalExtension = calloc(1, sizeof(LTE_SystemInformationBlockType1_v1320_IEs_t)); - memset(sib1_1310->nonCriticalExtension, 0, sizeof(LTE_SystemInformationBlockType1_v1320_IEs_t)); - /////Rel1320 - LTE_SystemInformationBlockType1_v1320_IEs_t *sib1_1320 = sib1_1310->nonCriticalExtension; - sib1_1320->freqHoppingParametersDL_r13 = calloc(1, sizeof(struct LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13)); - memset(sib1_1320->freqHoppingParametersDL_r13, 0, sizeof(struct LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13)); - sib1_1320->freqHoppingParametersDL_r13->mpdcch_pdsch_HoppingNB_r13 = calloc(1, sizeof(long)); - *sib1_1320->freqHoppingParametersDL_r13->mpdcch_pdsch_HoppingNB_r13 = LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__mpdcch_pdsch_HoppingNB_r13_nb2; - sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeA_r13 = calloc(1, - sizeof(struct LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeA_r13)); - memset(sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeA_r13, 0, - sizeof(struct LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeA_r13)); - sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeA_r13->present = - LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeA_r13_PR_interval_FDD_r13; - sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeA_r13->choice.interval_FDD_r13 = - LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeA_r13__interval_FDD_r13_int1; - sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeB_r13 = calloc(1, - sizeof(struct LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeB_r13)); - memset(sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeB_r13, 0, - sizeof(struct LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeB_r13)); - sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeB_r13->present = - LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeB_r13_PR_interval_FDD_r13; - sib1_1320->freqHoppingParametersDL_r13->interval_DLHoppingConfigCommonModeB_r13->choice.interval_FDD_r13 = - LTE_SystemInformationBlockType1_v1320_IEs__freqHoppingParametersDL_r13__interval_DLHoppingConfigCommonModeB_r13__interval_FDD_r13_int2; - sib1_1320->freqHoppingParametersDL_r13->mpdcch_pdsch_HoppingOffset_r13 = calloc(1, sizeof(long)); - *sib1_1320->freqHoppingParametersDL_r13->mpdcch_pdsch_HoppingOffset_r13 = 1; - sib1_1320->nonCriticalExtension = NULL; -#endif (*sib1)->si_WindowLength=LTE_SystemInformationBlockType1__si_WindowLength_ms20; (*sib1)->systemInfoValueTag=0; // (*sib1).nonCriticalExtension = calloc(1,sizeof(*(*sib1).nonCriticalExtension)); @@ -1265,10 +1192,8 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, uint8_t do_SIB23(uint8_t Mod_id, - int CC_id, BOOLEAN_t brOption -#if defined(ENABLE_ITTI) - , RrcConfigurationReq *configuration -#endif + int CC_id, BOOLEAN_t brOption, + RrcConfigurationReq *configuration ) { struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *sib2_part,*sib3_part; int eMTC_configured = configuration->eMTC_configured; @@ -1362,7 +1287,6 @@ uint8_t do_SIB23(uint8_t Mod_id, (*sib2)->ac_BarringInfo = NULL; (*sib2)->ext1 = NULL; (*sib2)->ext2 = NULL; -#if defined(ENABLE_ITTI) (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.numberOfRA_Preambles = rrconfig->rach_numberOfRA_Preambles; (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig = NULL; @@ -1753,121 +1677,7 @@ uint8_t do_SIB23(uint8_t Mod_id, = rrconfig->ue_TimersAndConstants_t311; (*sib2)->ue_TimersAndConstants.n311 = rrconfig->ue_TimersAndConstants_n311; -#else - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.numberOfRA_Preambles=LTE_RACH_ConfigCommon__preambleInfo__numberOfRA_Preambles_n64; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig = NULL; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.powerRampingStep=LTE_RACH_ConfigCommon__powerRampingParameters__powerRampingStep_dB2; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.preambleInitialReceivedTargetPower= - RACH_ConfigCommon__powerRampingParameters__preambleInitialReceivedTargetPower_dBm_100; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.preambleTransMax=LTE_RACH_ConfigCommon__ra_SupervisionInfo__preambleTransMax_n10; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.ra_ResponseWindowSize=LTE_RACH_ConfigCommon__ra_SupervisionInfo__ra_ResponseWindowSize_sf10; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.mac_ContentionResolutionTimer= - LTE_RACH_ConfigCommon__ra_SupervisionInfo__mac_ContentionResolutionTimer_sf48; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.maxHARQ_Msg3Tx = 4; - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1 = calloc(1, sizeof(struct LTE_RACH_ConfigCommon__ext1)); - memset((*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1, 0, sizeof(struct LTE_RACH_ConfigCommon__ext1)); - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1->preambleTransMax_CE_r13 = calloc(1, sizeof(LTE_PreambleTransMax_t)); - *(*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1->preambleTransMax_CE_r13 = LTE_PreambleTransMax_n5; // to be re-initialized when we find the enum - (*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1->rach_CE_LevelInfoList_r13 = calloc(1, sizeof(LTE_RACH_CE_LevelInfoList_r13_t)); - memset((*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1->rach_CE_LevelInfoList_r13, 0, sizeof(LTE_RACH_CE_LevelInfoList_r13_t)); - LTE_RACH_CE_LevelInfo_r13_t *rach_ce_levelinfo_r13 = calloc(1, sizeof(LTE_RACH_CE_LevelInfo_r13_t)); - memset(rach_ce_levelinfo_r13, 0, sizeof(LTE_RACH_CE_LevelInfo_r13_t)); - rach_ce_levelinfo_r13->preambleMappingInfo_r13.firstPreamble_r13 = 0; - rach_ce_levelinfo_r13->preambleMappingInfo_r13.lastPreamble_r13 = 63; - rach_ce_levelinfo_r13->ra_ResponseWindowSize_r13 = LTE_RACH_CE_LevelInfo_r13__ra_ResponseWindowSize_r13_sf80; - rach_ce_levelinfo_r13->mac_ContentionResolutionTimer_r13 = LTE_RACH_CE_LevelInfo_r13__mac_ContentionResolutionTimer_r13_sf200; - rach_ce_levelinfo_r13->rar_HoppingConfig_r13 = LTE_RACH_CE_LevelInfo_r13__rar_HoppingConfig_r13_off; - ASN_SEQUENCE_ADD(&(*sib2)->radioResourceConfigCommon.rach_ConfigCommon.ext1->rach_CE_LevelInfoList_r13->list, rach_ce_levelinfo_r13); - // BCCH-Config - (*sib2)->radioResourceConfigCommon.bcch_Config.modificationPeriodCoeff=LTE_BCCH_Config__modificationPeriodCoeff_n2; - // PCCH-Config - (*sib2)->radioResourceConfigCommon.pcch_Config.defaultPagingCycle = LTE_PCCH_Config__defaultPagingCycle_rf128; - (*sib2)->radioResourceConfigCommon.pcch_Config.nB=LTE_PCCH_Config__nB_oneT; - // PRACH-Config - (*sib2)->radioResourceConfigCommon.prach_Config.rootSequenceIndex = Mod_id;//0;//384; - (*sib2)->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.prach_ConfigIndex = 0;//3; - (*sib2)->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.highSpeedFlag = 0; - (*sib2)->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig = 1;//12; - (*sib2)->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.prach_FreqOffset = 2; - // PDSCH-Config - (*sib2)->radioResourceConfigCommon.pdsch_ConfigCommon.referenceSignalPower=0; // corresponds to 24.7 dBm 5 MHz/ 27.7 10 MHz/ 30.7 20 MHz - (*sib2)->radioResourceConfigCommon.pdsch_ConfigCommon.p_b=0; - // PUSCH-Config - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.n_SB=1; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode=LTE_PUSCH_ConfigCommon__pusch_ConfigBasic__hoppingMode_interSubFrame; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset=0; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM=0; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled=1; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH=0; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled=0; - (*sib2)->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift=0; - // PUCCH-Config - (*sib2)->radioResourceConfigCommon.pucch_ConfigCommon.deltaPUCCH_Shift=LTE_PUCCH_ConfigCommon__deltaPUCCH_Shift_ds1; - (*sib2)->radioResourceConfigCommon.pucch_ConfigCommon.nRB_CQI = 1; - (*sib2)->radioResourceConfigCommon.pucch_ConfigCommon.nCS_AN = 0; - (*sib2)->radioResourceConfigCommon.pucch_ConfigCommon.n1PUCCH_AN = 32; - (*sib2)->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present=LTE_SoundingRS_UL_ConfigCommon_PR_release; - (*sib2)->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.release=0; - // uplinkPowerControlCommon - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.p0_NominalPUSCH = -108; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.p0_NominalPUCCH = -108; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.alpha=LTE_UplinkPowerControlCommon__alpha_al1; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1=LTE_DeltaFList_PUCCH__deltaF_PUCCH_Format1_deltaF2; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1b=LTE_DeltaFList_PUCCH__deltaF_PUCCH_Format1b_deltaF3; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2=LTE_DeltaFList_PUCCH__deltaF_PUCCH_Format2_deltaF0; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2a=LTE_DeltaFList_PUCCH__deltaF_PUCCH_Format2a_deltaF0; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2b=LTE_DeltaFList_PUCCH__deltaF_PUCCH_Format2b_deltaF0; - (*sib2)->radioResourceConfigCommon.uplinkPowerControlCommon.deltaPreambleMsg3 = 6; - (*sib2)->radioResourceConfigCommon.ul_CyclicPrefixLength=UL_CyclicPrefixLength_len1; - (*sib2)->radioResourceConfigCommon.ext4 = calloc(1, sizeof(struct LTE_RadioResourceConfigCommonSIB__ext4)); - memset((*sib2)->radioResourceConfigCommon.ext4, 0, sizeof(struct LTE_RadioResourceConfigCommonSIB__ext4)); - (*sib2)->radioResourceConfigCommon.ext4->bcch_Config_v1310 = calloc(1, sizeof(LTE_BCCH_Config_v1310_t)); - memset((*sib2)->radioResourceConfigCommon.ext4->bcch_Config_v1310, 0, sizeof(LTE_BCCH_Config_v1310_t)); - (*sib2)->radioResourceConfigCommon.ext4->bcch_Config_v1310->modificationPeriodCoeff_v1310 = LTE_BCCH_Config_v1310__modificationPeriodCoeff_v1310_n64; - (*sib2)->radioResourceConfigCommon.ext4->pcch_Config_v1310 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->freqHoppingParameters_r13 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->pdsch_ConfigCommon_v1310 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->pusch_ConfigCommon_v1310 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310 = calloc(1, sizeof(LTE_PRACH_ConfigSIB_v1310_t)); - memset((*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310, 0, sizeof(PRACH_ConfigSIB_v1310_t)); - LTE_RSRP_Range_t rsrp_range = 60; - ASN_SEQUENCE_ADD(&(*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->rsrp_ThresholdsPrachInfoList_r13.list, &rsrp_range); - (*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->mpdcch_startSF_CSS_RA_r13 = calloc(1, sizeof(struct LTE_PRACH_ConfigSIB_v1310__mpdcch_startSF_CSS_RA_r13)); - memset((*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->mpdcch_startSF_CSS_RA_r13, 0, sizeof(struct LTE_PRACH_ConfigSIB_v1310__mpdcch_startSF_CSS_RA_r13)); - (*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->mpdcch_startSF_CSS_RA_r13->present = LTE_PRACH_ConfigSIB_v1310__mpdcch_startSF_CSS_RA_r13_PR_fdd_r13; - (*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->mpdcch_startSF_CSS_RA_r13->choice.fdd_r13 = LTE_PRACH_ConfigSIB_v1310__mpdcch_startSF_CSS_RA_r13__fdd_r13_v5; - (*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->prach_HoppingOffset_r13 = NULL; - LTE_PRACH_ParametersCE_r13_t *prach_parametersce_r13 = calloc(1, sizeof(LTE_PRACH_ParametersCE_r13_t)); - memset(prach_parametersce_r13, 0, sizeof(LTE_PRACH_ParametersCE_r13_t)); - prach_parametersce_r13->prach_ConfigIndex_r13 = 3; - prach_parametersce_r13->prach_FreqOffset_r13 = 1; - prach_parametersce_r13->prach_StartingSubframe_r13 = NULL; - prach_parametersce_r13->maxNumPreambleAttemptCE_r13 = calloc(1, sizeof(long)); - *prach_parametersce_r13->maxNumPreambleAttemptCE_r13 = LTE_PRACH_ParametersCE_r13__maxNumPreambleAttemptCE_r13_n3; - prach_parametersce_r13->numRepetitionPerPreambleAttempt_r13 = LTE_PRACH_ParametersCE_r13__numRepetitionPerPreambleAttempt_r13_n1; - long maxavailablenarrowband = 2; - ASN_SEQUENCE_ADD(&prach_parametersce_r13->mpdcch_NarrowbandsToMonitor_r13.list, &maxavailablenarrowband); - prach_parametersce_r13->mpdcch_NumRepetition_RA_r13 = LTE_PRACH_ParametersCE_r13__mpdcch_NumRepetition_RA_r13_r1; - prach_parametersce_r13->prach_HoppingConfig_r13 = LTE_PRACH_ParametersCE_r13__prach_HoppingConfig_r13_off; - ASN_SEQUENCE_ADD(&(*sib2)->radioResourceConfigCommon.ext4->prach_ConfigCommon_v1310->prach_ParametersListCE_r13.list, prach_parametersce_r13); - (*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310 = calloc(1, sizeof(LTE_PUCCH_ConfigCommon_v1310_t)); - memset((*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310, 0, sizeof(LTE_PUCCH_ConfigCommon_v1310_t)); - (*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->n1PUCCH_AN_InfoList_r13 = calloc(1, sizeof(LTE_N1PUCCH_AN_InfoList_r13_t)); - long pucch_info_value1 = 0; - long pucch_info_value2 = 2; - ASN_SEQUENCE_ADD(&(*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->n1PUCCH_AN_InfoList_r13->list, &pucch_info_value1); - ASN_SEQUENCE_ADD(&(*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->n1PUCCH_AN_InfoList_r13->list, &pucch_info_value2); - (*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->pucch_NumRepetitionCE_Msg4_Level0_r13 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->pucch_NumRepetitionCE_Msg4_Level1_r13 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->pucch_NumRepetitionCE_Msg4_Level2_r13 = NULL; - (*sib2)->radioResourceConfigCommon.ext4->pucch_ConfigCommon_v1310->pucch_NumRepetitionCE_Msg4_Level3_r13 = NULL; - (*sib2)->ue_TimersAndConstants.t300=UE_TimersAndConstants__t300_ms1000; - (*sib2)->ue_TimersAndConstants.t301=UE_TimersAndConstants__t301_ms1000; - (*sib2)->ue_TimersAndConstants.t310=UE_TimersAndConstants__t310_ms1000; - (*sib2)->ue_TimersAndConstants.n310=UE_TimersAndConstants__n310_n20; - (*sib2)->ue_TimersAndConstants.t311=UE_TimersAndConstants__t311_ms10000; - (*sib2)->ue_TimersAndConstants.n311=UE_TimersAndConstants__n311_n1; -#endif + (*sib2)->freqInfo.additionalSpectrumEmission = 1; (*sib2)->freqInfo.ul_CarrierFreq = NULL; (*sib2)->freqInfo.ul_Bandwidth = NULL; @@ -2631,21 +2441,12 @@ do_RRCConnectionSetup( SRB1_config->rlc_Config = SRB1_rlc_config; SRB1_rlc_config->present = LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue; SRB1_rlc_config->choice.explicitValue.present=LTE_RLC_Config_PR_am; -#if defined(ENABLE_ITTI) SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = rrc->srb1_timer_poll_retransmit; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = rrc->srb1_poll_pdu; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = rrc->srb1_poll_byte; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = rrc->srb1_max_retx_threshold; SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = rrc->srb1_timer_reordering; SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = rrc->srb1_timer_status_prohibit; -#else - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = LTE_T_PollRetransmit_ms20;; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = LTE_PollPDU_p4;; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = LTE_PollByte_kBinfinity; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = LTE_UL_AM_RLC__maxRetxThreshold_t8; - SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = LTE_T_Reordering_ms35; - SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = LTE_T_StatusProhibit_ms0; -#endif SRB1_lchan_config = CALLOC(1,sizeof(*SRB1_lchan_config)); SRB1_config->logicalChannelConfig = SRB1_lchan_config; SRB1_lchan_config->present = LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; @@ -3006,21 +2807,12 @@ uint8_t do_RRCConnectionSetup_BR( SRB1_config->rlc_Config = SRB1_rlc_config; // check this SRB1_rlc_config->present = LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue; SRB1_rlc_config->choice.explicitValue.present = LTE_RLC_Config_PR_am; -#if defined(ENABLE_ITTI) SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = rrc->srb1_timer_poll_retransmit; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = rrc->srb1_poll_pdu; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = rrc->srb1_poll_byte; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = rrc->srb1_max_retx_threshold; SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = rrc->srb1_timer_reordering; SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = rrc->srb1_timer_status_prohibit; -#else - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = LTE_T_PollRetransmit_ms20; // FIXME should be 80 - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = LTE_PollPDU_p4; // FIXME should be infinity - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = LTE_PollByte_kBinfinity; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = LTE_UL_AM_RLC__maxRetxThreshold_t8; - SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = LTE_T_Reordering_ms35; - SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = LTE_T_StatusProhibit_ms0; -#endif SRB1_lchan_config = CALLOC(1, sizeof(*SRB1_lchan_config)); SRB1_config->logicalChannelConfig = SRB1_lchan_config; SRB1_lchan_config->present = LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; @@ -3310,9 +3102,9 @@ uint8_t do_RRCConnectionSetup_BR( rrcConnectionSetup->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r8.radioResourceConfigDedicated.sps_Config = NULL; rrcConnectionSetup->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r8.radioResourceConfigDedicated.physicalConfigDedicated = physicalConfigDedicated2; // rrcConnectionSetup->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r8.radioResourceConfigDedicated.mac_MainConfig = NULL; -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_DL_CCCH_Message, (void *)&dl_ccch_msg); -#endif + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_LTE_DL_CCCH_Message, (void *)&dl_ccch_msg); + } enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_DL_CCCH_Message, NULL, (void *)&dl_ccch_msg, @@ -3320,31 +3112,8 @@ uint8_t do_RRCConnectionSetup_BR( 100); AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); -#if defined(ENABLE_ITTI) -# if !defined(DISABLE_XER_SPRINT) - { - char message_string[20000]; - size_t message_string_size; - if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_LTE_DL_CCCH_Message, (void *) &dl_ccch_msg)) > 0) { - MessageDef *msg_p; - msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); - msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; - memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); - itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p); - } - } -# endif -#endif -#ifdef USER_MODE - LOG_D(RRC,"RRCConnectionSetup_BR Encoded %d bits (%d bytes), ecause %d\n", - enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); -#endif - // FREEMEM(SRB_list); - // free(SRB1_config); - // free(SRB1_rlc_config); - // free(SRB1_lchan_config); - // free(SRB1_ul_SpecificParameters); + return((enc_rval.encoded+7)/8); } @@ -3461,6 +3230,98 @@ uint8_t do_UECapabilityEnquiry( const protocol_ctxt_t *const ctxt_pP, return((enc_rval.encoded+7)/8); } +//------------------------------------------------------------------------------ +uint8_t do_NR_UECapabilityEnquiry( const protocol_ctxt_t *const ctxt_pP, + uint8_t *const buffer, + const uint8_t Transaction_id) +//------------------------------------------------------------------------------ +{ + LTE_DL_DCCH_Message_t dl_dcch_msg; + LTE_RAT_Type_t rat_nr=LTE_RAT_Type_nr; + LTE_RAT_Type_t rat_eutra_nr=LTE_RAT_Type_eutra_nr; + asn_enc_rval_t enc_rval; + memset(&dl_dcch_msg,0,sizeof(LTE_DL_DCCH_Message_t)); + dl_dcch_msg.message.present = LTE_DL_DCCH_MessageType_PR_c1; + dl_dcch_msg.message.choice.c1.present = LTE_DL_DCCH_MessageType__c1_PR_ueCapabilityEnquiry; + dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.rrc_TransactionIdentifier = Transaction_id; + dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.present = LTE_UECapabilityEnquiry__criticalExtensions_PR_c1; + dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.choice.c1.present = + LTE_UECapabilityEnquiry__criticalExtensions__c1_PR_ueCapabilityEnquiry_r8; + dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.count=0; + ASN_SEQUENCE_ADD(&dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list, + &rat_nr); + ASN_SEQUENCE_ADD(&dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list, + &rat_eutra_nr); + + /* request NR configuration */ + LTE_UECapabilityEnquiry_r8_IEs_t *r8 = &dl_dcch_msg.message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8; + LTE_UECapabilityEnquiry_v8a0_IEs_t r8_a0; + LTE_UECapabilityEnquiry_v1180_IEs_t r11_80; + LTE_UECapabilityEnquiry_v1310_IEs_t r13_10; + LTE_UECapabilityEnquiry_v1430_IEs_t r14_30; + LTE_UECapabilityEnquiry_v1510_IEs_t r15_10; + + memset(&r8_a0, 0, sizeof(r8_a0)); + memset(&r11_80, 0, sizeof(r11_80)); + memset(&r13_10, 0, sizeof(r13_10)); + memset(&r14_30, 0, sizeof(r14_30)); + memset(&r15_10, 0, sizeof(r15_10)); + + r8->nonCriticalExtension = &r8_a0; + r8_a0.nonCriticalExtension = &r11_80; + r11_80.nonCriticalExtension = &r13_10; + r13_10.nonCriticalExtension = &r14_30; + r14_30.nonCriticalExtension = &r15_10; + + /* TODO: no hardcoded values here */ + + OCTET_STRING_t req_freq; + //unsigned char req_freq_buf[5] = { 0x00, 0x20, 0x1a, 0x02, 0x68 }; // bands 7 & nr78 + //unsigned char req_freq_buf[5] = { 0x00, 0x20, 0x1a, 0x08, 0x18 }; // bands 7 & nr260 + + //unsigned char req_freq_buf[13] = { 0x00, 0xc0, 0x18, 0x01, 0x01, 0x30, 0x4b, 0x04, 0x0e, 0x08, 0x24, 0x04, 0xd0 }; + unsigned char req_freq_buf[21] = { +0x01, 0x60, 0x18, 0x05, 0x80, 0xc0, 0x04, 0x04, 0xc1, 0x2c, 0x10, 0x08, 0x20, 0x30, 0x40, 0xe0, 0x82, 0x40, 0x28, 0x80, 0x9a + }; + + req_freq.buf = req_freq_buf; + req_freq.size = 5; + req_freq.size = 21; + + r15_10.requestedFreqBandsNR_MRDC_r15 = &req_freq; + + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_LTE_DL_DCCH_Message, (void *)&dl_dcch_msg); + } + + enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_DL_DCCH_Message, + NULL, + (void *)&dl_dcch_msg, + buffer, + 100); + + if(enc_rval.encoded == -1) { + LOG_I(RRC, "[eNB AssertFatal]ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + return -1; + } + + LOG_D(RRC,"[eNB %d] NR UECapabilityRequest for UE %x Encoded %zd bits (%zd bytes)\n", + ctxt_pP->module_id, + ctxt_pP->rnti, + enc_rval.encoded, + (enc_rval.encoded+7)/8); + + if (enc_rval.encoded==-1) { + LOG_E(RRC,"[eNB %d] ASN1 : NR UECapabilityRequest encoding failed for UE %x\n", + ctxt_pP->module_id, + ctxt_pP->rnti); + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + uint16_t do_RRCConnectionReconfiguration_BR(const protocol_ctxt_t *const ctxt_pP, uint8_t *buffer, @@ -3568,25 +3429,10 @@ uint16_t do_RRCConnectionReconfiguration_BR(const protocol_ctxt_t *const RRC_BUF_SIZE); AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed %s, %lu!\n", enc_rval.failed_type->name, enc_rval.encoded); -#ifdef XER_PRINT - xer_fprint(stdout,&asn_DEF_DL_DCCH_Message,(void *)&dl_dcch_msg); -#endif -#if defined(ENABLE_ITTI) -# if !defined(DISABLE_XER_SPRINT) - { - char message_string[30000]; - size_t message_string_size; - - if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_LTE_DL_DCCH_Message, (void *) &dl_dcch_msg)) > 0) { - MessageDef *msg_p; - msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB, RRC_DL_DCCH, message_string_size + sizeof (IttiMsgText)); - msg_p->ittiMsg.rrc_dl_dcch.size = message_string_size; - memcpy(&msg_p->ittiMsg.rrc_dl_dcch.text, message_string, message_string_size); - itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p); - } + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout,&asn_DEF_LTE_DL_DCCH_Message,(void *)&dl_dcch_msg); } -# endif -#endif + LOG_I(RRC,"RRCConnectionReconfiguration Encoded %d bits (%d bytes)\n",(int)enc_rval.encoded,(int)(enc_rval.encoded+7)/8); return((enc_rval.encoded+7)/8); } @@ -3840,21 +3686,12 @@ do_RRCConnectionReestablishment( SRB1_config->rlc_Config = SRB1_rlc_config; SRB1_rlc_config->present = LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue; SRB1_rlc_config->choice.explicitValue.present=LTE_RLC_Config_PR_am; -#if defined(ENABLE_ITTI) SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = rrc->srb1_timer_poll_retransmit; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = rrc->srb1_poll_pdu; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = rrc->srb1_poll_byte; SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = rrc->srb1_max_retx_threshold; SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = rrc->srb1_timer_reordering; SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = rrc->srb1_timer_status_prohibit; -#else - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = LTE_T_PollRetransmit_ms20;; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = LTE_PollPDU_p4;; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = LTE_PollByte_kBinfinity; - SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = LTE_UL_AM_RLC__maxRetxThreshold_t8; - SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = LTE_T_Reordering_ms35; - SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = LTE_T_StatusProhibit_ms0; -#endif SRB1_lchan_config = CALLOC(1, sizeof(*SRB1_lchan_config)); SRB1_config->logicalChannelConfig = SRB1_lchan_config; SRB1_lchan_config->present = LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.h b/openair2/RRC/LTE/MESSAGES/asn1_msg.h index 5203bc64ed..dda2340610 100644 --- a/openair2/RRC/LTE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.h @@ -76,12 +76,11 @@ uint8_t do_MIB(rrc_eNB_carrier_data_t *carrier, uint32_t N_RB_DL, uint32_t phich uint8_t do_MIB_FeMBMS(rrc_eNB_carrier_data_t *carrier, uint32_t N_RB_DL, uint32_t additionalNonMBSFNSubframes, uint32_t frame); /** \brief Generate configuration structure for DRX_Config -@param Mod_id Instance of eNB @param CC_id Id of component to configure @param configuration Pointer Configuration Request structure @param UEcap Pointer Configuration UE capablities @return DRX_Config structure pointer or NULL => error */ -LTE_DRX_Config_t *do_DrxConfig(uint8_t Mod_id, int CC_id, RrcConfigurationReq *configuration, LTE_UE_EUTRA_Capability_t *UEcap); +LTE_DRX_Config_t *do_DrxConfig(int CC_id, RrcConfigurationReq *configuration, LTE_UE_EUTRA_Capability_t *UEcap); /** \brief Generate configuration for SIB1 (eNB). @@ -92,10 +91,8 @@ LTE_DRX_Config_t *do_DrxConfig(uint8_t Mod_id, int CC_id, RrcConfigurationReq *c @param br_flag Do for BL/CE UE configuration @return size of encoded bit stream in bytes*/ -uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier,int Mod_id,int CC_id, BOOLEAN_t brOption -#if defined(ENABLE_ITTI) - ,RrcConfigurationReq *configuration -#endif +uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier,int Mod_id,int CC_id, BOOLEAN_t brOption, + RrcConfigurationReq *configuration ); /** @@ -121,10 +118,8 @@ uint8_t do_SIB1_MBMS(rrc_eNB_carrier_data_t *carrier,int Mod_id,int CC_id, RrcCo @param MBMS_flag Indicates presence of MBMS system information (when 1) @return size of encoded bit stream in bytes*/ -uint8_t do_SIB23(uint8_t Mod_id,int CC_id, BOOLEAN_t brOption -#if defined(ENABLE_ITTI) - , RrcConfigurationReq *configuration -#endif +uint8_t do_SIB23(uint8_t Mod_id,int CC_id, BOOLEAN_t brOption, + RrcConfigurationReq *configuration ); /** @@ -363,6 +358,13 @@ do_UECapabilityEnquiry( const uint8_t Transaction_id ); +uint8_t +do_NR_UECapabilityEnquiry( + const protocol_ctxt_t *const ctxt_pP, + uint8_t *const buffer, + const uint8_t Transaction_id +); + uint8_t do_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, uint8_t *const buffer, diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg_NB_IoT.c b/openair2/RRC/LTE/MESSAGES/asn1_msg_NB_IoT.c index 480f5c3516..350a8baf77 100644 --- a/openair2/RRC/LTE/MESSAGES/asn1_msg_NB_IoT.c +++ b/openair2/RRC/LTE/MESSAGES/asn1_msg_NB_IoT.c @@ -68,10 +68,8 @@ //#include "PHY/defs.h" #include "enb_config.h" +#include "intertask_interface.h" -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif @@ -178,21 +176,15 @@ uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, memset(PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc,0,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); asn_set_empty(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list);//.size=0; //left as it is??? -#if defined(ENABLE_ITTI) + dummy_mcc[0] = (configuration->mcc / 100) % 10; dummy_mcc[1] = (configuration->mcc / 10) % 10; dummy_mcc[2] = (configuration->mcc / 1) % 10; -#else - dummy_mcc[0] = 0; - dummy_mcc[1] = 0; - dummy_mcc[2] = 1; -#endif ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[0]); ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[1]); ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[2]); PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.size=0; PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.count=0; -#if defined(ENABLE_ITTI) if (configuration->mnc >= 100) { dummy_mnc[0] = (configuration->mnc / 100) % 10; @@ -210,11 +202,6 @@ uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, } } -#else - dummy_mnc[0] = 0; - dummy_mnc[1] = 1; - dummy_mnc[2] = 0xf; -#endif ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[0]); ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[1]); @@ -230,28 +217,16 @@ uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, // 16 bits = 2 byte (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf = MALLOC(2); //MALLOC works in byte //lefts as it is? -#if defined(ENABLE_ITTI) (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = (configuration->tac >> 8) & 0xff; (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = (configuration->tac >> 0) & 0xff; -#else - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = 0x01; -#endif (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.size=2; (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.bits_unused=0; // 28 bits --> i have to use 32 bits = 4 byte (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf = MALLOC(8); // why allocate 8 byte? -#if defined(ENABLE_ITTI) (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = (configuration->cell_identity >> 20) & 0xff; (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = (configuration->cell_identity >> 12) & 0xff; (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = (configuration->cell_identity >> 4) & 0xff; (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = (configuration->cell_identity << 4) & 0xf0; -#else - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = 0x10; -#endif (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.size=4; (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.bits_unused=4; //Still set to "notBarred" as in the previous case @@ -264,11 +239,8 @@ uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, *((*sib1_NB_IoT)->p_Max_r13) = 23; //FIXME (*sib1_NB_IoT)->freqBandIndicator_r13 = -#if defined(ENABLE_ITTI) configuration->eutra_band; -#else - 5; //if not configured we use band 5 (UL: 824 MHz - 849MHz / DL: 869 MHz - 894 MHz FDD mode) -#endif + //OPTIONAL new parameters, to be used? /* * freqBandInfo_r13 @@ -305,10 +277,8 @@ uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, ASN_SEQUENCE_ADD(&schedulingInfo_NB_IoT[0].sib_MappingInfo_r13.list,&sib_type_NB_IoT[0]); ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->schedulingInfoList_r13.list,&schedulingInfo_NB_IoT[0]); //printf("[ASN Debug] SI P: %ld\n",(*sib1_NB_IoT)->schedulingInfoList_r13.list.array[0]->si_Periodicity_r13); -#if defined(ENABLE_ITTI) if (configuration->frame_type == TDD) -#endif { //FIXME in NB-IoT mandatory to be FDD --> so must give an error LOG_E(RRC,"[NB-IoT %d] Frame Type is TDD --> not supported by NB-IoT, exiting\n", Mod_id); //correct? @@ -342,9 +312,7 @@ uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, enc_rval.failed_type->name, enc_rval.encoded); } -#ifdef USER_MODE LOG_D(RRC,"[NB-IoT] SystemInformationBlockType1-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { return(-1); @@ -563,10 +531,9 @@ uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, 900); // AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", // enc_rval.failed_type->name, enc_rval.encoded); - //#if defined(ENABLE_ITTI)..... -#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT] SystemInformation-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif + if (enc_rval.encoded==-1) { msg("[RRC] ASN1 : SI-NB encoding failed for SIB23_NB_IoT\n"); @@ -748,10 +715,8 @@ uint8_t do_RRCConnectionSetup_NB_IoT( enc_rval.failed_type->name, enc_rval.encoded); } -#ifdef USER_MODE - LOG_D(RRC,"RRCConnectionSetup-NB Encoded %zd bits (%zd bytes), ecause %d\n", - enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); -#endif + LOG_D(RRC,"RRCConnectionSetup-NB Encoded %zd bits (%zd bytes)\n", + enc_rval.encoded,(enc_rval.encoded+7)/8); return((enc_rval.encoded+7)/8); } @@ -793,15 +758,11 @@ uint8_t do_SecurityModeCommand_NB_IoT( enc_rval.failed_type->name, enc_rval.encoded); } - //#if defined(ENABLE_ITTI) - //# if !defined(DISABLE_XER_SPRINT).... -#ifdef USER_MODE LOG_D(RRC,"[NB-IoT %d] securityModeCommand-NB for UE %x Encoded %zd bits (%zd bytes)\n", ctxt_pP->module_id, ctxt_pP->rnti, enc_rval.encoded, (enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { LOG_E(RRC,"[NB-IoT %d] ASN1 : securityModeCommand-NB encoding failed for UE %x\n", @@ -850,15 +811,12 @@ uint8_t do_UECapabilityEnquiry_NB_IoT( enc_rval.failed_type->name, enc_rval.encoded); } - //#if defined(ENABLE_ITTI) - //# if !defined(DISABLE_XER_SPRINT).... -#ifdef USER_MODE LOG_D(RRC,"[NB-IoT %d] UECapabilityEnquiry-NB for UE %x Encoded %zd bits (%zd bytes)\n", ctxt_pP->module_id, ctxt_pP->rnti, enc_rval.encoded, (enc_rval.encoded+7)/8); -#endif + if (enc_rval.encoded==-1) { LOG_E(RRC,"[NB-IoT %d] ASN1 : UECapabilityEnquiry-NB encoding failed for UE %x\n", @@ -940,8 +898,6 @@ uint16_t do_RRCConnectionReconfiguration_NB_IoT( xer_fprint(stdout,&asn_DEF_LTE_DL_DCCH_Message_NB,(void *)&dl_dcch_msg_NB_IoT); } - //#if defined(ENABLE_ITTI) - //# if !defined(DISABLE_XER_SPRINT)... LOG_I(RRC,"RRCConnectionReconfiguration-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); return((enc_rval.encoded+7)/8); } @@ -977,10 +933,8 @@ uint8_t do_RRCConnectionReestablishmentReject_NB_IoT( } //Only change in "asn_DEF_DL_CCCH_Message_NB" -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %zd bits (%zd bytes)\n", enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); } @@ -1025,10 +979,8 @@ uint8_t do_RRCConnectionReject_NB_IoT( enc_rval.failed_type->name, enc_rval.encoded); } -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionReject-NB Encoded %zd bits (%zd bytes)\n", enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); } diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index 66c4401e57..4116f5367e 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -2724,8 +2724,9 @@ int decode_SIB1_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_in LOG_I(RRC,"Setting SIStatus bit 0 to 1\n"); UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus_MBMS = 1; UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIB1systemInfoValueTag_MBMS = sib1_MBMS->systemInfoValueTag_r14; -#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) + /* + if (EPC_MODE_ENABLED) { int cell_valid = 0; @@ -2781,8 +2782,8 @@ int decode_SIB1_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_in LOG_E(RRC, "Synched with a cell, but PLMN doesn't match our SIM, the message PHY_FIND_NEXT_CELL_REQ is sent but lost in current UE implementation! \n"); } } + } */ -#endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_OUT ); return 0; } @@ -2922,8 +2923,8 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, LOG_I(RRC,"Setting SIStatus bit 0 to 1\n"); UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus = 1; UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIB1systemInfoValueTag = sib1->systemInfoValueTag; -#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) - { + + if (EPC_MODE_ENABLED) { int cell_valid = 0; if (sib1->cellAccessRelatedInfo.cellBarred == LTE_SystemInformationBlockType1__cellAccessRelatedInfo__cellBarred_notBarred) { @@ -2982,7 +2983,7 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, LOG_E(RRC, "Synched with a cell, but PLMN doesn't match our SIM, the message PHY_FIND_NEXT_CELL_REQ is sent but lost in current UE implementation! \n"); } } -#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_OUT ); return 0; } @@ -3545,7 +3546,7 @@ int decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) { case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2: if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&2) == 0) { UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=2; - new_sib=1; + //new_sib=1; memcpy( UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index], &typeandinfo->choice.sib2, sizeof(LTE_SystemInformationBlockType2_t) ); LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB2 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index ); dump_sib2( UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index] ); @@ -3613,7 +3614,47 @@ int decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) { } #endif } - } + }else{ + //LOG_W( RRC, "[UE %d] Received new SIB1/SIB2/SIB3 with MBMSs %d\n", ctxt_pP->module_id, ((&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList == NULL ? 0:1) ); + if((&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList != NULL && (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&4096) == 0){ + LOG_W( RRC, "[UE %d] Received SIB2 with MBSFN SF Config\n", ctxt_pP->module_id ); + + memcpy( UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index], &typeandinfo->choice.sib2, sizeof(LTE_SystemInformationBlockType2_t) ); + LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB2 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n", + ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id ); + rrc_mac_config_req_ue(ctxt_pP->module_id, 0, eNB_index, + (LTE_RadioResourceConfigCommonSIB_t *)NULL, + (struct LTE_PhysicalConfigDedicated *)NULL, + (LTE_SCellToAddMod_r10_t *)NULL, + (LTE_MeasObjectToAddMod_t **)NULL, + (LTE_MAC_MainConfig_t *)NULL, + 0, + (struct LTE_LogicalChannelConfig *)NULL, + (LTE_MeasGapConfig_t *)NULL, + (LTE_TDD_Config_t *)NULL, + (LTE_MobilityControlInfo_t *)NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->mbsfn_SubframeConfigList + ,0, + (LTE_MBSFN_AreaInfoList_r9_t *)NULL, + (LTE_PMCH_InfoList_r9_t *)NULL, +#ifdef CBA + 0,0, +#endif + 0, + NULL, + NULL, + 0, + (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL, + (LTE_MBSFN_AreaInfoList_r9_t *)NULL + ); + + } + } break; // case SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2 @@ -3756,8 +3797,8 @@ int decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) { (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL, (LTE_MBSFN_AreaInfoList_r9_t *)NULL ); - break; } + break; //SIB18 case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib18_v1250: @@ -3823,19 +3864,30 @@ int decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) { default: break; } + if (new_sib == 1) { + UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt++; + + if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt == sib1->schedulingInfoList.list.count) + rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_SIB_COMPLETE ); + + LOG_I(RRC,"SIStatus %x, SIcnt %d/%d\n", + UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus, + UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt, + sib1->schedulingInfoList.list.count); + } } - if (new_sib == 1) { - UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt++; + //if (new_sib == 1) { + // UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt++; - if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt == sib1->schedulingInfoList.list.count) - rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_SIB_COMPLETE ); + // if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt == sib1->schedulingInfoList.list.count) + // rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_SIB_COMPLETE ); - LOG_I(RRC,"SIStatus %x, SIcnt %d/%d\n", - UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus, - UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt, - sib1->schedulingInfoList.list.count); - } + // LOG_I(RRC,"SIStatus %x, SIcnt %d/%d\n", + // UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus, + // UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt, + // sib1->schedulingInfoList.list.count); + //} VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_OUT); return 0; @@ -4158,7 +4210,7 @@ int decode_MCCH_Message( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB ctxt_pP->frame, mbsfn_sync_area); return 0; // avoid decoding to prevent memory bloating - } else { + } else if(UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State >= RRC_CONNECTED /*|| UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State == RRC_RECONFIGURED*/){ dec_rval = uper_decode_complete(NULL, &asn_DEF_LTE_MCCH_Message, (void **)&mcch, @@ -4256,7 +4308,8 @@ void decode_MBSFNAreaConfiguration( module_id_t ue_mod_idP, uint8_t eNB_index, f (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL, (LTE_MBSFN_AreaInfoList_r9_t *)NULL ); - UE_rrc_inst[ue_mod_idP].Info[eNB_index].MCCHStatus[mbsfn_sync_area] = 1; + if(UE_rrc_inst[ue_mod_idP].Info[eNB_index].State >= RRC_CONNECTED /*|| UE_rrc_inst[ue_mod_idP].Info[eNB_index].State == RRC_RECONFIGURED*/) + UE_rrc_inst[ue_mod_idP].Info[eNB_index].MCCHStatus[mbsfn_sync_area] = 1; PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_idP, ENB_FLAG_NO, UE_rrc_inst[ue_mod_idP].Info[eNB_index].rnti, frameP, 0,eNB_index); // Config Radio Bearer for MBMS user data (similar way to configure for eNB side in init_MBMS function) rrc_pdcp_config_asn1_req(&ctxt, diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h index ad51927caa..f050733a13 100644 --- a/openair2/RRC/LTE/rrc_defs.h +++ b/openair2/RRC/LTE/rrc_defs.h @@ -92,6 +92,7 @@ #define PC5_DISCOVERY_PAYLOAD_SIZE 29 +#define DEBUG_SCG_CONFIG 1 typedef enum { UE_STATE_OFF_NETWORK, @@ -264,7 +265,8 @@ typedef enum UE_STATE_e { RRC_SI_RECEIVED, RRC_CONNECTED, RRC_RECONFIGURED, - RRC_HO_EXECUTION + RRC_HO_EXECUTION, + RRC_NR_NSA, } UE_STATE_t; typedef enum HO_STATE_e { @@ -644,6 +646,8 @@ typedef struct eNB_RRC_UE_s { uint32_t ue_rrc_inactivity_timer; uint8_t e_rab_release_command_flag; int8_t reestablishment_xid; + int does_nr; + int nr_capabilities_requested; } eNB_RRC_UE_t; typedef uid_t ue_uid_t; diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index dbeaa9f6a5..1d25bf180a 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -83,6 +83,7 @@ #include "rrc_eNB_S1AP.h" #include "rrc_eNB_GTPV1U.h" +#include "rrc_eNB_M2AP.h" #include "pdcp.h" #include "gtpv1u_eNB_task.h" @@ -112,6 +113,8 @@ extern uint32_t to_earfcn_DL(int eutra_bandP, uint32_t dl_CarrierFreq, uint32_t extern int rrc_eNB_process_security(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, security_capabilities_t *security_capabilities_pP); extern void process_eNB_security_key (const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, uint8_t *security_key_pP); extern int derive_keNB_star(const uint8_t *kenb_32, const uint16_t pci, const uint32_t earfcn_dl, const bool is_rel8_only, uint8_t *kenb_star); +extern int rrc_eNB_generate_RRCConnectionReconfiguration_endc(protocol_ctxt_t *ctxt, rrc_eNB_ue_context_t *ue_context, unsigned char *buffer, int buffer_size, OCTET_STRING_t *scg_group_config, OCTET_STRING_t *scg_RB_config); +extern struct rrc_eNB_ue_context_s * get_first_ue_context(eNB_RRC_INST *rrc_instance_pP); pthread_mutex_t rrc_release_freelist; RRC_release_list_t rrc_release_info; @@ -151,21 +154,15 @@ init_SI( (int)configuration->N_RB_DL[CC_id]); RC.rrc[ctxt_pP->module_id]->carrier[CC_id].MIB_FeMBMS = (uint8_t *) malloc16(4); do_MIB_FeMBMS(&RC.rrc[ctxt_pP->module_id]->carrier[CC_id], -#ifdef ENABLE_ITTI configuration->N_RB_DL[CC_id], - 0 //additionalNonMBSFN -#else - 50,0 -#endif - ,0); + 0, //additionalNonMBSFN + 0); RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB1_MBMS = 0; RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SIB1_MBMS = (uint8_t *) malloc16(32); AssertFatal(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SIB1_MBMS!=NULL,PROTOCOL_RRC_CTXT_FMT" init_SI: FATAL, no memory for SIB1_MBMS allocated\n", PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); - RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB1_MBMS = do_SIB1_MBMS(&RC.rrc[ctxt_pP->module_id]->carrier[CC_id],ctxt_pP->module_id,CC_id -#if defined(ENABLE_ITTI) - , configuration -#endif + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB1_MBMS = do_SIB1_MBMS(&RC.rrc[ctxt_pP->module_id]->carrier[CC_id],ctxt_pP->module_id,CC_id, + configuration ); LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" Contents of SIB1-MBMS\n", PROTOCOL_RRC_CTXT_ARGS(ctxt_pP) @@ -891,7 +888,6 @@ rrc_eNB_free_mem_UE_context( //uint8_t Status; //rnti_t rnti; //uint64_t random_ue_identity; -#if defined(ENABLE_ITTI) //UE_S_TMSI Initialue_identity_s_TMSI; //EstablishmentCause_t establishment_cause; //ReestablishmentCause_t reestablishment_cause; @@ -904,7 +900,6 @@ rrc_eNB_free_mem_UE_context( //transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; //rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB]; #endif -#endif } //----------------------------------------------------------------------------- @@ -1284,6 +1279,52 @@ rrc_eNB_generate_UECapabilityEnquiry( PDCP_TRANSMISSION_MODE_CONTROL); } +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_NR_UECapabilityEnquiry( + const protocol_ctxt_t *const ctxt_pP, + rrc_eNB_ue_context_t *const ue_context_pP +) +//----------------------------------------------------------------------------- +{ + uint8_t buffer[100]; + uint8_t size; + T(T_ENB_RRC_UE_CAPABILITY_ENQUIRY, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + size = do_NR_UECapabilityEnquiry( + ctxt_pP, + buffer, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id)); + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size); + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" --- PDCP_DATA_REQ/%d Bytes (NR UECapabilityEnquiry MUI %d) --->[PDCP][RB %02d]\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size, + rrc_eNB_mui, + DCCH); + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" rrcNRUECapabilityEnquiry UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + rrc_eNB_mui, + size); + rrc_data_req( + ctxt_pP, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); +} + //----------------------------------------------------------------------------- void rrc_eNB_generate_RRCConnectionReject( @@ -2790,6 +2831,8 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t uint8_t buffer[RRC_BUF_SIZE]; uint16_t size; int i; + MessageDef *message_p = NULL; + /* Configure SRB1/SRB2, PhysicalConfigDedicated, LTE_MAC_MainConfig for UE */ eNB_RRC_INST *rrc_inst = RC.rrc[ctxt_pP->module_id]; struct LTE_PhysicalConfigDedicated **physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated; @@ -2813,11 +2856,14 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t LTE_MAC_MainConfig_t *mac_MainConfig = NULL; LTE_MeasObjectToAddModList_t *MeasObj_list = NULL; LTE_MeasObjectToAddMod_t *MeasObj = NULL; + LTE_MeasObjectToAddMod_t *MeasObj2 = NULL; LTE_ReportConfigToAddModList_t *ReportConfig_list = NULL; LTE_ReportConfigToAddMod_t *ReportConfig_per, *ReportConfig_A1, *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; + LTE_ReportConfigToAddMod_t *ReportConfig_NR = NULL; LTE_MeasIdToAddModList_t *MeasId_list = NULL; LTE_MeasIdToAddMod_t *MeasId0, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; + LTE_MeasIdToAddMod_t *MeasId6; long *sr_ProhibitTimer_r9 = NULL; long *logicalchannelgroup = NULL; long *logicalchannelgroup_drb = NULL; @@ -2972,43 +3018,28 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer = LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf200; // sf20 = 20 subframes // LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf1000 mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange = LTE_MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB3; // Value dB1 =1 dB, dB3 = 3 dB + /* CDRX Configuration */ + mac_MainConfig->drx_Config = NULL; + rnti_t rnti = ue_context_pP->ue_id_rnti; + module_id_t module_id = ctxt_pP->module_id; + LOG_D(RRC, "Processing the DRX configuration in RRC Connection Reconfiguration\n"); - if (!NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { - /* CDRX Configuration */ - // Need to check if UE is a BR UE - rnti_t rnti = ue_context_pP->ue_id_rnti; - module_id_t module_id = ctxt_pP->module_id; - int UE_id = find_UE_id(module_id, rnti); - eNB_MAC_INST *mac = RC.mac[module_id]; - UE_list_t *UE_list = &(mac->UE_list); + /* Process the IE drx_Config */ + if (NODE_IS_MONOLITHIC(rrc_inst->node_type)) { + mac_MainConfig->drx_Config = do_DrxConfig(cc_id, &rrc_inst->configuration, UEcap); // drx_Config IE - if (UE_id != -1) { - if ((rrc_inst->carrier[cc_id].sib1->tdd_Config == NULL) && - (UE_list->UE_template[ue_context_pP->ue_context.primaryCC_id][UE_id].rach_resource_type == 0)) { - // CDRX can be only configured in case of FDD and non BR UE (09/04/19) - LOG_D(RRC, "Processing the DRX configuration in RRC Connection Reconfiguration\n"); - - /* Process the IE drx_Config */ - if (cc_id < MAX_NUM_CCs) { - mac_MainConfig->drx_Config = do_DrxConfig(module_id, cc_id, &rrc_inst->configuration, UEcap); // drx_Config IE - } else { - LOG_E(RRC, "Invalid CC_id for DRX configuration\n"); - } - - /* Set timers and thresholds values in local MAC context of UE */ - eNB_Config_Local_DRX(module_id, ue_context_pP->ue_id_rnti, mac_MainConfig->drx_Config); - LOG_D(RRC, "DRX configured in mac main config for RRC Connection Reconfiguration\n"); - } else { // CDRX not implemented for TDD and LTE-M (09/04/19) - mac_MainConfig->drx_Config = NULL; - } - } else { // UE_id invalid - LOG_E(RRC, "Invalid UE_id found!\n"); - mac_MainConfig->drx_Config = NULL; + if (mac_MainConfig->drx_Config == NULL) { + LOG_W(RRC, "drx_Configuration parameter is NULL, cannot configure local UE parameters or CDRX is deactivated\n"); + } else { + /* Send DRX configuration to MAC task to configure timers of local UE context */ + message_p = itti_alloc_new_message(TASK_RRC_ENB, RRC_MAC_DRX_CONFIG_REQ); + RRC_MAC_DRX_CONFIG_REQ(message_p).rnti = rnti; + RRC_MAC_DRX_CONFIG_REQ(message_p).drx_Configuration = mac_MainConfig->drx_Config; + itti_send_msg_to_task(TASK_MAC_ENB, module_id, message_p); + LOG_D(RRC, "DRX configured in MAC Main Configuration for RRC Connection Reconfiguration\n"); } - } else { // No CDRX with the CU/DU split in this version - LOG_E(RRC, "CU/DU split activated\n"); - mac_MainConfig->drx_Config = NULL; } + /* End of CDRX configuration */ sr_ProhibitTimer_r9 = CALLOC(1, sizeof(long)); *sr_ProhibitTimer_r9 = 0; // SR tx on PUCCH, Value in number of SR period(s). Value 0 = no timer for SR, Value 2 = 2*SR @@ -3114,6 +3145,16 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t MeasId5->measObjectId = 1; MeasId5->reportConfigId = 6; ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId5); + + if (ue_context_pP->ue_context.does_nr) { + MeasId6 = calloc(1, sizeof(LTE_MeasIdToAddMod_t)); + if (MeasId6 == NULL) exit(1); + MeasId6->measId = 7; + MeasId6->measObjectId = 2; + MeasId6->reportConfigId = 7; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId6); + } + // LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list; // Add one EUTRA Measurement Object MeasObj_list = CALLOC(1, sizeof(*MeasObj_list)); @@ -3163,6 +3204,27 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj); // LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list; + if (ue_context_pP->ue_context.does_nr) { + MeasObj2 = calloc(1, sizeof(LTE_MeasObjectToAddMod_t)); + if (MeasObj2 == NULL) exit(1); + MeasObj2->measObjectId = 2; + MeasObj2->measObject.present = LTE_MeasObjectToAddMod__measObject_PR_measObjectNR_r15; + MeasObj2->measObject.choice.measObjectNR_r15.carrierFreq_r15 = 642256; //634000; //(634000 = 3.51GHz) (640000 = 3.6GHz) (641272 = 3619.08MHz = 3600 + 30/1000*106*12/2) (642256 is for 3.6GHz and absoluteFrequencySSB = 642016) + MeasObj2->measObject.choice.measObjectNR_r15.rs_ConfigSSB_r15.measTimingConfig_r15.periodicityAndOffset_r15.present = LTE_MTC_SSB_NR_r15__periodicityAndOffset_r15_PR_sf20_r15; + MeasObj2->measObject.choice.measObjectNR_r15.rs_ConfigSSB_r15.measTimingConfig_r15.periodicityAndOffset_r15.choice.sf20_r15 = 0; + MeasObj2->measObject.choice.measObjectNR_r15.rs_ConfigSSB_r15.measTimingConfig_r15.ssb_Duration_r15 = LTE_MTC_SSB_NR_r15__ssb_Duration_r15_sf4; + MeasObj2->measObject.choice.measObjectNR_r15.rs_ConfigSSB_r15.subcarrierSpacingSSB_r15 = LTE_RS_ConfigSSB_NR_r15__subcarrierSpacingSSB_r15_kHz30; + MeasObj2->measObject.choice.measObjectNR_r15.quantityConfigSet_r15 = 1; + MeasObj2->measObject.choice.measObjectNR_r15.ext1 = calloc(1, sizeof(struct LTE_MeasObjectNR_r15__ext1)); + if (MeasObj2->measObject.choice.measObjectNR_r15.ext1 == NULL) exit(1); + MeasObj2->measObject.choice.measObjectNR_r15.ext1->bandNR_r15 = calloc(1, sizeof(struct LTE_MeasObjectNR_r15__ext1__bandNR_r15)); + if (MeasObj2->measObject.choice.measObjectNR_r15.ext1->bandNR_r15 == NULL) exit(1); + MeasObj2->measObject.choice.measObjectNR_r15.ext1->bandNR_r15->present = LTE_MeasObjectNR_r15__ext1__bandNR_r15_PR_setup; + MeasObj2->measObject.choice.measObjectNR_r15.ext1->bandNR_r15->choice.setup = 78; + + ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj2); + } + if (!ue_context_pP->ue_context.measurement_info->events) { ue_context_pP->ue_context.measurement_info->events = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info->events))); } @@ -3175,6 +3237,9 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t ReportConfig_A3 = CALLOC(1, sizeof(*ReportConfig_A3)); ReportConfig_A4 = CALLOC(1, sizeof(*ReportConfig_A4)); ReportConfig_A5 = CALLOC(1, sizeof(*ReportConfig_A5)); + if (ue_context_pP->ue_context.does_nr) { + ReportConfig_NR = CALLOC(1, sizeof(*ReportConfig_NR)); + } ReportConfig_per->reportConfigId = 1; ReportConfig_per->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.present = @@ -3280,6 +3345,30 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120; ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity; ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5); + + if (ue_context_pP->ue_context.does_nr) { + ReportConfig_NR->reportConfigId = 7; + ReportConfig_NR->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigInterRAT; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.present = LTE_ReportConfigInterRAT__triggerType_PR_event; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.present = LTE_ReportConfigInterRAT__triggerType__event__eventId_PR_eventB1_NR_r15; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.b1_ThresholdNR_r15.present = LTE_ThresholdNR_r15_PR_nr_RSRP_r15; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.b1_ThresholdNR_r15.choice.nr_RSRP_r15 = 46; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.reportOnLeave_r15 = FALSE; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.hysteresis = 2; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.timeToTrigger = LTE_TimeToTrigger_ms80; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.maxReportCells = 4; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.reportInterval = LTE_ReportInterval_ms120; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.reportAmount = LTE_ReportConfigInterRAT__reportAmount_infinity; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7 = calloc(1, sizeof(struct LTE_ReportConfigInterRAT__ext7)); + if (ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7 == NULL) exit(1); + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15 = calloc(1, sizeof(struct LTE_ReportQuantityNR_r15)); + if (ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15 == NULL) exit(1); + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_rsrp = TRUE; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_rsrq = TRUE; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_sinr = TRUE; + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_NR); + } + // LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list; /* A3 event update */ @@ -3445,6 +3534,8 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt uint8_t buffer[RRC_BUF_SIZE]; uint16_t size; int i; + MessageDef *message_p = NULL; + /* Configure SRB1/SRB2, PhysicalConfigDedicated, LTE_MAC_MainConfig for UE */ eNB_RRC_INST *rrc_inst = RC.rrc[ctxt_pP->module_id]; struct LTE_PhysicalConfigDedicated **physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated; @@ -3490,8 +3581,34 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt LTE_C_RNTI_t *cba_RNTI = NULL; int measurements_enabled; uint8_t xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id); //Transaction_id, - uint8_t cc_id = ue_context_pP->ue_context.primaryCC_id; - LTE_UE_EUTRA_Capability_t *UEcap = ue_context_pP->ue_context.UE_Capability; + +#ifdef CBA // Contention Based Access + uint8_t *cba_RNTI_buf; + cba_RNTI = CALLOC(1, sizeof(LTE_C_RNTI_t)); + cba_RNTI_buf = CALLOC(1, 2 * sizeof(uint8_t)); + cba_RNTI->buf = cba_RNTI_buf; + cba_RNTI->size = 2; + cba_RNTI->bits_unused = 0; + + /* Associate UEs to the CBA groups as a function of their UE id */ + if (rrc_inst->num_active_cba_groups) { + cba_RNTI->buf[0] = rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups] & 0xff; + cba_RNTI->buf[1] = 0xff; + LOG_D(RRC, "[eNB %d] Frame %d: cba_RNTI = %x in group %d is attribued to UE %d\n", + enb_mod_idP, + frameP, + rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups], + ue_mod_idP % rrc_inst->num_active_cba_groups, ue_mod_idP); + } else { + cba_RNTI->buf[0] = 0x0; + cba_RNTI->buf[1] = 0x0; + LOG_D(RRC, "[eNB %d] Frame %d: no cba_RNTI is configured for UE %d\n", + enb_mod_idP, + frameP, + ue_mod_idP); + } +#endif + T(T_ENB_RRC_CONNECTION_RECONFIGURATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), @@ -3627,42 +3744,30 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf200; // sf20 = 20 subframes // LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf1000 mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange = LTE_MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB3; // Value dB1 =1 dB, dB3 = 3 dB - if (!NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { - /* CDRX Configuration */ - // Need to check if UE is a BR UE - rnti_t rnti = ue_context_pP->ue_id_rnti; - module_id_t module_id = ctxt_pP->module_id; - int UE_id = find_UE_id(module_id, rnti); - eNB_MAC_INST *mac = RC.mac[module_id]; - UE_list_t *UE_list = &(mac->UE_list); - - if (UE_id != -1) { - if ((rrc_inst->carrier[cc_id].sib1->tdd_Config == NULL) && - (UE_list->UE_template[ue_context_pP->ue_context.primaryCC_id][UE_id].rach_resource_type == 0)) { - // CDRX can be only configured in case of FDD and non BR UE (09/04/19) - LOG_D(RRC, "Processing the DRX configuration in RRC Connection Reconfiguration\n"); - - /* Process the IE drx_Config */ - if (cc_id < MAX_NUM_CCs) { - mac_MainConfig->drx_Config = do_DrxConfig(module_id, cc_id, &rrc_inst->configuration, UEcap); // drx_Config IE - } else { - LOG_E(RRC, "Invalid CC_id for DRX configuration\n"); - } - - /* Set timers and thresholds values in local MAC context of UE */ - eNB_Config_Local_DRX(module_id, ue_context_pP->ue_id_rnti, mac_MainConfig->drx_Config); - LOG_D(RRC, "DRX configured in mac main config for RRC Connection Reconfiguration\n"); - } else { // CDRX not implemented for TDD and LTE-M (09/04/19) - mac_MainConfig->drx_Config = NULL; - } - } else { // UE_id invalid - LOG_E(RRC, "Invalid UE_id found!\n"); - mac_MainConfig->drx_Config = NULL; + /* CDRX Configuration */ + mac_MainConfig->drx_Config = NULL; + rnti_t rnti = ue_context_pP->ue_id_rnti; + module_id_t module_id = ctxt_pP->module_id; + uint8_t cc_id = ue_context_pP->ue_context.primaryCC_id; + LTE_UE_EUTRA_Capability_t *UEcap = ue_context_pP->ue_context.UE_Capability; + LOG_D(RRC, "Processing the DRX configuration in RRC Connection Reconfiguration\n"); + + /* Process the IE drx_Config */ + if (NODE_IS_MONOLITHIC(rrc_inst->node_type)) { + mac_MainConfig->drx_Config = do_DrxConfig(cc_id, &rrc_inst->configuration, UEcap); // drx_Config IE + + if (mac_MainConfig->drx_Config == NULL) { + LOG_W(RRC, "drx_Configuration parameter is NULL, cannot configure local UE parameters or CDRX is deactivated\n"); + } else { + /* Send DRX configuration to MAC task to configure timers of local UE context */ + message_p = itti_alloc_new_message(TASK_RRC_ENB, RRC_MAC_DRX_CONFIG_REQ); + RRC_MAC_DRX_CONFIG_REQ(message_p).rnti = rnti; + RRC_MAC_DRX_CONFIG_REQ(message_p).drx_Configuration = mac_MainConfig->drx_Config; + itti_send_msg_to_task(TASK_MAC_ENB, module_id, message_p); + LOG_D(RRC, "DRX configured in MAC Main Configuration for RRC Connection Reconfiguration\n"); } - } else { // No CDRX with the CU/DU split in this version - LOG_E(RRC, "CU/DU split activated\n"); - mac_MainConfig->drx_Config = NULL; } + /* End of CDRX configuration */ sr_ProhibitTimer_r9 = CALLOC(1, sizeof(long)); *sr_ProhibitTimer_r9 = 0; // SR tx on PUCCH, Value in number of SR period(s). Value 0 = no timer for SR, Value 2 = 2*SR @@ -4234,6 +4339,10 @@ rrc_eNB_process_MeasurementReport( ctxt_pP->subframe); break; + case 7: + LOG_D(RRC, "NR event frame %d subframe %d\n", ctxt_pP->frame, ctxt_pP->subframe); + break; + default: LOG_D(RRC,"Other event report frame %d and subframe %d \n", ctxt_pP->frame, ctxt_pP->subframe); break; @@ -4247,6 +4356,22 @@ rrc_eNB_process_MeasurementReport( ue_context_pP->ue_context.measResults->measResultPCell.rsrqResult/2 - 20); } + /* TODO: improve NR triggering */ + if (measResults2->measId == 7) { + if (ue_context_pP->ue_context.Status != RRC_NR_NSA) { + MessageDef *msg; + ue_context_pP->ue_context.Status = RRC_NR_NSA; + + msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_ENDC_SGNB_ADDITION_REQ); + X2AP_ENDC_SGNB_ADDITION_REQ(msg).rnti = ctxt_pP->rnti; + LOG_I(RRC, + "[eNB %d] frame %d subframe %d: UE rnti %x switching to NSA mode\n", + ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->subframe, ctxt_pP->rnti); + itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg); + return; + } + } + if (measResults2->measResultNeighCells == NULL) return; @@ -4754,7 +4879,6 @@ check_handovers( if (ue_context_p->ue_context.Status == RRC_RECONFIGURED && ue_context_p->ue_context.handover_info != NULL && ue_context_p->ue_context.handover_info->forwarding_state == FORWARDING_NO_EMPTY ) { -#if defined(ENABLE_ITTI) MessageDef *msg_p; int result; protocol_ctxt_t ctxt; @@ -4885,7 +5009,6 @@ check_handovers( ue_context_p->ue_context.handover_info->endmark_state = ENDMARK_EMPTY; ue_context_p->ue_context.handover_info->state = HO_FORWARDING_COMPLETE; -#endif } } } @@ -5801,7 +5924,6 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct securityConfigHO->handoverType.choice.intraLTE.securityAlgorithmConfig = NULL; /* TODO: to be checked */ securityConfigHO->handoverType.choice.intraLTE.keyChangeIndicator = 0; securityConfigHO->handoverType.choice.intraLTE.nextHopChainingCount = 0; -#if defined(ENABLE_ITTI) /* Initialize NAS list */ dedicatedInfoNASList = CALLOC(1, sizeof(struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList)); @@ -5834,7 +5956,6 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct dedicatedInfoNASList = NULL; } -#endif measurements_enabled = RC.rrc[ENB_INSTANCE_TO_MODULE_ID(ctxt_pP->instance)]->configuration.enable_x2 || RC.rrc[ENB_INSTANCE_TO_MODULE_ID(ctxt_pP->instance)]->configuration.enable_measurement_reports; memset(buffer, 0, RRC_BUF_SIZE); @@ -5883,7 +6004,6 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct *_size = size = ho_size; LOG_DUMPMSG(RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Connection Reconfiguration handover\n"); -#if defined(ENABLE_ITTI) /* Free all NAS PDUs */ for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { @@ -5893,8 +6013,6 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer = NULL; } } - -#endif LOG_I(RRC, "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration handover (bytes %d, UE id %x)\n", ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); @@ -6034,26 +6152,31 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( LTE_SRB_ToAddModList_t *SRB_configList = ue_context_pP->ue_context.SRB_configList2[xid]; LTE_DRB_ToReleaseList_t *DRB_Release_configList2 = ue_context_pP->ue_context.DRB_Release_configList2[xid]; LTE_DRB_Identity_t *drb_id_p = NULL; + ue_context_pP->ue_context.ue_reestablishment_timer = 0; ue_context_pP->ue_context.ue_rrc_inactivity_timer = 1; // reset rrc inactivity timer - if (!NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { - /* CDRX: activated if ack was expected */ - int UE_id_mac = find_UE_id(ctxt_pP->module_id, ue_context_pP->ue_context.rnti); + /* CDRX: activated when RRC Connection Reconfiguration Complete is received */ + rnti_t rnti = ue_context_pP->ue_id_rnti; + module_id_t module_id = ctxt_pP->module_id; + + if (NODE_IS_MONOLITHIC(RC.rrc[module_id]->node_type)) { + int UE_id_mac = find_UE_id(module_id, rnti); if (UE_id_mac == -1) { - LOG_E(RRC,PROTOCOL_RRC_CTXT_UE_FMT" rrc_eNB_process_RRCConnectionReconfigurationComplete without UE_id(MAC) rnti %x, let's return\n",PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),ue_context_pP->ue_context.rnti); + LOG_E(RRC, "Can't find UE_id(MAC) of UE rnti %x\n", rnti); return; } - UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id_mac]); + UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[module_id]->UE_list.UE_sched_ctrl[UE_id_mac]); if (UE_scheduling_control->cdrx_waiting_ack == TRUE) { UE_scheduling_control->cdrx_waiting_ack = FALSE; - UE_scheduling_control->cdrx_configured = TRUE; + UE_scheduling_control->cdrx_configured = TRUE; // Set to TRUE when RRC Connection Reconfiguration is received LOG_I(RRC, "CDRX configuration activated after RRC Connection Reconfiguration Complete reception\n"); } - } // No CDRX with the CU/DU split in this version of the code + } + /* End of CDRX processing */ T(T_ENB_RRC_CONNECTION_RECONFIGURATION_COMPLETE, T_INT(ctxt_pP->module_id), @@ -6304,6 +6427,16 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( free(DRB_Release_configList2); ue_context_pP->ue_context.DRB_Release_configList2[xid] = NULL; } + + /* let's request NR capabilities if the UE supports NR + * maybe not the right place/time to request + */ + if (ue_context_pP->ue_context.does_nr && + !ue_context_pP->ue_context.nr_capabilities_requested) { + ue_context_pP->ue_context.nr_capabilities_requested = 1; + rrc_eNB_generate_NR_UECapabilityEnquiry(ctxt_pP, ue_context_pP); + } + } //----------------------------------------------------------------------------- @@ -7122,6 +7255,48 @@ rrc_eNB_decode_ccch( return rval; } +//----------------------------------------------------------------------------- +static int +is_en_dc_supported( + LTE_UE_EUTRA_Capability_t *c +) +//----------------------------------------------------------------------------- +{ + /* to be refined - check that the eNB is connected to a gNB, check that + * the bands supported by the UE include the band of the gNB + */ +#define NCE nonCriticalExtension + return c != NULL + && c->NCE != NULL + && c->NCE->NCE != NULL + && c->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15 != NULL + && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15->en_DC_r15 != NULL + && *c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15->en_DC_r15 == LTE_IRAT_ParametersNR_r15__en_DC_r15_supported; +#undef NCE +} + //----------------------------------------------------------------------------- int rrc_eNB_decode_dcch( @@ -7651,6 +7826,22 @@ rrc_eNB_decode_dcch( LOG_I(RRC, "got UE capabilities for UE %x\n", ctxt_pP->rnti); + int eutra_index = -1; + + for (i = 0; i < ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.count; i++) { + if (ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[i]->rat_Type == LTE_RAT_Type_eutra) { + if (eutra_index != -1) { + LOG_E(RRC, "fatal: more than 1 eutra capability\n"); + exit(1); + } + eutra_index = i; + } + } + + /* do nothing if no EUTRA capabilities (TODO: may be NR capabilities, to be processed somehow) */ + if (eutra_index == -1) + break; + if (ue_context_p->ue_context.UE_Capability) { LOG_I(RRC, "freeing old UE capabilities for UE %x\n", ctxt_pP->rnti); ASN_STRUCT_FREE(asn_DEF_LTE_UE_EUTRA_Capability, @@ -7661,15 +7852,10 @@ rrc_eNB_decode_dcch( dec_rval = uper_decode(NULL, &asn_DEF_LTE_UE_EUTRA_Capability, (void **)&ue_context_p->ue_context.UE_Capability, - ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. - choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. - array[0]->ueCapabilityRAT_Container.buf, - ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. - choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. - array[0]->ueCapabilityRAT_Container.size, 0, 0); - ue_context_p->ue_context.UE_Capability_size = ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. - choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. - array[0]->ueCapabilityRAT_Container.size; + ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[eutra_index]->ueCapabilityRAT_Container.buf, + ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[eutra_index]->ueCapabilityRAT_Container.size, + 0, 0); + ue_context_p->ue_context.UE_Capability_size = ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[eutra_index]->ueCapabilityRAT_Container.size; if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_LTE_UE_EUTRA_Capability, ue_context_p->ue_context.UE_Capability); @@ -7684,6 +7870,9 @@ rrc_eNB_decode_dcch( ue_context_p->ue_context.UE_Capability = 0; } + if (dec_rval.code == RC_OK) + ue_context_p->ue_context.does_nr = is_en_dc_supported(ue_context_p->ue_context.UE_Capability); + if (EPC_MODE_ENABLED) { rrc_eNB_send_S1AP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, @@ -8247,6 +8436,100 @@ void rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX, VCD_FUNCTION_OUT); } +void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP, x2ap_ENDC_sgnb_addition_req_ACK_t *m) { + + + NR_CG_Config_t *CG_Config = NULL; + + { + int i; + printf("%d: ", m->rrc_buffer_size); + for (i=0; irrc_buffer_size; i++) printf("%2.2x", (unsigned char)m->rrc_buffer[i]); + printf("\n"); + + } + asn_dec_rval_t dec_rval = uper_decode_complete( NULL, + &asn_DEF_NR_CG_Config, + (void **)&CG_Config, + (uint8_t *)m->rrc_buffer, + (int) m->rrc_buffer_size);//m->rrc_buffer_size); + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + AssertFatal(1==0,"NR_UL_DCCH_MESSAGE decode error\n"); + // free the memory + SEQUENCE_free( &asn_DEF_NR_CG_Config, CG_Config, 1 ); + return; + } + xer_fprint(stdout,&asn_DEF_NR_CG_Config, CG_Config); + // recreate enough of X2 EN-DC Container + + AssertFatal(CG_Config->criticalExtensions.choice.c1->present == NR_CG_Config__criticalExtensions__c1_PR_cg_Config, + "CG_Config not present\n"); + + OCTET_STRING_t *scg_CellGroupConfig = NULL; + OCTET_STRING_t *nr1_conf = NULL; + + if(CG_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig){ + scg_CellGroupConfig = CG_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig; +#ifdef DEBUG_SCG_CONFIG + { + int size_s = CG_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig->size; + int i; + LOG_I(RRC, "Dumping scg_CellGroupConfig: %d", size_s); + for (i=0; icriticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig->buf[i]); + printf("\n"); + + } +#endif + + } + else{ + LOG_W(RRC, "SCG Cell group configuration is not present in the Addition Response message \n"); + return; + } + if(CG_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config){ + nr1_conf = CG_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config; +#ifdef DEBUG_SCG_CONFIG + { + int size_s = CG_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config->size; + int i; + LOG_I(RRC, "Dumping scg_RB_Config: %d", size_s); + for (i=0; icriticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config->buf[i]); + printf("\n"); + + } +#endif + } + else{ + LOG_W(RRC, "SCG RB configuration is not present in the Addition Response message \n"); + return; + } + + protocol_ctxt_t ctxt; + rrc_eNB_ue_context_t *ue_context; + unsigned char buffer[8192]; + int size; + + ue_context = rrc_eNB_get_ue_context(RC.rrc[enb_mod_idP], m->rnti); + + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, + 0, + ENB_FLAG_YES, + m->rnti, + 0, 0); + + size = rrc_eNB_generate_RRCConnectionReconfiguration_endc(&ctxt, ue_context, buffer, 8192, scg_CellGroupConfig, nr1_conf); + + rrc_data_req(&ctxt, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); +} + + //----------------------------------------------------------------------------- void *rrc_enb_process_itti_msg(void *notUsed) { MessageDef *msg_p; @@ -8525,6 +8808,12 @@ void *rrc_enb_process_itti_msg(void *notUsed) { break; } + case X2AP_ENDC_SGNB_ADDITION_REQ_ACK: { + rrc_eNB_process_AdditionResponseInformation(ENB_INSTANCE_TO_MODULE_ID(instance), &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg_p)); + break; + } + + /* Messages from eNB app */ case RRC_CONFIGURATION_REQ: LOG_I(RRC, "[eNB %d] Received %s : %p\n", instance, msg_name_p, &RRC_CONFIGURATION_REQ(msg_p)); @@ -8543,6 +8832,43 @@ void *rrc_enb_process_itti_msg(void *notUsed) { rrc_subframe_process(&RRC_SUBFRAME_PROCESS(msg_p).ctxt, RRC_SUBFRAME_PROCESS(msg_p).CC_id); break; + case M2AP_SETUP_RESP: + rrc_eNB_process_M2AP_SETUP_RESP(&ctxt,0/*CC_id*/,ENB_INSTANCE_TO_MODULE_ID(instance),&M2AP_SETUP_RESP(msg_p)); + break; + + case M2AP_MBMS_SCHEDULING_INFORMATION: + rrc_eNB_process_M2AP_MBMS_SCHEDULING_INFORMATION(&ctxt,0/*CC_id*/,ENB_INSTANCE_TO_MODULE_ID(instance),&M2AP_MBMS_SCHEDULING_INFORMATION(msg_p)); + break; + + case M2AP_MBMS_SESSION_START_REQ: + rrc_eNB_process_M2AP_MBMS_SESSION_START_REQ(&ctxt,0/*CC_id*/,ENB_INSTANCE_TO_MODULE_ID(instance),&M2AP_MBMS_SESSION_START_REQ(msg_p)); + break; + + case M2AP_MBMS_SESSION_STOP_REQ: + rrc_eNB_process_M2AP_MBMS_SESSION_STOP_REQ(&ctxt,&M2AP_MBMS_SESSION_STOP_REQ(msg_p)); + break; + + case M2AP_RESET: + rrc_eNB_process_M2AP_RESET(&ctxt,&M2AP_RESET(msg_p)); + break; + + case M2AP_ENB_CONFIGURATION_UPDATE_ACK: + rrc_eNB_process_M2AP_ENB_CONFIGURATION_UPDATE_ACK(&ctxt,&M2AP_ENB_CONFIGURATION_UPDATE_ACK(msg_p)); + break; + + case M2AP_ERROR_INDICATION: + rrc_eNB_process_M2AP_ERROR_INDICATION(&ctxt,&M2AP_ERROR_INDICATION(msg_p)); + break; + + case M2AP_MBMS_SERVICE_COUNTING_REQ: + rrc_eNB_process_M2AP_MBMS_SERVICE_COUNTING_REQ(&ctxt,&M2AP_MBMS_SERVICE_COUNTING_REQ(msg_p)); + break; + + case M2AP_MCE_CONFIGURATION_UPDATE: + rrc_eNB_process_M2AP_MCE_CONFIGURATION_UPDATE(&ctxt,&M2AP_MCE_CONFIGURATION_UPDATE(msg_p)); + break; + + default: LOG_E(RRC, "[eNB %d] Received unexpected message %s\n", instance, msg_name_p); break; @@ -8566,11 +8892,17 @@ rrc_enb_task( //----------------------------------------------------------------------------- { rrc_enb_init(); + itti_mark_task_ready(TASK_RRC_ENB); LOG_I(RRC,"Entering main loop of RRC message task\n"); while (1) { (void) rrc_enb_process_itti_msg(NULL); +{ + //extern volatile int go_nr; + void rrc_go_nr(void); + //if (go_nr) rrc_go_nr(); +} } } diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c index 749dff3ace..6bbdef181b 100644 --- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c +++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c @@ -27,7 +27,6 @@ * \email: lionel.gauthier@eurecom.fr */ -//#if defined(ENABLE_USE_MME) # include "rrc_defs.h" # include "rrc_extern.h" # include "RRC/LTE/MESSAGES/asn1_msg.h" @@ -35,10 +34,10 @@ # include "rrc_eNB_UE_context.h" # include "msc.h" -//# if defined(ENABLE_ITTI) -# include "asn1_conversions.h" -# include "intertask_interface.h" -//#endif + +#include "asn1_conversions.h" +#include "intertask_interface.h" + # include "common/ran_context.h" @@ -113,7 +112,6 @@ gtpv_data_req( return FALSE; } LOG_D(GTPU,"gtpv_data_req ue rnti %x sdu_sizeP %d rb id %ld", ctxt_pP->rnti, sdu_sizeP, rb_idP); -#if defined(ENABLE_ITTI) { MessageDef *message_p; // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). @@ -167,8 +165,6 @@ gtpv_data_req( return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } } -#endif - return TRUE; } diff --git a/openair2/RRC/LTE/rrc_eNB_M2AP.c b/openair2/RRC/LTE/rrc_eNB_M2AP.c new file mode 100644 index 0000000000..bd586dfc71 --- /dev/null +++ b/openair2/RRC/LTE/rrc_eNB_M2AP.c @@ -0,0 +1,1234 @@ +/* + * 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 rrc_eNB_M2AP.c + * \brief rrc M2AP procedures for eNB + * \author Javier Morgade + * \version 0.1 + * \company Vicomtech Spain + * \email: javier.morgade@ieee.org + */ + +# include "rrc_defs.h" +# include "rrc_extern.h" +# include "RRC/LTE/MESSAGES/asn1_msg.h" +# include "rrc_eNB_M2AP.h" +//# include "rrc_eNB_UE_context.h" +# include "msc.h" +# include "asn1_conversions.h" +# include "intertask_interface.h" +# include "common/ran_context.h" + +extern RAN_CONTEXT_t RC; + +static m2ap_setup_resp_t * m2ap_setup_resp_g=NULL; +static m2ap_mbms_scheduling_information_t *m2ap_mbms_scheduling_information_g=NULL; + + +static void +rrc_M2AP_openair_rrc_top_init_MBMS(int eMBMS_active){ + module_id_t module_id; + int CC_id; + + (void)CC_id; + LOG_D(RRC, "[OPENAIR][INIT] Init function start: NB_eNB_INST=%d\n", RC.nb_inst); + + if (RC.nb_inst > 0) { + LOG_I(RRC,"[eNB] eMBMS active state is %d \n", eMBMS_active); + + for (module_id=0; module_idcarrier[CC_id].MBMS_flag = (uint8_t)eMBMS_active; + } + } + } +} + + + +static uint8_t rrc_M2AP_do_MBSFNAreaConfig( + uint8_t Mod_id, + uint8_t sync_area, + uint8_t *buffer, + LTE_MCCH_Message_t *mcch_message, + LTE_MBSFNAreaConfiguration_r9_t **mbsfnAreaConfiguration, + const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +) { + int i,j,k; + + asn_enc_rval_t enc_rval; + LTE_MBSFN_SubframeConfig_t *mbsfn_SubframeConfig1; + LTE_PMCH_Info_r9_t *pmch_Info_1; + LTE_MBMS_SessionInfo_r9_t *mbms_Session_1; + // MBMS_SessionInfo_r9_t *mbms_Session_2; + //eNB_RRC_INST *rrc = RC.rrc[Mod_id]; + //rrc_eNB_carrier_data_t *carrier = &rrc->carrier[0]; + memset(mcch_message,0,sizeof(LTE_MCCH_Message_t)); + mcch_message->message.present = LTE_MCCH_MessageType_PR_c1; + mcch_message->message.choice.c1.present = LTE_MCCH_MessageType__c1_PR_mbsfnAreaConfiguration_r9; + *mbsfnAreaConfiguration = &mcch_message->message.choice.c1.choice.mbsfnAreaConfiguration_r9; + // Common Subframe Allocation (CommonSF-Alloc-r9) + + for(i=0; inum_mbms_area_config_list; i++){ + for(j=0;j < m2ap_mbms_scheduling_information->mbms_area_config_list[i].num_mbms_sf_config_list; j++){ + + mbsfn_SubframeConfig1= CALLOC(1,sizeof(*mbsfn_SubframeConfig1)); + memset((void *)mbsfn_SubframeConfig1,0,sizeof(*mbsfn_SubframeConfig1)); + // + mbsfn_SubframeConfig1->radioframeAllocationPeriod= m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].radioframe_allocation_period;//LTE_MBSFN_SubframeConfig__radioframeAllocationPeriod_n4; + mbsfn_SubframeConfig1->radioframeAllocationOffset= m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].radioframe_allocation_offset; + if(m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].is_four_sf){ + mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames; + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(3); + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[2] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation) & 0xFF); + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[1] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation>>8) & 0xFF); + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation>>16) & 0xFF); + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 3; + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 0; + + + }else { + mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame; + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(1); + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 1; + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 2; + mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0] = (m2ap_mbms_scheduling_information->mbms_area_config_list[i].mbms_sf_config_list[j].subframe_allocation & 0x3F)<<2; + } + + ASN_SEQUENCE_ADD(&(*mbsfnAreaConfiguration)->commonSF_Alloc_r9.list,mbsfn_SubframeConfig1); + } + // commonSF-AllocPeriod-r9 + (*mbsfnAreaConfiguration)->commonSF_AllocPeriod_r9= m2ap_mbms_scheduling_information->mbms_area_config_list[i].common_sf_allocation_period;//LTE_MBSFNAreaConfiguration_r9__commonSF_AllocPeriod_r9_rf16; + // PMCHs Information List (PMCH-InfoList-r9) + for(j=0; j < m2ap_mbms_scheduling_information->mbms_area_config_list[i].num_pmch_config_list; j++){ + // PMCH_1 Config + pmch_Info_1 = CALLOC(1,sizeof(LTE_PMCH_Info_r9_t)); + memset((void *)pmch_Info_1,0,sizeof(LTE_PMCH_Info_r9_t)); + /* + * take the value of last mbsfn subframe in this CSA period because there is only one PMCH in this mbsfn area + * Note: this has to be set based on the subframeAllocation and CSA + */ + pmch_Info_1->pmch_Config_r9.sf_AllocEnd_r9= m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].allocated_sf_end; + pmch_Info_1->pmch_Config_r9.dataMCS_r9= m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].data_mcs; + pmch_Info_1->pmch_Config_r9.mch_SchedulingPeriod_r9= LTE_PMCH_Config_r9__mch_SchedulingPeriod_r9_rf16; + // MBMSs-SessionInfoList-r9 + for(k=0; k < m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].num_mbms_session_list; k++){ + // pmch_Info_1->mbms_SessionInfoList_r9 = CALLOC(1,sizeof(struct MBMS_SessionInfoList_r9)); + // Session 1 + mbms_Session_1 = CALLOC(1,sizeof(LTE_MBMS_SessionInfo_r9_t)); + memset(mbms_Session_1,0,sizeof(LTE_MBMS_SessionInfo_r9_t)); + // TMGI value + mbms_Session_1->tmgi_r9.plmn_Id_r9.present= LTE_TMGI_r9__plmn_Id_r9_PR_plmn_Index_r9; + mbms_Session_1->tmgi_r9.plmn_Id_r9.choice.plmn_Index_r9= 1; + // Service ID + //uint8_t TMGI[5] = {4,3,2,1,0};//TMGI is a string of octet, ref. TS 24.008 fig. 10.5.4a + char buf[4]; + buf[0] = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id << 24; + buf[1] = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id << 16; + buf[2] = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id << 8; + buf[3] = m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id << 0; + //INT32_TO_BUFFER(m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id,buf); + memset(&mbms_Session_1->tmgi_r9.serviceId_r9,0,sizeof(OCTET_STRING_t));// need to check + OCTET_STRING_fromBuf(&mbms_Session_1->tmgi_r9.serviceId_r9,(const char *)&buf[1],3); + // Session ID is still missing here, it can be used as an rab id or mrb id + mbms_Session_1->sessionId_r9 = CALLOC(1,sizeof(OCTET_STRING_t)); + mbms_Session_1->sessionId_r9->buf= MALLOC(1); + mbms_Session_1->sessionId_r9->size= 1; + mbms_Session_1->sessionId_r9->buf[0]= m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id; //1; + // Logical Channel ID + mbms_Session_1->logicalChannelIdentity_r9=m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid; //1; + LOG_D(RRC,"lcid %lu %d\n",mbms_Session_1->logicalChannelIdentity_r9,m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].lcid); + LOG_D(RRC,"service_id %d\n",m2ap_mbms_scheduling_information->mbms_area_config_list[i].pmch_config_list[j].mbms_session_list[k].service_id); + ASN_SEQUENCE_ADD(&pmch_Info_1->mbms_SessionInfoList_r9.list,mbms_Session_1); + } + ASN_SEQUENCE_ADD(&(*mbsfnAreaConfiguration)->pmch_InfoList_r9.list,pmch_Info_1); + } + } + + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout,&asn_DEF_LTE_MCCH_Message,(void *)mcch_message); + } + + enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_MCCH_Message, + NULL, + (void *)mcch_message, + buffer, + 100); + + if(enc_rval.encoded == -1) { + LOG_I(RRC, "[eNB AssertFatal]ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + return -1; + } + + LOG_I(RRC,"[eNB] MCCH Message Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + + if (enc_rval.encoded==-1) { + msg("[RRC] ASN1 : MCCH encoding failed for MBSFNAreaConfiguration\n"); + return(-1); + } + + return((enc_rval.encoded+7)/8); + +} + +static void rrc_M2AP_init_MBMS( + module_id_t enb_mod_idP, + int CC_id, + frame_t frameP +){ + // init the configuration for MTCH + protocol_ctxt_t ctxt; + + if (RC.rrc[enb_mod_idP]->carrier[CC_id].MBMS_flag > 0) { + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, enb_mod_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, 0,enb_mod_idP); + LOG_I(RRC, "[eNB %d] Frame %d : Radio Bearer config request for MBMS\n", enb_mod_idP, frameP); //check the lcid + // Configuring PDCP and RLC for MBMS Radio Bearer + rrc_pdcp_config_asn1_req(&ctxt, + (LTE_SRB_ToAddModList_t *)NULL, // LTE_SRB_ToAddModList + (LTE_DRB_ToAddModList_t *)NULL, // LTE_DRB_ToAddModList + (LTE_DRB_ToReleaseList_t *)NULL, + 0, // security mode + NULL, // key rrc encryption + NULL, // key rrc integrity + NULL // key encryption + , &(RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message->pmch_InfoList_r9) + ,NULL); + + if (!NODE_IS_CU(RC.rrc[enb_mod_idP]->node_type)) { + rrc_rlc_config_asn1_req(&ctxt, + NULL, // LTE_SRB_ToAddModList + NULL, // LTE_DRB_ToAddModList + NULL, // DRB_ToReleaseList + &(RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message->pmch_InfoList_r9) + ,0, 0 + ); + } + //rrc_mac_config_req(); + } +} + + +static void rrc_M2AP_init_MCCH( + const protocol_ctxt_t *const ctxt_pP, + uint8_t enb_mod_idP, + int CC_id, + const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +){ + + int sync_area = 0; + // initialize RRC_eNB_INST MCCH entry + eNB_RRC_INST *rrc = RC.rrc[enb_mod_idP]; + + RC.rrc[enb_mod_idP]->carrier[CC_id].MCCH_MESSAGE = + malloc(RC.rrc[enb_mod_idP]->carrier[CC_id].num_mbsfn_sync_area * sizeof(uint8_t *)); + + for (sync_area = 0; sync_area < RC.rrc[enb_mod_idP]->carrier[CC_id].num_mbsfn_sync_area; sync_area++) { + RC.rrc[enb_mod_idP]->carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] = 0; + RC.rrc[enb_mod_idP]->carrier[CC_id].MCCH_MESSAGE[sync_area] = (uint8_t *) malloc16(32); + AssertFatal(RC.rrc[enb_mod_idP]->carrier[CC_id].MCCH_MESSAGE[sync_area] != NULL, + "[eNB %d]init_MCCH: FATAL, no memory for MCCH MESSAGE allocated \n", enb_mod_idP); + RC.rrc[enb_mod_idP]->carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] = rrc_M2AP_do_MBSFNAreaConfig(enb_mod_idP, + sync_area, + (uint8_t *)RC.rrc[enb_mod_idP]->carrier[CC_id].MCCH_MESSAGE[sync_area], + &RC.rrc[enb_mod_idP]->carrier[CC_id].mcch, + &RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message, + m2ap_mbms_scheduling_information + ); + LOG_I(RRC, "mcch message pointer %p for sync area %d \n", + RC.rrc[enb_mod_idP]->carrier[CC_id].MCCH_MESSAGE[sync_area], + sync_area); + LOG_D(RRC, "[eNB %d] MCCH_MESSAGE contents for Sync Area %d (partial)\n", enb_mod_idP, sync_area); + LOG_D(RRC, "[eNB %d] CommonSF_AllocPeriod_r9 %ld\n", enb_mod_idP, + RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message->commonSF_AllocPeriod_r9); + LOG_D(RRC, + "[eNB %d] CommonSF_Alloc_r9.list.count (number of MBSFN Subframe Pattern) %d\n", + enb_mod_idP, RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message->commonSF_Alloc_r9.list.count); + LOG_D(RRC, "[eNB %d] MBSFN Subframe Pattern: %02x (in hex)\n", + enb_mod_idP, + RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message->commonSF_Alloc_r9.list.array[0]->subframeAllocation. + choice.oneFrame.buf[0]); + AssertFatal(RC.rrc[enb_mod_idP]->carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] != 255, + "RC.rrc[enb_mod_idP]->carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] == 255"); + RC.rrc[enb_mod_idP]->carrier[CC_id].MCCH_MESS[sync_area].Active = 1; + } + + + if (NODE_IS_MONOLITHIC(rrc->node_type)) { + rrc_mac_config_req_eNB(enb_mod_idP, CC_id, + 0,0,0,0,0, + 0, + 0,//rnti + (LTE_BCCH_BCH_Message_t *)NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (struct LTE_PhysicalConfigDedicated *)NULL, + (LTE_SCellToAddMod_r10_t *)NULL, + //(struct LTE_PhysicalConfigDedicatedSCell_r10 *)NULL, + (LTE_MeasObjectToAddMod_t **) NULL, + (LTE_MAC_MainConfig_t *) NULL, + 0, + (struct LTE_LogicalChannelConfig *)NULL, + (LTE_MeasGapConfig_t *) NULL, + (LTE_TDD_Config_t *) NULL, + (LTE_MobilityControlInfo_t *)NULL, + (LTE_SchedulingInfoList_t *) NULL, + 0, NULL, NULL, (LTE_MBSFN_SubframeConfigList_t *) NULL + , + 0, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL, + (LTE_PMCH_InfoList_r9_t *) & (RC.rrc[enb_mod_idP]->carrier[CC_id].mcch_message->pmch_InfoList_r9), + (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, + 0, + (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, + (LTE_SchedulingInfo_MBMS_r14_t *) NULL, + (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, + (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL + ); + } + + return; +} +//static uint8_t rrc_M2AP_do_SIB1( +// const protocol_ctxt_t *const ctxt_pP, +// uint8_t Mod_id, +// int CC_id, +// const m2ap_setup_resp_t *const m2ap_setup_resp, +// const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +//){ +// int i/*,j,l*/; +// +// //eNB_RRC_INST *rrc = RC.rrc[ctxt_pP->module_id]; +// //rrc_eNB_carrier_data_t *carrier=&rrc->carrier[CC_id]; +// +// asn_enc_rval_t enc_rval; +// +// uint8_t *buffer; +// +// LTE_SystemInformationBlockType1_t **sib1; +// +// LTE_BCCH_DL_SCH_Message_t *bcch_message = &RC.rrc[Mod_id]->carrier[CC_id].systemInformation; +// +// if (ctxt_pP->brOption) { +// buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB1_BR; +// bcch_message = &RC.rrc[Mod_id]->carrier[CC_id].siblock1_BR; +// sib1 = &RC.rrc[Mod_id]->carrier[CC_id].sib1_BR; +// } +// else +// { +// buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB1; +// bcch_message = &RC.rrc[Mod_id]->carrier[CC_id].siblock1; +// sib1 = &RC.rrc[Mod_id]->carrier[CC_id].sib1; +// } +// +// *sib1 = &bcch_message->message.choice.c1.choice.systemInformationBlockType1; +// +// uint8_t find_sib13=0; +// for(i=0; i<(*sib1)->schedulingInfoList.list.count; i++){ +// //for(j=0; j<(*sib1)->schedulingInfoList.list.array[i]->sib_MappingInfo.list.count;j++) +// // if((*sib1)->schedulingInfoList.list.array[i]->sib_MappingInfo.list.array[j] == LTE_SIB_Type_sibType13_v920) +// // find_sib13=1; +// } +// if(!find_sib13){ +// LTE_SchedulingInfo_t schedulingInfo; +// LTE_SIB_Type_t sib_type; +// memset(&schedulingInfo,0,sizeof(LTE_SchedulingInfo_t)); +// memset(&sib_type,0,sizeof(LTE_SIB_Type_t)); +// +// schedulingInfo.si_Periodicity=LTE_SchedulingInfo__si_Periodicity_rf8; +// sib_type=LTE_SIB_Type_sibType13_v920; +// ASN_SEQUENCE_ADD(&(*sib1)->schedulingInfoList.list,&schedulingInfo); +// } +// +// enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_BCCH_DL_SCH_Message, +// NULL, +// (void *)bcch_message, +// buffer, +// 900); +// AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", +// enc_rval.failed_type->name, enc_rval.encoded); +// LOG_W(RRC,"[eNB] SystemInformationBlockType1 Encoded %zd bits (%zd bytes) with new SIB13(%d) \n",enc_rval.encoded,(enc_rval.encoded+7)/8,find_sib13); +// +// +// RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB1 = ((enc_rval.encoded+7)/8); +// +// +// +// +// return 0; +//} + + + +static uint8_t rrc_M2AP_do_SIB23_SIB2( + const protocol_ctxt_t *const ctxt_pP, + uint8_t Mod_id, + int CC_id, + const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +){ + + int i,j,l; + + eNB_RRC_INST *rrc = RC.rrc[ctxt_pP->module_id]; + rrc_eNB_carrier_data_t *carrier=&rrc->carrier[CC_id]; + + + //struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *sib13_part=NULL; + LTE_MBSFN_SubframeConfigList_t *MBSFNSubframeConfigList/*,*MBSFNSubframeConfigList_copy*/; + //LTE_MBSFN_AreaInfoList_r9_t *MBSFNArea_list/*,*MBSFNArea_list_copy*/; + + asn_enc_rval_t enc_rval; + + LTE_BCCH_DL_SCH_Message_t *bcch_message = &RC.rrc[Mod_id]->carrier[CC_id].systemInformation; + uint8_t *buffer; + LTE_SystemInformationBlockType2_t **sib2; + + + if(ctxt_pP->brOption){ + buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB23_BR; + sib2 = &RC.rrc[Mod_id]->carrier[CC_id].sib2_BR; + LOG_I(RRC,"Running SIB2/3 Encoding for eMTC\n"); + + } else { + buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB23; + sib2 = &RC.rrc[Mod_id]->carrier[CC_id].sib2; + } + + + + if (bcch_message) { + //memset(bcch_message,0,sizeof(LTE_BCCH_DL_SCH_Message_t)); + } else { + LOG_E(RRC,"[eNB %d] BCCH_MESSAGE is null, exiting\n", Mod_id); + exit(-1); + } + + if (!sib2) { + LOG_E(RRC,"[eNB %d] sib2 is null, exiting\n", Mod_id); + exit(-1); + } + + //if (!sib3) { + // LOG_E(RRC,"[eNB %d] sib3 is null, exiting\n", Mod_id); + // exit(-1); + //} + + for (i=0; i < bcch_message->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.count; i++) { + struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *typeandinfo; + typeandinfo = bcch_message->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.array[i]; + switch(typeandinfo->present) { + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_NOTHING: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib3: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib4: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib5: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib6: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib7: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib8: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib9: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib10: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib11: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib12_v920: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib13_v920: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib14_v1130: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib15_v1130: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib16_v1130: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib17_v1250: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib18_v1250: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib19_v1250: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib20_v1310: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib21_v1430: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib24_v1530: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib25_v1530: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib26_v1530: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2: + + LOG_I(RRC,"Adding MBSFN subframe Configuration 1 to SIB2, %p %p\n",&typeandinfo->choice.sib2,*sib2); + + for(j=0; j < m2ap_mbms_scheduling_information->num_mbms_area_config_list ; j++) { + + (&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList = CALLOC(1,sizeof(struct LTE_MBSFN_SubframeConfigList)); + MBSFNSubframeConfigList = (&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList; + + for(l=0; l < m2ap_mbms_scheduling_information->mbms_area_config_list[j].num_mbms_sf_config_list; l++){ + LTE_MBSFN_SubframeConfig_t *sib2_mbsfn_SubframeConfig1; + sib2_mbsfn_SubframeConfig1= CALLOC(1,sizeof(*sib2_mbsfn_SubframeConfig1)); + memset((void *)sib2_mbsfn_SubframeConfig1,0,sizeof(*sib2_mbsfn_SubframeConfig1)); + + sib2_mbsfn_SubframeConfig1->radioframeAllocationPeriod = m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].radioframe_allocation_period; + sib2_mbsfn_SubframeConfig1->radioframeAllocationOffset = m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].radioframe_allocation_offset; + + + if(m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].is_four_sf){ + sib2_mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames; + + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(3); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 3; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 0; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[2] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[j].subframe_allocation) & 0xFF); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[1] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[j].subframe_allocation>>8) & 0xFF); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].subframe_allocation>>16) & 0xFF); + + }else{ + sib2_mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(1); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 1; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 2; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0]=(m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[j].subframe_allocation<<2); + + + } + + ASN_SEQUENCE_ADD(&MBSFNSubframeConfigList->list,sib2_mbsfn_SubframeConfig1); + } + } + + break; + + } + } + + + //xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message, (void *)bcch_message); + + enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_BCCH_DL_SCH_Message, + NULL, + (void *)bcch_message, + buffer, + 900); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + + LOG_I(RRC,"[eNB] MBMS SIB2 SystemInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + + if (enc_rval.encoded==-1) { + msg("[RRC] ASN1 : SI encoding failed for SIB23\n"); + return(-1); + } + + carrier->MBMS_flag =1; + + if (NODE_IS_MONOLITHIC(rrc->node_type)) { + rrc_mac_config_req_eNB(ctxt_pP->module_id, CC_id, + 0,0,0,0,0, + 0, + 0,//rnti + (LTE_BCCH_BCH_Message_t *)NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (struct LTE_PhysicalConfigDedicated *)NULL, + (LTE_SCellToAddMod_r10_t *)NULL, + //(struct LTE_PhysicalConfigDedicatedSCell_r10 *)NULL, + (LTE_MeasObjectToAddMod_t **) NULL, + (LTE_MAC_MainConfig_t *) NULL, + 0, + (struct LTE_LogicalChannelConfig *)NULL, + (LTE_MeasGapConfig_t *) NULL, + (LTE_TDD_Config_t *) NULL, + (LTE_MobilityControlInfo_t *)NULL, + (LTE_SchedulingInfoList_t *) NULL, + 0, NULL, + (LTE_AdditionalSpectrumEmission_t *)NULL, + (LTE_MBSFN_SubframeConfigList_t *) carrier->sib2->mbsfn_SubframeConfigList, + carrier->MBMS_flag, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL, + (LTE_PMCH_InfoList_r9_t *) NULL, + (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, + 0, + (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, + (LTE_SchedulingInfo_MBMS_r14_t *) NULL, + (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, + (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL + ); + } + + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB23 = ((enc_rval.encoded+7)/8); + + return 0; +} + +static uint8_t rrc_M2AP_do_SIB23_SIB13( + const protocol_ctxt_t *const ctxt_pP, + uint8_t Mod_id, + int CC_id, + const m2ap_setup_resp_t *const m2ap_setup_resp +){ + + int i; + eNB_RRC_INST *rrc = RC.rrc[ctxt_pP->module_id]; + rrc_eNB_carrier_data_t *carrier=&rrc->carrier[CC_id]; + + + struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *sib13_part=NULL; + //LTE_MBSFN_SubframeConfigList_t *MBSFNSubframeConfigList; + LTE_MBSFN_AreaInfoList_r9_t *MBSFNArea_list; + + asn_enc_rval_t enc_rval; + + LTE_BCCH_DL_SCH_Message_t *bcch_message = &RC.rrc[Mod_id]->carrier[CC_id].systemInformation; + uint8_t *buffer; + LTE_SystemInformationBlockType2_t **sib2; + + + if(ctxt_pP->brOption){ + buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB23_BR; + sib2 = &RC.rrc[Mod_id]->carrier[CC_id].sib2_BR; + LOG_I(RRC,"Running SIB2/3 Encoding for eMTC\n"); + } else { + buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB23; + sib2 = &RC.rrc[Mod_id]->carrier[CC_id].sib2; + } + + if (bcch_message) { + //memset(bcch_message,0,sizeof(LTE_BCCH_DL_SCH_Message_t)); + } else { + LOG_E(RRC,"[eNB %d] BCCH_MESSAGE is null, exiting\n", Mod_id); + exit(-1); + } + + if (!sib2) { + LOG_E(RRC,"[eNB %d] sib2 is null, exiting\n", Mod_id); + exit(-1); + } + + //if (!sib3) { + // LOG_E(RRC,"[eNB %d] sib3 is null, exiting\n", Mod_id); + // exit(-1); + //} + + /*for (int i=0; i<(*si)->criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.count; i++) { + struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *typeandinfo; + typeandinfo = (*si)->criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.array[i]; + switch(typeandinfo->present) { + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2: + LTE_SystemInformationBlockType2_t *sib2 = &typeandinfo->choice.sib2 + LOG_I(RRC,"Adding MBSFN subframe Configuration 1 to SIB2\n"); + LTE_MBSFN_SubframeConfig_t *sib2_mbsfn_SubframeConfig1; + (*sib2)->mbsfn_SubframeConfigList = CALLOC(1,sizeof(struct LTE_MBSFN_SubframeConfigList)); + MBSFNSubframeConfigList = (*sib2)->mbsfn_SubframeConfigList; + sib2_mbsfn_SubframeConfig1= CALLOC(1,sizeof(*sib2_mbsfn_SubframeConfig1)); + memset((void *)sib2_mbsfn_SubframeConfig1,0,sizeof(*sib2_mbsfn_SubframeConfig1)); + sib2_mbsfn_SubframeConfig1->radioframeAllocationPeriod= LTE_MBSFN_SubframeConfig__radioframeAllocationPeriod_n4; + sib2_mbsfn_SubframeConfig1->radioframeAllocationOffset= 1; + sib2_mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(1); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 1; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 2; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0]=0x38<<2; + + ASN_SEQUENCE_ADD(&MBSFNSubframeConfigList->list,sib2_mbsfn_SubframeConfig1); + + + break; + + } + }*/ + + + LTE_SystemInformationBlockType13_r9_t **sib13 = &RC.rrc[Mod_id]->carrier[CC_id].sib13; + + struct LTE_MBSFN_AreaInfo_r9 *MBSFN_Area1/*, *MBSFN_Area2*/; + sib13_part = CALLOC(1,sizeof(struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member)); + memset(sib13_part,0,sizeof(struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member)); + sib13_part->present = LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib13_v920; + + *sib13 = &sib13_part->choice.sib13_v920; + + (*sib13)->notificationConfig_r9.notificationRepetitionCoeff_r9=LTE_MBMS_NotificationConfig_r9__notificationRepetitionCoeff_r9_n2; + (*sib13)->notificationConfig_r9.notificationOffset_r9=0; + (*sib13)->notificationConfig_r9.notificationSF_Index_r9=1; + + // MBSFN-AreaInfoList + MBSFNArea_list= &(*sib13)->mbsfn_AreaInfoList_r9;//CALLOC(1,sizeof(*MBSFNArea_list)); + memset(MBSFNArea_list,0,sizeof(*MBSFNArea_list)); + +for( i=0; i < m2ap_setup_resp->num_mcch_config_per_mbsfn; i++){ + // MBSFN Area 1 + MBSFN_Area1= CALLOC(1, sizeof(*MBSFN_Area1)); + MBSFN_Area1->mbsfn_AreaId_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].mbsfn_area; + MBSFN_Area1->non_MBSFNregionLength= m2ap_setup_resp->mcch_config_per_mbsfn[i].pdcch_length; + MBSFN_Area1->notificationIndicator_r9= 0; + MBSFN_Area1->mcch_Config_r9.mcch_RepetitionPeriod_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].repetition_period;//LTE_MBSFN_AreaInfo_r9__mcch_Config_r9__mcch_RepetitionPeriod_r9_rf32; + MBSFN_Area1->mcch_Config_r9.mcch_Offset_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].offset; // in accordance with mbsfn subframe configuration in sib2 + MBSFN_Area1->mcch_Config_r9.mcch_ModificationPeriod_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].modification_period; + + // Subframe Allocation Info + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.buf= MALLOC(1); + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.size= 1; + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.buf[0]=m2ap_setup_resp->mcch_config_per_mbsfn[i].subframe_allocation_info<<2; // FDD: SF1 + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.bits_unused= 2; + MBSFN_Area1->mcch_Config_r9.signallingMCS_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].mcs; + ASN_SEQUENCE_ADD(&MBSFNArea_list->list,MBSFN_Area1); + } + + ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list, sib13_part); + + //xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message, (void *)bcch_message); + + enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_BCCH_DL_SCH_Message, + NULL, + (void *)bcch_message, + buffer, + 900); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + + LOG_I(RRC,"[eNB] MBMS SIB13 SystemInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + + if (enc_rval.encoded==-1) { + msg("[RRC] ASN1 : SI encoding failed for SIB23\n"); + return(-1); + } + + if (NODE_IS_MONOLITHIC(rrc->node_type)) { + rrc_mac_config_req_eNB(ctxt_pP->module_id, CC_id, + 0,0,0,0,0, + 0, + 0,//rnti + (LTE_BCCH_BCH_Message_t *)NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (struct LTE_PhysicalConfigDedicated *)NULL, + (LTE_SCellToAddMod_r10_t *)NULL, + //(struct LTE_PhysicalConfigDedicatedSCell_r10 *)NULL, + (LTE_MeasObjectToAddMod_t **) NULL, + (LTE_MAC_MainConfig_t *) NULL, + 0, + (struct LTE_LogicalChannelConfig *)NULL, + (LTE_MeasGapConfig_t *) NULL, + (LTE_TDD_Config_t *) NULL, + (LTE_MobilityControlInfo_t *)NULL, + (LTE_SchedulingInfoList_t *) NULL, + 0, NULL, NULL, (LTE_MBSFN_SubframeConfigList_t *) NULL + , + 0, + (LTE_MBSFN_AreaInfoList_r9_t *) & carrier->sib13->mbsfn_AreaInfoList_r9, + (LTE_PMCH_InfoList_r9_t *) NULL, + (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, + 0, + (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, + (LTE_SchedulingInfo_MBMS_r14_t *) NULL, + (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, + (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL + ); + } + + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB23 = ((enc_rval.encoded+7)/8); + + return 0; +} + + + +static uint8_t rrc_M2AP_do_SIB23_SIB2_SIB13( + const protocol_ctxt_t *const ctxt_pP, + uint8_t Mod_id, + int CC_id, + const m2ap_setup_resp_t *const m2ap_setup_resp, + const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +){ + + int i,j,l; + + eNB_RRC_INST *rrc = RC.rrc[ctxt_pP->module_id]; + rrc_eNB_carrier_data_t *carrier=&rrc->carrier[CC_id]; + + + struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *sib13_part=NULL; + LTE_MBSFN_SubframeConfigList_t *MBSFNSubframeConfigList/*,*MBSFNSubframeConfigList_copy*/; + + asn_enc_rval_t enc_rval; + + LTE_BCCH_DL_SCH_Message_t *bcch_message = &RC.rrc[Mod_id]->carrier[CC_id].systemInformation; + uint8_t *buffer; + LTE_SystemInformationBlockType2_t **sib2; + + LTE_MBSFN_AreaInfoList_r9_t *MBSFNArea_list/*,*MBSFNArea_list_copy*/; + LTE_SystemInformationBlockType13_r9_t **sib13 = &RC.rrc[Mod_id]->carrier[CC_id].sib13; + struct LTE_MBSFN_AreaInfo_r9 *MBSFN_Area1; + + if(ctxt_pP->brOption){ + buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB23_BR; + sib2 = &RC.rrc[Mod_id]->carrier[CC_id].sib2_BR; + LOG_I(RRC,"Running SIB2/3 Encoding for eMTC\n"); + + } else { + buffer = RC.rrc[Mod_id]->carrier[CC_id].SIB23; + sib2 = &RC.rrc[Mod_id]->carrier[CC_id].sib2; + } + + if (bcch_message) { + //memset(bcch_message,0,sizeof(LTE_BCCH_DL_SCH_Message_t)); + } else { + LOG_E(RRC,"[eNB %d] BCCH_MESSAGE is null, exiting\n", Mod_id); + exit(-1); + } + + if (!sib2) { + LOG_E(RRC,"[eNB %d] sib2 is null, exiting\n", Mod_id); + exit(-1); + } + + if(!sib13){ + LOG_I(RRC,"[eNB %d] sib13 is null, it should get created\n",Mod_id); + } + + //if (!sib3) { + // LOG_E(RRC,"[eNB %d] sib3 is null, exiting\n", Mod_id); + // exit(-1); + //} + + for (i=0; i < bcch_message->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.count; i++) { + struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *typeandinfo; + typeandinfo = bcch_message->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.array[i]; + switch(typeandinfo->present) { + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_NOTHING: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib3: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib4: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib5: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib6: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib7: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib8: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib9: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib10: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib11: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib12_v920: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib13_v920: + *sib13=&typeandinfo->choice.sib13_v920; + (*sib13)->notificationConfig_r9.notificationRepetitionCoeff_r9=LTE_MBMS_NotificationConfig_r9__notificationRepetitionCoeff_r9_n2; + (*sib13)->notificationConfig_r9.notificationOffset_r9=0; + (*sib13)->notificationConfig_r9.notificationSF_Index_r9=1; + // MBSFN-AreaInfoList + MBSFNArea_list= &(*sib13)->mbsfn_AreaInfoList_r9;//CALLOC(1,sizeof(*MBSFNArea_list)); + memset(MBSFNArea_list,0,sizeof(*MBSFNArea_list)); + + for( j=0; j < m2ap_setup_resp->num_mcch_config_per_mbsfn; j++){ + // MBSFN Area 1 + MBSFN_Area1= CALLOC(1, sizeof(*MBSFN_Area1)); + MBSFN_Area1->mbsfn_AreaId_r9= m2ap_setup_resp->mcch_config_per_mbsfn[j].mbsfn_area; + MBSFN_Area1->non_MBSFNregionLength= m2ap_setup_resp->mcch_config_per_mbsfn[j].pdcch_length; + MBSFN_Area1->notificationIndicator_r9= 0; + MBSFN_Area1->mcch_Config_r9.mcch_RepetitionPeriod_r9= m2ap_setup_resp->mcch_config_per_mbsfn[j].repetition_period;//LTE_MBSFN_AreaInfo_r9__mcch_Config_r9__mcch_RepetitionPeriod_r9_rf32; + MBSFN_Area1->mcch_Config_r9.mcch_Offset_r9= m2ap_setup_resp->mcch_config_per_mbsfn[j].offset; // in accordance with mbsfn subframe configuration in sib2 + MBSFN_Area1->mcch_Config_r9.mcch_ModificationPeriod_r9= m2ap_setup_resp->mcch_config_per_mbsfn[j].modification_period; + + // Subframe Allocation Info + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.buf= MALLOC(1); + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.size= 1; + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.buf[0]=m2ap_setup_resp->mcch_config_per_mbsfn[j].subframe_allocation_info<<2; // FDD: SF1 + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.bits_unused= 2; + MBSFN_Area1->mcch_Config_r9.signallingMCS_r9= m2ap_setup_resp->mcch_config_per_mbsfn[j].mcs; + ASN_SEQUENCE_ADD(&MBSFNArea_list->list,MBSFN_Area1); + } + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib14_v1130: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib15_v1130: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib16_v1130: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib17_v1250: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib18_v1250: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib19_v1250: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib20_v1310: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib21_v1430: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib24_v1530: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib25_v1530: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib26_v1530: + break; + case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2: + + LOG_I(RRC,"Adding MBSFN subframe Configuration 1 to SIB2, %p %p\n",&typeandinfo->choice.sib2,*sib2); + + for(j=0; j < m2ap_mbms_scheduling_information->num_mbms_area_config_list ; j++) { + + (&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList = CALLOC(1,sizeof(struct LTE_MBSFN_SubframeConfigList)); + MBSFNSubframeConfigList = (&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList; + + for(l=0; l < m2ap_mbms_scheduling_information->mbms_area_config_list[j].num_mbms_sf_config_list; l++){ + LTE_MBSFN_SubframeConfig_t *sib2_mbsfn_SubframeConfig1; + sib2_mbsfn_SubframeConfig1= CALLOC(1,sizeof(*sib2_mbsfn_SubframeConfig1)); + memset((void *)sib2_mbsfn_SubframeConfig1,0,sizeof(*sib2_mbsfn_SubframeConfig1)); + + sib2_mbsfn_SubframeConfig1->radioframeAllocationPeriod = m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].radioframe_allocation_period; + sib2_mbsfn_SubframeConfig1->radioframeAllocationOffset = m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].radioframe_allocation_offset; + + + if(m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].is_four_sf){ + sib2_mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames; + + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(3); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 3; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 0; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[2] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[j].subframe_allocation) & 0xFF); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[1] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[j].subframe_allocation>>8) & 0xFF); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0] = ((m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[l].subframe_allocation>>16) & 0xFF); + + }else{ + sib2_mbsfn_SubframeConfig1->subframeAllocation.present= LTE_MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf= MALLOC(1); + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.size= 1; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.bits_unused= 2; + sib2_mbsfn_SubframeConfig1->subframeAllocation.choice.oneFrame.buf[0]=(m2ap_mbms_scheduling_information->mbms_area_config_list[j].mbms_sf_config_list[j].subframe_allocation<<2); + + + } + + ASN_SEQUENCE_ADD(&MBSFNSubframeConfigList->list,sib2_mbsfn_SubframeConfig1); + } + } + + break; + + } + } + + if(*sib13==NULL){ + sib13_part = CALLOC(1,sizeof(struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member)); + memset(sib13_part,0,sizeof(struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member)); + sib13_part->present = LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib13_v920; + *sib13 = &sib13_part->choice.sib13_v920; + (*sib13)->notificationConfig_r9.notificationRepetitionCoeff_r9=LTE_MBMS_NotificationConfig_r9__notificationRepetitionCoeff_r9_n2; + (*sib13)->notificationConfig_r9.notificationOffset_r9=0; + (*sib13)->notificationConfig_r9.notificationSF_Index_r9=1; + + // MBSFN-AreaInfoList + MBSFNArea_list= &(*sib13)->mbsfn_AreaInfoList_r9;//CALLOC(1,sizeof(*MBSFNArea_list)); + memset(MBSFNArea_list,0,sizeof(*MBSFNArea_list)); + + for( i=0; i < m2ap_setup_resp->num_mcch_config_per_mbsfn; i++){ + // MBSFN Area 1 + MBSFN_Area1= CALLOC(1, sizeof(*MBSFN_Area1)); + MBSFN_Area1->mbsfn_AreaId_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].mbsfn_area; + MBSFN_Area1->non_MBSFNregionLength= m2ap_setup_resp->mcch_config_per_mbsfn[i].pdcch_length; + MBSFN_Area1->notificationIndicator_r9= 0; + MBSFN_Area1->mcch_Config_r9.mcch_RepetitionPeriod_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].repetition_period;//LTE_MBSFN_AreaInfo_r9__mcch_Config_r9__mcch_RepetitionPeriod_r9_rf32; + MBSFN_Area1->mcch_Config_r9.mcch_Offset_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].offset; // in accordance with mbsfn subframe configuration in sib2 + MBSFN_Area1->mcch_Config_r9.mcch_ModificationPeriod_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].modification_period; + + // Subframe Allocation Info + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.buf= MALLOC(1); + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.size= 1; + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.buf[0]=m2ap_setup_resp->mcch_config_per_mbsfn[i].subframe_allocation_info<<2; // FDD: SF1 + MBSFN_Area1->mcch_Config_r9.sf_AllocInfo_r9.bits_unused= 2; + MBSFN_Area1->mcch_Config_r9.signallingMCS_r9= m2ap_setup_resp->mcch_config_per_mbsfn[i].mcs; + ASN_SEQUENCE_ADD(&MBSFNArea_list->list,MBSFN_Area1); + } + + ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list, sib13_part); + } + + + //xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message, (void *)bcch_message); + + enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_BCCH_DL_SCH_Message, + NULL, + (void *)bcch_message, + buffer, + 900); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + + LOG_I(RRC,"[eNB] MBMS SIB2 SystemInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + + if (enc_rval.encoded==-1) { + msg("[RRC] ASN1 : SI encoding failed for SIB23\n"); + return(-1); + } + + carrier->MBMS_flag =1; + + if (NODE_IS_MONOLITHIC(rrc->node_type)) { + rrc_mac_config_req_eNB(ctxt_pP->module_id, CC_id, + 0,0,0,0,0, + 0, + 0,//rnti + (LTE_BCCH_BCH_Message_t *)NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (LTE_RadioResourceConfigCommonSIB_t *) NULL, + (struct LTE_PhysicalConfigDedicated *)NULL, + (LTE_SCellToAddMod_r10_t *)NULL, + //(struct LTE_PhysicalConfigDedicatedSCell_r10 *)NULL, + (LTE_MeasObjectToAddMod_t **) NULL, + (LTE_MAC_MainConfig_t *) NULL, + 0, + (struct LTE_LogicalChannelConfig *)NULL, + (LTE_MeasGapConfig_t *) NULL, + (LTE_TDD_Config_t *) NULL, + (LTE_MobilityControlInfo_t *)NULL, + (LTE_SchedulingInfoList_t *) NULL, + 0, NULL, + (LTE_AdditionalSpectrumEmission_t *)NULL, + (LTE_MBSFN_SubframeConfigList_t *) carrier->sib2->mbsfn_SubframeConfigList, + carrier->MBMS_flag, + (LTE_MBSFN_AreaInfoList_r9_t *) & carrier->sib13->mbsfn_AreaInfoList_r9, + (LTE_PMCH_InfoList_r9_t *) NULL, + (LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL, + 0, + (LTE_BCCH_DL_SCH_Message_MBMS_t *) NULL, + (LTE_SchedulingInfo_MBMS_r14_t *) NULL, + (struct LTE_NonMBSFN_SubframeConfig_r14 *) NULL, + (LTE_SystemInformationBlockType1_MBMS_r14_t *) NULL, + (LTE_MBSFN_AreaInfoList_r9_t *) NULL + ); + } + + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB23 = ((enc_rval.encoded+7)/8); + + return 0; +} + + +int +rrc_eNB_process_M2AP_SETUP_RESP( + const protocol_ctxt_t *const ctxt_pP, + int CC_id, + instance_t instance, + const m2ap_setup_resp_t *const m2ap_setup_resp +) +{ + //protocol_ctxt_t ctxt; + //LOG_W(RRC,"instance %d\n",instance); + + AssertFatal(RC.rrc[ctxt_pP->module_id]->carrier[0].SIB23 != NULL,"Memory fo SIB23 not allocated"); + AssertFatal(m2ap_setup_resp != NULL, "m2ap_setup_resp memory not allocated"); + + + pthread_mutex_lock(&RC.rrc[ctxt_pP->module_id]->cell_info_mutex); + //RC.rrc[ctxt_pP->module_id]->carrier[CC_id].num_mbsfn_sync_area = m2ap_setup_resp->num_mcch_config_per_mbsfn; + //rrc_M2AP_do_SIB23_SIB13(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_setup_resp); + m2ap_setup_resp_g = (m2ap_setup_resp_t*)calloc(1,sizeof(m2ap_setup_resp_t)); + memcpy(m2ap_setup_resp_g,m2ap_setup_resp,sizeof(m2ap_setup_resp_t)); + pthread_mutex_unlock(&RC.rrc[ctxt_pP->module_id]->cell_info_mutex); + + return 0; +} + + +int +rrc_eNB_process_M2AP_MBMS_SCHEDULING_INFORMATION( + const protocol_ctxt_t *const ctxt_pP, + int CC_id, + instance_t instance, + const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +) +{ + //protocol_ctxt_t ctxt; + //LOG_W(RRC,"instance %d\n",instance); + + AssertFatal(RC.rrc[ctxt_pP->module_id]->carrier[0].SIB23 != NULL,"Memory fo SIB23 not allocated"); + AssertFatal(m2ap_mbms_scheduling_information != NULL, "m2ap_mbms_scheduling_information memory not allocated"); + + //RC.rrc[ctxt_pP->module_id]->carrier[CC_id].num_mbsfn_sync_area = m2ap_setup_resp->num_mcch_config_per_mbsfn; + + pthread_mutex_lock(&RC.rrc[ctxt_pP->module_id]->cell_info_mutex); + m2ap_mbms_scheduling_information_g = (m2ap_mbms_scheduling_information_t*)calloc(1,sizeof(m2ap_mbms_scheduling_information_t)); + memcpy(m2ap_mbms_scheduling_information_g,m2ap_mbms_scheduling_information,sizeof(m2ap_mbms_scheduling_information_t)); + + /*if(m2ap_setup_resp_g != NULL){ + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].num_mbsfn_sync_area = m2ap_setup_resp_g->num_mcch_config_per_mbsfn; + rrc_M2AP_do_SIB23_SIB2(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_mbms_scheduling_information); + rrc_M2AP_do_SIB23_SIB13(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_setup_resp_g); + rrc_M2AP_init_MCCH(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_mbms_scheduling_information); + rrc_M2AP_init_MBMS(ctxt_pP->module_id, CC_id, 0); + rrc_M2AP_openair_rrc_top_init_MBMS(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].MBMS_flag); + }*/ + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, M2AP_MBMS_SCHEDULING_INFORMATION_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + pthread_mutex_unlock(&RC.rrc[ctxt_pP->module_id]->cell_info_mutex); + + + return 0; +} + +int +rrc_eNB_process_M2AP_MBMS_SESSION_START_REQ( + const protocol_ctxt_t *const ctxt_pP, + int CC_id, + instance_t instance, + const m2ap_session_start_req_t *const m2ap_mbms_session_start_req +) +{ + int split_cfg=0; + pthread_mutex_lock(&RC.rrc[ctxt_pP->module_id]->cell_info_mutex); + if(m2ap_setup_resp_g != NULL && m2ap_mbms_scheduling_information_g !=NULL ){ + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].num_mbsfn_sync_area = m2ap_setup_resp_g->num_mcch_config_per_mbsfn; + + //rrc_M2AP_do_SIB1(ctxt_pP,ctxt_pP->module_id,CC_id,NULL,NULL); + if(split_cfg){ + rrc_M2AP_do_SIB23_SIB2(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_mbms_scheduling_information_g); + rrc_M2AP_do_SIB23_SIB13(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_setup_resp_g); + }else{ + rrc_M2AP_do_SIB23_SIB2_SIB13(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_setup_resp_g,m2ap_mbms_scheduling_information_g); + } + rrc_M2AP_init_MCCH(ctxt_pP,ctxt_pP->module_id,CC_id,m2ap_mbms_scheduling_information_g); + rrc_M2AP_init_MBMS(ctxt_pP->module_id, CC_id, 0); + rrc_M2AP_openair_rrc_top_init_MBMS(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].MBMS_flag); + } + pthread_mutex_unlock(&RC.rrc[ctxt_pP->module_id]->cell_info_mutex); + + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, M2AP_MBMS_SESSION_START_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} + +int +rrc_eNB_process_M2AP_MBMS_SESSION_STOP_REQ( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_session_stop_req_t *const m2ap_session_stop_req +) +{ + return 0; +} + +int +rrc_eNB_process_M2AP_RESET( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_reset_t *const m2ap_reset +) +{ + return 0; +} + +int +rrc_eNB_process_M2AP_ENB_CONFIGURATION_UPDATE_ACK( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_enb_configuration_update_ack_t *const m2ap_enb_configuration_update_ack +) +{ + return 0; +} + +int +rrc_eNB_process_M2AP_ERROR_INDICATION( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_error_indication_t *const m2ap_error_indication +) +{ + return 0; +} + +int +rrc_eNB_process_M2AP_MBMS_SERVICE_COUNTING_REQ( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_mbms_service_counting_req_t *const m2ap_mbms_service_counting_req +) +{ + return 0; +} + +int +rrc_eNB_process_M2AP_MCE_CONFIGURATION_UPDATE( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_mce_configuration_update_t *const m2ap_mce_configuration_update +) +{ + return 0; +} + + + +void rrc_eNB_send_M2AP_MBMS_SCHEDULING_INFORMATION_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +) +{ + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, M2AP_MBMS_SCHEDULING_INFORMATION_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->instance), msg_p); +} + +void rrc_eNB_send_M2AP_MBMS_SESSION_START_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +) +{ + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, M2AP_MBMS_SESSION_START_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->instance), msg_p); +} + +void rrc_eNB_send_M2AP_MBMS_SESSION_STOP_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +) +{ + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, M2AP_MBMS_SESSION_STOP_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->instance), msg_p); +} + +void rrc_eNB_send_M2AP_MBMS_SESSION_UPDATE_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +) +{ + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, M2AP_MBMS_SESSION_UPDATE_RESP); + itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->instance), msg_p); +} diff --git a/openair2/RRC/LTE/rrc_eNB_M2AP.h b/openair2/RRC/LTE/rrc_eNB_M2AP.h new file mode 100644 index 0000000000..3b95aafb11 --- /dev/null +++ b/openair2/RRC/LTE/rrc_eNB_M2AP.h @@ -0,0 +1,115 @@ +/* + * 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 rrc_eNB_M2AP.h + * \brief rrc M2AP procedures for eNB + * \author Javier Morgade + * \version 0.1 + * \company Vicomtech, Spain + * \email: javier.morgade@ieee.org + */ + +#ifndef RRC_ENB_M2AP_H_ +#define RRC_ENB_M2AP_H_ + + +int +rrc_eNB_process_M2AP_SETUP_RESP( + const protocol_ctxt_t *const ctxt_pP, + int CC_id, + instance_t instance, + const m2ap_setup_resp_t *const m2ap_setup_resp +); + +int +rrc_eNB_process_M2AP_MBMS_SCHEDULING_INFORMATION( + const protocol_ctxt_t *const ctxt_pP, + int CC_id, + instance_t instance, + const m2ap_mbms_scheduling_information_t *const m2ap_mbms_scheduling_information +); + +int +rrc_eNB_process_M2AP_MBMS_SESSION_START_REQ( + const protocol_ctxt_t *const ctxt_pP, + int CC_id, + instance_t instance, + const m2ap_session_start_req_t *const m2ap_session_start_req +); + +int +rrc_eNB_process_M2AP_MBMS_SESSION_STOP_REQ( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_session_stop_req_t *const m2ap_session_stop_req +); + +int +rrc_eNB_process_M2AP_RESET( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_reset_t *const m2ap_reset +); + +int +rrc_eNB_process_M2AP_ENB_CONFIGURATION_UPDATE_ACK( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_enb_configuration_update_ack_t *const m2ap_enb_configuration_update_ack +); + +int +rrc_eNB_process_M2AP_ERROR_INDICATION( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_error_indication_t *const m2ap_error_indication +); + +int +rrc_eNB_process_M2AP_MBMS_SERVICE_COUNTING_REQ( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_mbms_service_counting_req_t *const m2ap_mbms_service_counting_req +); + +int +rrc_eNB_process_M2AP_MCE_CONFIGURATION_UPDATE( + const protocol_ctxt_t *const ctxt_pP, + const m2ap_mce_configuration_update_t *const m2ap_mce_configuration_update +); + + +void rrc_eNB_send_M2AP_MBMS_SCHEDULING_INFORMATION_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +); + +void rrc_eNB_send_M2AP_MBMS_SESSION_START_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +); + +void rrc_eNB_send_M2AP_MBMS_SESSION_STOP_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +); + +void rrc_eNB_send_M2AP_MBMS_SESSION_UPDATE_RESP( + const protocol_ctxt_t *const ctxt_pP + //,const rrc_eNB_mbms_context_t *const rrc_eNB_mbms_context +); + +#endif /* RRC_ENB_M2AP_H_ */ diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.c b/openair2/RRC/LTE/rrc_eNB_S1AP.c index 2512cf6820..59998cebcc 100644 --- a/openair2/RRC/LTE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LTE/rrc_eNB_S1AP.c @@ -58,7 +58,7 @@ #include "TLVDecoder.h" #include "S1AP_NAS-PDU.h" #include "flexran_agent_common_internal.h" - +#include "executables/softmodem-common.h" extern RAN_CONTEXT_t RC; extern int @@ -540,9 +540,10 @@ rrc_pdcp_config_security( derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, ue_context_pP->ue_context.kenb, &kRRCint); -#if !defined(USRP_REC_PLAY) + if (!IS_SOFTMODEM_IQPLAYER) { SET_LOG_DUMP(DEBUG_SECURITY) ; -#endif + } + if ( LOG_DUMPFLAG( DEBUG_SECURITY ) ) { if (print_keys ==1 ) { @@ -1686,6 +1687,9 @@ int rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(MessageDef *msg_p, const char *ms memcpy(&e_rab_release_params[0], &(S1AP_E_RAB_RELEASE_COMMAND (msg_p).e_rab_release_params[0]), sizeof(e_rab_release_t)*S1AP_MAX_E_RAB); eNB_ue_s1ap_id = S1AP_E_RAB_RELEASE_COMMAND (msg_p).eNB_ue_s1ap_id; nb_e_rabs_torelease = S1AP_E_RAB_RELEASE_COMMAND (msg_p).nb_e_rabs_torelease; + if (nb_e_rabs_torelease > S1AP_MAX_E_RAB) { + return -1; + } ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); if(ue_context_p != NULL) { diff --git a/openair2/RRC/LTE/rrc_eNB_endc.c b/openair2/RRC/LTE/rrc_eNB_endc.c new file mode 100644 index 0000000000..3d3d9787b5 --- /dev/null +++ b/openair2/RRC/LTE/rrc_eNB_endc.c @@ -0,0 +1,243 @@ +/* + * 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 "rrc_defs.h" +#include "rrc_extern.h" +#include "rrc_eNB_UE_context.h" +#include "common/ran_context.h" +#include "LTE_DL-DCCH-Message.h" + +#include +#include +#include +#include +#include +#include + +extern RAN_CONTEXT_t RC; +extern mui_t rrc_eNB_mui; + +int rrc_eNB_generate_RRCConnectionReconfiguration_endc(protocol_ctxt_t *ctxt, + rrc_eNB_ue_context_t *ue_context, + unsigned char *buffer, + int buffer_size, + OCTET_STRING_t *scg_group_config, + OCTET_STRING_t *scg_RB_config) +{ + asn_enc_rval_t enc_rval; + LTE_DL_DCCH_Message_t dl_dcch_msg; + LTE_RRCConnectionReconfiguration_t *r; + int trans_id; + LTE_RadioResourceConfigDedicated_t rrcd; +#if 0 + LTE_DRB_ToAddModList_t drb_list; + struct LTE_DRB_ToAddMod drb; + long eps_bearer_id; + struct LTE_RLC_Config rlc; + long lcid; + struct LTE_LogicalChannelConfig lc; +#endif + LTE_DRB_ToReleaseList_t drb_list; + LTE_DRB_Identity_t drb; + struct LTE_LogicalChannelConfig__ul_SpecificParameters ul_params; + long lcg; + struct LTE_RadioResourceConfigDedicated__mac_MainConfig mac; + struct LTE_MAC_MainConfig__ext4 mac_ext4; + struct LTE_MAC_MainConfig__ext4__dualConnectivityPHR dc_phr; + + memset(&rrcd, 0, sizeof(rrcd)); + memset(&drb_list, 0, sizeof(drb_list)); + memset(&drb, 0, sizeof(drb)); +#if 0 + memset(&rlc, 0, sizeof(rlc)); + memset(&lc, 0, sizeof(lc)); +#endif + memset(&ul_params, 0, sizeof(ul_params)); + memset(&mac, 0, sizeof(mac)); + memset(&mac_ext4, 0, sizeof(mac_ext4)); + memset(&dc_phr, 0, sizeof(dc_phr)); + + trans_id = rrc_eNB_get_next_transaction_identifier(ctxt->module_id); + + memset(&dl_dcch_msg,0,sizeof(LTE_DL_DCCH_Message_t)); + + dl_dcch_msg.message.present = LTE_DL_DCCH_MessageType_PR_c1; + dl_dcch_msg.message.choice.c1.present = LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionReconfiguration; + + r = &dl_dcch_msg.message.choice.c1.choice.rrcConnectionReconfiguration; + + r->rrc_TransactionIdentifier = trans_id; + r->criticalExtensions.present = LTE_RRCConnectionReconfiguration__criticalExtensions_PR_c1; + r->criticalExtensions.choice.c1.present = LTE_RRCConnectionReconfiguration__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r8; + r->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated = &rrcd; + +#if 0 + rrcd.drb_ToAddModList = &drb_list; + + eps_bearer_id = 5; + drb.eps_BearerIdentity = &eps_bearer_id; + drb.drb_Identity = 5; + drb.rlc_Config = &rlc; + lcid = 4; + drb.logicalChannelIdentity = &lcid; + drb.logicalChannelConfig = &lc; + + ASN_SEQUENCE_ADD(&drb_list.list, &drb); + + rlc.present = LTE_RLC_Config_PR_am; + rlc.choice.am.ul_AM_RLC.t_PollRetransmit = LTE_T_PollRetransmit_ms50; + rlc.choice.am.ul_AM_RLC.pollPDU = LTE_PollPDU_p16; + rlc.choice.am.ul_AM_RLC.pollByte = LTE_PollByte_kBinfinity; + rlc.choice.am.ul_AM_RLC.maxRetxThreshold = LTE_UL_AM_RLC__maxRetxThreshold_t8; + rlc.choice.am.dl_AM_RLC.t_Reordering = LTE_T_Reordering_ms35; + rlc.choice.am.dl_AM_RLC.t_StatusProhibit = LTE_T_StatusProhibit_ms25; + + lc.ul_SpecificParameters = &ul_params; +#endif + + /* release drb 1 */ + drb = 1; + ASN_SEQUENCE_ADD(&drb_list.list, &drb); + rrcd.drb_ToReleaseList = &drb_list; + + ul_params.priority = 12; + ul_params.prioritisedBitRate = LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; + ul_params.bucketSizeDuration = LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300; + lcg = 3; + ul_params.logicalChannelGroup = &lcg; + + rrcd.mac_MainConfig = &mac; + + mac.present = LTE_RadioResourceConfigDedicated__mac_MainConfig_PR_explicitValue; + mac.choice.explicitValue.timeAlignmentTimerDedicated = LTE_TimeAlignmentTimer_sf10240; + mac.choice.explicitValue.ext4 = &mac_ext4; + + mac_ext4.dualConnectivityPHR = &dc_phr; + + dc_phr.present = LTE_MAC_MainConfig__ext4__dualConnectivityPHR_PR_setup; + dc_phr.choice.setup.phr_ModeOtherCG_r12 = LTE_MAC_MainConfig__ext4__dualConnectivityPHR__setup__phr_ModeOtherCG_r12_virtual; + + /* NR config */ + struct LTE_RRCConnectionReconfiguration_v890_IEs cr_890; + struct LTE_RRCConnectionReconfiguration_v920_IEs cr_920; + struct LTE_RRCConnectionReconfiguration_v1020_IEs cr_1020; + struct LTE_RRCConnectionReconfiguration_v1130_IEs cr_1130; + struct LTE_RRCConnectionReconfiguration_v1250_IEs cr_1250; + struct LTE_RRCConnectionReconfiguration_v1310_IEs cr_1310; + struct LTE_RRCConnectionReconfiguration_v1430_IEs cr_1430; + struct LTE_RRCConnectionReconfiguration_v1510_IEs cr_1510; + struct LTE_RRCConnectionReconfiguration_v1510_IEs__nr_Config_r15 nr; + + memset(&cr_890, 0, sizeof(cr_890)); + memset(&cr_920, 0, sizeof(cr_920)); + memset(&cr_1020, 0, sizeof(cr_1020)); + memset(&cr_1130, 0, sizeof(cr_1130)); + memset(&cr_1250, 0, sizeof(cr_1250)); + memset(&cr_1310, 0, sizeof(cr_1310)); + memset(&cr_1430, 0, sizeof(cr_1430)); + memset(&cr_1510, 0, sizeof(cr_1510)); + memset(&nr, 0, sizeof(nr)); + + r->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.nonCriticalExtension = &cr_890; + cr_890.nonCriticalExtension = &cr_920; + cr_920.nonCriticalExtension = &cr_1020; + cr_1020.nonCriticalExtension = &cr_1130; + cr_1130.nonCriticalExtension = &cr_1250; + cr_1250.nonCriticalExtension = &cr_1310; + cr_1310.nonCriticalExtension = &cr_1430; + cr_1430.nonCriticalExtension = &cr_1510; + + cr_1510.nr_Config_r15 = &nr; + nr.present = LTE_RRCConnectionReconfiguration_v1510_IEs__nr_Config_r15_PR_setup; + nr.choice.setup.endc_ReleaseAndAdd_r15 = 0; /* FALSE */ + + OCTET_STRING_t dummy_scg_conf; + unsigned char scg_conf_buf[4] = { 0, 0, 0, 0 }; + if (scg_group_config!=NULL) + nr.choice.setup.nr_SecondaryCellGroupConfig_r15 = scg_group_config; //&scg_conf; + else{ + nr.choice.setup.nr_SecondaryCellGroupConfig_r15 = &dummy_scg_conf; + dummy_scg_conf.buf = scg_conf_buf; + dummy_scg_conf.size = 4; + } + +#ifdef DEBUG_SCG_CONFIG + { + int size_s = nr.choice.setup.nr_SecondaryCellGroupConfig_r15->size; + int i; + LOG_I(RRC, "Dumping nr_SecondaryCellGroupConfig: %d", size_s); + for (i=0; ibuf[i]); + printf("\n"); + + } +#endif + + + long sk_counter = 0; + cr_1510.sk_Counter_r15 = &sk_counter; + + OCTET_STRING_t dummy_nr1_conf; + unsigned char nr1_buf[4] = { 0, 0, 0, 0 }; + + if(scg_RB_config!=NULL) + cr_1510.nr_RadioBearerConfig1_r15 = scg_RB_config; + else{ + cr_1510.nr_RadioBearerConfig1_r15 = &dummy_nr1_conf; + dummy_nr1_conf.buf = nr1_buf; + dummy_nr1_conf.size = 4; + } + +#ifdef DEBUG_SCG_CONFIG + { + int size_s = cr_1510.nr_RadioBearerConfig1_r15->size; + int i; + LOG_I(RRC, "Dumping nr_RadioBearerConfig1: %d", size_s); + for (i=0; ibuf[i]); + printf("\n"); + + } +#endif + + +#if 0 + OCTET_STRING_t nr2_conf; + unsigned char nr2_buf[4] = { 0, 0, 0, 0 }; + cr_1510.nr_RadioBearerConfig2_r15 = &nr2_conf; + nr2_conf.buf = nr2_buf; + nr2_conf.size = 4; +#endif + + enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_DL_DCCH_Message, + NULL, + (void *)&dl_dcch_msg, + buffer, + buffer_size); + +{ +int len = (enc_rval.encoded + 7) / 8; +int i; +printf("len = %d\n", len); +for (i = 0; i < len; i++) printf(" %2.2x", buffer[i]); +printf("\n"); +} + + return (enc_rval.encoded + 7) / 8; +} diff --git a/openair2/RRC/LTE/rrc_proto.h b/openair2/RRC/LTE/rrc_proto.h index d5009de270..8f6baabcbf 100644 --- a/openair2/RRC/LTE/rrc_proto.h +++ b/openair2/RRC/LTE/rrc_proto.h @@ -584,6 +584,12 @@ rrc_eNB_generate_UECapabilityEnquiry( rrc_eNB_ue_context_t *const ue_context_pP ); +void +rrc_eNB_generate_NR_UECapabilityEnquiry( + const protocol_ctxt_t *const ctxt_pP, + rrc_eNB_ue_context_t *const ue_context_pP +); + void rrc_eNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, diff --git a/openair2/RRC/NAS/nas_config.c b/openair2/RRC/NAS/nas_config.c index ab4dbfc119..2eb439b9e9 100644 --- a/openair2/RRC/NAS/nas_config.c +++ b/openair2/RRC/NAS/nas_config.c @@ -230,6 +230,87 @@ int NAS_config(char *interfaceName, char *ipAddress, char *networkMask, char *br return returnValue; } +int nas_config_mbms(int interface_id, int thirdOctet, int fourthOctet, char *ifname) { + //char buf[5]; + char ipAddress[20]; + char broadcastAddress[20]; + char interfaceName[20]; + int returnValue; + //if(strcmp(ifname,"ue") == 0) + //sprintf(ipAddress, "%s.%d.%d", "20.0",thirdOctet,fourthOctet); + ////else + sprintf(ipAddress, "%s.%d.%d",baseNetAddress,thirdOctet,fourthOctet); + + sprintf(broadcastAddress, "%s.%d.255",baseNetAddress, thirdOctet); + sprintf(interfaceName, "%s%s%d", (UE_NAS_USE_TUN || ENB_NAS_USE_TUN)?"oaitun_":ifname, + UE_NAS_USE_TUN?ifname/*"ue"*/: (ENB_NAS_USE_TUN?ifname/*"enb"*/:""),interface_id); + bringInterfaceUp(interfaceName, 0); + // sets the machine address + returnValue= setInterfaceParameter(interfaceName, ipAddress,SIOCSIFADDR); + + // sets the machine network mask + if(!returnValue) + returnValue= setInterfaceParameter(interfaceName, netMask,SIOCSIFNETMASK); + + // sets the machine broadcast address + if(!returnValue) + returnValue= setInterfaceParameter(interfaceName, broadcastAddress,SIOCSIFBRDADDR); + + if(!returnValue) + bringInterfaceUp(interfaceName, 1); + + if(!returnValue) + LOG_I(OIP,"Interface %s successfully configured, ip address %s, mask %s broadcast address %s\n", + interfaceName, ipAddress, netMask, broadcastAddress); + else + LOG_E(OIP,"Interface %s couldn't be configured (ip address %s, mask %s broadcast address %s)\n", + interfaceName, ipAddress, netMask, broadcastAddress); + + return returnValue; +} + +int nas_config_mbms_s1(int interface_id, int thirdOctet, int fourthOctet, char *ifname) { + //char buf[5]; + char ipAddress[20]; + char broadcastAddress[20]; + char interfaceName[20]; + int returnValue; + //if(strcmp(ifname,"ue") == 0) + //sprintf(ipAddress, "%s.%d.%d", "20.0",thirdOctet,fourthOctet); + ////else + sprintf(ipAddress, "%s.%d.%d","10.0",thirdOctet,fourthOctet); + + sprintf(broadcastAddress, "%s.%d.255","10.0", thirdOctet); + sprintf(interfaceName, "%s%s%d", "oaitun_",ifname,interface_id); + bringInterfaceUp(interfaceName, 0); + // sets the machine address + returnValue= setInterfaceParameter(interfaceName, ipAddress,SIOCSIFADDR); + + // sets the machine network mask + if(!returnValue) + returnValue= setInterfaceParameter(interfaceName, "255.255.255.0",SIOCSIFNETMASK); + printf("returnValue %d\n",returnValue); + + // sets the machine broadcast address + if(!returnValue) + returnValue= setInterfaceParameter(interfaceName, broadcastAddress,SIOCSIFBRDADDR); + printf("returnValue %d\n",returnValue); + + if(!returnValue) + bringInterfaceUp(interfaceName, 1); + printf("returnValue %d\n",returnValue); + + if(!returnValue) + LOG_I(OIP,"Interface %s successfully configured, ip address %s, mask %s broadcast address %s\n", + interfaceName, ipAddress, "255.255.255.0", broadcastAddress); + else + LOG_E(OIP,"Interface %s couldn't be configured (ip address %s, mask %s broadcast address %s)\n", + interfaceName, ipAddress, "255.255.255.0", broadcastAddress); + + return returnValue; +} + + // non blocking full configuration of the interface (address, and the two lest octets of the address) int nas_config(int interface_id, int thirdOctet, int fourthOctet, char *ifname) { //char buf[5]; @@ -257,7 +338,7 @@ int nas_config(int interface_id, int thirdOctet, int fourthOctet, char *ifname) returnValue=bringInterfaceUp(interfaceName, 1); if(!returnValue) - LOG_I(OIP,"Interface %s successfuly configured, ip address %s, mask %s broadcast address %s\n", + LOG_I(OIP,"Interface %s successfully configured, ip address %s, mask %s broadcast address %s\n", interfaceName, ipAddress, netMask, broadcastAddress); else LOG_E(OIP,"Interface %s couldn't be configured (ip address %s, mask %s broadcast address %s)\n", diff --git a/openair2/RRC/NAS/nas_config.h b/openair2/RRC/NAS/nas_config.h index fdc3c98f1b..de84a854ca 100644 --- a/openair2/RRC/NAS/nas_config.h +++ b/openair2/RRC/NAS/nas_config.h @@ -63,6 +63,34 @@ int NAS_config(char *interfaceName, char *ipAddress, char *networkMask, char *br */ int nas_config(int interface_id, int thirdOctet, int fourthOctet, char *ifsuffix); +/*! \fn int nas_config_mbms(char*, int, int) + * \brief This function initializes the nasmesh interface using the basic values, + * basic address, network mask and broadcast address, as the default configured + * ones + * \param[in] interfaceName, the name of the interface, e.g. nasmesh0 or nasmesh1 + * \param[in] third octet of the ip address e.g. for the 10.1.2.3 address would be 2 + * \param[in] fourth octet of the ip address e.g. for the 10.1.2.3 address would be 3 + * \return 0 on success, otherwise 1, if couldn't open a socket and 2 if the ioctl fails + * \note + * @ingroup ????? + */ +int nas_config_mbms(int interface_id, int thirdOctet, int fourthOctet, char *ifsuffix); + +/*! \fn int nas_config_mbms_s1(char*, int, int) + * \brief This function initializes the nasmesh interface using the basic values, + * basic address, network mask and broadcast address, as the default configured + * ones + * \param[in] interfaceName, the name of the interface, e.g. nasmesh0 or nasmesh1 + * \param[in] third octet of the ip address e.g. for the 10.1.2.3 address would be 2 + * \param[in] fourth octet of the ip address e.g. for the 10.1.2.3 address would be 3 + * \return 0 on success, otherwise 1, if couldn't open a socket and 2 if the ioctl fails + * \note + * @ingroup ????? + */ +int nas_config_mbms_s1(int interface_id, int thirdOctet, int fourthOctet, char *ifsuffix); + + + /*! \fn int blocking_NAS_config(char*, char*, char*, char*) * \brief This function initializes the nasmesh interface, in a blocking way, * the system calls are interrupted diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index fb1ed160cb..1e8e45ef4d 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -36,9 +36,7 @@ #include "msc.h" #include "common/ran_context.h" -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "NR_MIB.h" #include "NR_BCCH-BCH-Message.h" diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 584667b52e..a4092c11fa 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -99,9 +99,7 @@ #include "gnb_config.h" #endif -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" #include "common/ran_context.h" @@ -125,10 +123,9 @@ typedef struct xer_sprint_string_s { size_t string_index; } xer_sprint_string_t; -//repplace LTE +//replace LTE //extern unsigned char NB_eNB_INST; extern unsigned char NB_gNB_INST; -extern uint8_t usim_test; extern RAN_CONTEXT_t RC; @@ -202,7 +199,7 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { mib->message.choice.mib->spare.size = 1; mib->message.choice.mib->spare.bits_unused = 7; // This makes a spare of 1 bits - mib->message.choice.mib->ssb_SubcarrierOffset = carrier->ssb_SubcarrierOffset; + mib->message.choice.mib->ssb_SubcarrierOffset = (carrier->ssb_SubcarrierOffset)&15; mib->message.choice.mib->pdcch_ConfigSIB1.controlResourceSetZero = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero; mib->message.choice.mib->pdcch_ConfigSIB1.searchSpaceZero = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero; AssertFatal(scc->ssbSubcarrierSpacing != NULL, "scc->ssbSubcarrierSpacing is null\n"); @@ -264,23 +261,18 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { return((enc_rval.encoded+7)/8); } -uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier -#if defined(ENABLE_ITTI) - , gNB_RrcConfigurationReq *configuration -#endif +uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, + gNB_RrcConfigurationReq *configuration ) { asn_enc_rval_t enc_rval; NR_BCCH_DL_SCH_Message_t *sib1_message ; struct NR_SIB1 *sib1 ; int i; struct NR_PLMN_IdentityInfo nr_plmn_info; -#if defined(ENABLE_ITTI) + // TODO : Add support for more than one PLMN //int num_plmn = configuration->num_plmn; int num_plmn = 1; -#else - int num_plmn = 1; -#endif struct NR_PLMN_Identity nr_plmn[num_plmn]; NR_MCC_MNC_Digit_t nr_mcc_digit[num_plmn][3]; NR_MCC_MNC_Digit_t nr_mnc_digit[num_plmn][3]; @@ -304,30 +296,18 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier memset(nr_plmn,0,num_plmn*sizeof(struct NR_PLMN_Identity)); for (i = 0; i < num_plmn; ++i) { -#ifdef ENABLE_ITTI nr_mcc_digit[i][0] = (configuration->mcc[i]/100)%10; nr_mcc_digit[i][1] = (configuration->mcc[i]/10)%10; nr_mcc_digit[i][2] = (configuration->mcc[i])%10; -#else - nr_mcc_digit[i][0] = 0; - nr_mcc_digit[i][1] = 0; - nr_mcc_digit[i][2] = 1; -#endif nr_plmn[i].mcc = CALLOC(1,sizeof(struct NR_MCC)); memset(nr_plmn[i].mcc,0,sizeof(struct NR_MCC)); asn_set_empty(&nr_plmn[i].mcc->list); ASN_SEQUENCE_ADD(&nr_plmn[i].mcc->list, &nr_mcc_digit[i][0]); ASN_SEQUENCE_ADD(&nr_plmn[i].mcc->list, &nr_mcc_digit[i][1]); ASN_SEQUENCE_ADD(&nr_plmn[i].mcc->list, &nr_mcc_digit[i][2]); -#ifdef ENABLE_ITTI nr_mnc_digit[i][0] = (configuration->mnc[i]/100)%10; nr_mnc_digit[i][1] = (configuration->mnc[i]/10)%10; nr_mnc_digit[i][2] = (configuration->mnc[i])%10; -#else - nr_mnc_digit[i][0] = 0; - nr_mnc_digit[i][1] = 0; - nr_mnc_digit[i][2] = 1; -#endif memset(&nr_plmn[i].mnc,0,sizeof(NR_MNC_t)); nr_plmn[i].mnc.list.size=0; nr_plmn[i].mnc.list.count=0; @@ -339,17 +319,10 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier nr_plmn_info.cellIdentity.buf = MALLOC(8); memset(nr_plmn_info.cellIdentity.buf,0,8); -#ifdef ENABLE_ITTI nr_plmn_info.cellIdentity.buf[0]= (configuration->cell_identity >> 20) & 0xff; nr_plmn_info.cellIdentity.buf[1]= (configuration->cell_identity >> 12) & 0xff; nr_plmn_info.cellIdentity.buf[2]= (configuration->cell_identity >> 4) & 0xff; nr_plmn_info.cellIdentity.buf[3]= (configuration->cell_identity << 4) & 0xff; -#else - nr_plmn_info.cellIdentity.buf[0]= 0x00; - nr_plmn_info.cellIdentity.buf[1]= 0x00; - nr_plmn_info.cellIdentity.buf[2]= 0x00; - nr_plmn_info.cellIdentity.buf[3]= 0x10; -#endif nr_plmn_info.cellIdentity.size= 4; nr_plmn_info.cellIdentity.bits_unused= 4; nr_plmn_info.cellReservedForOperatorUse = 0; @@ -383,7 +356,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier } - void do_RLC_BEARER(uint8_t Mod_id, int CC_id, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_BearerToAddModList, @@ -601,10 +573,8 @@ void do_SpCellConfig(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *common_configuration; common_configuration = CALLOC(1,sizeof(gNB_RrcConfigurationReq)); //Fill servingcellconfigcommon config value - //Fill common config to structure // rrc->configuration = common_configuration; spconfig->reconfigurationWithSync = CALLOC(1,sizeof(struct NR_ReconfigurationWithSync)); - } diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index df960609d4..3f647cb887 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -61,10 +61,8 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc, @param carrier pointer to Carrier information @param configuration Pointer Configuration Request structure @return size of encoded bit stream in bytes*/ -uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier -#if defined(ENABLE_ITTI) - , gNB_RrcConfigurationReq *configuration -#endif +uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, + gNB_RrcConfigurationReq *configuration ); void do_RLC_BEARER(uint8_t Mod_id, diff --git a/openair2/RRC/NR/nr_rrc_common.c b/openair2/RRC/NR/nr_rrc_common.c index f5ab3f2366..daa9663ca8 100644 --- a/openair2/RRC/NR/nr_rrc_common.c +++ b/openair2/RRC/NR/nr_rrc_common.c @@ -29,7 +29,7 @@ */ #include "nr_rrc_extern.h" -#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "COMMON/openair_defs.h" #include "COMMON/platform_types.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index c30478f0b0..e19d94b341 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -117,10 +117,8 @@ typedef struct rach_dedicated_s{ }rach_dedicated_t; void rrc_config_servingcellconfigcommon(uint8_t Mod_id, - int CC_id - #if defined(ENABLE_ITTI) - ,gNB_RrcConfigurationReq *common_configuration - #endif + int CC_id, + gNB_RrcConfigurationReq *common_configuration ); void rrc_config_rlc_bearer(uint8_t Mod_id, @@ -138,4 +136,4 @@ void rrc_config_physicalcellgroup(uint8_t Mod_id, physicalcellgroup_t *physicalcellgroup_config ); -#endif \ No newline at end of file +#endif diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index db3d550684..02b4154c41 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -67,21 +67,15 @@ #include "NR_EstablishmentCause.h" //------------------- -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif +#include "intertask_interface.h" /* TODO: be sure this include is correct. * It solves a problem of compilation of the RRH GW, * issue #186. */ -#if !defined(ENABLE_ITTI) #include "as_message.h" -#endif -#if defined(ENABLE_USE_MME) #include "commonDef.h" -#endif /*I will change the name of the structure for compile purposes--> hope not to undo this process*/ @@ -296,7 +290,6 @@ typedef struct gNB_RRC_UE_s { rnti_t rnti; uint64_t random_ue_identity; -#if defined(ENABLE_ITTI) /* Information from UE RRC ConnectionRequest */ UE_S_TMSI Initialue_identity_s_TMSI; NR_EstablishmentCause_t establishment_cause; @@ -329,7 +322,6 @@ typedef struct gNB_RRC_UE_s { uint32_t enb_gtp_teid[S1AP_MAX_E_RAB]; transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB]; -#endif uint32_t ul_failure_timer; uint32_t ue_release_timer; uint32_t ue_release_timer_thres; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index bd13c6cc22..5770b80595 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -70,7 +70,6 @@ void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc,LTE_UE_CapabilityRAT_ContainerL void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_p); void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellconfigcommon, - NR_RRCReconfiguration_IEs_t *reconfig, NR_CellGroupConfig_t *secondaryCellGroup, int scg_id, int servCellIndex, @@ -94,9 +93,7 @@ int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo); -#if defined(ENABLE_ITTI) /**\brief RRC eNB task. \param void *args_p Pointer on arguments to start the task. */ void *rrc_gnb_task(void *args_p); -#endif diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a9e680e0a4..fba6610554 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -69,17 +69,19 @@ #include "UTIL/OSA/osa_defs.h" #endif -# include "rrc_eNB_S1AP.h" -# include "rrc_eNB_GTPV1U.h" +#include "rrc_eNB_S1AP.h" +#include "rrc_eNB_GTPV1U.h" + #include "pdcp.h" #include "gtpv1u_eNB_task.h" -# include "intertask_interface.h" - +#include "intertask_interface.h" #include "SIMULATION/TOOLS/sim.h" // for taus +#include "executables/softmodem-common.h" + //#define XER_PRINT @@ -178,8 +180,6 @@ void rrc_gNB_generate_SgNBAdditionRequestAcknowledge( ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// -extern int phy_test; - static void init_NR_SI(gNB_RRC_INST *rrc) { @@ -204,7 +204,7 @@ static void init_NR_SI(gNB_RRC_INST *rrc) { ); - if (phy_test > 0) { + if (get_softmodem_params()->phy_test > 0) { // This is for phytest only, emulate first X2 message if uecap.raw file is present FILE *fd; @@ -277,7 +277,6 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu AssertFatal(rrc != NULL, "RC.nrrrc not initialized!"); AssertFatal(NUMBER_OF_UE_MAX < (module_id_t)0xFFFFFFFFFFFFFFFF, " variable overflow"); AssertFatal(configuration!=NULL,"configuration input is null\n"); - rrc->module_id = gnb_mod_idP; rrc->Nb_ue = 0; @@ -300,9 +299,54 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu }//END openair_rrc_gNB_configuration -///---------------------------------------------------------------------------------------------------------------/// -///---------------------------------------------------------------------------------------------------------------/// +void rrc_gNB_process_AdditionRequestInformation(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_addition_req_t *m) { + + LTE_UL_DCCH_Message_t *LTE_UL_DCCH_Message = NULL; + + asn_dec_rval_t dec_rval = uper_decode_complete( NULL, + &asn_DEF_LTE_UL_DCCH_Message, + (void **)<E_UL_DCCH_Message, + (uint8_t *)m->rrc_buffer, + (int) m->rrc_buffer_size);//m->rrc_buffer_size); + +/* asn_dec_rval_t dec_rval = uper_decode( NULL, + &asn_DEF_LTE_UL_DCCH_Message, + (void **)<E_UL_DCCH_Message, + (uint8_t *)m->rrc_buffer, + (int) m->rrc_buffer_size, 0, 0);//m->rrc_buffer_size); +*/ + gNB_RRC_INST *rrc=RC.nrrrc[gnb_mod_idP]; + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + AssertFatal(1==0,"NR_UL_DCCH_MESSAGE decode error\n"); + // free the memory + SEQUENCE_free( &asn_DEF_LTE_UL_DCCH_Message, LTE_UL_DCCH_Message, 1 ); + return; + } + xer_fprint(stdout,&asn_DEF_LTE_UL_DCCH_Message, LTE_UL_DCCH_Message); + // recreate enough of X2 EN-DC Container + AssertFatal(LTE_UL_DCCH_Message->message.choice.c1.present == LTE_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation, + "ueCapabilityInformation not present\n"); + NR_CG_ConfigInfo_t *CG_ConfigInfo = calloc(1,sizeof(*CG_ConfigInfo)); + CG_ConfigInfo->criticalExtensions.present = NR_CG_ConfigInfo__criticalExtensions_PR_c1; + CG_ConfigInfo->criticalExtensions.choice.c1 = calloc(1,sizeof(*CG_ConfigInfo->criticalExtensions.choice.c1)); + CG_ConfigInfo->criticalExtensions.choice.c1->present = NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo; + CG_ConfigInfo->criticalExtensions.choice.c1->choice.cg_ConfigInfo = calloc(1,sizeof(*CG_ConfigInfo->criticalExtensions.choice.c1->choice.cg_ConfigInfo)); + NR_CG_ConfigInfo_IEs_t *cg_ConfigInfo = CG_ConfigInfo->criticalExtensions.choice.c1->choice.cg_ConfigInfo; + cg_ConfigInfo->ue_CapabilityInfo = calloc(1,sizeof(*cg_ConfigInfo->ue_CapabilityInfo)); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_UE_CapabilityRAT_ContainerList,NULL,(void*)<E_UL_DCCH_Message->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList,m->rrc_buffer,m->rrc_buffer_size); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + OCTET_STRING_fromBuf(cg_ConfigInfo->ue_CapabilityInfo, + (const char *)m->rrc_buffer, + (enc_rval.encoded+7)>>3); + parse_CG_ConfigInfo(rrc,CG_ConfigInfo); + +} + +///---------------------------------------------------------------------------------------------------------------/// +///---------------------------------------------------------------------------------------------------------------/// void *rrc_gnb_task(void *args_p) { MessageDef *msg_p; const char *msg_name_p; @@ -396,6 +440,17 @@ void *rrc_gnb_task(void *args_p) { openair_rrc_gNB_configuration(GNB_INSTANCE_TO_MODULE_ID(instance), &NRRRC_CONFIGURATION_REQ(msg_p)); break; + /* Messages from X2AP */ + case X2AP_ENDC_SGNB_ADDITION_REQ: + LOG_I(NR_RRC, "Received ENDC sgNB addition request from X2AP \n"); + rrc_gNB_process_AdditionRequestInformation(GNB_INSTANCE_TO_MODULE_ID(instance), &X2AP_ENDC_SGNB_ADDITION_REQ(msg_p)); + break; + + case X2AP_ENDC_SGNB_RECONF_COMPLETE: + LOG_I(NR_RRC, "Handling of reconfiguration complete message at RRC gNB is pending \n"); + break; + + default: LOG_E(NR_RRC, "[gNB %d] Received unexpected message %s\n", instance, msg_name_p); break; diff --git a/openair2/RRC/NR/rrc_gNB_internode.c b/openair2/RRC/NR/rrc_gNB_internode.c index 41a0f25e5e..581015db56 100644 --- a/openair2/RRC/NR/rrc_gNB_internode.c +++ b/openair2/RRC/NR/rrc_gNB_internode.c @@ -85,13 +85,15 @@ int generate_CG_Config(gNB_RRC_INST *rrc, cg_Config->criticalExtensions.choice.c1->present = NR_CG_Config__criticalExtensions__c1_PR_cg_Config; cg_Config->criticalExtensions.choice.c1->choice.cg_Config = calloc(1,sizeof(NR_CG_Config_IEs_t)); char buffer[1024]; + int total_size; asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_RRCReconfiguration, NULL, (void *)reconfig, buffer, 1024); AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig = calloc(1,sizeof(OCTET_STRING_t)); OCTET_STRING_fromBuf(cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig, (const char *)buffer, - (enc_rval.encoded+7)>>3); + (enc_rval.encoded+7)>>3); + total_size = (enc_rval.encoded+7)>>3; LOG_I(RRC,"Dumping NR_RRCReconfiguration message (%jd bytes)\n",(enc_rval.encoded+7)>>3); for (int i=0;i<(enc_rval.encoded+7)>>3;i++) { @@ -117,8 +119,9 @@ int generate_CG_Config(gNB_RRC_INST *rrc, fd = fopen("rbconfig.raw","w"); fwrite((void*)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd); fclose(fd); + total_size = total_size + ((enc_rval.encoded+7)>>3); - return(0); + return(total_size); } #endif diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 8e2e25fe3b..cf48aef459 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -103,6 +103,9 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ rrc_gNB_carrier_data_t *carrier=&rrc->carrier; + MessageDef *msg; + msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_ENDC_SGNB_ADDITION_REQ_ACK); + // NR RRCReconfiguration AssertFatal(rrc->Nb_ue < MAX_NR_RRC_UE_CONTEXTS,"cannot add another UE\n"); @@ -127,8 +130,19 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ ue_context_p->ue_id_rnti = ue_context_p->ue_context.secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity; NR_CG_Config_t *CG_Config = calloc(1,sizeof(*CG_Config)); memset((void*)CG_Config,0,sizeof(*CG_Config)); - generate_CG_Config(rrc,CG_Config,ue_context_p->ue_context.reconfig,ue_context_p->ue_context.rb_config); + int CG_Config_size = generate_CG_Config(rrc,CG_Config,ue_context_p->ue_context.reconfig,ue_context_p->ue_context.rb_config); + + //X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = CG_Config_size; //Need to verify correct value for the buffer_size // Send to X2 entity to transport to MeNB + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CG_Config, + NULL, + (void *)CG_Config, + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer, + 1024); + + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = (enc_rval.encoded+7)>>3; + + itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); //Check right id instead of hardcoding rrc->Nb_ue++; // configure MAC and RLC diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 84b99ed25e..1df17a19aa 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -41,10 +41,12 @@ #include "BOOLEAN.h" #include "assertions.h" #include "common/utils/nr/nr_common.h" +#include "SIMULATION/TOOLS/sim.h" +#include "executables/softmodem-common.h" + #define false 0 #define true 1 -extern int phy_test; void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CellGroupConfig_t *secondaryCellGroup, @@ -64,7 +66,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco RLC_BearerConfig->servedRadioBearer = calloc(1,sizeof(*RLC_BearerConfig->servedRadioBearer)); RLC_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; - RLC_BearerConfig->servedRadioBearer->choice.drb_Identity=5; + RLC_BearerConfig->servedRadioBearer->choice.drb_Identity=1; RLC_BearerConfig->reestablishRLC=calloc(1,sizeof(*RLC_BearerConfig->reestablishRLC)); *RLC_BearerConfig->reestablishRLC=NR_RLC_BearerConfig__reestablishRLC_true; RLC_BearerConfig->rlc_Config=calloc(1,sizeof(*RLC_BearerConfig->rlc_Config)); @@ -106,7 +108,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig = NULL; secondaryCellGroup->mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->bsr_Config)); secondaryCellGroup->mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf80; - secondaryCellGroup->mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf320; + secondaryCellGroup->mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf320; secondaryCellGroup->mac_CellGroupConfig->tag_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->tag_Config)); secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToReleaseList = NULL; secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToAddModList = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToAddModList)); @@ -148,7 +150,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco *secondaryCellGroup->spCellConfig->servCellIndex = servCellIndex; secondaryCellGroup->spCellConfig->reconfigurationWithSync=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->reconfigurationWithSync)); secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon=servingcellconfigcommon; - secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity=(phy_test==1) ? 0x1234 : (taus()&0xffff); + secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity=(get_softmodem_params()->phy_test==1) ? 0x1234 : (taus()&0xffff); secondaryCellGroup->spCellConfig->reconfigurationWithSync->t304=NR_ReconfigurationWithSync__t304_ms2000; secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated = NULL; secondaryCellGroup->spCellConfig->reconfigurationWithSync->ext1 = NULL; @@ -375,7 +377,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->sp_ZP_CSI_RS_ResourceSetsToAddModList=NULL; secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->sp_ZP_CSI_RS_ResourceSetsToReleaseList=NULL; secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->p_ZP_CSI_RS_ResourceSet=NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->sps_Config = NULL; + secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->sps_Config = NULL; //calloc(1,sizeof(struct NR_SetupRelease_SPS_Config)); secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->radioLinkMonitoringConfig = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->radioLinkMonitoringConfig)); secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->radioLinkMonitoringConfig->present = NR_SetupRelease_RadioLinkMonitoringConfig_PR_setup; @@ -794,7 +796,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco bwp->bwp_Dedicated->pdsch_Config->choice.setup->sp_ZP_CSI_RS_ResourceSetsToAddModList=NULL; bwp->bwp_Dedicated->pdsch_Config->choice.setup->sp_ZP_CSI_RS_ResourceSetsToReleaseList=NULL; bwp->bwp_Dedicated->pdsch_Config->choice.setup->p_ZP_CSI_RS_ResourceSet=NULL; - bwp->bwp_Dedicated->sps_Config = NULL; + bwp->bwp_Dedicated->sps_Config = NULL; //calloc(1,sizeof(struct NR_SetupRelease_SPS_Config)); bwp->bwp_Dedicated->radioLinkMonitoringConfig = calloc(1,sizeof(*bwp->bwp_Dedicated->radioLinkMonitoringConfig)); bwp->bwp_Dedicated->radioLinkMonitoringConfig->present = NR_SetupRelease_RadioLinkMonitoringConfig_PR_setup; @@ -2044,7 +2046,7 @@ void fill_default_rbconfig(NR_RadioBearerConfig_t *rbconfig) { drb_ToAddMod->cnAssociation = calloc(1,sizeof(*drb_ToAddMod->cnAssociation)); drb_ToAddMod->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity; drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity=5; - drb_ToAddMod->drb_Identity = 4; + drb_ToAddMod->drb_Identity = 1; drb_ToAddMod->reestablishPDCP = NULL; drb_ToAddMod->recoverPDCP = NULL; drb_ToAddMod->pdcp_Config = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config)); @@ -2073,7 +2075,7 @@ void fill_default_rbconfig(NR_RadioBearerConfig_t *rbconfig) { rbconfig->securityConfig = calloc(1,sizeof(*rbconfig->securityConfig)); rbconfig->securityConfig->securityAlgorithmConfig = calloc(1,sizeof(*rbconfig->securityConfig->securityAlgorithmConfig)); - rbconfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm = NR_CipheringAlgorithm_nea2; + rbconfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm = NR_CipheringAlgorithm_nea0; rbconfig->securityConfig->securityAlgorithmConfig->integrityProtAlgorithm=NULL; rbconfig->securityConfig->keyToUse = calloc(1,sizeof(*rbconfig->securityConfig->keyToUse)); *rbconfig->securityConfig->keyToUse = NR_SecurityConfig__keyToUse_master; diff --git a/openair2/RRC/NR_UE/main_ue.c b/openair2/RRC/NR_UE/main_ue.c index 89075331ef..07409c6026 100644 --- a/openair2/RRC/NR_UE/main_ue.c +++ b/openair2/RRC/NR_UE/main_ue.c @@ -32,10 +32,10 @@ #include "defs.h" #include "rrc_proto.h" +#include "common/utils/LOG/log.h" NR_UE_RRC_INST_t* nr_l3_init_ue(char* rrc_config_path){ //LOG_I(RRC, "[MAIN] NR UE MAC initialization...\n"); return openair_rrc_top_init_ue_nr(rrc_config_path); - } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 8a6823a572..87e899845e 100755 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -44,8 +44,8 @@ #include "rrc_vars.h" #include "mac_proto.h" +#include "executables/softmodem-common.h" -extern int phy_test; // from LTE-RRC DL-DCCH RRCConnectionReconfiguration nr-secondary-cell-group-config (encoded) int8_t nr_rrc_ue_decode_secondary_cellgroup_config( @@ -319,7 +319,7 @@ NR_UE_RRC_INST_t* openair_rrc_top_init_ue_nr(char* rrc_config_path){ RRC_LIST_INIT(NR_UE_rrc_inst->CSI_ResourceConfig_list, NR_maxNrofCSI_ResourceConfigurations); RRC_LIST_INIT(NR_UE_rrc_inst->CSI_ReportConfig_list, NR_maxNrofCSI_ReportConfigurations); - if (phy_test==1) { + if (get_softmodem_params()->phy_test==1) { // read in files for RRCReconfiguration and RBconfig FILE *fd; char filename[1024]; @@ -329,6 +329,11 @@ NR_UE_RRC_INST_t* openair_rrc_top_init_ue_nr(char* rrc_config_path){ sprintf(filename,"reconfig.raw"); fd = fopen(filename,"r"); char buffer[1024]; + AssertFatal(fd, + "cannot read file %s: errno %d, %s\n", + filename, + errno, + strerror(errno)); int msg_len=fread(buffer,1,1024,fd); fclose(fd); process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, buffer,msg_len); @@ -337,6 +342,11 @@ NR_UE_RRC_INST_t* openair_rrc_top_init_ue_nr(char* rrc_config_path){ else sprintf(filename,"rbconfig.raw"); fd = fopen(filename,"r"); + AssertFatal(fd, + "cannot read file %s: errno %d, %s\n", + filename, + errno, + strerror(errno)); msg_len=fread(buffer,1,1024,fd); fclose(fd); process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, buffer,msg_len); @@ -477,14 +487,14 @@ int8_t nr_rrc_ue_decode_NR_DL_DCCH_Message( case NR_DL_DCCH_MessageType__c1_PR_spare2: case NR_DL_DCCH_MessageType__c1_PR_spare1: default: - // not support or unuse + // not supported or unused break; } break; case NR_DL_DCCH_MessageType_PR_NOTHING: case NR_DL_DCCH_MessageType_PR_messageClassExtension: default: - // not support or unuse + // not supported or unused break; } diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index 4e1485ac5f..cb1207757d 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -40,6 +40,7 @@ #include "platform_types.h" #include "LAYER2/NR_MAC_UE/mac.h" +#include "LAYER2/NR_MAC_COMMON/nr_mac.h" #include "rrc_list.h" #include "NR_asn_constant.h" #include "NR_MeasConfig.h" diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c deleted file mode 100644 index faff4fcfb9..0000000000 --- a/openair2/UTIL/LOG/log.c +++ /dev/null @@ -1,1832 +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 log.c -* \brief log implementaion -* \author Navid Nikaein -* \date 2009 - 2014 -* \version 0.5 -* @ingroup util - -*/ - -#define _GNU_SOURCE /* required for pthread_getname_np */ -//#define LOG_TEST 1 - -#define COMPONENT_LOG -#define COMPONENT_LOG_IF -#include -#define LOG_MAIN -#include "log.h" -#include "vcd_signal_dumper.h" -#include "assertions.h" - -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#endif - -# include -# include -#include "common/config/config_userapi.h" -// main log variables - - -mapping log_level_names[] = { - {"emerg", LOG_EMERG}, - {"alert", LOG_ALERT}, - {"crit", LOG_CRIT}, - {"error", LOG_ERR}, - {"warn", LOG_WARNING}, - {"notice", LOG_NOTICE}, - {"info", LOG_INFO}, - {"debug", LOG_DEBUG}, - {"file", LOG_FILE}, - {"trace", LOG_TRACE}, - {NULL, -1} -}; -mapping log_verbosity_names[] = { - {"none", 0x0}, - {"low", 0x5}, - {"medium", 0x15}, - {"high", 0x35}, - {"full", 0x75}, - {NULL, -1} -}; - -// vars for the log thread -LOG_params log_list[2000]; -int log_list_tail = 0; -int log_list_nb_elements = 0; - -pthread_mutex_t log_lock; -pthread_cond_t log_notify; - - -#if !defined(LOG_NO_THREAD) -int log_list_head = 0; -int log_shutdown; -#endif - -static int gfd; - -static char *log_level_highlight_start[] = {LOG_RED, LOG_RED, LOG_RED, LOG_RED, LOG_ORANGE, LOG_BLUE, "", ""}; /*!< \brief Optional start-format strings for highlighting */ -static char *log_level_highlight_end[] = {LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET,LOG_RESET, "",""}; /*!< \brief Optional end-format strings for highlighting */ - -#if defined(ENABLE_ITTI) -static log_instance_type_t log_instance_type; -#endif - -/* get log parameters from configuration file */ -void log_getconfig(log_t *g_log) { - char *gloglevel = NULL; - char *glogverbo = NULL; - int level,verbosity; - paramdef_t logparams_defaults[] = LOG_GLOBALPARAMS_DESC; - paramdef_t logparams_level[MAX_LOG_COMPONENTS]; - paramdef_t logparams_verbosity[MAX_LOG_COMPONENTS]; - paramdef_t logparams_logfile[MAX_LOG_COMPONENTS]; - - int ret = config_get( logparams_defaults,sizeof(logparams_defaults)/sizeof(paramdef_t),CONFIG_STRING_LOG_PREFIX); - if (ret <0) { - fprintf(stderr,"[LOG] init aborted, configuration couldn't be performed"); - return; - } - memset(logparams_level, 0, sizeof(paramdef_t)*MAX_LOG_COMPONENTS); - memset(logparams_verbosity,0, sizeof(paramdef_t)*MAX_LOG_COMPONENTS); - memset(logparams_logfile, 0, sizeof(paramdef_t)*MAX_LOG_COMPONENTS); - for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) { - if(g_log->log_component[i].name == NULL) { - g_log->log_component[i].name = malloc(16); - sprintf((char *)g_log->log_component[i].name,"comp%i?",i); - logparams_logfile[i].paramflags = PARAMFLAG_DONOTREAD; - logparams_level[i].paramflags = PARAMFLAG_DONOTREAD; - logparams_verbosity[i].paramflags = PARAMFLAG_DONOTREAD; - } - sprintf(logparams_level[i].optname, LOG_CONFIG_LEVEL_FORMAT, g_log->log_component[i].name); - sprintf(logparams_verbosity[i].optname,LOG_CONFIG_VERBOSITY_FORMAT, g_log->log_component[i].name); - sprintf(logparams_logfile[i].optname, LOG_CONFIG_LOGFILE_FORMAT, g_log->log_component[i].name); -/* workaround: all log options in existing configuration files use lower case component names - where component names include uppercase char in log.h.... */ - for (int j=0 ; jlog_component[PHY].name = "PHY"; - g_log->log_component[PHY].level = LOG_EMERG; - g_log->log_component[PHY].flag = LOG_MED; - g_log->log_component[PHY].interval = 1; - g_log->log_component[PHY].fd = 0; - g_log->log_component[PHY].filelog = 0; - g_log->log_component[PHY].filelog_name = "/tmp/phy.log"; - - g_log->log_component[MAC].name = "MAC"; - g_log->log_component[MAC].level = LOG_EMERG; - g_log->log_component[MAC].flag = LOG_MED; - g_log->log_component[MAC].interval = 1; - g_log->log_component[MAC].fd = 0; - g_log->log_component[MAC].filelog = 0; - g_log->log_component[MAC].filelog_name = "/tmp/mac.log"; - - g_log->log_component[OPT].name = "OPT"; - g_log->log_component[OPT].level = LOG_EMERG; - g_log->log_component[OPT].flag = LOG_MED; - g_log->log_component[OPT].interval = 1; - g_log->log_component[OPT].fd = 0; - g_log->log_component[OPT].filelog = 0; - g_log->log_component[OPT].filelog_name = ""; - - g_log->log_component[RLC].name = "RLC"; - g_log->log_component[RLC].level = LOG_INFO; - g_log->log_component[RLC].flag = LOG_MED; - g_log->log_component[RLC].interval = 1; - g_log->log_component[RLC].fd = 0; - g_log->log_component[RLC].filelog = 0; - g_log->log_component[RLC].filelog_name = "/tmp/rlc.log"; - - g_log->log_component[PDCP].name = "PDCP"; - g_log->log_component[PDCP].level = LOG_INFO; - g_log->log_component[PDCP].flag = LOG_MED; - g_log->log_component[PDCP].interval = 1; - g_log->log_component[PDCP].fd = 0; - g_log->log_component[PDCP].filelog = 0; - g_log->log_component[PDCP].filelog_name = "/tmp/pdcp.log"; - - g_log->log_component[RRC].name = "RRC"; - g_log->log_component[RRC].level = LOG_TRACE; - g_log->log_component[RRC].flag = LOG_MED; - g_log->log_component[RRC].interval = 1; - g_log->log_component[RRC].fd = 0; - g_log->log_component[RRC].filelog = 0; - g_log->log_component[RRC].filelog_name = "/tmp/rrc.log"; - - g_log->log_component[EMU].name = "EMU"; - g_log->log_component[EMU].level = LOG_EMERG; - g_log->log_component[EMU].flag = LOG_MED; - g_log->log_component[EMU].interval = 1; - g_log->log_component[EMU].fd = 0; - g_log->log_component[EMU].filelog = 0; - g_log->log_component[EMU].filelog_name = ""; - - g_log->log_component[OMG].name = "OMG"; - g_log->log_component[OMG].level = LOG_EMERG; - g_log->log_component[OMG].flag = LOG_MED; - g_log->log_component[OMG].interval = 1; - g_log->log_component[OMG].fd = 0; - g_log->log_component[OMG].filelog = 0; - g_log->log_component[OMG].filelog_name = "/tmp/omg.csv"; - - g_log->log_component[OTG].name = "OTG"; - g_log->log_component[OTG].level = LOG_EMERG; - g_log->log_component[OTG].flag = LOG_MED; - g_log->log_component[OTG].interval = 1; - g_log->log_component[OTG].fd = 0; - g_log->log_component[OTG].filelog = 0; - g_log->log_component[OTG].filelog_name = "/tmp/otg.log"; - - g_log->log_component[OTG_LATENCY].name = "OTG_LATENCY"; - g_log->log_component[OTG_LATENCY].level = LOG_EMERG; - g_log->log_component[OTG_LATENCY].flag = LOG_MED; - g_log->log_component[OTG_LATENCY].interval = 1; - g_log->log_component[OTG_LATENCY].fd = 0; - g_log->log_component[OTG_LATENCY].filelog = 0; - g_log->log_component[OTG_LATENCY].filelog_name = "/tmp/otg_latency.dat"; - - g_log->log_component[OTG_LATENCY_BG].name = "OTG_LATENCY_BG"; - g_log->log_component[OTG_LATENCY_BG].level = LOG_EMERG; - g_log->log_component[OTG_LATENCY_BG].flag = LOG_MED; - g_log->log_component[OTG_LATENCY_BG].interval = 1; - g_log->log_component[OTG_LATENCY_BG].fd = 0; - g_log->log_component[OTG_LATENCY_BG].filelog = 0; - g_log->log_component[OTG_LATENCY_BG].filelog_name = "/tmp/otg_latency_bg.dat"; - - g_log->log_component[OTG_GP].name = "OTG_GP"; - g_log->log_component[OTG_GP].level = LOG_EMERG; - g_log->log_component[OTG_GP].flag = LOG_MED; - g_log->log_component[OTG_GP].interval = 1; - g_log->log_component[OTG_GP].fd = 0; - g_log->log_component[OTG_GP].filelog = 0; - g_log->log_component[OTG_GP].filelog_name = "/tmp/otg_goodput.dat"; - - g_log->log_component[OTG_GP_BG].name = "OTG_GP_BG"; - g_log->log_component[OTG_GP_BG].level = LOG_EMERG; - g_log->log_component[OTG_GP_BG].flag = LOG_MED; - g_log->log_component[OTG_GP_BG].interval = 1; - g_log->log_component[OTG_GP_BG].fd = 0; - g_log->log_component[OTG_GP_BG].filelog = 0; - g_log->log_component[OTG_GP_BG].filelog_name = "/tmp/otg_goodput_bg.dat"; - - g_log->log_component[OTG_JITTER].name = "OTG_JITTER"; - g_log->log_component[OTG_JITTER].level = LOG_EMERG; - g_log->log_component[OTG_JITTER].flag = LOG_MED; - g_log->log_component[OTG_JITTER].interval = 1; - g_log->log_component[OTG_JITTER].fd = 0; - g_log->log_component[OTG_JITTER].filelog = 0; - g_log->log_component[OTG_JITTER].filelog_name = "/tmp/otg_jitter.dat"; - - g_log->log_component[OCG].name = "OCG"; - g_log->log_component[OCG].level = LOG_EMERG; - g_log->log_component[OCG].flag = LOG_MED; - g_log->log_component[OCG].interval = 1; - g_log->log_component[OCG].fd = 0; - g_log->log_component[OCG].filelog = 0; - g_log->log_component[OCG].filelog_name = ""; - - g_log->log_component[PERF].name = "PERF"; - g_log->log_component[PERF].level = LOG_EMERG; - g_log->log_component[PERF].flag = LOG_MED; - g_log->log_component[PERF].interval = 1; - g_log->log_component[PERF].fd = 0; - g_log->log_component[PERF].filelog = 0; - g_log->log_component[PERF].filelog_name = ""; - - g_log->log_component[OIP].name = "OIP"; - g_log->log_component[OIP].level = LOG_EMERG; - g_log->log_component[OIP].flag = LOG_MED; - g_log->log_component[OIP].interval = 1; - g_log->log_component[OIP].fd = 0; - g_log->log_component[OIP].filelog = 0; - g_log->log_component[OIP].filelog_name = ""; - - g_log->log_component[CLI].name = "CLI"; - g_log->log_component[CLI].level = LOG_EMERG; - g_log->log_component[CLI].flag = LOG_MED; - g_log->log_component[CLI].interval = 1; - g_log->log_component[CLI].fd = 0; - g_log->log_component[CLI].filelog = 0; - g_log->log_component[CLI].filelog_name = ""; - - g_log->log_component[MSC].name = "MSC"; - g_log->log_component[MSC].level = LOG_EMERG; - g_log->log_component[MSC].flag = LOG_MED; - g_log->log_component[MSC].interval = 1; - g_log->log_component[MSC].fd = 0; - g_log->log_component[MSC].filelog = 0; - g_log->log_component[MSC].filelog_name = "/tmp/msc.log"; - - g_log->log_component[PROTO_AGENT].name = "PROTO_AGENT"; - g_log->log_component[PROTO_AGENT].level = LOG_EMERG; - g_log->log_component[PROTO_AGENT].flag = LOG_MED; - g_log->log_component[PROTO_AGENT].interval = 1; - g_log->log_component[PROTO_AGENT].fd = 0; - g_log->log_component[PROTO_AGENT].filelog = 0; - g_log->log_component[PROTO_AGENT].filelog_name = "/tmp/proto_agent.log"; - - - - g_log->log_component[PROTO_AGENT].name = "PROTO_AGENT"; - g_log->log_component[PROTO_AGENT].level = LOG_EMERG; - g_log->log_component[PROTO_AGENT].flag = LOG_MED; - g_log->log_component[PROTO_AGENT].interval = 1; - g_log->log_component[PROTO_AGENT].fd = 0; - g_log->log_component[PROTO_AGENT].filelog = 0; - g_log->log_component[PROTO_AGENT].filelog_name = "/tmp/proto_agent.log"; - - g_log->log_component[F1U].name = "F1U"; - g_log->log_component[F1U].level = LOG_EMERG; - g_log->log_component[F1U].flag = LOG_MED; - g_log->log_component[F1U].interval = 1; - g_log->log_component[F1U].fd = 0; - g_log->log_component[F1U].filelog = 0; - g_log->log_component[F1U].filelog_name = "/tmp/f1u.log"; - - g_log->log_component[OCM].name = "OCM"; - g_log->log_component[OCM].level = LOG_EMERG; - g_log->log_component[OCM].flag = LOG_MED; - g_log->log_component[OCM].interval = 1; - g_log->log_component[OCM].fd = 0; - g_log->log_component[OCM].filelog = 0; - g_log->log_component[OCM].filelog_name = "/tmp/ocm.log"; - - g_log->log_component[HW].name = "HW"; - g_log->log_component[HW].level = LOG_EMERG; - g_log->log_component[HW].flag = LOG_MED; - g_log->log_component[HW].interval = 1; - g_log->log_component[HW].fd = 0; - g_log->log_component[HW].filelog = 0; - g_log->log_component[HW].filelog_name = ""; - - g_log->log_component[OSA].name = "OSA"; - g_log->log_component[OSA].level = LOG_EMERG; - g_log->log_component[OSA].flag = LOG_MED; - g_log->log_component[OSA].interval = 1; - g_log->log_component[OSA].fd = 0; - g_log->log_component[OSA].filelog = 0; - g_log->log_component[OSA].filelog_name = ""; - - g_log->log_component[RAL_ENB].name = "eRAL"; - g_log->log_component[RAL_ENB].level = LOG_EMERG; - g_log->log_component[RAL_ENB].flag = LOG_MED; - g_log->log_component[RAL_ENB].interval = 1; - g_log->log_component[RAL_ENB].fd = 0; - g_log->log_component[RAL_ENB].filelog = 0; - g_log->log_component[RAL_ENB].filelog_name = ""; - - g_log->log_component[RAL_UE].name = "mRAL"; - g_log->log_component[RAL_UE].level = LOG_EMERG; - g_log->log_component[RAL_UE].flag = LOG_MED; - g_log->log_component[RAL_UE].interval = 1; - g_log->log_component[RAL_UE].fd = 0; - g_log->log_component[RAL_UE].filelog = 0; - g_log->log_component[RAL_UE].filelog_name = ""; - - g_log->log_component[ENB_APP].name = "ENB_APP"; - g_log->log_component[ENB_APP].level = LOG_EMERG; - g_log->log_component[ENB_APP].flag = LOG_MED; - g_log->log_component[ENB_APP].interval = 1; - g_log->log_component[ENB_APP].fd = 0; - g_log->log_component[ENB_APP].filelog = 0; - g_log->log_component[ENB_APP].filelog_name = ""; - - g_log->log_component[FLEXRAN_AGENT].name = "FLEXRAN_AGENT"; - g_log->log_component[FLEXRAN_AGENT].level = LOG_DEBUG; - g_log->log_component[FLEXRAN_AGENT].flag = LOG_MED; - g_log->log_component[FLEXRAN_AGENT].interval = 1; - g_log->log_component[FLEXRAN_AGENT].fd = 0; - g_log->log_component[FLEXRAN_AGENT].filelog = 0; - g_log->log_component[FLEXRAN_AGENT].filelog_name = ""; - - g_log->log_component[TMR].name = "TMR"; - g_log->log_component[TMR].level = LOG_EMERG; - g_log->log_component[TMR].flag = LOG_MED; - g_log->log_component[TMR].interval = 1; - g_log->log_component[TMR].fd = 0; - g_log->log_component[TMR].filelog = 0; - g_log->log_component[TMR].filelog_name = ""; - - g_log->log_component[USIM].name = "USIM"; - g_log->log_component[USIM].level = LOG_DEBUG; - g_log->log_component[USIM].flag = LOG_NONE; - g_log->log_component[USIM].interval = 1; - g_log->log_component[USIM].fd = 0; - g_log->log_component[USIM].filelog = 0; - g_log->log_component[USIM].filelog_name = "/tmp/usim.txt"; - - /* following log component are used for the localization*/ - g_log->log_component[LOCALIZE].name = "LOCALIZE"; - g_log->log_component[LOCALIZE].level = LOG_EMERG; - g_log->log_component[LOCALIZE].flag = LOG_MED; - g_log->log_component[LOCALIZE].interval = 1; - g_log->log_component[LOCALIZE].fd = 0; - g_log->log_component[LOCALIZE].filelog = 0; - g_log->log_component[LOCALIZE].filelog_name = "/tmp/localize.log"; -#endif // ! defined(CN_BUILD) - - g_log->log_component[NAS].name = "NAS"; - g_log->log_component[NAS].level = LOG_TRACE; - g_log->log_component[NAS].flag = LOG_MED; - g_log->log_component[NAS].interval = 1; - g_log->log_component[NAS].fd = 0; - g_log->log_component[NAS].filelog = 0; - g_log->log_component[NAS].filelog_name = "/tmp/nas.log"; - - g_log->log_component[UDP_].name = "UDP"; - g_log->log_component[UDP_].level = LOG_EMERG; - g_log->log_component[UDP_].flag = LOG_FULL; - g_log->log_component[UDP_].interval = 1; - g_log->log_component[UDP_].fd = 0; - g_log->log_component[UDP_].filelog = 0; - g_log->log_component[UDP_].filelog_name = ""; - - g_log->log_component[GTPU].name = "GTPV1U"; - g_log->log_component[GTPU].level = LOG_EMERG; - g_log->log_component[GTPU].flag = LOG_FULL; - g_log->log_component[GTPU].interval = 1; - g_log->log_component[GTPU].fd = 0; - g_log->log_component[GTPU].filelog = 0; - g_log->log_component[GTPU].filelog_name = ""; - - g_log->log_component[S1AP].name = "S1AP"; - g_log->log_component[S1AP].level = LOG_EMERG; - g_log->log_component[S1AP].flag = LOG_FULL; - g_log->log_component[S1AP].interval = 1; - g_log->log_component[S1AP].fd = 0; - g_log->log_component[S1AP].filelog = 0; - g_log->log_component[S1AP].filelog_name = ""; - - g_log->log_component[SCTP].name = "SCTP"; - g_log->log_component[SCTP].level = LOG_EMERG; - g_log->log_component[SCTP].flag = LOG_MED; - g_log->log_component[SCTP].interval = 1; - g_log->log_component[SCTP].fd = 0; - g_log->log_component[SCTP].filelog = 0; - g_log->log_component[SCTP].filelog_name = ""; - - g_log->log_component[RRH].name = "RRH"; - g_log->log_component[RRH].level = LOG_EMERG; - g_log->log_component[RRH].flag = LOG_MED; - g_log->log_component[RRH].interval = 1; - g_log->log_component[RRH].fd = 0; - g_log->log_component[RRH].filelog = 0; - g_log->log_component[RRH].filelog_name = ""; - - g_log->level2string[LOG_EMERG] = "G"; //EMERG - g_log->level2string[LOG_ALERT] = "A"; // ALERT - g_log->level2string[LOG_CRIT] = "C"; // CRITIC - g_log->level2string[LOG_ERR] = "E"; // ERROR - g_log->level2string[LOG_WARNING] = "W"; // WARNING - g_log->level2string[LOG_NOTICE] = "N"; // NOTICE - g_log->level2string[LOG_INFO] = "I"; //INFO - g_log->level2string[LOG_DEBUG] = "D"; // DEBUG - g_log->level2string[LOG_FILE] = "F"; // file - g_log->level2string[LOG_TRACE] = "T"; // TRACE - - g_log->onlinelog = 1; //online log file - g_log->syslog = 0; - g_log->filelog = 0; - g_log->level = LOG_TRACE; - g_log->flag = LOG_LOW; - - g_log->config.remote_ip = 0; - g_log->config.remote_level = LOG_EMERG; - g_log->config.facility = LOG_LOCAL7; - g_log->config.audit_ip = 0; - g_log->config.audit_facility = LOG_LOCAL6; - g_log->config.format = 0x00; // online debug inactive - - g_log->filelog_name = "/tmp/openair.log"; - - if (g_log->syslog) { -#if ! defined(CN_BUILD) - openlog(g_log->log_component[EMU].name, LOG_PID, g_log->config.facility); -#endif // ! defined(CN_BUILD) - } - log_getconfig(g_log); - if (g_log->filelog) { - gfd = open(g_log->filelog_name, O_WRONLY | O_CREAT, 0666); - } - - // could put a loop here to check for all comps - for (i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) { - if (g_log->log_component[i].filelog == 1 ) { - g_log->log_component[i].fd = open(g_log->log_component[i].filelog_name, - O_WRONLY | O_CREAT | O_APPEND, 0666); - } - } - - printf("log init done\n"); - - return 0; -} - -void nfapi_log(char *file, char *func, int line, int comp, int level, const char* format, va_list args) -{ - //logRecord_mt(file,func,line, pthread_self(), comp, level, format, ##args) - int len = 0; - log_component_t *c; - char *log_start; - char *log_end; - /* The main difference with the version above is the use of this local log_buffer. - * The other difference is the return value of snprintf which was not used - * correctly. It was not a big problem because in practice MAX_LOG_TOTAL is - * big enough so that the buffer is never full. - */ - char log_buffer[MAX_LOG_TOTAL]; - - /* for no gcc warnings */ - (void)log_start; - (void)log_end; - - c = &g_log->log_component[comp]; - - // do not apply filtering for LOG_F - // only log messages which are enabled and are below the global log level and component's level threshold - if ((level != LOG_FILE) && ((level > c->level) || (level > g_log->level))) { - /* if ((level != LOG_FILE) && - ((level > c->level) || - (level > g_log->level) || - ( c->level > g_log->level))) { - */ - return; - } - - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, VCD_FUNCTION_IN); - - // adjust syslog level for TRACE messages - if (g_log->syslog) { - if (g_log->level > LOG_DEBUG) { - g_log->level = LOG_DEBUG; - } - } - - // make sure that for log trace the extra info is only printed once, reset when the level changes - if ((level == LOG_FILE) || (c->flag == LOG_NONE) || (level == LOG_TRACE)) { - log_start = log_buffer; - len = vsnprintf(log_buffer, MAX_LOG_TOTAL, format, args); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - log_end = log_buffer + len; - } else { - if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_start[level]); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - log_start = log_buffer + len; - - if ( (g_log->flag & FLAG_COMP) || (c->flag & FLAG_COMP) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", - g_log->log_component[comp].name); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - if ( (g_log->flag & FLAG_LEVEL) || (c->flag & FLAG_LEVEL) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", - g_log->level2string[level]); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - if ( (g_log->flag & FLAG_THREAD) || (c->flag & FLAG_THREAD) ) { -# define THREAD_NAME_LEN 128 - char threadname[THREAD_NAME_LEN]; - if (pthread_getname_np(pthread_self(), threadname, THREAD_NAME_LEN) != 0) - { - perror("pthread_getname_np : "); - } else { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", threadname); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } -# undef THREAD_NAME_LEN - } - - if ( (g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s] ", - func); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - if ( (g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s:%d]", - file, line); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - //len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%08lx]", thread_id); - //if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - - len += vsnprintf(&log_buffer[len], MAX_LOG_TOTAL - len, format, args); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - log_end = log_buffer + len; - - if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_end[level]); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - } - - va_end(args); - - // OAI printf compatibility - if ((g_log->onlinelog == 1) && (level != LOG_FILE)) -#ifdef RTAI - if (len > MAX_LOG_TOTAL) { - rt_printk ("[OPENAIR] FIFO_PRINTF WROTE OUTSIDE ITS MEMORY BOUNDARY : ERRORS WILL OCCUR\n"); - } - - if (len > 0) { - rtf_put (FIFO_PRINTF_NO, log_buffer, len); - } - -#else - fwrite(log_buffer, len, 1, stdout); -#endif - -#ifndef RTAI - - if (g_log->syslog) { - syslog(g_log->level, "%s", log_buffer); - } - - if (g_log->filelog) { - if (write(gfd, log_buffer, len) < len) { - // TODO assert ? - } - } - - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - if (write(g_log->log_component[comp].fd, log_buffer, len) < len) { - // TODO assert ? - } - } - -#else - - // online print messges - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - printf(log_buffer); - } - -#endif - -#if defined(ENABLE_ITTI) - - if (level <= LOG_DEBUG) { - task_id_t origin_task_id = TASK_UNKNOWN; - MessagesIds messages_id; - MessageDef *message_p; - size_t message_string_size; - char *message_msg_p; - - message_string_size = log_end - log_start; - -#if !defined(DISABLE_ITTI_DETECT_SUB_TASK_ID) - - /* Try to identify sub task ID from log information (comp, log_instance_type) */ - switch (comp) { - case PHY: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_PHY_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_PHY_UE; - break; - - default: - break; - } - - break; - - case MAC: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_MAC_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_MAC_UE; - - default: - break; - } - - break; - - case RLC: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_RLC_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_RLC_UE; - - default: - break; - } - - break; - - case PDCP: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_PDCP_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_PDCP_UE; - - default: - break; - } - - break; - - default: - break; - } - -#endif - - switch (level) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - messages_id = ERROR_LOG; - break; - - case LOG_WARNING: - messages_id = WARNING_LOG; - break; - - case LOG_NOTICE: - messages_id = NOTICE_LOG; - break; - - case LOG_INFO: - messages_id = INFO_LOG; - break; - - default: - messages_id = DEBUG_LOG; - break; - } - - message_p = itti_alloc_new_message_sized(origin_task_id, messages_id, message_string_size); - - switch (level) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - message_msg_p = (char *) &message_p->ittiMsg.error_log; - break; - - case LOG_WARNING: - message_msg_p = (char *) &message_p->ittiMsg.warning_log; - break; - - case LOG_NOTICE: - message_msg_p = (char *) &message_p->ittiMsg.notice_log; - break; - - case LOG_INFO: - message_msg_p = (char *) &message_p->ittiMsg.info_log; - break; - - default: - message_msg_p = (char *) &message_p->ittiMsg.debug_log; - break; - } - - memcpy(message_msg_p, log_start, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); - } - -#endif -#if 0 - LOG_params log_params; - int len; - - len = vsnprintf(log_params.l_buff_info, MAX_LOG_INFO-1, format, args); - - //2 first parameters must be passed as 'const' to the thread function - log_params.file = strdup(file); - log_params.func = strdup(func); - log_params.line = line; - log_params.comp = PHY;//comp; - log_params.level = 6; // INFO - level; - log_params.format = format; - log_params.len = len; - - if (pthread_mutex_lock(&log_lock) != 0) { - return; - } - - log_list_tail++; - log_list[log_list_tail - 1] = log_params; - - if (log_list_tail >= 1000) { - log_list_tail = 0; - } - - if (log_list_nb_elements < 1000) { - log_list_nb_elements++; - } - - if(pthread_cond_signal(&log_notify) != 0) { - pthread_mutex_unlock(&log_lock); - return; - } - - if(pthread_mutex_unlock(&log_lock) != 0) { - return; - } - -#endif -} - -//log record: add to a list -void logRecord(const char *file, const char *func, int line, int comp, - int level, const char *format, ...) -{ - va_list args; - LOG_params log_params; - int len; - - va_start(args, format); - len = vsnprintf(log_params.l_buff_info, MAX_LOG_INFO-1, format, args); - va_end(args); - - //2 first parameters must be passed as 'const' to the thread function - log_params.file = strdup(file); - log_params.func = strdup(func); - log_params.line = line; - log_params.comp = comp; - log_params.level = level; - log_params.format = format; - log_params.len = len; - - if (pthread_mutex_lock(&log_lock) != 0) { - return; - } - - log_list_tail++; - log_list[log_list_tail - 1] = log_params; - - if (log_list_tail >= 1000) { - log_list_tail = 0; - } - - if (log_list_nb_elements < 1000) { - log_list_nb_elements++; - } - - if(pthread_cond_signal(&log_notify) != 0) { - pthread_mutex_unlock(&log_lock); - return; - } - - if(pthread_mutex_unlock(&log_lock) != 0) { - return; - } - - //log = malloc(sizeof(LOG_elt)); - //log->next = NULL; - //log->log_params = log_params; - /* Add log task to queue */ - //log_list_add_tail_eurecom(log, &log_list); - -} - -void logRecord_thread_safe(const char *file, const char *func, - int line, int comp, int level, - int len, const char *params_string) -{ - log_component_t *c; - int total_len = 0; - char log_buffer[MAX_LOG_TOTAL]; - - c = &g_log->log_component[comp]; - - // do not apply filtering for LOG_F - // only log messages which are enabled and are below the global log level and component's level threshold - if ((level != LOG_FILE) && ((c->level > g_log->level) || - (level > c->level) || (level > g_log->level))) { - return; - } - - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_IN); - - // adjust syslog level for TRACE messages - if (g_log->syslog) { - if (g_log->level > LOG_DEBUG) { - g_log->level = LOG_DEBUG; - } - } - - // make sure that for log trace the extra info is only printed once, reset when the level changes - if ((level == LOG_FILE) || (c->flag == LOG_NONE) || (level ==LOG_TRACE )) { - total_len = snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - 1, "%s", - params_string); - } else { - if ((g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR)) { - total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "%s", - log_level_highlight_start[level]); - } - - if ((g_log->flag & FLAG_COMP) || (c->flag & FLAG_COMP) ) { - total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%s]", - g_log->log_component[comp].name); - } - - if ((g_log->flag & FLAG_LEVEL) || (c->flag & FLAG_LEVEL)) { - total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%s]", - g_log->level2string[level]); - } - - if ((g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT)) { - total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%s] ", - func); - } - - if ((g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { - total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%s:%d]", - file, line); - } - - len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - len, "%s", - params_string); - - if ((g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR)) { - total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "%s", - log_level_highlight_end[level]); - } - } - - // OAI printf compatibility - if ((g_log->onlinelog == 1) && (level != LOG_FILE)) { - fprintf(stdout, "%s", log_buffer); - } - - if (g_log->syslog) { - syslog(g_log->level, "%s", log_buffer); - } - - if (g_log->filelog) { - if (write(gfd, log_buffer, total_len) < total_len) { - // TODO assert ? - } - } - - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - if (write(g_log->log_component[comp].fd, log_buffer, total_len) < total_len) { - // TODO assert ? - } - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_OUT); -} - -#if !defined(LOG_NO_THREAD) -void *log_thread_function(void *list) -{ - - LOG_params log_params; - - for(;;) { - - //log_elt = NULL; - - /* Lock must be taken to wait on conditional variable */ - pthread_mutex_lock(&log_lock); - - /* Wait on condition variable, check for spurious wakeups. - When returning from pthread_cond_wait(), we own the lock. */ - - // sleep - while((log_list_nb_elements == 0) && (log_shutdown == 0)) { - pthread_cond_wait(&log_notify, &log_lock); - } - - // exit - if ((log_shutdown==1) && (log_list_nb_elements == 0)) { - break; - } - - /* Grab our task */ - //log_elt = log_list_remove_head(&log_list); - log_params = log_list[log_list_head]; - log_list_head++; - log_list_nb_elements--; - - if (log_list_head >= 1000) { - log_list_head = 0; - } - - - /* Unlock */ - pthread_mutex_unlock(&log_lock); - - /* Get to work */ - logRecord_thread_safe(log_params.file, - log_params.func, - log_params.line, - log_params.comp, - log_params.level, - log_params.len, - log_params.l_buff_info); - - //free(log_elt); - } -} -#endif - -#if 0 -/* This function does not work. When multiple threads call it at the same time - * for the same component, both threads end up using the same buffer. - * The output is the completely messed up/wrong. - * Kept in case the fix below is not correct or acceptable. - */ -//log record, format, and print: executed in the main thread (mt) -void logRecord_mt(const char *file, const char *func, int line, int comp, - int level, const char *format, ...) -{ - int len = 0; - va_list args; - log_component_t *c; - char *log_start; - char *log_end; - - /* for no gcc warnings */ - (void)log_start; - (void)log_end; - - c = &g_log->log_component[comp]; - - // do not apply filtering for LOG_F - // only log messages which are enabled and are below the global log level and component's level threshold - if ((level != LOG_FILE) && ((level > c->level) || (level > g_log->level))) { - /* if ((level != LOG_FILE) && - ((level > c->level) || - (level > g_log->level) || - ( c->level > g_log->level))) { - */ - return; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_IN); - - va_start(args, format); - - // adjust syslog level for TRACE messages - if (g_log->syslog) { - if (g_log->level > LOG_DEBUG) { - g_log->level = LOG_DEBUG; - } - } - - // make sure that for log trace the extra info is only printed once, reset when the level changes - if ((level == LOG_FILE) || (c->flag == LOG_NONE) || (level == LOG_TRACE)) { - log_start = c->log_buffer; - len = vsnprintf(c->log_buffer, MAX_LOG_TOTAL-1, format, args); - log_end = c->log_buffer + len; - } else { - if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { - len += snprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_start[level]); - } - - log_start = c->log_buffer + len; - - if ( (g_log->flag & FLAG_COMP) || (c->flag & FLAG_COMP) ) { - len += snprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", - g_log->log_component[comp].name); - } - - if ( (g_log->flag & FLAG_LEVEL) || (c->flag & FLAG_LEVEL) ) { - len += snprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", - g_log->level2string[level]); - } - - if ( (g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT) ) { - len += snprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, "[%s] ", - func); - } - - if ( (g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { - len += snprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, "[%s:%d]", - file, line); - } - - len += vsnprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, format, args); - log_end = c->log_buffer + len; - - if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { - len += snprintf(&c->log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_end[level]); - } - } - - va_end(args); - - // OAI printf compatibility - if ((g_log->onlinelog == 1) && (level != LOG_FILE)) - fwrite(c->log_buffer, len, 1, stdout); - - if (g_log->syslog) { - syslog(g_log->level, "%s", c->log_buffer); - } - - if (g_log->filelog) { - if (write(gfd, c->log_buffer, len) < len) { - // TODO assert ? - } - } - - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - if (write(g_log->log_component[comp].fd, c->log_buffer, len) < len) { - // TODO assert ? - } - } - -#if defined(ENABLE_ITTI) - - if (level <= LOG_DEBUG) { - task_id_t origin_task_id = TASK_UNKNOWN; - MessagesIds messages_id; - MessageDef *message_p; - size_t message_string_size; - char *message_msg_p; - - message_string_size = log_end - log_start; - -#if !defined(DISABLE_ITTI_DETECT_SUB_TASK_ID) - - /* Try to identify sub task ID from log information (comp, log_instance_type) */ - switch (comp) { - case PHY: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_PHY_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_PHY_UE; - break; - - default: - break; - } - - break; - - case MAC: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_MAC_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_MAC_UE; - - default: - break; - } - - break; - - case RLC: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_RLC_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_RLC_UE; - - default: - break; - } - - break; - - case PDCP: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_PDCP_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_PDCP_UE; - - default: - break; - } - - break; - - default: - break; - } - -#endif - - switch (level) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - messages_id = ERROR_LOG; - break; - - case LOG_WARNING: - messages_id = WARNING_LOG; - break; - - case LOG_NOTICE: - messages_id = NOTICE_LOG; - break; - - case LOG_INFO: - messages_id = INFO_LOG; - break; - - default: - messages_id = DEBUG_LOG; - break; - } - - message_p = itti_alloc_new_message_sized(origin_task_id, messages_id, message_string_size); - - switch (level) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - message_msg_p = (char *) &message_p->ittiMsg.error_log; - break; - - case LOG_WARNING: - message_msg_p = (char *) &message_p->ittiMsg.warning_log; - break; - - case LOG_NOTICE: - message_msg_p = (char *) &message_p->ittiMsg.notice_log; - break; - - case LOG_INFO: - message_msg_p = (char *) &message_p->ittiMsg.info_log; - break; - - default: - message_msg_p = (char *) &message_p->ittiMsg.debug_log; - break; - } - - memcpy(message_msg_p, log_start, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); - } - -#endif - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_OUT); -} -#endif /* #if 0 */ - -//log record, format, and print: executed in the main thread (mt) -void logRecord_mt(const char *file, const char *func, int line, int comp, - int level, const char *format, ...) -{ - int len = 0; - va_list args; - log_component_t *c; - char *log_start; - char *log_end; - /* The main difference with the version above is the use of this local log_buffer. - * The other difference is the return value of snprintf which was not used - * correctly. It was not a big problem because in practice MAX_LOG_TOTAL is - * big enough so that the buffer is never full. - */ - char log_buffer[MAX_LOG_TOTAL]; - - /* for no gcc warnings */ - (void)log_start; - (void)log_end; - - c = &g_log->log_component[comp]; - - // do not apply filtering for LOG_F - // only log messages which are enabled and are below the global log level and component's level threshold - if ((level != LOG_FILE) && ((level > c->level) || (level > g_log->level))) { - /* if ((level != LOG_FILE) && - ((level > c->level) || - (level > g_log->level) || - ( c->level > g_log->level))) { - */ - return; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_IN); - - va_start(args, format); - - // adjust syslog level for TRACE messages - if (g_log->syslog) { - if (g_log->level > LOG_DEBUG) { - g_log->level = LOG_DEBUG; - } - } - - // make sure that for log trace the extra info is only printed once, reset when the level changes - if ((level == LOG_FILE) || (c->flag == LOG_NONE) || (level == LOG_TRACE)) { - log_start = log_buffer; - len = vsnprintf(log_buffer, MAX_LOG_TOTAL, format, args); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - log_end = log_buffer + len; - } else { - if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_start[level]); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - log_start = log_buffer + len; - - if ( (g_log->flag & FLAG_COMP) || (c->flag & FLAG_COMP) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", - g_log->log_component[comp].name); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - if ( (g_log->flag & FLAG_LEVEL) || (c->flag & FLAG_LEVEL) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", - g_log->level2string[level]); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - if ( (g_log->flag & FLAG_THREAD) || (c->flag & FLAG_THREAD) ) { -# define THREAD_NAME_LEN 128 - char threadname[THREAD_NAME_LEN]; - if (pthread_getname_np(pthread_self(), threadname, THREAD_NAME_LEN) != 0) - { - perror("pthread_getname_np : "); - } else { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", threadname); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } -# undef THREAD_NAME_LEN - } - - if ( (g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s] ", - func); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - if ( (g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s:%d]", - file, line); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - - len += vsnprintf(&log_buffer[len], MAX_LOG_TOTAL - len, format, args); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - log_end = log_buffer + len; - - if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { - len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_end[level]); - if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - } - } - - va_end(args); - - // OAI printf compatibility - if ((g_log->onlinelog == 1) && (level != LOG_FILE)) - fwrite(log_buffer, len, 1, stdout); - - if (g_log->syslog) { - syslog(g_log->level, "%s", log_buffer); - } - - if (g_log->filelog) { - if (write(gfd, log_buffer, len) < len) { - // TODO assert ? - } - } - - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - if (write(g_log->log_component[comp].fd, log_buffer, len) < len) { - // TODO assert ? - } - } - -#if defined(ENABLE_ITTI) - - if (level <= LOG_DEBUG) { - task_id_t origin_task_id = TASK_UNKNOWN; - MessagesIds messages_id; - MessageDef *message_p; - size_t message_string_size; - char *message_msg_p; - - message_string_size = log_end - log_start; - -#if !defined(DISABLE_ITTI_DETECT_SUB_TASK_ID) - - /* Try to identify sub task ID from log information (comp, log_instance_type) */ - switch (comp) { - case PHY: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_PHY_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_PHY_UE; - break; - - default: - break; - } - - break; - - case MAC: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_MAC_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_MAC_UE; - - default: - break; - } - - break; - - case RLC: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_RLC_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_RLC_UE; - - default: - break; - } - - break; - - case PDCP: - switch (log_instance_type) { - case LOG_INSTANCE_ENB: - origin_task_id = TASK_PDCP_ENB; - break; - - case LOG_INSTANCE_UE: - origin_task_id = TASK_PDCP_UE; - - default: - break; - } - - break; - - default: - break; - } - -#endif - - switch (level) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - messages_id = ERROR_LOG; - break; - - case LOG_WARNING: - messages_id = WARNING_LOG; - break; - - case LOG_NOTICE: - messages_id = NOTICE_LOG; - break; - - case LOG_INFO: - messages_id = INFO_LOG; - break; - - default: - messages_id = DEBUG_LOG; - break; - } - - message_p = itti_alloc_new_message_sized(origin_task_id, messages_id, message_string_size); - - switch (level) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - message_msg_p = (char *) &message_p->ittiMsg.error_log; - break; - - case LOG_WARNING: - message_msg_p = (char *) &message_p->ittiMsg.warning_log; - break; - - case LOG_NOTICE: - message_msg_p = (char *) &message_p->ittiMsg.notice_log; - break; - - case LOG_INFO: - message_msg_p = (char *) &message_p->ittiMsg.info_log; - break; - - default: - message_msg_p = (char *) &message_p->ittiMsg.debug_log; - break; - } - - memcpy(message_msg_p, log_start, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); - } - -#endif - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_OUT); -} - -int set_log(int component, int level, int interval) -{ - /* Checking parameters */ - DevCheck((component >= MIN_LOG_COMPONENTS) && (component < MAX_LOG_COMPONENTS), - component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS); - DevCheck((level <= LOG_TRACE) && (level >= LOG_EMERG), level, LOG_TRACE, - LOG_EMERG); - DevCheck((interval >= 0) && (interval <= 0xFF), interval, 0, 0xFF); - - g_log->log_component[component].level = level; - - switch (level) { - case LOG_TRACE: - g_log->log_component[component].flag = LOG_MED ; - break; - - case LOG_DEBUG: - g_log->log_component[component].flag = LOG_MED ; - break; - - case LOG_INFO: - g_log->log_component[component].flag = LOG_LOW ; - break; - - default: - g_log->log_component[component].flag = LOG_NONE ; - break; - } - - g_log->log_component[component].interval = interval; - - return 0; -} - -int set_comp_log(int component, int level, int verbosity, int interval) -{ - /* Checking parameters */ - DevCheck((component >= MIN_LOG_COMPONENTS) && (component < MAX_LOG_COMPONENTS), - component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS); - DevCheck((level <= LOG_TRACE) && (level >= LOG_EMERG), level, LOG_TRACE, - LOG_EMERG); - DevCheck((interval >= 0) && (interval <= 0xFF), interval, 0, 0xFF); - -#if 0 - if ((verbosity == LOG_NONE) || (verbosity == LOG_LOW) || - (verbosity == LOG_MED) || (verbosity == LOG_FULL) || - (verbosity == LOG_HIGH)) { - g_log->log_component[component].flag = verbosity; - } -#else - g_log->log_component[component].flag = verbosity; -#endif - - g_log->log_component[component].level = level; - g_log->log_component[component].interval = interval; - - return 0; -} - -void set_glog(int level, int verbosity) -{ - if( g_log->level >= 0) g_log->level = level; - if( g_log->flag >= 0) g_log->flag = verbosity; -} -void set_glog_syslog(int enable) -{ - g_log->syslog = enable; -} -void set_glog_onlinelog(int enable) -{ - g_log->onlinelog = enable; -} -void set_glog_filelog(int enable) -{ - g_log->filelog = enable; -} - -void set_component_filelog(int comp) -{ - if (g_log->log_component[comp].filelog == 0) { - g_log->log_component[comp].filelog = 1; - - if (g_log->log_component[comp].fd == 0) { - g_log->log_component[comp].fd = open(g_log->log_component[comp].filelog_name, - O_WRONLY | O_CREAT | O_TRUNC, 0666); - } - } -} - -/* - * for the two functions below, the passed array must have a final entry - * with string value NULL - */ -/* map a string to an int. Takes a mapping array and a string as arg */ -int map_str_to_int(mapping *map, const char *str) -{ - while (1) { - if (map->name == NULL) { - return(-1); - } - - if (!strcmp(map->name, str)) { - return(map->value); - } - - map++; - } -} - -/* map an int to a string. Takes a mapping array and a value */ -char *map_int_to_str(mapping *map, int val) -{ - while (1) { - if (map->name == NULL) { - return NULL; - } - - if (map->value == val) { - return map->name; - } - - map++; - } -} - -int is_newline( char *str, int size) -{ - int i; - - for ( i = 0; i < size; i++ ) { - if ( str[i] == '\n' ) { - return 1; - } - } - - /* if we get all the way to here, there must not have been a newline! */ - return 0; -} - -void logClean (void) -{ - int i; - - if (g_log->syslog) { - closelog(); - } - - if (g_log->filelog) { - close(gfd); - } - - for (i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) { - if (g_log->log_component[i].filelog) { - close(g_log->log_component[i].fd); - } - } -} - -#if defined(ENABLE_ITTI) -void log_set_instance_type (log_instance_type_t instance) -{ - log_instance_type = instance; -} -#endif - -#ifdef LOG_TEST - -int main(int argc, char *argv[]) -{ - - logInit(); - - //set_log_syslog(1); - test_log(); - - return 1; -} - -int test_log(void) -{ - LOG_ENTER(MAC); // because the default level is DEBUG - LOG_I(EMU, "1 Starting OAI logs version %s Build date: %s on %s\n", - BUILD_VERSION, BUILD_DATE, BUILD_HOST); - LOG_D(MAC, "1 debug MAC \n"); - LOG_N(MAC, "1 notice MAC \n"); - LOG_W(MAC, "1 warning MAC \n"); - - set_comp_log(EMU, LOG_INFO, FLAG_ONLINE); - set_comp_log(MAC, LOG_WARNING, 0); - - LOG_I(EMU, "2 Starting OAI logs version %s Build date: %s on %s\n", - BUILD_VERSION, BUILD_DATE, BUILD_HOST); - LOG_E(MAC, "2 emerge MAC\n"); - LOG_D(MAC, "2 debug MAC \n"); - LOG_N(MAC, "2 notice MAC \n"); - LOG_W(MAC, "2 warning MAC \n"); - LOG_I(MAC, "2 info MAC \n"); - - - set_comp_log(MAC, LOG_NOTICE, 1); - - LOG_ENTER(MAC); - LOG_I(EMU, "3 Starting OAI logs version %s Build date: %s on %s\n", - BUILD_VERSION, BUILD_DATE, BUILD_HOST); - LOG_D(MAC, "3 debug MAC \n"); - LOG_N(MAC, "3 notice MAC \n"); - LOG_W(MAC, "3 warning MAC \n"); - LOG_I(MAC, "3 info MAC \n"); - - set_comp_log(MAC, LOG_DEBUG,1); - set_comp_log(EMU, LOG_DEBUG,1); - - LOG_ENTER(MAC); - LOG_I(EMU, "4 Starting OAI logs version %s Build date: %s on %s\n", - BUILD_VERSION, BUILD_DATE, BUILD_HOST); - LOG_D(MAC, "4 debug MAC \n"); - LOG_N(MAC, "4 notice MAC \n"); - LOG_W(MAC, "4 warning MAC \n"); - LOG_I(MAC, "4 info MAC \n"); - - - set_comp_log(MAC, LOG_DEBUG,0); - set_comp_log(EMU, LOG_DEBUG,0); - - LOG_I(LOG, "5 Starting OAI logs version %s Build date: %s on %s\n", - BUILD_VERSION, BUILD_DATE, BUILD_HOST); - LOG_D(MAC, "5 debug MAC \n"); - LOG_N(MAC, "5 notice MAC \n"); - LOG_W(MAC, "5 warning MAC \n"); - LOG_I(MAC, "5 info MAC \n"); - - - set_comp_log(MAC, LOG_TRACE,0X07F); - set_comp_log(EMU, LOG_TRACE,0X07F); - - LOG_ENTER(MAC); - LOG_I(LOG, "6 Starting OAI logs version %s Build date: %s on %s\n", - BUILD_VERSION, BUILD_DATE, BUILD_HOST); - LOG_D(MAC, "6 debug MAC \n"); - LOG_N(MAC, "6 notice MAC \n"); - LOG_W(MAC, "6 warning MAC \n"); - LOG_I(MAC, "6 info MAC \n"); - LOG_EXIT(MAC); - - return 0; -} -#endif diff --git a/openair2/UTIL/OMV/structures.h b/openair2/UTIL/OMV/structures.h index ee33632059..5c48641f86 100644 --- a/openair2/UTIL/OMV/structures.h +++ b/openair2/UTIL/OMV/structures.h @@ -49,7 +49,7 @@ typedef struct Geo { int node_type; int Neighbors; // number of neighboring nodes (distance between the node and its neighbors < 100) int Neighbor[NUMBER_OF_UE_MAX]; // array of its neighbors - //relavent to UE only + //relevant to UE only unsigned short state; unsigned short rnti; unsigned int connected_eNB; diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c index b7ccb07461..b297c96e56 100644 --- a/openair2/X2AP/x2ap_eNB.c +++ b/openair2/X2AP/x2ap_eNB.c @@ -101,7 +101,6 @@ void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa x2ap_eNB_instance_t *instance_p; x2ap_eNB_data_t *x2ap_enb_data_p; DevAssert(sctp_new_association_resp != NULL); - printf("x2ap_eNB_handle_sctp_association_resp at 1\n"); dump_trees(); instance_p = x2ap_eNB_get_instance(instance); DevAssert(instance_p != NULL); @@ -129,7 +128,6 @@ void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa x2ap_enb_data_p = x2ap_get_eNB(instance_p, -1, sctp_new_association_resp->ulp_cnx_id); DevAssert(x2ap_enb_data_p != NULL); - printf("x2ap_eNB_handle_sctp_association_resp at 2\n"); dump_trees(); if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { @@ -142,17 +140,17 @@ void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa return; } - printf("x2ap_eNB_handle_sctp_association_resp at 3\n"); dump_trees(); /* Update parameters */ x2ap_enb_data_p->assoc_id = sctp_new_association_resp->assoc_id; x2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams; x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams; - printf("x2ap_eNB_handle_sctp_association_resp at 4\n"); dump_trees(); /* Prepare new x2 Setup Request */ - x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p); - //x2ap_eNB_generate_ENDC_x2_setup_request(instance_p, x2ap_enb_data_p); + if(instance_p->cell_type == CELL_MACRO_GNB) + x2ap_gNB_generate_ENDC_x2_setup_request(instance_p, x2ap_enb_data_p); + else + x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p); } static @@ -448,6 +446,78 @@ void x2ap_eNB_handle_handover_req_ack(instance_t instance, x2ap_eNB_generate_x2_handover_request_ack(instance_p, target, x2ap_handover_req_ack); } +static +void x2ap_eNB_handle_sgNB_add_req(instance_t instance, + x2ap_ENDC_sgnb_addition_req_t *x2ap_ENDC_sgnb_addition_req) +{ + x2ap_id_manager *id_manager; + x2ap_eNB_instance_t *instance_p; + x2ap_eNB_data_t *x2ap_eNB_data; + int ue_id; + + /* TODO: remove hardcoded value */ + x2ap_eNB_data = x2ap_is_eNB_id_in_list(3584); + DevAssert(x2ap_eNB_data != NULL); + + instance_p = x2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + /* allocate x2ap ID */ + id_manager = &instance_p->id_manager; + ue_id = x2ap_allocate_new_id(id_manager); + if (ue_id == -1) { + X2AP_ERROR("could not allocate a new X2AP UE ID\n"); + /* TODO: cancel NSA: send (to be defined) message to RRC */ + exit(1); + } + /* id_source is ue_id, id_target is unknown yet */ + x2ap_set_ids(id_manager, ue_id, x2ap_ENDC_sgnb_addition_req->rnti, ue_id, -1); + x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_NSA_PREPARE); + + x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(instance_p, x2ap_eNB_data, ue_id); +} + +static +void x2ap_gNB_trigger_sgNB_add_req_ack(instance_t instance, + x2ap_ENDC_sgnb_addition_req_ACK_t *x2ap_ENDC_sgnb_addition_req_ACK) +{ + /* TODO: remove this hack (the goal is to find the correct + * eNodeB structure for the other end) - we need a proper way for RRC + * and X2AP to identify eNodeBs + * RRC knows about mod_id and X2AP knows about eNB_id (eNB_ID in + * the configuration file) + * as far as I understand.. CROUX + */ + + + x2ap_eNB_instance_t *instance_p; + x2ap_eNB_data_t *target; + /*int source_assoc_id = x2ap_ENDC_sgnb_addition_req_ACK->source_assoc_id; + int ue_id; + int id_source; + int id_target;*/ + + instance_p = x2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + /*target = x2ap_get_eNB(NULL, source_assoc_id, 0); + DevAssert(target != NULL);*/ + + // rnti is a new information, save it + + /*ue_id = x2ap_handover_req_ack->x2_id_target; + id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id); + id_target = ue_id; + x2ap_set_ids(&instance_p->id_manager, ue_id, x2ap_handover_req_ack->rnti, id_source, id_target);*/ + + + //target = x2ap_get_eNB(NULL, 17, 0); + target = x2ap_is_eNB_id_in_list (3585); //Currently hardcoded. Need to extract it differently + DevAssert(target != NULL); + x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK(instance_p, target, x2ap_ENDC_sgnb_addition_req_ACK, 0); +} + + static void x2ap_eNB_ue_context_release(instance_t instance, x2ap_ue_context_release_t *x2ap_ue_context_release) @@ -513,6 +583,17 @@ void *x2ap_task(void *arg) { &X2AP_UE_CONTEXT_RELEASE(received_msg)); break; + case X2AP_ENDC_SGNB_ADDITION_REQ: + x2ap_eNB_handle_sgNB_add_req(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &X2AP_ENDC_SGNB_ADDITION_REQ(received_msg)); + break; + + case X2AP_ENDC_SGNB_ADDITION_REQ_ACK: + x2ap_gNB_trigger_sgNB_add_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(received_msg)); + LOG_I(X2AP, "Received elements for X2AP_ENDC_SGNB_ADDITION_REQ_ACK \n"); + break; + case SCTP_INIT_MSG_MULTI_CNF: x2ap_eNB_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg), &received_msg->ittiMsg.sctp_init_msg_multi_cnf); @@ -556,7 +637,6 @@ int is_x2ap_enabled(void) static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; if (pthread_mutex_lock(&mutex)) goto mutex_error; - if (config_loaded) { if (pthread_mutex_unlock(&mutex)) goto mutex_error; return enabled; @@ -569,13 +649,20 @@ int is_x2ap_enabled(void) /* TODO: do it per module - we check only first eNB */ config_get(p, sizeof(p)/sizeof(paramdef_t), "eNBs.[0]"); - if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0) - enabled = 1; + if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0){ + enabled = 1; + } + + /*Consider also the case of enabling X2AP for a gNB by parsing a gNB configuration file*/ + + config_get(p, sizeof(p)/sizeof(paramdef_t), "gNBs.[0]"); + if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0){ + enabled = 1; + } config_loaded = 1; if (pthread_mutex_unlock(&mutex)) goto mutex_error; - return enabled; mutex_error: diff --git a/openair2/X2AP/x2ap_eNB_decoder.c b/openair2/X2AP/x2ap_eNB_decoder.c index 7b178fb109..93b82c2765 100644 --- a/openair2/X2AP/x2ap_eNB_decoder.c +++ b/openair2/X2AP/x2ap_eNB_decoder.c @@ -60,8 +60,14 @@ static int x2ap_eNB_decode_initiating_message(X2AP_X2AP_PDU_t *pdu) break; case X2AP_ProcedureCode_id_endcX2Setup: - X2AP_INFO("X2AP_ProcedureCode_id_endcX2Setup message!\n"); - break; + X2AP_INFO("X2AP_ProcedureCode_id_endcX2Setup message!\n"); + break; + case X2AP_ProcedureCode_id_sgNBAdditionPreparation: + X2AP_INFO("X2AP_ProcedureCode_id_sgNBAdditionPreparation message!\n"); + break; + case X2AP_ProcedureCode_id_sgNBReconfigurationCompletion: + X2AP_INFO("X2AP_ProcedureCode_id_sgNBReconfigurationCompletion message!\n"); + break; default: X2AP_ERROR("Unknown procedure ID (%d) for initiating message\n", @@ -93,6 +99,10 @@ static int x2ap_eNB_decode_successful_outcome(X2AP_X2AP_PDU_t *pdu) X2AP_INFO("x2ap_eNB_decode_successfuloutcome_message!\n"); break; + case X2AP_ProcedureCode_id_sgNBAdditionPreparation: + X2AP_INFO("x2ap_eNB_decode_successfuloutcome_message!\n"); + break; + default: X2AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n", (int)pdu->choice.successfulOutcome.procedureCode); @@ -134,9 +144,9 @@ int x2ap_eNB_decode_pdu(X2AP_X2AP_PDU_t *pdu, const uint8_t *const buffer, uint3 length, 0, 0); - if (asn1_xer_print) { + //if (asn1_xer_print) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, pdu); - } + //} if (dec_ret.code != RC_OK) { X2AP_ERROR("Failed to decode pdu\n"); diff --git a/openair2/X2AP/x2ap_eNB_encoder.c b/openair2/X2AP/x2ap_eNB_encoder.c index 8b1c030d35..392206e4d7 100644 --- a/openair2/X2AP/x2ap_eNB_encoder.c +++ b/openair2/X2AP/x2ap_eNB_encoder.c @@ -44,9 +44,9 @@ int x2ap_eNB_encode_pdu(X2AP_X2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) DevAssert(buffer != NULL); DevAssert(len != NULL); - if (asn1_xer_print) { + //if (asn1_xer_print) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)pdu); - } + //} encoded = aper_encode_to_new_buffer(&asn_DEF_X2AP_X2AP_PDU, 0, pdu, (void **)buffer); diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c index e43db6aa8a..47a3475063 100644 --- a/openair2/X2AP/x2ap_eNB_generate_messages.c +++ b/openair2/X2AP/x2ap_eNB_generate_messages.c @@ -39,6 +39,7 @@ #include "x2ap_ids.h" #include "x2ap_eNB_itti_messaging.h" +#include "X2AP_SupportedSULFreqBandItem.h" #include "msc.h" #include "assertions.h" @@ -1097,7 +1098,6 @@ int x2ap_eNB_generate_senb_addition_request (x2ap_eNB_instance_t *instance_p, x2 return ret; } -//Panos: int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, x2ap_senb_addition_req_ack_t *x2ap_addition_req_ack) { @@ -1118,8 +1118,6 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p DevAssert(instance_p != NULL); DevAssert(x2ap_eNB_data_p != NULL); - //Panos: The fact that we have separate IDs here is because the ID for a specific UE might be different - //between the 2 eNBs? //ue_id = x2ap_addition_req_ack->x2_id_target; //Panos: change name to master_x2... //id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id); //id_target = ue_id; @@ -1128,7 +1126,6 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p memset(&pdu, 0, sizeof(pdu)); pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome; pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_seNBAdditionPreparation; - //Panos: What does the criticality indicate here? pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject; pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_SeNBAdditionRequestAcknowledge; out = &pdu.choice.successfulOutcome.value.choice.SeNBAdditionRequestAcknowledge; @@ -1144,7 +1141,6 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p /* mandatory */ ie = (X2AP_SeNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SeNBAdditionRequestAcknowledge_IEs_t)); ie->id = X2AP_ProtocolIE_ID_id_SeNB_UE_X2AP_ID; - //Panos: Why for the X2_HANDOVER_REQ_ACK here the criticality is ignore whereas in the specs it is reject? ie->criticality = X2AP_Criticality_reject; ie->value.present = X2AP_SeNBAdditionRequestAcknowledge_IEs__value_PR_UE_X2AP_ID_1; ie->value.choice.UE_X2AP_ID_1 = 0; @@ -1230,17 +1226,17 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p return ret; } -/*setup request message from an eNB to a gNB*/ -int x2ap_eNB_generate_ENDC_x2_setup_request( +/*setup request message from a gNB to an eNB*/ +int x2ap_gNB_generate_ENDC_x2_setup_request( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p) { - printf("In x2ap_eNB_generate_ENDC_x2_setup_request \n"); X2AP_X2AP_PDU_t pdu; X2AP_ENDCX2SetupRequest_t *out; X2AP_ENDCX2SetupRequest_IEs_t *ie; - X2AP_ENB_ENDCX2SetupReqIEs_t *ie_ENB_ENDC; + X2AP_En_gNB_ENDCX2SetupReqIEs_t *ie_GNB_ENDC; X2AP_PLMN_Identity_t *plmn; - ServedEUTRAcellsENDCX2ManagementList__Member *servedCellMember; + ServedNRcellsENDCX2ManagementList__Member *servedCellMember; + X2AP_SupportedSULFreqBandItem_t *SULFreqBandItem; uint8_t *buffer; uint32_t len; @@ -1262,24 +1258,166 @@ int x2ap_eNB_generate_ENDC_x2_setup_request( ie = (X2AP_ENDCX2SetupRequest_IEs_t *)calloc(1, sizeof(X2AP_ENDCX2SetupRequest_IEs_t)); ie->id = X2AP_ProtocolIE_ID_id_InitiatingNodeType_EndcX2Setup; ie->value.present = X2AP_ENDCX2SetupRequest_IEs__value_PR_InitiatingNodeType_EndcX2Setup; - ie->value.choice.InitiatingNodeType_EndcX2Setup.present = X2AP_InitiatingNodeType_EndcX2Setup_PR_init_eNB; + ie->value.choice.InitiatingNodeType_EndcX2Setup.present = X2AP_InitiatingNodeType_EndcX2Setup_PR_init_en_gNB; - ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqIEs_t *)calloc(1, sizeof(X2AP_ENB_ENDCX2SetupReqIEs_t)); + ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqIEs_t *)calloc(1, sizeof(X2AP_En_gNB_ENDCX2SetupReqIEs_t)); + ie_GNB_ENDC->id = X2AP_ProtocolIE_ID_id_Globalen_gNB_ID; + ie_GNB_ENDC->criticality = X2AP_Criticality_reject; + ie_GNB_ENDC->value.present = X2AP_En_gNB_ENDCX2SetupReqAckIEs__value_PR_GlobalGNB_ID; + ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.present = X2AP_GNB_ID_PR_gNB_ID; + INT32_TO_OCTET_STRING(instance_p->eNB_id, + &ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID); + +X2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, + ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.buf[0], + ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.buf[1], + ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.buf[2]); + +MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &ie_GNB_ENDC->value.choice.GlobalGNB_ID.pLMN_Identity); + + ASN_SEQUENCE_ADD(&ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_en_gNB.list, ie_GNB_ENDC); + + ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqIEs_t *)calloc(1, sizeof(X2AP_En_gNB_ENDCX2SetupReqIEs_t)); + ie_GNB_ENDC->id = X2AP_ProtocolIE_ID_id_ServedNRcellsENDCX2ManagementList; + ie_GNB_ENDC->criticality = X2AP_Criticality_reject; + ie_GNB_ENDC->value.present = X2AP_En_gNB_ENDCX2SetupReqIEs__value_PR_ServedNRcellsENDCX2ManagementList; + + { + for (int i = 0; inum_cc; i++){ + servedCellMember = (ServedNRcellsENDCX2ManagementList__Member *)calloc(1,sizeof(ServedNRcellsENDCX2ManagementList__Member)); + { + servedCellMember->servedNRCellInfo.nrpCI = instance_p->Nid_cell[i]; + + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &servedCellMember->servedNRCellInfo.nrCellID.pLMN_Identity); + NR_CELL_ID_TO_BIT_STRING(instance_p->eNB_id, + &servedCellMember->servedNRCellInfo.nrCellID.nRcellIdentifier); + servedCellMember->servedNRCellInfo.fiveGS_TAC = calloc(1, sizeof(X2AP_FiveGS_TAC_t)); + if (servedCellMember->servedNRCellInfo.fiveGS_TAC == NULL) + exit(1); + NR_FIVEGS_TAC_ID_TO_BIT_STRING(instance_p->tac, servedCellMember->servedNRCellInfo.fiveGS_TAC); + + X2AP_INFO("TAC: %d -> %02x%02x%02x\n", instance_p->tac, + servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[0], + servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[1], + servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[2]); + + plmn = (X2AP_PLMN_Identity_t *)calloc(1,sizeof(X2AP_PLMN_Identity_t)); + { + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); + ASN_SEQUENCE_ADD(&servedCellMember->servedNRCellInfo.broadcastPLMNs.list, plmn); + } + + if (instance_p->frame_type[i] == TDD) { + X2AP_FreqBandNrItem_t *freq_band; + servedCellMember->servedNRCellInfo.nrModeInfo.present = X2AP_ServedNRCell_Information__nrModeInfo_PR_tdd; + servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.nRARFCN = 0; //instance_p->tdd_nRARFCN[i]; + /* addition of Frequency Band List */ + freq_band = calloc(1, sizeof(X2AP_FreqBandNrItem_t)); + if (freq_band == NULL) + exit(1); + freq_band->freqBandIndicatorNr = 1; /* TODO: put correct value */ + + SULFreqBandItem = calloc(1, sizeof(X2AP_SupportedSULFreqBandItem_t)); + SULFreqBandItem->freqBandIndicatorNr=80; /* TODO: put correct value */ + ASN_SEQUENCE_ADD(&freq_band->supportedSULBandList.list, SULFreqBandItem); + + ASN_SEQUENCE_ADD(&servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.freqBandListNr, freq_band); + switch (instance_p->N_RB_DL[i]) { + case 50: + //This is not correct. Just to be able to test X2 only using an eNB instead of gNB + servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb51; + break; + case 93 : + servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb93; + break; + case 106: + servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb106; + break; + case 121: + servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb121; + break; + /*More cases to be added */ + default: + AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); + break; + } + } + else { + AssertFatal(0,"ENDC_X2Setuprequest not supported for FDD!"); + } + /*Don't know where to extract the value of measurementTimingConfiguration from. Set it to 0 for now */ + INT8_TO_OCTET_STRING(0, &servedCellMember->servedNRCellInfo.measurementTimingConfiguration); + } + ASN_SEQUENCE_ADD(&ie_GNB_ENDC->value.choice.ServedNRcellsENDCX2ManagementList.list, servedCellMember); + } + } + ASN_SEQUENCE_ADD(&ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_en_gNB.list, ie_GNB_ENDC); + + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { + X2AP_ERROR("Failed to encode ENDC X2 setup request\n"); + return -1; + } + + MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id); + + x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0); + + return ret; +} + +int x2ap_eNB_generate_ENDC_x2_setup_response( + x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p) +{ + X2AP_X2AP_PDU_t pdu; + X2AP_ENDCX2SetupResponse_t *out; + X2AP_ENDCX2SetupResponse_IEs_t *ie; + X2AP_ENB_ENDCX2SetupReqAckIEs_t *ie_ENB_ENDC; + X2AP_PLMN_Identity_t *plmn; + ServedEUTRAcellsENDCX2ManagementList__Member *servedCellMember; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + DevAssert(instance_p != NULL); + DevAssert(x2ap_eNB_data_p != NULL); + + x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING; + + /* Prepare the X2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_endcX2Setup; + pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_ENDCX2SetupResponse; + out = &pdu.choice.successfulOutcome.value.choice.ENDCX2SetupResponse; + + ie = (X2AP_ENDCX2SetupResponse_IEs_t *)calloc(1, sizeof(X2AP_ENDCX2SetupResponse_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_RespondingNodeType_EndcX2Setup; + ie->value.present = X2AP_ENDCX2SetupResponse_IEs__value_PR_RespondingNodeType_EndcX2Setup; + ie->value.choice.RespondingNodeType_EndcX2Setup.present = X2AP_RespondingNodeType_EndcX2Setup_PR_respond_eNB; + + ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqAckIEs_t *)calloc(1, sizeof(X2AP_ENB_ENDCX2SetupReqAckIEs_t)); ie_ENB_ENDC->id = X2AP_ProtocolIE_ID_id_GlobalENB_ID; ie_ENB_ENDC->criticality = X2AP_Criticality_reject; - ie_ENB_ENDC->value.present = X2AP_ENB_ENDCX2SetupReqIEs__value_PR_GlobalENB_ID; + ie_ENB_ENDC->value.present = X2AP_ENB_ENDCX2SetupReqAckIEs__value_PR_GlobalENB_ID; ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.present = X2AP_ENB_ID_PR_macro_eNB_ID; MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id, &ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, &ie_ENB_ENDC->value.choice.GlobalENB_ID.pLMN_Identity); - ASN_SEQUENCE_ADD(&ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list, ie_ENB_ENDC); + ASN_SEQUENCE_ADD(&ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list, ie_ENB_ENDC); - ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqIEs_t *)calloc(1, sizeof(X2AP_ENB_ENDCX2SetupReqIEs_t)); + ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqAckIEs_t *)calloc(1, sizeof(X2AP_ENB_ENDCX2SetupReqAckIEs_t)); ie_ENB_ENDC->id = X2AP_ProtocolIE_ID_id_ServedEUTRAcellsENDCX2ManagementList; ie_ENB_ENDC->criticality = X2AP_Criticality_reject; - ie_ENB_ENDC->value.present = X2AP_ENB_ENDCX2SetupReqIEs__value_PR_ServedEUTRAcellsENDCX2ManagementList; + ie_ENB_ENDC->value.present = X2AP_ENB_ENDCX2SetupReqAckIEs__value_PR_ServedEUTRAcellsENDCX2ManagementList; { for (int i = 0; inum_cc; i++){ @@ -1299,11 +1437,11 @@ int x2ap_eNB_generate_ENDC_x2_setup_request( ASN_SEQUENCE_ADD(&servedCellMember->servedEUTRACellInfo.broadcastPLMNs.list, plmn); } - if (instance_p->frame_type[i] == FDD) { - servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD; + if (instance_p->frame_type[i] == FDD) { + servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD; servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; - switch (instance_p->N_RB_DL[i]) { + switch (instance_p->N_RB_DL[i]) { case 6: servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6; servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6; @@ -1334,177 +1472,13 @@ int x2ap_eNB_generate_ENDC_x2_setup_request( } } else { - AssertFatal(0,"X2Setuprequest not supported for TDD!"); + AssertFatal(0,"X2Setupresponse not supported for TDD!"); } } ASN_SEQUENCE_ADD(&ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list, servedCellMember); } } - ASN_SEQUENCE_ADD(&ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list, ie_ENB_ENDC); - - - ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); - - if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { - X2AP_ERROR("Failed to encode ENDC X2 setup request\n"); - return -1; - } - - MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id); - - x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0); - - return ret; -} - - -/*setup request message from an eNB to a gNB*/ -int x2ap_gNB_generate_ENDC_x2_setup_response( - x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p) -{ - X2AP_INFO("In x2ap_gNB_generate_ENDC_x2_setup_response ()!\n"); - X2AP_X2AP_PDU_t pdu; - X2AP_ENDCX2SetupResponse_t *out; - X2AP_ENDCX2SetupResponse_IEs_t *ie; - X2AP_En_gNB_ENDCX2SetupReqAckIEs_t *ie_GNB_ENDC; - X2AP_PLMN_Identity_t *plmn; - ServedNRcellsENDCX2ManagementList__Member *servedCellMember; - - uint8_t *buffer; - uint32_t len; - int ret = 0; - - DevAssert(instance_p != NULL); - DevAssert(x2ap_eNB_data_p != NULL); - - x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING; - - /* Prepare the X2AP message to encode */ - memset(&pdu, 0, sizeof(pdu)); - pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome; - pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_endcX2Setup; - pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject; - pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_ENDCX2SetupResponse; - out = &pdu.choice.successfulOutcome.value.choice.ENDCX2SetupResponse; - - ie = (X2AP_ENDCX2SetupResponse_IEs_t *)calloc(1, sizeof(X2AP_ENDCX2SetupResponse_IEs_t)); - ie->id = X2AP_ProtocolIE_ID_id_RespondingNodeType_EndcX2Setup; - ie->value.present = X2AP_ENDCX2SetupResponse_IEs__value_PR_RespondingNodeType_EndcX2Setup; - ie->value.choice.RespondingNodeType_EndcX2Setup.present = X2AP_RespondingNodeType_EndcX2Setup_PR_respond_en_gNB; - - ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqAckIEs_t *)calloc(1, sizeof(X2AP_En_gNB_ENDCX2SetupReqAckIEs_t)); - ie_GNB_ENDC->id = X2AP_ProtocolIE_ID_id_Globalen_gNB_ID; - ie_GNB_ENDC->criticality = X2AP_Criticality_reject; - ie_GNB_ENDC->value.present = X2AP_En_gNB_ENDCX2SetupReqAckIEs__value_PR_GlobalGNB_ID; - ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.present = X2AP_GNB_ID_PR_gNB_ID; - - INT32_TO_OCTET_STRING(instance_p->eNB_id, - &ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID); - - X2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, - ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.buf[0], - ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.buf[1], - ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.buf[2]); - - MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, - &ie_GNB_ENDC->value.choice.GlobalGNB_ID.pLMN_Identity); - - ASN_SEQUENCE_ADD(&ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_en_gNB.list, ie_GNB_ENDC); - - ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqAckIEs_t *)calloc(1, sizeof(X2AP_En_gNB_ENDCX2SetupReqAckIEs_t)); - ie_GNB_ENDC->id = X2AP_ProtocolIE_ID_id_ServedNRcellsENDCX2ManagementList; - ie_GNB_ENDC->criticality = X2AP_Criticality_reject; - ie_GNB_ENDC->value.present = X2AP_En_gNB_ENDCX2SetupReqAckIEs__value_PR_ServedNRcellsENDCX2ManagementList; - - { - for (int i = 0; inum_cc; i++){ - servedCellMember = (ServedNRcellsENDCX2ManagementList__Member *)calloc(1,sizeof(ServedNRcellsENDCX2ManagementList__Member)); - { - servedCellMember->servedNRCellInfo.nrpCI = instance_p->Nid_cell[i]; - - MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, - &servedCellMember->servedNRCellInfo.nrCellID.pLMN_Identity); - NR_CELL_ID_TO_BIT_STRING(instance_p->eNB_id, - &servedCellMember->servedNRCellInfo.nrCellID.nRcellIdentifier); - servedCellMember->servedNRCellInfo.fiveGS_TAC = calloc(1, sizeof(X2AP_FiveGS_TAC_t)); - if (servedCellMember->servedNRCellInfo.fiveGS_TAC == NULL) - exit(1); - NR_FIVEGS_TAC_ID_TO_BIT_STRING(instance_p->tac, servedCellMember->servedNRCellInfo.fiveGS_TAC); - - X2AP_INFO("TAC: %d -> %02x%02x%02x\n", instance_p->tac, - servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[0], - servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[1], - servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[2]); - - plmn = (X2AP_PLMN_Identity_t *)calloc(1,sizeof(X2AP_PLMN_Identity_t)); - { - MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); - ASN_SEQUENCE_ADD(&servedCellMember->servedNRCellInfo.broadcastPLMNs.list, plmn); - } - - if (instance_p->frame_type[i] == TDD) { // Panos: Remember to change that to TDD - X2AP_FreqBandNrItem_t *freq_band; - servedCellMember->servedNRCellInfo.nrModeInfo.present = X2AP_ServedNRCell_Information__nrModeInfo_PR_tdd; - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.nRARFCN = 0; //instance_p->tdd_nRARFCN[i]; - - /* addition of Frequency Band List */ - freq_band = calloc(1, sizeof(X2AP_FreqBandNrItem_t)); - if (freq_band == NULL) - exit(1); - freq_band->freqBandIndicatorNr = 1; /* TODO: put correct value */ - ASN_SEQUENCE_ADD(&servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.freqBandListNr, freq_band); - - switch (instance_p->N_RB_DL[i]) { - case 50: - //This is not correct. Just to be able to test X2 only using an eNB instead of gNB - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb51; - break; - case 93 : - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb93; - break; - case 106: - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb106; - break; - case 121: - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRNRB = X2AP_NRNRB_nrb121; - break; - - /*More cases to be added */ - - default: - AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); - break; - } - - instance_p->nr_SCS[i] = 30; // Hardcoded for now. Normally this should originate from the gNB config file - switch (instance_p->nr_SCS[i]) { - case 15: - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRSCS = X2AP_NRSCS_scs15; - break; - case 30: - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRSCS = X2AP_NRSCS_scs30; - break; - case 60: - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRSCS = X2AP_NRSCS_scs60; - break; - case 120: - servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nR_TxBW.nRSCS = X2AP_NRSCS_scs120; - break; - default: - AssertFatal(0,"Failed: Check value for nr_SCS"); - break; - } - } - else { - AssertFatal(0,"nr_X2Setupresponse not supported for FDD!"); - } - /*Don't know where to extract the value of measurementTimingConfiguration from. Set it to 0 for now */ - INT8_TO_OCTET_STRING(0, &servedCellMember->servedNRCellInfo.measurementTimingConfiguration); - } - ASN_SEQUENCE_ADD(&ie_GNB_ENDC->value.choice.ServedNRcellsENDCX2ManagementList.list, servedCellMember); - } - } - ASN_SEQUENCE_ADD(&ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_en_gNB.list, ie_GNB_ENDC); + ASN_SEQUENCE_ADD(&ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list, ie_ENB_ENDC); ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); @@ -1521,3 +1495,360 @@ int x2ap_gNB_generate_ENDC_x2_setup_response( return ret; } +int x2ap_eNB_generate_ENDC_x2_SgNB_addition_request( + x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id) +{ + X2AP_X2AP_PDU_t pdu; + X2AP_SgNBAdditionRequest_t *out; + X2AP_SgNBAdditionRequest_IEs_t *ie; + X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t *e_RABS_ToBeAdded_SgNBAddReq_ItemIEs; + X2AP_E_RABs_ToBeAdded_SgNBAddReq_Item_t *e_RABS_ToBeAdded_SgNBAddReq_Item; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + // Currently hardcoded (dummy) values filling the fields of SgNB_addition_request message. To be substituted + // with values coming from RRC. + uint16_t nRencryptionAlgorithms = 0; + uint16_t nRintegrityProtectionAlgorithms = 0; + uint8_t SgNBSecurityKey[32] = { 0 }; + int uEaggregateMaximumBitRateDownlink = 100000000; + int uEaggregateMaximumBitRateUplink = 100000000; + int e_rabs_tobeadded = 1; + int e_RAB_ID = 1; + int drb_ID = 2; + long int pDCPatSgNB = X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present; + long int mCGresources = X2AP_EN_DC_ResourceConfiguration__mCGresources_not_present; + long int sCGresources = X2AP_EN_DC_ResourceConfiguration__sCGresources_not_present; + long qCI = 1; + X2AP_Pre_emptionCapability_t pre_emptionCapability = X2AP_Pre_emptionCapability_shall_not_trigger_pre_emption; + X2AP_Pre_emptionVulnerability_t pre_emptionVulnerability = X2AP_Pre_emptionVulnerability_not_pre_emptable; + priority_level_t priority_level = PRIORITY_LEVEL_NO_PRIORITY; + e_rab_tobe_added_t e_MCG_rabs_tobeadded; + e_MCG_rabs_tobeadded.gtp_teid = 0; + e_MCG_rabs_tobeadded.eNB_addr.length = 24; + uint8_t buf[20] = { 0 }; + memcpy(e_MCG_rabs_tobeadded.eNB_addr.buffer, buf, 20*sizeof(uint8_t)); + + FILE *fd; + fd = fopen("../../../executables/uecap.raw","r"); + if (fd != NULL) { + OCTET_STRING_t CG_Config_Info; + CG_Config_Info.size = 4096; + CG_Config_Info.buf = (uint8_t *)calloc(4096, sizeof(uint8_t)); + int msg_len=fread(CG_Config_Info.buf,1,CG_Config_Info.size,fd); + CG_Config_Info.size = msg_len; + + /*char buffer[4096]; + int msg_len=fread(buffer,1,4096,fd);*/ + LOG_I(RRC,"Read in %d bytes for uecap\n",msg_len); + + + /*OCTET_STRING_t CG_Config_Info; + CG_Config_Info.size = 4096; + CG_Config_Info.buf = (uint8_t *)calloc(4096, sizeof(uint8_t));*/ + + + DevAssert(instance_p != NULL); + DevAssert(x2ap_eNB_data_p != NULL); + + x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING; + + + + /* Prepare the X2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_sgNBAdditionPreparation; + pdu.choice.initiatingMessage.criticality = X2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_SgNBAdditionRequest; + out = &pdu.choice.initiatingMessage.value.choice.SgNBAdditionRequest; + + ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID; //Not sure about that + ie->criticality= X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_UE_X2AP_ID; + ie->value.choice.UE_X2AP_ID = x2ap_id_get_id_source(&instance_p->id_manager, ue_id); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_NRUESecurityCapabilities; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_NRUESecurityCapabilities; + INT16_TO_BIT_STRING(nRencryptionAlgorithms, &ie->value.choice.NRUESecurityCapabilities.nRencryptionAlgorithms); + INT16_TO_BIT_STRING(nRintegrityProtectionAlgorithms, &ie->value.choice.NRUESecurityCapabilities.nRintegrityProtectionAlgorithms); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_SgNBSecurityKey; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_SgNBSecurityKey; + KENB_STAR_TO_BIT_STRING(SgNBSecurityKey, &ie->value.choice.SgNBSecurityKey); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_SgNBUEAggregateMaximumBitRate; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_UEAggregateMaximumBitRate; + ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink.buf = (uint8_t *)calloc(4, sizeof(uint8_t)); + INT32_TO_BUFFER(uEaggregateMaximumBitRateDownlink, ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink.buf); + ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink.size = 4; + + ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink.buf = (uint8_t *)calloc(4, sizeof(uint8_t)); + INT32_TO_BUFFER(uEaggregateMaximumBitRateUplink, ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink.buf); + ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink.size = 4; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t)); + //Not sure if id should be X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_List or X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList + ie->id = X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_E_RABs_ToBeAdded_SgNBAddReqList; + + for (int i=0;iid = X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReq_Item; + e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->criticality = X2AP_Criticality_ignore; + e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->value.present = X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs__value_PR_E_RABs_ToBeAdded_SgNBAddReq_Item; + e_RABS_ToBeAdded_SgNBAddReq_Item = &e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->value.choice.E_RABs_ToBeAdded_SgNBAddReq_Item; + { + e_RABS_ToBeAdded_SgNBAddReq_Item->drb_ID = drb_ID; + e_RABS_ToBeAdded_SgNBAddReq_Item->e_RAB_ID = e_RAB_ID; + e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.pDCPatSgNB = pDCPatSgNB; + e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.mCGresources = mCGresources; + e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.sCGresources = sCGresources; + if (pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){ + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.present = X2AP_E_RABs_ToBeAdded_SgNBAddReq_Item__resource_configuration_PR_sgNBPDCPpresent; + + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.qCI = qCI; + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = pre_emptionCapability; + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority. pre_emptionVulnerability = pre_emptionVulnerability; + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = priority_level; + + //Continue from filling the UL_GTPtunnelEndpointInformation inspired from how it is done for the HO case + INT32_TO_OCTET_STRING(e_MCG_rabs_tobeadded.gtp_teid, &e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.gTP_TEID); + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size = e_MCG_rabs_tobeadded.eNB_addr.length/8; + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = e_MCG_rabs_tobeadded.eNB_addr.length%8; + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf = + calloc(1, e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size); + + memcpy (e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf, + e_MCG_rabs_tobeadded.eNB_addr.buffer, + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size); + } + + } + ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list, e_RABS_ToBeAdded_SgNBAddReq_ItemIEs); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_MeNBtoSgNBContainer; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_MeNBtoSgNBContainer; + ie->value.choice.MeNBtoSgNBContainer.buf = (uint8_t *)calloc(CG_Config_Info.size, sizeof(uint8_t)); + memcpy(ie->value.choice.MeNBtoSgNBContainer.buf, CG_Config_Info.buf, CG_Config_Info.size); + ie->value.choice.MeNBtoSgNBContainer.size = CG_Config_Info.size; //4096; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { + X2AP_ERROR("Failed to encode ENDC X2 SgNB_addition request message\n"); + return -1; + } + + MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id); + + x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0); + fclose(fd); + } + else { + LOG_I(RRC, "uecap.raw file could not be opened... \n"); + return -1; + } + + return ret; + +} + + +int x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, + x2ap_ENDC_sgnb_addition_req_ACK_t *x2ap_sgnb_addition_req_ACK, int ue_id) +{ + + X2AP_X2AP_PDU_t pdu; + X2AP_SgNBAdditionRequestAcknowledge_t *out; + X2AP_SgNBAdditionRequestAcknowledge_IEs_t *ie; + X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs_t *e_RABS_AdmittedToBeAdded_SgNBAddReq_ItemIEs; + X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item_t *e_RABS_AdmittedToBeAdded_SgNBAddReq_Item; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + int MeNB_UE_X2AP_id = ue_id; + int SgNB_UE_X2AP_id = 0; + + // Currently hardcoded (dummy) values filling the fields of SgNB_addition_request message. To be substituted + // with values coming from RRC. + uint16_t nRencryptionAlgorithms = 0; + uint16_t nRintegrityProtectionAlgorithms = 0; + uint8_t SgNBSecurityKey[32] = { 0 }; + int uEaggregateMaximumBitRateDownlink = 100000000; + int uEaggregateMaximumBitRateUplink = 100000000; + int e_rabs_admitted_tobeadded = 1; + int e_RAB_ID = 1; + long int pDCPatSgNB = X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present; + long int mCGresources = X2AP_EN_DC_ResourceConfiguration__mCGresources_not_present; + long int sCGresources = X2AP_EN_DC_ResourceConfiguration__sCGresources_not_present; + e_rab_setup_t e_SCG_rabs_tobeadded; + e_SCG_rabs_tobeadded.gtp_teid = 0; + e_SCG_rabs_tobeadded.eNB_addr.length = 24; + uint8_t buf[20] = { 0 }; + memcpy(e_SCG_rabs_tobeadded.eNB_addr.buffer, buf, 20*sizeof(uint8_t)); + + DevAssert(instance_p != NULL); + DevAssert(x2ap_eNB_data_p != NULL); + + x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING; + + // Prepare the X2AP message to encode + memset(&pdu, 0, sizeof(pdu)); + pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_sgNBAdditionPreparation; + pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_SgNBAdditionRequestAcknowledge; + out = &pdu.choice.successfulOutcome.value.choice.SgNBAdditionRequestAcknowledge; + + // MeNB_UE_X2AP_id + ie = (X2AP_SgNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequestAcknowledge_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID; + ie->criticality= X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequestAcknowledge_IEs__value_PR_UE_X2AP_ID; + ie->value.choice.UE_X2AP_ID = MeNB_UE_X2AP_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + // SgNB_UE_X2AP_id + ie = (X2AP_SgNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequestAcknowledge_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID; + ie->criticality= X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequestAcknowledge_IEs__value_PR_SgNB_UE_X2AP_ID; + ie->value.choice.UE_X2AP_ID = SgNB_UE_X2AP_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequestAcknowledge_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList; + ie->criticality = X2AP_Criticality_ignore; + ie->value.present = X2AP_SgNBAdditionRequestAcknowledge_IEs__value_PR_E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList; + + for (int i=0;iid = X2AP_ProtocolIE_ID_id_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item; + e_RABS_AdmittedToBeAdded_SgNBAddReq_ItemIEs->criticality = X2AP_Criticality_ignore; + e_RABS_AdmittedToBeAdded_SgNBAddReq_ItemIEs->value.present = X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs__value_PR_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item; + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item = &e_RABS_AdmittedToBeAdded_SgNBAddReq_ItemIEs->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item; + { + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->e_RAB_ID = e_RAB_ID; + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.pDCPatSgNB = pDCPatSgNB; + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.mCGresources = mCGresources; + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.sCGresources = sCGresources; + if (pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){ + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.present = X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item__resource_configuration_PR_sgNBPDCPpresent; + + INT32_TO_OCTET_STRING(e_SCG_rabs_tobeadded.gtp_teid, &e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.gTP_TEID); + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size = e_SCG_rabs_tobeadded.eNB_addr.length/8; + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = e_SCG_rabs_tobeadded.eNB_addr.length%8; + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.buf = + calloc(1, e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size); + + memcpy (e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.buf, + e_SCG_rabs_tobeadded.eNB_addr.buffer, + e_RABS_AdmittedToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size); + } + + } + ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list, e_RABS_AdmittedToBeAdded_SgNBAddReq_ItemIEs); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequestAcknowledge_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_SgNBtoMeNBContainer; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBAdditionRequestAcknowledge_IEs__value_PR_SgNBtoMeNBContainer; + ie->value.choice.SgNBtoMeNBContainer.buf = (uint8_t *)calloc(x2ap_sgnb_addition_req_ACK->rrc_buffer_size, sizeof(uint8_t)); + memcpy(ie->value.choice.SgNBtoMeNBContainer.buf, x2ap_sgnb_addition_req_ACK->rrc_buffer, x2ap_sgnb_addition_req_ACK->rrc_buffer_size); + ie->value.choice.SgNBtoMeNBContainer.size = x2ap_sgnb_addition_req_ACK->rrc_buffer_size; //4096; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { + X2AP_ERROR("Failed to encode ENDC X2 SgNB_addition request message\n"); + return -1; + } + + MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id); + + x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0); + + return ret; + +} + + +int x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete( + x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id, int SgNB_ue_id) +{ + X2AP_X2AP_PDU_t pdu; + X2AP_SgNBReconfigurationComplete_t *out; + X2AP_SgNBReconfigurationComplete_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + DevAssert(instance_p != NULL); + DevAssert(x2ap_eNB_data_p != NULL); + + x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING; + + + /* Prepare the X2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_sgNBReconfigurationCompletion; + pdu.choice.initiatingMessage.criticality = X2AP_Criticality_ignore; + pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_SgNBReconfigurationComplete; + out = &pdu.choice.initiatingMessage.value.choice.SgNBReconfigurationComplete; + + ie = (X2AP_SgNBReconfigurationComplete_IEs_t *)calloc(1, sizeof(X2AP_SgNBReconfigurationComplete_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID; + ie->criticality= X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBReconfigurationComplete_IEs__value_PR_UE_X2AP_ID; + ie->value.choice.UE_X2AP_ID = ue_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBReconfigurationComplete_IEs_t *)calloc(1, sizeof(X2AP_SgNBReconfigurationComplete_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID; + ie->criticality = X2AP_Criticality_reject; + ie->value.present = X2AP_SgNBReconfigurationComplete_IEs__value_PR_SgNB_UE_X2AP_ID; + ie->value.choice.SgNB_UE_X2AP_ID = SgNB_ue_id; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ie = (X2AP_SgNBReconfigurationComplete_IEs_t *)calloc(1, sizeof(X2AP_SgNBReconfigurationComplete_IEs_t)); + ie->id = X2AP_ProtocolIE_ID_id_ResponseInformationSgNBReconfComp; + ie->criticality = X2AP_Criticality_ignore; + ie->value.present = X2AP_SgNBReconfigurationComplete_IEs__value_PR_ResponseInformationSgNBReconfComp; + ie->value.choice.ResponseInformationSgNBReconfComp.present = X2AP_ResponseInformationSgNBReconfComp_PR_success_SgNBReconfComp; + // meNBtoSgNBContainer should contain the RRCReconfigurationComplete message from the UE but in the specs 36.423(9.1.4.4) its presence is not mandatory + ie->value.choice.ResponseInformationSgNBReconfComp.choice.success_SgNBReconfComp.meNBtoSgNBContainer = NULL; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { + X2AP_ERROR("Failed to encode ENDC X2 SgNB_addition request message\n"); + return -1; + } + + x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0); + + return ret; + +} diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.h b/openair2/X2AP/x2ap_eNB_generate_messages.h index 6b0cd9c2da..114ed84a68 100644 --- a/openair2/X2AP/x2ap_eNB_generate_messages.h +++ b/openair2/X2AP/x2ap_eNB_generate_messages.h @@ -66,8 +66,15 @@ int x2ap_eNB_generate_senb_addition_request (x2ap_eNB_instance_t *instance_p, x2 int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, x2ap_senb_addition_req_ack_t *x2ap_addition_req_ack); -int x2ap_eNB_generate_ENDC_x2_setup_request(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p); +int x2ap_gNB_generate_ENDC_x2_setup_request(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p); -int x2ap_gNB_generate_ENDC_x2_setup_response( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p); +int x2ap_eNB_generate_ENDC_x2_setup_response( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p); + +int x2ap_eNB_generate_ENDC_x2_SgNB_addition_request( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id); + +int x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, x2ap_ENDC_sgnb_addition_req_ACK_t *x2ap_sgnb_addition_req_ACK, int ue_id); + +int x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete( + x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id, int SgNB_ue_id); #endif /* X2AP_ENB_GENERATE_MESSAGES_H_ */ diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c index bde7bd59d9..b7a9b70596 100644 --- a/openair2/X2AP/x2ap_eNB_handler.c +++ b/openair2/X2AP/x2ap_eNB_handler.c @@ -103,7 +103,7 @@ int x2ap_eNB_handle_senb_addition_request_reject (instance_t instance, uint32_t stream, X2AP_X2AP_PDU_t *pdu); -int x2ap_gNB_handle_ENDC_x2_setup_request(instance_t instance, +int x2ap_eNB_handle_ENDC_x2_setup_request(instance_t instance, uint32_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu); @@ -114,8 +114,26 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, uint32_t stream, X2AP_X2AP_PDU_t *pdu); +static +int x2ap_gNB_handle_ENDC_sGNB_addition_request (instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu); -/* Handlers matrix. Only eNB related procedure present here */ +static +int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu); + +static +int x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete (instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu); + + +/* Handlers matrix. Only eNB related procedure present here. Placement of callback functions according to X2AP_ProcedureCode.h */ x2ap_message_decoded_callback x2ap_messages_callback[][3] = { { x2ap_eNB_handle_handover_preparation, x2ap_eNB_handle_handover_response, 0 }, /* handoverPreparation */ { x2ap_eNB_handle_handover_cancel, 0, 0 }, /* handoverCancel */ @@ -144,6 +162,8 @@ x2ap_message_decoded_callback x2ap_messages_callback[][3] = { { 0, 0, 0 }, /* seNBinitiatedSeNBRelease */ { 0, 0, 0 }, /* seNBCounterCheck */ { 0, 0, 0 }, /* retrieveUEContext */ + { x2ap_gNB_handle_ENDC_sGNB_addition_request, x2ap_eNB_handle_ENDC_sGNB_addition_response, 0 }, /*X2AP_ProcedureCode_id_sgNBAdditionPreparation*/ + { x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete, 0, 0 }, /*X2AP_ProcedureCode_id_sgNBReconfigurationCompletion*/ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, @@ -151,9 +171,7 @@ x2ap_message_decoded_callback x2ap_messages_callback[][3] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { x2ap_gNB_handle_ENDC_x2_setup_request, x2ap_gNB_handle_ENDC_x2_setup_response, 0 }, + { x2ap_eNB_handle_ENDC_x2_setup_request, x2ap_gNB_handle_ENDC_x2_setup_response, 0 }, /*X2AP_ProcedureCode_id_endcX2Setup*/ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } @@ -1324,7 +1342,7 @@ int x2ap_eNB_handle_senb_addition_request_reject (instance_t instance, } int -x2ap_gNB_handle_ENDC_x2_setup_request(instance_t instance, +x2ap_eNB_handle_ENDC_x2_setup_request(instance_t instance, uint32_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu) @@ -1332,12 +1350,12 @@ x2ap_gNB_handle_ENDC_x2_setup_request(instance_t instance, X2AP_ENDCX2SetupRequest_t *x2_ENDC_SetupRequest; X2AP_ENDCX2SetupRequest_IEs_t *ie; - X2AP_ENB_ENDCX2SetupReqIEs_t *ie_ENB_ENDC; - ServedEUTRAcellsENDCX2ManagementList__Member *servedCellMember; + X2AP_En_gNB_ENDCX2SetupReqIEs_t *ie_GNB_ENDC; + ServedNRcellsENDCX2ManagementList__Member *servedCellMember; x2ap_eNB_instance_t *instance_p; x2ap_eNB_data_t *x2ap_eNB_data; - uint32_t eNB_id = 0; + uint32_t gNB_id = 0; x2ap_eNB_data = NULL; DevAssert (pdu != NULL); @@ -1372,156 +1390,11 @@ x2ap_gNB_handle_ENDC_x2_setup_request(instance_t instance, X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); return -1; } else { - if (ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list.count > 0) { - //Panos: Here the container parameter in X2AP_FIND_PROTOCOLIE_BY_ID should be the x2_ENDC_SetupRequest - //message or the ie to which there are more nested information elements? - for (int i=0; ivalue.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list.count;i++) { + if (ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_en_gNB.list.count > 0) { - ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqIEs_t*) ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list.array[i]; - if (ie_ENB_ENDC == NULL ) { - X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); - return -1; - } + for (int i=0; ivalue.choice.InitiatingNodeType_EndcX2Setup.choice.init_en_gNB.list.count;i++) { - else if (ie_ENB_ENDC->id == X2AP_ProtocolIE_ID_id_GlobalENB_ID) { - if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.present == X2AP_ENB_ID_PR_home_eNB_ID) { - // Home eNB ID = 28 bits - uint8_t *eNB_id_buf = ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.home_eNB_ID.buf; - if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) { - //TODO: handle case were size != 28 -> notify ? reject ? - } - eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4); - X2AP_DEBUG("Home eNB id: %07x\n", eNB_id); - } else { - // Macro eNB = 20 bits - uint8_t *eNB_id_buf = ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf; - if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) { - //TODO: handle case were size != 20 -> notify ? reject ? - } - eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4); - X2AP_DEBUG("macro eNB id: %05x\n", eNB_id); - } - X2AP_DEBUG("Adding eNB to the list of associated eNBs\n"); - if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) { - /* - * eNB has not been found in list of associated eNB, - * * * * Add it to the tail of list and initialize data - */ - if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) { - /* - * ?? - */ - return -1; - } else { - x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING; - x2ap_eNB_data->eNB_id = eNB_id; - } - } else { - x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING; - - /* - * eNB has been found in list, consider the x2 setup request as a reset connection, - * * * * reseting any previous UE state if sctp association is != than the previous one - */ - if (x2ap_eNB_data->assoc_id != assoc_id) { - /* - * ??: Send an overload cause... - */ - X2AP_ERROR("Rejecting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id); - - // Panos: Here we should be calling an ENDC specific setup_failure function instead - x2ap_eNB_generate_x2_setup_failure (instance, - assoc_id, - X2AP_Cause_PR_protocol, - X2AP_CauseProtocol_unspecified, - -1); - return -1; - } - /* - * * TODO: call the reset procedure - */ - } - } - else if (ie_ENB_ENDC->id == X2AP_ProtocolIE_ID_id_ServedEUTRAcellsENDCX2ManagementList){ - if (ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count > 0) { - x2ap_eNB_data->num_cc = ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count; - for (int i=0; ivalue.choice.ServedEUTRAcellsENDCX2ManagementList.list.count;i++) { - servedCellMember = (ServedEUTRAcellsENDCX2ManagementList__Member *)ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.array[i]; - x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedEUTRACellInfo.pCI; - } - } - } - } - } - else { - X2AP_ERROR("%s %d: init_eNB list is empty \n",__FILE__,__LINE__); - return -1; - } - } - - instance_p = x2ap_eNB_get_instance(instance); - DevAssert(instance_p != NULL); - - // Panos: Here we should be calling an ENDC specific setup response function - return x2ap_gNB_generate_ENDC_x2_setup_response(instance_p, x2ap_eNB_data); - //return x2ap_eNB_generate_x2_setup_response(instance_p, x2ap_eNB_data); -} - -int -x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, - uint32_t assoc_id, - uint32_t stream, - X2AP_X2AP_PDU_t *pdu) -{ - - X2AP_ENDCX2SetupResponse_t *x2_ENDC_SetupResponse; - X2AP_ENDCX2SetupResponse_IEs_t *ie; - X2AP_En_gNB_ENDCX2SetupReqAckIEs_t *ie_GNB_ENDC; - ServedNRcellsENDCX2ManagementList__Member *servedCellMember; - - x2ap_eNB_instance_t *instance_p; - x2ap_eNB_data_t *x2ap_eNB_data; - uint32_t gNB_id = 0; - - x2ap_eNB_data = NULL; - DevAssert (pdu != NULL); - x2_ENDC_SetupResponse = &pdu->choice.successfulOutcome.value.choice.ENDCX2SetupResponse; - - /* - * We received a new valid X2 Setup Request on a stream != 0. - * * * * This should not happen -> reject eNB x2 setup request. - */ - - if (stream != 0) { - X2AP_ERROR("Received new x2 setup request on stream != 0\n"); - /* - * Send a x2 setup failure with protocol cause unspecified - */ - // Panos: Here we should be calling an ENDC specific setup_failure function instead - return x2ap_eNB_generate_x2_setup_failure (instance, - assoc_id, - X2AP_Cause_PR_protocol, - X2AP_CauseProtocol_unspecified, - -1); - } - - X2AP_DEBUG("Received a new X2 setup request\n"); - - X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_ENDCX2SetupResponse_IEs_t, ie, x2_ENDC_SetupResponse, - X2AP_ProtocolIE_ID_id_RespondingNodeType_EndcX2Setup, true); - - - - if (ie == NULL ) { - X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); - return -1; - } else { - if (ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_en_gNB.list.count > 0) { - //Panos: Here the container parameter in X2AP_FIND_PROTOCOLIE_BY_ID should be the x2_ENDC_SetupRequest - //message or the ie to which there are more nested information elements? - for (int i=0; ivalue.choice.RespondingNodeType_EndcX2Setup.choice.respond_en_gNB.list.count;i++) { - - ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqAckIEs_t*) ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_en_gNB.list.array[i]; + ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqIEs_t*) ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list.array[i]; if (ie_GNB_ENDC == NULL ) { X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); return -1; @@ -1606,6 +1479,146 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, } } + instance_p = x2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + return x2ap_eNB_generate_ENDC_x2_setup_response(instance_p, x2ap_eNB_data); +} + +int +x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu) +{ + + X2AP_ENDCX2SetupResponse_t *x2_ENDC_SetupResponse; + X2AP_ENDCX2SetupResponse_IEs_t *ie; + X2AP_ENB_ENDCX2SetupReqAckIEs_t *ie_ENB_ENDC; + ServedEUTRAcellsENDCX2ManagementList__Member *servedCellMember; + + x2ap_eNB_instance_t *instance_p; + x2ap_eNB_data_t *x2ap_eNB_data; + uint32_t eNB_id = 0; + + x2ap_eNB_data = NULL; + DevAssert (pdu != NULL); + x2_ENDC_SetupResponse = &pdu->choice.successfulOutcome.value.choice.ENDCX2SetupResponse; + + /* + * We received a new valid X2 Setup Request on a stream != 0. + * * * * This should not happen -> reject eNB x2 setup request. + */ + + if (stream != 0) { + X2AP_ERROR("Received new x2 setup request on stream != 0\n"); + /* + * Send a x2 setup failure with protocol cause unspecified + */ + // Here we should be calling an ENDC specific setup_failure function instead + return x2ap_eNB_generate_x2_setup_failure (instance, + assoc_id, + X2AP_Cause_PR_protocol, + X2AP_CauseProtocol_unspecified, + -1); + } + + X2AP_DEBUG("Received a new X2 setup request\n"); + + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_ENDCX2SetupResponse_IEs_t, ie, x2_ENDC_SetupResponse, + X2AP_ProtocolIE_ID_id_RespondingNodeType_EndcX2Setup, true); + + + + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } else { + if (ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.count > 0) { + for (int i=0; ivalue.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.count;i++) { + + ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqAckIEs_t*) ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.array[i]; + if (ie_ENB_ENDC == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + else if (ie_ENB_ENDC->id == X2AP_ProtocolIE_ID_id_GlobalENB_ID) { + if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.present == X2AP_ENB_ID_PR_home_eNB_ID) { + // Home eNB ID = 28 bits + uint8_t *eNB_id_buf = ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.home_eNB_ID.buf; + if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) { + //TODO: handle case were size != 28 -> notify ? reject ? + } + eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4); + X2AP_DEBUG("Home eNB id: %07x\n", eNB_id); + } else { + // Macro eNB = 20 bits + uint8_t *eNB_id_buf = ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf; + if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) { + //TODO: handle case were size != 20 -> notify ? reject ? + } + eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4); + X2AP_DEBUG("macro eNB id: %05x\n", eNB_id); + } + X2AP_DEBUG("Adding eNB to the list of associated eNBs\n"); + if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) { + /* + * eNB has not been found in list of associated eNB, + * * * * Add it to the tail of list and initialize data + */ + if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) { + /* + * ?? + */ + return -1; + } else { + x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING; + x2ap_eNB_data->eNB_id = eNB_id; + } + } else { + x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING; + + /* + * eNB has been found in list, consider the x2 setup request as a reset connection, + * * * * reseting any previous UE state if sctp association is != than the previous one + */ + if (x2ap_eNB_data->assoc_id != assoc_id) { + /* + * ??: Send an overload cause... + */ + X2AP_ERROR("Rejecting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id); + + // Here we should be calling an ENDC specific setup_failure function instead + x2ap_eNB_generate_x2_setup_failure (instance, + assoc_id, + X2AP_Cause_PR_protocol, + X2AP_CauseProtocol_unspecified, + -1); + return -1; + } + /* + * * TODO: call the reset procedure + */ + } + } + else if (ie_ENB_ENDC->id == X2AP_ProtocolIE_ID_id_ServedEUTRAcellsENDCX2ManagementList){ + if (ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count > 0) { + x2ap_eNB_data->num_cc = ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count; + for (int i=0; ivalue.choice.ServedEUTRAcellsENDCX2ManagementList.list.count;i++) { + servedCellMember = (ServedEUTRAcellsENDCX2ManagementList__Member *)ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.array[i]; + x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedEUTRACellInfo.pCI; + } + } + } + } + } + else { + X2AP_ERROR("%s %d: init_eNB list is empty \n",__FILE__,__LINE__); + return -1; + } + } + /* Optionaly set the target eNB name */ /* The association is now ready as source and target eNBs know parameters of each other. @@ -1622,4 +1635,379 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, return 0; } +static +int x2ap_gNB_handle_ENDC_sGNB_addition_request (instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu) +{ + + + X2AP_SgNBAdditionRequest_t *x2SgNBAdditionRequest; + X2AP_SgNBAdditionRequest_IEs_t *ie; + + X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t *e_RABS_ToBeAdded_SgNBAddReq_ItemIEs; + X2AP_E_RABs_ToBeAdded_SgNBAddReq_Item_t *e_RABS_ToBeAdded_SgNBAddReq_Item; + + x2ap_eNB_instance_t *instance_p; + x2ap_eNB_data_t *x2ap_eNB_data; + MessageDef *msg; + int ue_id; + + DevAssert (pdu != NULL); + x2SgNBAdditionRequest = &pdu->choice.initiatingMessage.value.choice.SgNBAdditionRequest; + + /*if (stream == 0) { + X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n"); + // TODO: send a x2 failure response + return 0; + }*/ + + X2AP_DEBUG ("Received a new X2 SgNB Addition request\n"); + + x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0); + DevAssert(x2ap_eNB_data != NULL); + + X2AP_INFO("X2AP Association id: %d \n",assoc_id); + + instance_p = x2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + //Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead + msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_ADDITION_REQ); + + /* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, + X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true); + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + + // allocate a new X2AP UE ID + ue_id = x2ap_allocate_new_id(&instance_p->id_manager); + if (ue_id == -1) { + X2AP_ERROR("could not allocate a new X2AP UE ID\n"); + // TODO: cancel handover: send HO preparation failure to source eNB + exit(1); + } + // rnti is unknown yet, must not be set to -1, 0 is fine + x2ap_set_ids(&instance_p->id_manager, ue_id, 0, ie->value.choice.UE_X2AP_ID, ue_id); + x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_TARGET); + + X2AP_ENDC_SGNB_ADDITION_REQ(msg).ue_x2_id = ue_id; + + + /* X2AP_ProtocolIE_ID_id_NRUESecurityCapabilities */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, + X2AP_ProtocolIE_ID_id_NRUESecurityCapabilities, true); + + X2AP_ENDC_SGNB_ADDITION_REQ(msg).security_capabilities.encryption_algorithms = + BIT_STRING_to_uint16(&ie->value.choice.NRUESecurityCapabilities.nRencryptionAlgorithms); + + X2AP_ENDC_SGNB_ADDITION_REQ(msg).security_capabilities.integrity_algorithms = + BIT_STRING_to_uint16(&ie->value.choice.NRUESecurityCapabilities.nRintegrityProtectionAlgorithms); + + /* X2AP_ProtocolIE_ID_id_SgNBSecurityKey */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, + X2AP_ProtocolIE_ID_id_SgNBSecurityKey, true); + + if ((ie->value.choice.SgNBSecurityKey.buf) && + (ie->value.choice.SgNBSecurityKey.size == 32)) { + memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).kgnb, ie->value.choice.SgNBSecurityKey.buf, 32); + } else { + X2AP_WARN ("Size of eNB key star does not match the expected value\n"); + } + + + /* X2AP_ProtocolIE_ID_id_SgNBUEAggregateMaximumBitRate */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, + X2AP_ProtocolIE_ID_id_SgNBUEAggregateMaximumBitRate, true); + + //X2AP_ENDC_SGNB_ADDITION_REQ(msg).ue_ambr.br_dl =ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink; + //X2AP_ENDC_SGNB_ADDITION_REQ(msg).ue_ambr.br_ul = ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink; + + /* X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, + X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList, true); + + + if (ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.count > 0) { + + X2AP_ENDC_SGNB_ADDITION_REQ(msg).nb_e_rabs_tobeadded = ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.count; + + for (int i=0;ivalue.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.count;i++) { + e_RABS_ToBeAdded_SgNBAddReq_ItemIEs = (X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t *) ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.array[i]; + e_RABS_ToBeAdded_SgNBAddReq_Item = &e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->value.choice.E_RABs_ToBeAdded_SgNBAddReq_Item; + + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].e_rab_id = e_RABS_ToBeAdded_SgNBAddReq_Item->e_RAB_ID ; + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].drb_ID = e_RABS_ToBeAdded_SgNBAddReq_Item->drb_ID; + if(e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){ + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.qci = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.qCI; + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability; + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability; + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.priority_level = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel; + + memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].eNB_addr.buffer, + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf, + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size); + + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].eNB_addr.length = + e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.bits_unused; + + OCTET_STRING_TO_INT32(&e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.gTP_TEID, + X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].gtp_teid); + } + + } + + } + else { + X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n"); + } + + /* X2AP_ProtocolIE_ID_id_MeNBtoSgNBContainer */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, + X2AP_ProtocolIE_ID_id_MeNBtoSgNBContainer, true); + + X2AP_MeNBtoSgNBContainer_t *container = &ie->value.choice.MeNBtoSgNBContainer; + + if (ie->value.choice.MeNBtoSgNBContainer.size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s + { printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); } + + memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).rrc_buffer, ie->value.choice.MeNBtoSgNBContainer.buf, ie->value.choice.MeNBtoSgNBContainer.size); + X2AP_ENDC_SGNB_ADDITION_REQ(msg).rrc_buffer_size = ie->value.choice.MeNBtoSgNBContainer.size; + + itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg); + + return 0; +} + + +static +int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu) +{ + + X2AP_SgNBAdditionRequestAcknowledge_t *x2SgNBAdditionRequest_ack; + X2AP_SgNBAdditionRequestAcknowledge_IEs_t *ie; + + X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs_t *e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs; + X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item_t *e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item; + + x2ap_eNB_instance_t *instance_p; + x2ap_eNB_data_t *x2ap_eNB_data; + MessageDef *msg; + int ue_id; + int id_source; + int id_target; + int rnti; + + DevAssert (pdu != NULL); + x2SgNBAdditionRequest_ack = &pdu->choice.successfulOutcome.value.choice.SgNBAdditionRequestAcknowledge; + + /*if (stream == 0) { + X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n"); + // TODO: send a x2 failure response + return 0; + }*/ + + X2AP_DEBUG ("Received a new X2 SgNB Addition request\n"); + + x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0); + DevAssert(x2ap_eNB_data != NULL); + + X2AP_INFO("X2AP Association id: %d \n",assoc_id); + + instance_p = x2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + //Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead + msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_ADDITION_REQ_ACK); + + /* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack, + X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true); + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + id_source = ie->value.choice.UE_X2AP_ID; + + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID; + + + /* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack, + X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true); + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + id_target = ie->value.choice.SgNB_UE_X2AP_ID; + + ue_id = id_source; + + if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) { + X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring sGNB addition response\n", + id_source, id_target); + itti_free(ITTI_MSG_ORIGIN_ID(msg), msg); + return 0; + } + + rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id); + + /* id_target is a new information, store it */ + x2ap_set_ids(&instance_p->id_manager, ue_id, rnti, id_source, id_target); + + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rnti = rnti; + + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = ie->value.choice.SgNB_UE_X2AP_ID; + + /* X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack, + X2AP_ProtocolIE_ID_id_E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList, true); + + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + + if (ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.count > 0) { + + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).nb_e_rabs_admitted_tobeadded = ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.count; + + for (int i=0;ivalue.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.count;i++) { + + e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs = (X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs_t *) ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.array[i]; + e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item = &e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item; + + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].e_rab_id = e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->e_RAB_ID ; + if(e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->en_DC_ResourceConfiguration.pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){ + + memcpy(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].eNB_addr.buffer, + e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.buf, + e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size); + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].eNB_addr.length = + e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.bits_unused; + + OCTET_STRING_TO_INT32(&e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.gTP_TEID, + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid); + } + + } + + } + else { + X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n"); + } + + /* X2AP_ProtocolIE_ID_id_SgNBtoMeNBContainer */ + + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack, + X2AP_ProtocolIE_ID_id_SgNBtoMeNBContainer, true); + + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + //X2AP_MeNBtoSgNBContainer_t *container = &ie->value.choice.MeNBtoSgNBContainer; + + if (ie->value.choice.SgNBtoMeNBContainer.size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s + { printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); } + + memcpy(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer, ie->value.choice.SgNBtoMeNBContainer.buf, ie->value.choice.SgNBtoMeNBContainer.size); + X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = ie->value.choice.SgNBtoMeNBContainer.size; + + itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg); + + return 0; +} + +static +int x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete (instance_t instance, + uint32_t assoc_id, + uint32_t stream, + X2AP_X2AP_PDU_t *pdu) { + + X2AP_SgNBReconfigurationComplete_t *x2SgNBReconfigurationComplete; + X2AP_SgNBReconfigurationComplete_IEs_t *ie; + + x2ap_eNB_instance_t *instance_p; + x2ap_eNB_data_t *x2ap_eNB_data; + MessageDef *msg; + int ue_id; + + DevAssert (pdu != NULL); + x2SgNBReconfigurationComplete = &pdu->choice.initiatingMessage.value.choice.SgNBReconfigurationComplete; + + /*if (stream == 0) { + X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n"); + // TODO: send a x2 failure response + return 0; + }*/ + + X2AP_DEBUG ("Received X2 SgNB Reconfiguration complete message\n"); + + x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0); + DevAssert(x2ap_eNB_data != NULL); + + X2AP_INFO("X2AP Association id: %d \n",assoc_id); + + instance_p = x2ap_eNB_get_instance(instance); + DevAssert(instance_p != NULL); + + //Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead + msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_RECONF_COMPLETE); + + /* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete, + X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true); + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID; + + + /* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */ + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete, + X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true); + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).SgNB_ue_x2_id = ie->value.choice.SgNB_UE_X2AP_ID; + + + X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete, + X2AP_ProtocolIE_ID_id_ResponseInformationSgNBReconfComp, true); + if (ie == NULL ) { + X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + + if(ie->value.choice.ResponseInformationSgNBReconfComp.present == X2AP_ResponseInformationSgNBReconfComp_PR_success_SgNBReconfComp){ + X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).reconf_response = X2AP_RECONF_RESPONSE_SUCCESS; + } + else { + X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).reconf_response = X2AP_RECONF_RESPONSE_REJECT; + } + + itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg); + + + return 0; +} + + diff --git a/openair2/X2AP/x2ap_eNB_management_procedures.c b/openair2/X2AP/x2ap_eNB_management_procedures.c index 986ca10902..469a76a261 100644 --- a/openair2/X2AP/x2ap_eNB_management_procedures.c +++ b/openair2/X2AP/x2ap_eNB_management_procedures.c @@ -129,8 +129,8 @@ struct x2ap_eNB_data_s *x2ap_get_eNB(x2ap_eNB_instance_t *instance_p, struct x2ap_eNB_data_s temp; struct x2ap_eNB_data_s *found; -printf("x2ap_get_eNB at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id); -dump_trees(); +//printf("x2ap_get_eNB at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id); +//dump_trees(); memset(&temp, 0, sizeof(struct x2ap_eNB_data_s)); diff --git a/openair2/X2AP/x2ap_ids.h b/openair2/X2AP/x2ap_ids.h index 3d2799e8c4..f2670f3612 100644 --- a/openair2/X2AP/x2ap_ids.h +++ b/openair2/X2AP/x2ap_ids.h @@ -37,7 +37,8 @@ typedef enum { X2ID_STATE_SOURCE_PREPARE, X2ID_STATE_SOURCE_OVERALL, - X2ID_STATE_TARGET + X2ID_STATE_TARGET, + X2ID_STATE_NSA_PREPARE, } x2id_state_t; typedef struct { diff --git a/openair3/COMMON/messages_types.h b/openair3/COMMON/messages_types.h index 56a16da554..f91881bf11 100644 --- a/openair3/COMMON/messages_types.h +++ b/openair3/COMMON/messages_types.h @@ -38,5 +38,7 @@ #include "sgw_lite_messages_types.h" #include "udp_messages_types.h" #include "mme_app_messages_types.h" +#include "m2ap_messages_types.h" + #endif /* MESSAGES_TYPES_H_ */ diff --git a/openair3/M3AP/MESSAGES/ASN1/R14/m3ap-14.0.0.asn1 b/openair3/M3AP/MESSAGES/ASN1/R14/m3ap-14.0.0.asn1 new file mode 100644 index 0000000000..b5878c27be --- /dev/null +++ b/openair3/M3AP/MESSAGES/ASN1/R14/m3ap-14.0.0.asn1 @@ -0,0 +1,1065 @@ +-- ************************************************************** +-- +-- Elementary Procedure definitions +-- +-- ************************************************************** +M3AP-PDU-Descriptions { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-PDU-Descriptions (0) } +DEFINITIONS AUTOMATIC TAGS ::= +BEGIN +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** +IMPORTS + Criticality, + ProcedureCode +FROM M3AP-CommonDataTypes + MBMSSessionStartRequest, + MBMSSessionStartResponse, + MBMSSessionStartFailure, + MBMSSessionStopRequest, + MBMSSessionStopResponse, + MBMSSessionUpdateRequest, + MBMSSessionUpdateResponse, + MBMSSessionUpdateFailure, + MCEConfigurationUpdate, + MCEConfigurationUpdateAcknowledge, + MCEConfigurationUpdateFailure, + M3SetupRequest, + M3SetupResponse, + M3SetupFailure, + ErrorIndication, + Reset, + ResetAcknowledge, + PrivateMessage +FROM M3AP-PDU-Contents + id-mBMSsessionStart, + id-mBMSsessionStop, + id-mBMSsessionUpdate, + id-mCEConfigurationUpdate, + id-m3Setup, + id-errorIndication, + id-Reset, + id-privateMessage +FROM M3AP-Constants; +-- ************************************************************** +-- +-- Interface Elementary Procedure Class +-- +-- ************************************************************** +M3AP-ELEMENTARY-PROCEDURE ::= CLASS { + &InitiatingMessage , + &SuccessfulOutcome OPTIONAL, + &UnsuccessfulOutcome OPTIONAL, + &procedureCode ProcedureCode UNIQUE, + &criticality Criticality DEFAULT ignore +} +WITH SYNTAX { + INITIATING MESSAGE &InitiatingMessage + [SUCCESSFUL OUTCOME &SuccessfulOutcome] + [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome] + PROCEDURE CODE &procedureCode + [CRITICALITY &criticality] +} +-- ************************************************************** +-- +-- Interface PDU Definition +-- +-- ************************************************************** +M3AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} +InitiatingMessage ::= SEQUENCE { + procedureCode M3AP-ELEMENTARY-PROCEDURE.&procedureCode ({M3AP-ELEMENTARY-PROCEDURES}), + criticality M3AP-ELEMENTARY-PROCEDURE.&criticality ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M3AP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} +SuccessfulOutcome ::= SEQUENCE { + procedureCode M3AP-ELEMENTARY-PROCEDURE.&procedureCode ({M3AP-ELEMENTARY-PROCEDURES}), + criticality M3AP-ELEMENTARY-PROCEDURE.&criticality ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M3AP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode M3AP-ELEMENTARY-PROCEDURE.&procedureCode ({M3AP-ELEMENTARY-PROCEDURES}), + criticality M3AP-ELEMENTARY-PROCEDURE.&criticality ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M3AP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} +-- ************************************************************** +-- +-- Interface Elementary Procedure List +-- +-- ************************************************************** +M3AP-ELEMENTARY-PROCEDURES M3AP-ELEMENTARY-PROCEDURE ::= { + M3AP-ELEMENTARY-PROCEDURES-CLASS-1 | + M3AP-ELEMENTARY-PROCEDURES-CLASS-2 , + ... +} +M3AP-ELEMENTARY-PROCEDURES-CLASS-1 M3AP-ELEMENTARY-PROCEDURE ::= { + mBMSsessionStart | + mBMSsessionStop | + mBMSsessionUpdate | + reset | + m3Setup | + mCEConfigurationUpdate , + ... +} +M3AP-ELEMENTARY-PROCEDURES-CLASS-2 M3AP-ELEMENTARY-PROCEDURE ::= { + errorIndication | + privateMessage , + ... +} +-- ************************************************************** +-- +-- Interface Elementary Procedures +-- +-- ************************************************************** +mBMSsessionStart M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MBMSSessionStartRequest + SUCCESSFUL OUTCOME MBMSSessionStartResponse + UNSUCCESSFUL OUTCOME MBMSSessionStartFailure + PROCEDURE CODE id-mBMSsessionStart + CRITICALITY reject +} +mBMSsessionStop M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MBMSSessionStopRequest + SUCCESSFUL OUTCOME MBMSSessionStopResponse + PROCEDURE CODE id-mBMSsessionStop + CRITICALITY reject +} +mBMSsessionUpdate M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MBMSSessionUpdateRequest + SUCCESSFUL OUTCOME MBMSSessionUpdateResponse + UNSUCCESSFUL OUTCOME MBMSSessionUpdateFailure + PROCEDURE CODE id-mBMSsessionUpdate + CRITICALITY reject +} +errorIndication M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ErrorIndication + PROCEDURE CODE id-errorIndication + CRITICALITY ignore +} +reset M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Reset + SUCCESSFUL OUTCOME ResetAcknowledge + PROCEDURE CODE id-Reset + CRITICALITY reject +} +privateMessage M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PrivateMessage + PROCEDURE CODE id-privateMessage + CRITICALITY ignore +} +mCEConfigurationUpdate M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MCEConfigurationUpdate + SUCCESSFUL OUTCOME MCEConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME MCEConfigurationUpdateFailure + PROCEDURE CODE id-mCEConfigurationUpdate + CRITICALITY reject +} +m3Setup M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE M3SetupRequest + SUCCESSFUL OUTCOME M3SetupResponse + UNSUCCESSFUL OUTCOME M3SetupFailure + PROCEDURE CODE id-m3Setup + CRITICALITY reject +} +END + +-- ************************************************************** +-- +-- PDU definitions for M3AP. +-- +-- ************************************************************** +M3AP-PDU-Contents { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-PDU-Contents (1) } +DEFINITIONS AUTOMATIC TAGS ::= +BEGIN +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** +IMPORTS + Absolute-Time-ofMBMS-Data, + Cause, + CriticalityDiagnostics, + Global-MCE-ID, + MBMS-E-RAB-QoS-Parameters, + MBMS-Service-associatedLogicalM3-ConnectionItem, + MBMS-Service-Area, + MBMSServiceArea1, + MBMS-Session-Duration, + MBMS-Session-ID, + MCE-MBMS-M3AP-ID, + MCEname, + MinimumTimeToMBMSDataTransfer, + MME-MBMS-M3AP-ID, + TimeToWait, + TMGI, + TNL-Information, + Reestablishment, + MBMS-Cell-List +FROM M3AP-IEs + PrivateIE-Container{}, + ProtocolExtensionContainer{}, + ProtocolIE-Container{}, + ProtocolIE-ContainerList{}, + ProtocolIE-ContainerPair{}, + ProtocolIE-ContainerPairList{}, + ProtocolIE-Single-Container{}, + M3AP-PRIVATE-IES, + M3AP-PROTOCOL-EXTENSION, + M3AP-PROTOCOL-IES, + M3AP-PROTOCOL-IES-PAIR +FROM M3AP-Containers + id-AllocationAndRetentionPriority, + id-MCE-MBMS-M3AP-ID, + id-MME-MBMS-M3AP-ID, + id-TMGI, + id-MBMS-Session-ID, + id-MBMS-E-RAB-QoS-Parameters, + id-MBMS-Session-Duration, + id-MBMS-Service-Area, + id-TNL-Information, +id-Alternative-TNL-Information, + id-CriticalityDiagnostics, + id-Cause, + id-MBMS-Service-Area-List, + id-MBMS-Service-Area-List-Item, + id-TimeToWait, + id-ResetType, + id-MBMS-Service-associatedLogicalM3-ConnectionItem, + id-MBMS-Service-associatedLogicalM3-ConnectionListResAck, + id-MBMSServiceAreaList, + id-MinimumTimeToMBMSDataTransfer, + id-Time-ofMBMS-DataStop, + id-Time-ofMBMS-DataTransfer, + id-Global-MCE-ID, + id-MCEname, + id-Reestablishment, + id-MBMS-Cell-List, + maxnoofMBMSServiceAreaIdentitiesPerMCE, + maxnooferrors, + maxNrOfIndividualM3ConnectionsToReset +FROM M3AP-Constants; +-- ************************************************************** +-- +-- MBMS SESSION START REQUEST +-- +-- ************************************************************** +MBMSSessionStartRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MBMSSessionStartRequest-IEs}}, + ... +} +MBMSSessionStartRequest-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY reject TYPE MME-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory}| + { ID id-MBMS-Session-ID CRITICALITY ignore TYPE MBMS-Session-ID PRESENCE optional}| + { ID id-MBMS-E-RAB-QoS-Parameters CRITICALITY reject TYPE MBMS-E-RAB-QoS-Parameters PRESENCE mandatory}| + { ID id-MBMS-Session-Duration CRITICALITY reject TYPE MBMS-Session-Duration PRESENCE mandatory}| + { ID id-MBMS-Service-Area CRITICALITY reject TYPE MBMS-Service-Area PRESENCE mandatory}| + { ID id-MinimumTimeToMBMSDataTransfer CRITICALITY reject TYPE MinimumTimeToMBMSDataTransfer PRESENCE mandatory}| + { ID id-TNL-Information CRITICALITY reject TYPE TNL-Information PRESENCE mandatory}| + { ID id-Time-ofMBMS-DataTransfer CRITICALITY ignore TYPE Absolute-Time-ofMBMS-Data PRESENCE optional}| + { ID id-Reestablishment CRITICALITY ignore TYPE Reestablishment PRESENCE optional}| + { ID id-Alternative-TNL-Information CRITICALITY ignore TYPE TNL-Information PRESENCE optional}| + { ID id-MBMS-Cell-List CRITICALITY reject TYPE MBMS-Cell-List PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- MBMS SESSION START RESPONSE +-- +-- ************************************************************** +MBMSSessionStartResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionStartResponse-IEs}}, + ... +} +MBMSSessionStartResponse-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- MBMS SESSION START FAILURE +-- +-- ************************************************************** +MBMSSessionStartFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionStartFailure-IEs}}, + ... +} +MBMSSessionStartFailure-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- MBMS SESSION STOP REQUEST +-- +-- ************************************************************** +MBMSSessionStopRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MBMSSessionStopRequest-IEs}}, + ... +} +MBMSSessionStopRequest-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY reject TYPE MME-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-MCE-MBMS-M3AP-ID CRITICALITY reject TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-Time-ofMBMS-DataStop CRITICALITY ignore TYPE Absolute-Time-ofMBMS-Data PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- MBMS SESSION STOP RESPONSE +-- +-- ************************************************************** +MBMSSessionStopResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionStopResponse-IEs}}, + ... +} +MBMSSessionStopResponse-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} +-- ************************************************************** +-- +-- MBMS SESSION UPDATE REQUEST +-- +-- ************************************************************** +MBMSSessionUpdateRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MBMSSessionUpdateRequest-IEs}}, + ... +} +MBMSSessionUpdateRequest-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY reject TYPE MME-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-MCE-MBMS-M3AP-ID CRITICALITY reject TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory}| + { ID id-MBMS-Session-ID CRITICALITY ignore TYPE MBMS-Session-ID PRESENCE optional}| + { ID id-MBMS-E-RAB-QoS-Parameters CRITICALITY reject TYPE MBMS-E-RAB-QoS-Parameters PRESENCE mandatory}| + { ID id-MBMS-Session-Duration CRITICALITY reject TYPE MBMS-Session-Duration PRESENCE mandatory}| + { ID id-MBMS-Service-Area CRITICALITY ignore TYPE MBMS-Service-Area PRESENCE optional}| + { ID id-MinimumTimeToMBMSDataTransfer CRITICALITY reject TYPE MinimumTimeToMBMSDataTransfer PRESENCE mandatory}| + { ID id-TNL-Information CRITICALITY ignore TYPE TNL-Information PRESENCE optional}| + { ID id-Time-ofMBMS-DataTransfer CRITICALITY ignore TYPE Absolute-Time-ofMBMS-Data PRESENCE optional}| + { ID id-MBMS-Cell-List CRITICALITY reject TYPE MBMS-Cell-List PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- MBMS SESSION UPDATE RESPONSE +-- +-- ************************************************************** +MBMSSessionUpdateResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionUpdateResponse-IEs}}, + ... +} +MBMSSessionUpdateResponse-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- MBMS SESSION UPDATE FAILURE +-- +-- ************************************************************** +MBMSSessionUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionUpdateFailure-IEs}}, + ... +} +MBMSSessionUpdateFailure-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- ERROR INDICATION +-- +-- ************************************************************** +ErrorIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ErrorIndication-IEs}}, + ... +} +ErrorIndication-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE optional } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE optional } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} +-- ************************************************************** +-- +-- Reset +-- +-- ************************************************************** +Reset ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetIEs} }, + ... +} +ResetIEs M3AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-ResetType CRITICALITY reject TYPE ResetType PRESENCE mandatory }, + ... +} +ResetType ::= CHOICE { + m3-Interface ResetAll, + partOfM3-Interface MBMS-Service-associatedLogicalM3-ConnectionListRes, + ... +} +ResetAll ::= ENUMERATED { + reset-all, + ... +} +MBMS-Service-associatedLogicalM3-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualM3ConnectionsToReset)) OF ProtocolIE-Single-Container { +{ MBMS-Service-associatedLogicalM3-ConnectionItemRes } } +MBMS-Service-associatedLogicalM3-ConnectionItemRes M3AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM3-ConnectionItem CRITICALITY reject TYPE MBMS-Service-associatedLogicalM3-ConnectionItem PRESENCE +mandatory }, + ... +} +-- ************************************************************** +-- +-- Reset Acknowledge +-- +-- ************************************************************** +ResetAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetAcknowledgeIEs} }, + ... +} +ResetAcknowledgeIEs M3AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM3-ConnectionListResAck CRITICALITY ignore TYPE MBMS-Service-associatedLogicalM3-ConnectionListResAck PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +MBMS-Service-associatedLogicalM3-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualM3ConnectionsToReset)) OF ProtocolIE-Single-Container +{ { MBMS-Service-associatedLogicalM3-ConnectionItemResAck } } +MBMS-Service-associatedLogicalM3-ConnectionItemResAck M3AP-PROTOCOL-IES ::= { +{ ID id-MBMS-Service-associatedLogicalM3-ConnectionItem CRITICALITY ignore TYPE MBMS-Service-associatedLogicalM3-ConnectionItem PRESENCE +mandatory }, + ... +} +-- ************************************************************** +-- +-- PRIVATE MESSAGE +-- +-- ************************************************************** +PrivateMessage ::= SEQUENCE { + privateIEs PrivateIE-Container {{PrivateMessage-IEs}}, + ... +} +PrivateMessage-IEs M3AP-PRIVATE-IES ::= { + ... +} +-- ************************************************************** +-- +-- M3 SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** +-- ************************************************************** +-- +-- M3 Setup Request +-- +-- ************************************************************** +M3SetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {M3SetupRequestIEs} }, + ... +} +M3SetupRequestIEs M3AP-PROTOCOL-IES ::= { + { ID id-Global-MCE-ID CRITICALITY reject TYPE Global-MCE-ID PRESENCE mandatory}| + { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional}| + { ID id-MBMSServiceAreaList CRITICALITY reject TYPE MBMSServiceAreaListItem PRESENCE mandatory}, + ... +} +MBMSServiceAreaListItem ::= SEQUENCE (SIZE(1..maxnoofMBMSServiceAreaIdentitiesPerMCE)) OF MBMSServiceArea1 +-- ************************************************************** +-- +-- M3 Setup Response +-- +-- ************************************************************** +M3SetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {M3SetupResponseIEs} }, + ... +} +M3SetupResponseIEs M3AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- M3 Setup Failure +-- +-- ************************************************************** +M3SetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {M3SetupFailureIEs} }, + ... +} +M3SetupFailureIEs M3AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- MCE CONFIGURATION UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** +-- ************************************************************** +-- +-- MCE Configuration Update +-- +-- ************************************************************** +MCEConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MCEConfigurationUpdateIEs} }, + ... +} +MCEConfigurationUpdateIEs M3AP-PROTOCOL-IES ::= { + { ID id-Global-MCE-ID CRITICALITY reject TYPE Global-MCE-ID PRESENCE optional}| + { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional}| + { ID id-MBMSServiceAreaList CRITICALITY reject TYPE MBMSServiceAreaListItem PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- MCE Configuration Update Acknowledge +-- +-- ************************************************************** +MCEConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MCEConfigurationUpdateAcknowledgeIEs} }, + ... +} +MCEConfigurationUpdateAcknowledgeIEs M3AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- MCE Configuration Update Failure +-- +-- ************************************************************** +MCEConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MCEConfigurationUpdateFailureIEs} }, + ... +} +MCEConfigurationUpdateFailureIEs M3AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} +END + +-- ************************************************************** +-- +-- Information Element Definitions +-- +-- ************************************************************** +M3AP-IEs { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-IEs (2) } +DEFINITIONS AUTOMATIC TAGS ::= +BEGIN +IMPORTS + id-AllocationAndRetentionPriority, + maxnooferrors, + maxnoofCellsforMBMS +FROM M3AP-Constants + Criticality, + ProcedureCode, + ProtocolIE-ID, + TriggeringMessage +FROM M3AP-CommonDataTypes + ProtocolExtensionContainer{}, + ProtocolIE-Single-Container{}, + M3AP-PROTOCOL-EXTENSION, + M3AP-PROTOCOL-IES +FROM M3AP-Containers; +-- A +Absolute-Time-ofMBMS-Data ::= BIT STRING (SIZE (64)) +AllocationAndRetentionPriority ::= SEQUENCE { + priorityLevel PriorityLevel, + pre-emptionCapability Pre-emptionCapability, + pre-emptionVulnerability Pre-emptionVulnerability, + iE-Extensions ProtocolExtensionContainer { {AllocationAndRetentionPriority-ExtIEs} } OPTIONAL +} +AllocationAndRetentionPriority-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +-- B +BitRate ::= INTEGER (0..10000000000) +-- C +Cause ::= CHOICE { + radioNetwork CauseRadioNetwork, + transport CauseTransport, + nAS CauseNAS, + protocol CauseProtocol, + misc CauseMisc, + ... +} +CauseMisc ::= ENUMERATED { + control-processing-overload, + not-enough-user-plane-processing-resources, + hardware-failure, + om-intervention, +unspecified, + ... +} +CauseNAS ::= ENUMERATED { + unspecified, + ... +} +CauseProtocol ::= ENUMERATED { + transfer-syntax-error, + abstract-syntax-error-reject, + abstract-syntax-error-ignore-and-notify, + message-not-compatible-with-receiver-state, + semantic-error, + abstract-syntax-error-falsely-constructed-message, + unspecified, + ... +} +CauseRadioNetwork ::= ENUMERATED { + unknown-or-already-allocated-MME-MBMS-M3AP-ID, + unknown-or-already-allocated-MCE-MBMS-M3AP-ID, + unknown-or-inconsistent-pair-of-MBMS-M3AP-IDs, + radio-resources-not-available, + invalid-QoS-combination, + interaction-with-other-procedure, + not-supported-QCI-value, + unspecified, + ..., + uninvolved-MCE +} +CauseTransport ::= ENUMERATED { + transport-resource-unavailable, + unspecified, + ... +} +CriticalityDiagnostics ::= SEQUENCE { + procedureCode ProcedureCode OPTIONAL, + triggeringMessage TriggeringMessage OPTIONAL, + procedureCriticality Criticality OPTIONAL, + iEsCriticalityDiagnostics CriticalityDiagnostics-IE-List OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {CriticalityDiagnostics-ExtIEs} } OPTIONAL, + ... +} +CriticalityDiagnostics-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..maxnooferrors)) OF + SEQUENCE { + iECriticality Criticality, + iE-ID ProtocolIE-ID, + typeOfError TypeOfError, + iE-Extensions ProtocolExtensionContainer { {CriticalityDiagnostics-IE-List-ExtIEs} } OPTIONAL, + ... +} +CriticalityDiagnostics-IE-List-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +-- D +-- E +ECGI ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + eUTRANcellIdentifier EUTRANCellIdentifier, + iE-Extensions ProtocolExtensionContainer { {ECGI-ExtIEs} } OPTIONAL, + ... +} +ECGI-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +EUTRANCellIdentifier ::= BIT STRING (SIZE (28)) +ExtendedMCE-ID ::= OCTET STRING (SIZE(1)) +-- F +-- G +Global-MCE-ID ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + mCE-ID MCE-ID, + extendedMCE-ID ExtendedMCE-ID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {GlobalMCE-ID-ExtIEs} } OPTIONAL, + ... +} +GlobalMCE-ID-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +GBR-QosInformation ::= SEQUENCE { + mBMS-E-RAB-MaximumBitrateDL BitRate, + mBMS-E-RAB-GuaranteedBitrateDL BitRate, + iE-Extensions ProtocolExtensionContainer { { GBR-QosInformation-ExtIEs} } OPTIONAL, + ... +} +GBR-QosInformation-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +GTP-TEID ::= OCTET STRING (SIZE (4)) +-- H +-- I +IPAddress ::= OCTET STRING (SIZE(4..16, ...)) +-- J +-- K +-- L +-- M +MBMS-Cell-List ::= SEQUENCE (SIZE(1.. maxnoofCellsforMBMS)) OF ECGI +MBMS-E-RAB-QoS-Parameters ::= SEQUENCE { + qCI QCI, + gbrQosInformation GBR-QosInformation OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { MBMS-E-RAB-QoS-Parameters-ExtIEs} } OPTIONAL, + ... +} +MBMS-E-RAB-QoS-Parameters-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { +-- Extension for Release 10 ARP support -- + {ID id-AllocationAndRetentionPriority CRITICALITY ignore EXTENSION AllocationAndRetentionPriority PRESENCE mandatory}, + ... +} +MBMS-Service-associatedLogicalM3-ConnectionItem ::= SEQUENCE { + mME-MBMS-M3AP-ID MME-MBMS-M3AP-ID OPTIONAL, + mCE-MBMS-M3AP-ID MCE-MBMS-M3AP-ID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { MBMS-Service-associatedLogicalM3-ConnectionItemExtIEs} } OPTIONAL, + ... +} +MBMS-Service-associatedLogicalM3-ConnectionItemExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +MBMSServiceArea1 ::= OCTET STRING (SIZE (2)) +MBMS-Service-Area ::= OCTET STRING +MBMS-Session-Duration ::= OCTET STRING (SIZE (3)) +MBMS-Session-ID ::= OCTET STRING (SIZE (1)) +MCE-MBMS-M3AP-ID ::= INTEGER (0..65535) +MCE-ID ::= OCTET STRING (SIZE(2)) +MCEname ::= PrintableString (SIZE (1..150,...)) +MinimumTimeToMBMSDataTransfer ::= OCTET STRING (SIZE (1)) +MME-MBMS-M3AP-ID ::= INTEGER (0..65535) +-- N +-- O +-- P +Pre-emptionCapability ::= ENUMERATED { + shall-not-trigger-pre-emption, + may-trigger-pre-emption +} +Pre-emptionVulnerability ::= ENUMERATED { + not-pre-emptable, + pre-emptable +} +PriorityLevel ::= INTEGER { spare (0), highest (1), lowest (14), no-priority (15) } (0..15) +PLMN-Identity ::= OCTET STRING (SIZE(3)) +-- Q +QCI ::= INTEGER (0..255) +-- R +Reestablishment ::= ENUMERATED {true, ...} +-- S +-- T +TimeToWait ::= ENUMERATED {v1s, v2s, v5s, v10s, v20s, v60s, ...} +TMGI ::= SEQUENCE { + pLMNidentity PLMN-Identity, + serviceID OCTET STRING (SIZE (3)), + iE-Extensions ProtocolExtensionContainer { {TMGI-ExtIEs} } OPTIONAL +} +TMGI-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +TNL-Information ::= SEQUENCE { + iPMCAddress IPAddress, + iPSourceAddress IPAddress, gTP-DLTEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { {TNL-Information-ExtIEs} } OPTIONAL, + ... +} +TNL-Information-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +TypeOfError ::= ENUMERATED { + not-understood, + missing, + ... +} +-- U +-- V +-- W +-- X +-- Y +-- Z +END + +-- ************************************************************** +-- +-- Common definitions +-- +-- ************************************************************** +M3AP-CommonDataTypes { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-CommonDataTypes (3) } +DEFINITIONS AUTOMATIC TAGS ::= +BEGIN +-- ************************************************************** +-- +-- Extension constants +-- +-- ************************************************************** +maxPrivateIEs INTEGER ::= 65535 +maxProtocolExtensions INTEGER ::= 65535 +maxProtocolIEs INTEGER ::= 65535 +-- ************************************************************** +-- +-- Common Data Types +-- +-- ************************************************************** +Criticality ::= ENUMERATED { reject, ignore, notify } +Presence ::= ENUMERATED { optional, conditional, mandatory } +PrivateIE-ID ::= CHOICE { + local INTEGER (0.. maxPrivateIEs), + global OBJECT IDENTIFIER +} +ProcedureCode ::= INTEGER (0..255) +ProtocolIE-ID ::= INTEGER (0..maxProtocolIEs) +TriggeringMessage ::= ENUMERATED { initiating-message, successful-outcome, unsuccessful-outcome} +END + +-- ************************************************************** +-- +-- Constant definitions +-- +-- ************************************************************** +M3AP-Constants { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-Constants (4) } +DEFINITIONS AUTOMATIC TAGS ::= +BEGIN +IMPORTS + ProcedureCode, + ProtocolIE-ID +FROM M3AP-CommonDataTypes; +-- ************************************************************** +-- +-- Elementary Procedures +-- +-- ************************************************************** +id-mBMSsessionStart ProcedureCode ::= 0 +id-mBMSsessionStop ProcedureCode ::= 1 +id-errorIndication ProcedureCode ::= 2 +id-privateMessage ProcedureCode ::= 3 +id-Reset ProcedureCode ::= 4 +id-mBMSsessionUpdate ProcedureCode ::= 5 +id-mCEConfigurationUpdate ProcedureCode ::= 6 +id-m3Setup ProcedureCode ::= 7 +-- ************************************************************** +-- +-- Lists +-- +-- ************************************************************** +maxnoofMBMSServiceAreaIdentitiesPerMCE INTEGER ::= 65536 +maxnooferrors INTEGER ::= 256 +maxNrOfIndividualM3ConnectionsToReset INTEGER ::= 256 +maxnoofCellsforMBMS INTEGER ::= 4096 +-- ************************************************************** +-- +-- IEs +-- +-- ************************************************************** +id-MME-MBMS-M3AP-ID ProtocolIE-ID ::= 0 +id-MCE-MBMS-M3AP-ID ProtocolIE-ID ::= 1 +id-TMGI ProtocolIE-ID ::= 2 +id-MBMS-Session-ID ProtocolIE-ID ::= 3 +id-MBMS-E-RAB-QoS-Parameters ProtocolIE-ID ::= 4 +id-MBMS-Session-Duration ProtocolIE-ID ::= 5 +id-MBMS-Service-Area ProtocolIE-ID ::= 6 +id-TNL-Information ProtocolIE-ID ::= 7 +id-CriticalityDiagnostics ProtocolIE-ID ::= 8 +id-Cause ProtocolIE-ID ::= 9 +id-MBMS-Service-Area-List ProtocolIE-ID ::= 10 +id-MBMS-Service-Area-List-Item ProtocolIE-ID ::= 11 +id-TimeToWait ProtocolIE-ID ::= 12 +id-ResetType ProtocolIE-ID ::= 13 +id-MBMS-Service-associatedLogicalM3-ConnectionItem ProtocolIE-ID ::= 14 +id-MBMS-Service-associatedLogicalM3-ConnectionListResAck ProtocolIE-ID ::= 15 +id-MinimumTimeToMBMSDataTransfer ProtocolIE-ID ::= 16 +id-AllocationAndRetentionPriority ProtocolIE-ID ::= 17 +id-Global-MCE-ID ProtocolIE-ID ::= 18 +id-MCEname ProtocolIE-ID ::= 19 +id-MBMSServiceAreaList ProtocolIE-ID ::= 20 +id-Time-ofMBMS-DataTransfer ProtocolIE-ID ::= 21 +id-Time-ofMBMS-DataStop ProtocolIE-ID ::= 22 +id-Reestablishment ProtocolIE-ID ::= 23 +id-Alternative-TNL-Information ProtocolIE-ID ::= 24 +id-MBMS-Cell-List ProtocolIE-ID ::= 25 +END +-- ************************************************************** +-- +-- Container definitions +-- +-- ************************************************************** +M3AP-Containers { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-Containers (5) } +DEFINITIONS AUTOMATIC TAGS ::= +BEGIN +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** +IMPORTS + maxPrivateIEs, + maxProtocolExtensions, + maxProtocolIEs, + Criticality, + Presence, + PrivateIE-ID, + ProtocolIE-ID +FROM M3AP-CommonDataTypes; +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** +M3AP-PROTOCOL-IES ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** +M3AP-PROTOCOL-IES-PAIR ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &firstCriticality Criticality, + &FirstValue, + &secondCriticality Criticality, + &SecondValue, + &presence Presence +} +WITH SYNTAX { + ID &id + FIRST CRITICALITY &firstCriticality + FIRST TYPE &FirstValue + SECOND CRITICALITY &secondCriticality + SECOND TYPE &SecondValue + PRESENCE &presence +} +-- ************************************************************** +-- +-- Class Definition for Protocol Extensions +-- +-- ************************************************************** +M3AP-PROTOCOL-EXTENSION ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Extension, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + EXTENSION &Extension + PRESENCE &presence +} +-- ************************************************************** +-- +-- Class Definition for Private IEs +-- +-- ************************************************************** +M3AP-PRIVATE-IES ::= CLASS { + &id PrivateIE-ID, + &criticality Criticality, + &Value, + &presence Presence +} + +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} +-- ************************************************************** +-- +-- Container for Protocol IEs +-- +-- ************************************************************** +ProtocolIE-Container {M3AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-Field {{IEsSetParam}} +ProtocolIE-Single-Container {M3AP-PROTOCOL-IES : IEsSetParam} ::= + ProtocolIE-Field {{IEsSetParam}} +ProtocolIE-Field {M3AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE { + id M3AP-PROTOCOL-IES.&id ({IEsSetParam}), + criticality M3AP-PROTOCOL-IES.&criticality ({IEsSetParam}{@id}), + value M3AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id}) +} +-- ************************************************************** +-- +-- Container for Protocol IE Pairs +-- +-- ************************************************************** +ProtocolIE-ContainerPair {M3AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-FieldPair {{IEsSetParam}} +ProtocolIE-FieldPair {M3AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE { + id M3AP-PROTOCOL-IES-PAIR.&id ({IEsSetParam}), + firstCriticality M3AP-PROTOCOL-IES-PAIR.&firstCriticality ({IEsSetParam}{@id}), + firstValue M3AP-PROTOCOL-IES-PAIR.&FirstValue ({IEsSetParam}{@id}), + secondCriticality M3AP-PROTOCOL-IES-PAIR.&secondCriticality ({IEsSetParam}{@id}), + secondValue M3AP-PROTOCOL-IES-PAIR.&SecondValue ({IEsSetParam}{@id}) +} +-- ************************************************************** +-- +-- Container Lists for Protocol IE Containers +-- +-- ************************************************************** +ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, M3AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-Container {{IEsSetParam}} +ProtocolIE-ContainerPairList {INTEGER : lowerBound, INTEGER : upperBound, M3AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-ContainerPair {{IEsSetParam}} +-- ************************************************************** +-- +-- Container for Protocol Extensions +-- +-- ************************************************************** +ProtocolExtensionContainer {M3AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= + SEQUENCE (SIZE (1..maxProtocolExtensions)) OF + ProtocolExtensionField {{ExtensionSetParam}} +ProtocolExtensionField {M3AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE { + id M3AP-PROTOCOL-EXTENSION.&id ({ExtensionSetParam}), + criticality M3AP-PROTOCOL-EXTENSION.&criticality ({ExtensionSetParam}{@id}), + extensionValue M3AP-PROTOCOL-EXTENSION.&Extension ({ExtensionSetParam}{@id}) +} +-- ************************************************************** +-- +-- Container for Private IEs +-- +-- ************************************************************** +PrivateIE-Container {M3AP-PRIVATE-IES : IEsSetParam} ::= + SEQUENCE (SIZE (1..maxPrivateIEs)) OF + PrivateIE-Field {{IEsSetParam}} +PrivateIE-Field {M3AP-PRIVATE-IES : IEsSetParam} ::= SEQUENCE { + id M3AP-PRIVATE-IES.&id ({IEsSetParam}), + criticality M3AP-PRIVATE-IES.&criticality ({IEsSetParam}{@id}), + value M3AP-PRIVATE-IES.&Value ({IEsSetParam}{@id}) +} +END + diff --git a/openair3/M3AP/MESSAGES/ASN1/R14/m3ap-14.0.0.asn1.bak b/openair3/M3AP/MESSAGES/ASN1/R14/m3ap-14.0.0.asn1.bak new file mode 100644 index 0000000000..fac7864ba3 --- /dev/null +++ b/openair3/M3AP/MESSAGES/ASN1/R14/m3ap-14.0.0.asn1.bak @@ -0,0 +1,1360 @@ +-- M3AP-PDU-Descriptions.asn +-- +-- 3GPP TS 36.444 V13.2.0 (2016-03) +-- http://www.3gpp.org/ftp/Specs/archive/36_series/36.444/36444-d20.zip +-- +-- 9.3.3 Elementary Procedure Definitions +-- + +-- ************************************************************** +-- +-- Elementary Procedure definitions +-- +-- ************************************************************** + +M3AP-PDU-Descriptions { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-PDU-Descriptions (0) } +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + Criticality, + ProcedureCode +FROM M3AP-CommonDataTypes + + MBMSSessionStartRequest, + MBMSSessionStartResponse, + MBMSSessionStartFailure, + MBMSSessionStopRequest, + MBMSSessionStopResponse, + MBMSSessionUpdateRequest, + MBMSSessionUpdateResponse, + MBMSSessionUpdateFailure, + MCEConfigurationUpdate, + MCEConfigurationUpdateAcknowledge, + MCEConfigurationUpdateFailure, + M3SetupRequest, + M3SetupResponse, + M3SetupFailure, + ErrorIndication, + Reset, + ResetAcknowledge, + PrivateMessage + +FROM M3AP-PDU-Contents + + id-mBMSsessionStart, + id-mBMSsessionStop, + id-mBMSsessionUpdate, + id-mCEConfigurationUpdate, + id-m3Setup, + id-errorIndication, + id-Reset, + id-privateMessage +FROM M3AP-Constants; + + +-- ************************************************************** +-- +-- Interface Elementary Procedure Class +-- +-- ************************************************************** + +M3AP-ELEMENTARY-PROCEDURE ::= CLASS { + &InitiatingMessage , + &SuccessfulOutcome OPTIONAL, + &UnsuccessfulOutcome OPTIONAL, + &procedureCode ProcedureCode UNIQUE, + &criticality Criticality DEFAULT ignore +} +WITH SYNTAX { + INITIATING MESSAGE &InitiatingMessage + [SUCCESSFUL OUTCOME &SuccessfulOutcome] + [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome] + PROCEDURE CODE &procedureCode + [CRITICALITY &criticality] +} + +-- ************************************************************** +-- +-- Interface PDU Definition +-- +-- ************************************************************** + +M3AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode M3AP-ELEMENTARY-PROCEDURE.&procedureCode ({M3AP-ELEMENTARY-PROCEDURES}), + criticality M3AP-ELEMENTARY-PROCEDURE.&criticality ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M3AP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode M3AP-ELEMENTARY-PROCEDURE.&procedureCode ({M3AP-ELEMENTARY-PROCEDURES}), + criticality M3AP-ELEMENTARY-PROCEDURE.&criticality ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M3AP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode M3AP-ELEMENTARY-PROCEDURE.&procedureCode ({M3AP-ELEMENTARY-PROCEDURES}), + criticality M3AP-ELEMENTARY-PROCEDURE.&criticality ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value M3AP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome ({M3AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + + +-- ************************************************************** +-- +-- Interface Elementary Procedure List +-- +-- ************************************************************** + +M3AP-ELEMENTARY-PROCEDURES M3AP-ELEMENTARY-PROCEDURE ::= { + M3AP-ELEMENTARY-PROCEDURES-CLASS-1 | + M3AP-ELEMENTARY-PROCEDURES-CLASS-2 , + ... +} + +M3AP-ELEMENTARY-PROCEDURES-CLASS-1 M3AP-ELEMENTARY-PROCEDURE ::= { + mBMSsessionStart | + mBMSsessionStop | + mBMSsessionUpdate | + reset | + m3Setup | + mCEConfigurationUpdate , + ... +} + +M3AP-ELEMENTARY-PROCEDURES-CLASS-2 M3AP-ELEMENTARY-PROCEDURE ::= { + errorIndication | + privateMessage , + ... + +} + + +-- ************************************************************** +-- +-- Interface Elementary Procedures +-- +-- ************************************************************** + +mBMSsessionStart M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MBMSSessionStartRequest + SUCCESSFUL OUTCOME MBMSSessionStartResponse + UNSUCCESSFUL OUTCOME MBMSSessionStartFailure + PROCEDURE CODE id-mBMSsessionStart + CRITICALITY reject +} + +mBMSsessionStop M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MBMSSessionStopRequest + SUCCESSFUL OUTCOME MBMSSessionStopResponse + PROCEDURE CODE id-mBMSsessionStop + CRITICALITY reject +} + +mBMSsessionUpdate M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MBMSSessionUpdateRequest + SUCCESSFUL OUTCOME MBMSSessionUpdateResponse + UNSUCCESSFUL OUTCOME MBMSSessionUpdateFailure + PROCEDURE CODE id-mBMSsessionUpdate + CRITICALITY reject +} + +errorIndication M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ErrorIndication + PROCEDURE CODE id-errorIndication + CRITICALITY ignore +} + +reset M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Reset + SUCCESSFUL OUTCOME ResetAcknowledge + PROCEDURE CODE id-Reset + CRITICALITY reject +} + +privateMessage M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PrivateMessage + PROCEDURE CODE id-privateMessage + CRITICALITY ignore +} + +mCEConfigurationUpdate M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MCEConfigurationUpdate + SUCCESSFUL OUTCOME MCEConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME MCEConfigurationUpdateFailure + PROCEDURE CODE id-mCEConfigurationUpdate + CRITICALITY reject +} + + +m3Setup M3AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE M3SetupRequest + SUCCESSFUL OUTCOME M3SetupResponse + UNSUCCESSFUL OUTCOME M3SetupFailure + PROCEDURE CODE id-m3Setup + CRITICALITY reject +} + +END + +-- M3AP-PDU-Contents.asn +-- +-- 3GPP TS 36.444 V13.2.0 (2016-03) +-- http://www.3gpp.org/ftp/Specs/archive/36_series/36.444/36444-d20.zip +-- +-- 9.3.4 PDU Definitions +-- + +-- ************************************************************** +-- +-- PDU definitions for M3AP. +-- +-- ************************************************************** + +M3AP-PDU-Contents { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-PDU-Contents (1) } +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + + Absolute-Time-ofMBMS-Data, + Cause, + CriticalityDiagnostics, + Global-MCE-ID, + MBMS-E-RAB-QoS-Parameters, + MBMS-Service-associatedLogicalM3-ConnectionItem, + MBMS-Service-Area, + MBMSServiceArea1, + MBMS-Session-Duration, + MBMS-Session-ID, + MCE-MBMS-M3AP-ID, + MCEname, + MinimumTimeToMBMSDataTransfer, + MME-MBMS-M3AP-ID, + TimeToWait, + TMGI, + TNL-Information, + Reestablishment, + MBMS-Cell-List + +FROM M3AP-IEs + + PrivateIE-Container{}, + ProtocolExtensionContainer{}, + ProtocolIE-Container{}, + ProtocolIE-ContainerList{}, + ProtocolIE-ContainerPair{}, + ProtocolIE-ContainerPairList{}, + ProtocolIE-Single-Container{}, + M3AP-PRIVATE-IES, + M3AP-PROTOCOL-EXTENSION, + M3AP-PROTOCOL-IES, + M3AP-PROTOCOL-IES-PAIR +FROM M3AP-Containers + + id-AllocationAndRetentionPriority, + id-MCE-MBMS-M3AP-ID, + id-MME-MBMS-M3AP-ID, + id-TMGI, + id-MBMS-Session-ID, + id-MBMS-E-RAB-QoS-Parameters, + id-MBMS-Session-Duration, + id-MBMS-Service-Area, + id-TNL-Information, + id-Alternative-TNL-Information, + id-CriticalityDiagnostics, + id-Cause, + id-MBMS-Service-Area-List, + id-MBMS-Service-Area-List-Item, + id-TimeToWait, + id-ResetType, + id-MBMS-Service-associatedLogicalM3-ConnectionItem, + id-MBMS-Service-associatedLogicalM3-ConnectionListResAck, + id-MBMSServiceAreaList, + id-MinimumTimeToMBMSDataTransfer, + id-Time-ofMBMS-DataStop, + id-Time-ofMBMS-DataTransfer, + id-Global-MCE-ID, + id-MCEname, + id-Reestablishment, + id-MBMS-Cell-List, + maxnoofMBMSServiceAreaIdentitiesPerMCE, + maxnooferrors, + maxNrOfIndividualM3ConnectionsToReset + +FROM M3AP-Constants; + +-- ************************************************************** +-- +-- MBMS SESSION START REQUEST +-- +-- ************************************************************** + +MBMSSessionStartRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MBMSSessionStartRequest-IEs}}, + ... +} + +MBMSSessionStartRequest-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY reject TYPE MME-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory}| + { ID id-MBMS-Session-ID CRITICALITY ignore TYPE MBMS-Session-ID PRESENCE optional}| + { ID id-MBMS-E-RAB-QoS-Parameters CRITICALITY reject TYPE MBMS-E-RAB-QoS-Parameters PRESENCE mandatory}| + { ID id-MBMS-Session-Duration CRITICALITY reject TYPE MBMS-Session-Duration PRESENCE mandatory}| + { ID id-MBMS-Service-Area CRITICALITY reject TYPE MBMS-Service-Area PRESENCE mandatory}| + { ID id-MinimumTimeToMBMSDataTransfer CRITICALITY reject TYPE MinimumTimeToMBMSDataTransfer PRESENCE mandatory}| + { ID id-TNL-Information CRITICALITY reject TYPE TNL-Information PRESENCE mandatory}| + { ID id-Time-ofMBMS-DataTransfer CRITICALITY ignore TYPE Absolute-Time-ofMBMS-Data PRESENCE optional}| + { ID id-Reestablishment CRITICALITY ignore TYPE Reestablishment PRESENCE optional}| + { ID id-Alternative-TNL-Information CRITICALITY ignore TYPE TNL-Information PRESENCE optional}| + { ID id-MBMS-Cell-List CRITICALITY reject TYPE MBMS-Cell-List PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MBMS SESSION START RESPONSE +-- +-- ************************************************************** + +MBMSSessionStartResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionStartResponse-IEs}}, + ... +} + +MBMSSessionStartResponse-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- MBMS SESSION START FAILURE +-- +-- ************************************************************** + +MBMSSessionStartFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionStartFailure-IEs}}, + ... +} + +MBMSSessionStartFailure-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- MBMS SESSION STOP REQUEST +-- +-- ************************************************************** + +MBMSSessionStopRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MBMSSessionStopRequest-IEs}}, + ... +} + +MBMSSessionStopRequest-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY reject TYPE MME-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-MCE-MBMS-M3AP-ID CRITICALITY reject TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-Time-ofMBMS-DataStop CRITICALITY ignore TYPE Absolute-Time-ofMBMS-Data PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MBMS SESSION STOP RESPONSE +-- +-- ************************************************************** + +MBMSSessionStopResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionStopResponse-IEs}}, + ... +} + +MBMSSessionStopResponse-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} + +-- ************************************************************** +-- +-- MBMS SESSION UPDATE REQUEST +-- +-- ************************************************************** + +MBMSSessionUpdateRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{MBMSSessionUpdateRequest-IEs}}, + ... +} + +MBMSSessionUpdateRequest-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY reject TYPE MME-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-MCE-MBMS-M3AP-ID CRITICALITY reject TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory}| + { ID id-TMGI CRITICALITY reject TYPE TMGI PRESENCE mandatory}| + { ID id-MBMS-Session-ID CRITICALITY ignore TYPE MBMS-Session-ID PRESENCE optional}| + { ID id-MBMS-E-RAB-QoS-Parameters CRITICALITY reject TYPE MBMS-E-RAB-QoS-Parameters PRESENCE mandatory}| + { ID id-MBMS-Session-Duration CRITICALITY reject TYPE MBMS-Session-Duration PRESENCE mandatory}| + { ID id-MBMS-Service-Area CRITICALITY ignore TYPE MBMS-Service-Area PRESENCE optional}| + { ID id-MinimumTimeToMBMSDataTransfer CRITICALITY reject TYPE MinimumTimeToMBMSDataTransfer PRESENCE mandatory}| + { ID id-TNL-Information CRITICALITY ignore TYPE TNL-Information PRESENCE optional}| + { ID id-Time-ofMBMS-DataTransfer CRITICALITY ignore TYPE Absolute-Time-ofMBMS-Data PRESENCE optional}| + { ID id-MBMS-Cell-List CRITICALITY reject TYPE MBMS-Cell-List PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MBMS SESSION UPDATE RESPONSE +-- +-- ************************************************************** + +MBMSSessionUpdateResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionUpdateResponse-IEs}}, + ... +} + +MBMSSessionUpdateResponse-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MBMS SESSION UPDATE FAILURE +-- +-- ************************************************************** + +MBMSSessionUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MBMSSessionUpdateFailure-IEs}}, + ... +} + +MBMSSessionUpdateFailure-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- ERROR INDICATION +-- +-- ************************************************************** + +ErrorIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ErrorIndication-IEs}}, + ... +} + +ErrorIndication-IEs M3AP-PROTOCOL-IES ::= { + { ID id-MME-MBMS-M3AP-ID CRITICALITY ignore TYPE MME-MBMS-M3AP-ID PRESENCE optional } | + { ID id-MCE-MBMS-M3AP-ID CRITICALITY ignore TYPE MCE-MBMS-M3AP-ID PRESENCE optional } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} + + +-- ************************************************************** +-- +-- Reset +-- +-- ************************************************************** + +Reset ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetIEs} }, + ... +} + +ResetIEs M3AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-ResetType CRITICALITY reject TYPE ResetType PRESENCE mandatory }, + ... +} + +ResetType ::= CHOICE { + m3-Interface ResetAll, + partOfM3-Interface MBMS-Service-associatedLogicalM3-ConnectionListRes, + ... +} + + + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +MBMS-Service-associatedLogicalM3-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualM3ConnectionsToReset)) OF ProtocolIE-Single-Container { { MBMS-Service-associatedLogicalM3-ConnectionItemRes } } + +MBMS-Service-associatedLogicalM3-ConnectionItemRes M3AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM3-ConnectionItem CRITICALITY reject TYPE MBMS-Service-associatedLogicalM3-ConnectionItem PRESENCE mandatory }, + ... +} + + +-- ************************************************************** +-- +-- Reset Acknowledge +-- +-- ************************************************************** + +ResetAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetAcknowledgeIEs} }, + ... +} + +ResetAcknowledgeIEs M3AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM3-ConnectionListResAck CRITICALITY ignore TYPE MBMS-Service-associatedLogicalM3-ConnectionListResAck PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +MBMS-Service-associatedLogicalM3-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualM3ConnectionsToReset)) OF ProtocolIE-Single-Container { { MBMS-Service-associatedLogicalM3-ConnectionItemResAck } } + +MBMS-Service-associatedLogicalM3-ConnectionItemResAck M3AP-PROTOCOL-IES ::= { + { ID id-MBMS-Service-associatedLogicalM3-ConnectionItem CRITICALITY ignore TYPE MBMS-Service-associatedLogicalM3-ConnectionItem PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- PRIVATE MESSAGE +-- +-- ************************************************************** + +PrivateMessage ::= SEQUENCE { + privateIEs PrivateIE-Container {{PrivateMessage-IEs}}, + ... +} + +PrivateMessage-IEs M3AP-PRIVATE-IES ::= { + ... +} + + +-- ************************************************************** +-- +-- M3 SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- M3 Setup Request +-- +-- ************************************************************** + +M3SetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {M3SetupRequestIEs} }, + ... +} + +M3SetupRequestIEs M3AP-PROTOCOL-IES ::= { + { ID id-Global-MCE-ID CRITICALITY reject TYPE Global-MCE-ID PRESENCE mandatory}| + { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional}| + { ID id-MBMSServiceAreaList CRITICALITY reject TYPE MBMSServiceAreaListItem PRESENCE mandatory}, + ... +} + + +MBMSServiceAreaListItem ::= SEQUENCE (SIZE(1..maxnoofMBMSServiceAreaIdentitiesPerMCE)) OF MBMSServiceArea1 + + +-- ************************************************************** +-- +-- M3 Setup Response +-- +-- ************************************************************** + +M3SetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {M3SetupResponseIEs} }, + ... +} + + +M3SetupResponseIEs M3AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- M3 Setup Failure +-- +-- ************************************************************** + +M3SetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {M3SetupFailureIEs} }, + ... +} + +M3SetupFailureIEs M3AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MCE CONFIGURATION UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MCE Configuration Update +-- +-- ************************************************************** + +MCEConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MCEConfigurationUpdateIEs} }, + ... +} + +MCEConfigurationUpdateIEs M3AP-PROTOCOL-IES ::= { + { ID id-Global-MCE-ID CRITICALITY reject TYPE Global-MCE-ID PRESENCE optional}| + { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional}| + { ID id-MBMSServiceAreaList CRITICALITY reject TYPE MBMSServiceAreaListItem PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MCE Configuration Update Acknowledge +-- +-- ************************************************************** + +MCEConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MCEConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +MCEConfigurationUpdateAcknowledgeIEs M3AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MCE Configuration Update Failure +-- +-- ************************************************************** + +MCEConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MCEConfigurationUpdateFailureIEs} }, + ... +} + +MCEConfigurationUpdateFailureIEs M3AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +END + +-- M3AP-IEs.asn +-- +-- 3GPP TS 36.444 V13.2.0 (2016-03) +-- http://www.3gpp.org/ftp/Specs/archive/36_series/36.444/36444-d20.zip +-- +-- 9.3.5 Information Element Definitions +-- + +-- ************************************************************** +-- +-- Information Element Definitions +-- +-- ************************************************************** + +M3AP-IEs { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-IEs (2) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + id-AllocationAndRetentionPriority, + maxnooferrors, + maxnoofCellsforMBMS + +FROM M3AP-Constants + + Criticality, + ProcedureCode, + ProtocolIE-ID, + TriggeringMessage +FROM M3AP-CommonDataTypes + + ProtocolExtensionContainer{}, + ProtocolIE-Single-Container{}, + M3AP-PROTOCOL-EXTENSION, + M3AP-PROTOCOL-IES +FROM M3AP-Containers; + +-- A + +Absolute-Time-ofMBMS-Data ::= BIT STRING (SIZE (64)) + +AllocationAndRetentionPriority ::= SEQUENCE { + priorityLevel PriorityLevel, + pre-emptionCapability Pre-emptionCapability, + pre-emptionVulnerability Pre-emptionVulnerability, + iE-Extensions ProtocolExtensionContainer { {AllocationAndRetentionPriority-ExtIEs} } OPTIONAL +} + +AllocationAndRetentionPriority-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} +-- B + +BitRate ::= INTEGER (0..10000000000) + +-- C + +Cause ::= CHOICE { + radioNetwork CauseRadioNetwork, + transport CauseTransport, + nAS CauseNAS, + protocol CauseProtocol, + misc CauseMisc, + ... +} + +CauseMisc ::= ENUMERATED { + control-processing-overload, + not-enough-user-plane-processing-resources, + hardware-failure, + om-intervention, + unspecified, + ... +} + +CauseNAS ::= ENUMERATED { + unspecified, + ... +} + +CauseProtocol ::= ENUMERATED { + transfer-syntax-error, + abstract-syntax-error-reject, + abstract-syntax-error-ignore-and-notify, + message-not-compatible-with-receiver-state, + semantic-error, + abstract-syntax-error-falsely-constructed-message, + unspecified, + ... +} + +CauseRadioNetwork ::= ENUMERATED { + unknown-or-already-allocated-MME-MBMS-M3AP-ID, + unknown-or-already-allocated-MCE-MBMS-M3AP-ID, + unknown-or-inconsistent-pair-of-MBMS-M3AP-IDs, + radio-resources-not-available, + invalid-QoS-combination, + interaction-with-other-procedure, + not-supported-QCI-value, + unspecified, + ..., + uninvolved-MCE + +} + +CauseTransport ::= ENUMERATED { + transport-resource-unavailable, + unspecified, + ... +} + +CriticalityDiagnostics ::= SEQUENCE { + procedureCode ProcedureCode OPTIONAL, + triggeringMessage TriggeringMessage OPTIONAL, + procedureCriticality Criticality OPTIONAL, + iEsCriticalityDiagnostics CriticalityDiagnostics-IE-List OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {CriticalityDiagnostics-ExtIEs} } OPTIONAL, + ... +} + + +CriticalityDiagnostics-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + +CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..maxnooferrors)) OF + SEQUENCE { + iECriticality Criticality, + iE-ID ProtocolIE-ID, + typeOfError TypeOfError, + iE-Extensions ProtocolExtensionContainer { {CriticalityDiagnostics-IE-List-ExtIEs} } OPTIONAL, + ... +} + +CriticalityDiagnostics-IE-List-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- D +-- E + +ECGI ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + eUTRANcellIdentifier EUTRANCellIdentifier, + iE-Extensions ProtocolExtensionContainer { {ECGI-ExtIEs} } OPTIONAL, + ... +} + +ECGI-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + +EUTRANCellIdentifier ::= BIT STRING (SIZE (28)) + +ExtendedMCE-ID ::= OCTET STRING (SIZE(1)) + +-- F +-- G + +Global-MCE-ID ::= SEQUENCE { + pLMN-Identity PLMN-Identity, + mCE-ID MCE-ID, + extendedMCE-ID ExtendedMCE-ID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {GlobalMCE-ID-ExtIEs} } OPTIONAL, + ... +} + +GlobalMCE-ID-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + +GBR-QosInformation ::= SEQUENCE { + mBMS-E-RAB-MaximumBitrateDL BitRate, + mBMS-E-RAB-GuaranteedBitrateDL BitRate, + iE-Extensions ProtocolExtensionContainer { { GBR-QosInformation-ExtIEs} } OPTIONAL, + ... +} + +GBR-QosInformation-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + +GTP-TEID ::= OCTET STRING (SIZE (4)) + +-- H +-- I + +IPAddress ::= OCTET STRING (SIZE(4..16, ...)) + +-- J +-- K +-- L +-- M + +MBMS-Cell-List ::= SEQUENCE (SIZE(1.. maxnoofCellsforMBMS)) OF ECGI + +MBMS-E-RAB-QoS-Parameters ::= SEQUENCE { + qCI QCI, + gbrQosInformation GBR-QosInformation OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { MBMS-E-RAB-QoS-Parameters-ExtIEs} } OPTIONAL, + ... +} + +MBMS-E-RAB-QoS-Parameters-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { +-- Extension for Release 10 ARP support -- + {ID id-AllocationAndRetentionPriority CRITICALITY ignore EXTENSION AllocationAndRetentionPriority PRESENCE mandatory}, + ... +} + +MBMS-Service-associatedLogicalM3-ConnectionItem ::= SEQUENCE { + mME-MBMS-M3AP-ID MME-MBMS-M3AP-ID OPTIONAL, + mCE-MBMS-M3AP-ID MCE-MBMS-M3AP-ID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { MBMS-Service-associatedLogicalM3-ConnectionItemExtIEs} } OPTIONAL, + ... +} + + +MBMS-Service-associatedLogicalM3-ConnectionItemExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + +MBMSServiceArea1 ::= OCTET STRING (SIZE (2)) + +MBMS-Service-Area ::= OCTET STRING + + +MBMS-Session-Duration ::= OCTET STRING (SIZE (3)) + +MBMS-Session-ID ::= OCTET STRING (SIZE (1)) + + +MCE-MBMS-M3AP-ID ::= INTEGER (0..65535) + +MCE-ID ::= OCTET STRING (SIZE(2)) + +MCEname ::= PrintableString (SIZE (1..150,...)) + +MinimumTimeToMBMSDataTransfer ::= OCTET STRING (SIZE (1)) + +MME-MBMS-M3AP-ID ::= INTEGER (0..65535) + +-- N +-- O +-- P + +Pre-emptionCapability ::= ENUMERATED { + shall-not-trigger-pre-emption, + may-trigger-pre-emption +} + +Pre-emptionVulnerability ::= ENUMERATED { + not-pre-emptable, + pre-emptable +} + +PriorityLevel ::= INTEGER { spare (0), highest (1), lowest (14), no-priority (15) } (0..15) + +PLMN-Identity ::= OCTET STRING (SIZE(3)) + +-- Q + +QCI ::= INTEGER (0..255) + +-- R + +Reestablishment ::= ENUMERATED {true, ...} + +-- S +-- T + +TimeToWait ::= ENUMERATED {v1s, v2s, v5s, v10s, v20s, v60s, ...} + +TMGI ::= SEQUENCE { + pLMNidentity PLMN-Identity, + serviceID OCTET STRING (SIZE (3)), + iE-Extensions ProtocolExtensionContainer { {TMGI-ExtIEs} } OPTIONAL +} + +TMGI-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + + +TNL-Information ::= SEQUENCE { + iPMCAddress IPAddress, + iPSourceAddress IPAddress, + gTP-DLTEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { {TNL-Information-ExtIEs} } OPTIONAL, + ... +} + +TNL-Information-ExtIEs M3AP-PROTOCOL-EXTENSION ::= { + ... +} + +TypeOfError ::= ENUMERATED { + not-understood, + missing, + ... +} + + +-- U +-- V +-- W +-- X +-- Y +-- Z + +END + +-- M3AP-CommonDataTypes.asn +-- +-- 3GPP TS 36.444 V13.2.0 (2016-03) +-- http://www.3gpp.org/ftp/Specs/archive/36_series/36.444/36444-d20.zip +-- +-- 9.3.6 Common Definitions +-- + +-- ************************************************************** +-- +-- Common definitions +-- +-- ************************************************************** + +M3AP-CommonDataTypes { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-CommonDataTypes (3) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- Extension constants +-- +-- ************************************************************** + +maxPrivateIEs INTEGER ::= 65535 +maxProtocolExtensions INTEGER ::= 65535 +maxProtocolIEs INTEGER ::= 65535 + +-- ************************************************************** +-- +-- Common Data Types +-- +-- ************************************************************** + +Criticality ::= ENUMERATED { reject, ignore, notify } + +Presence ::= ENUMERATED { optional, conditional, mandatory } + +PrivateIE-ID ::= CHOICE { + local INTEGER (0.. maxPrivateIEs), + global OBJECT IDENTIFIER +} + +ProcedureCode ::= INTEGER (0..255) + + +ProtocolIE-ID ::= INTEGER (0..maxProtocolIEs) + + +TriggeringMessage ::= ENUMERATED { initiating-message, successful-outcome, unsuccessful-outcome} + +END + +-- M3AP-Containers.asn +-- +-- 3GPP TS 36.444 V13.2.0 (2016-03) +-- http://www.3gpp.org/ftp/Specs/archive/36_series/36.444/36444-d20.zip +-- +-- 9.3.8 Container Definitions +-- + +-- ************************************************************** +-- +-- Container definitions +-- +-- ************************************************************** + +M3AP-Containers { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-Containers (5) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + maxPrivateIEs, + maxProtocolExtensions, + maxProtocolIEs, + Criticality, + Presence, + PrivateIE-ID, + ProtocolIE-ID +FROM M3AP-CommonDataTypes; + +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** + +M3AP-PROTOCOL-IES ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** + +M3AP-PROTOCOL-IES-PAIR ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &firstCriticality Criticality, + &FirstValue, + &secondCriticality Criticality, + &SecondValue, + &presence Presence +} +WITH SYNTAX { + ID &id + FIRST CRITICALITY &firstCriticality + FIRST TYPE &FirstValue + SECOND CRITICALITY &secondCriticality + SECOND TYPE &SecondValue + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol Extensions +-- +-- ************************************************************** + +M3AP-PROTOCOL-EXTENSION ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Extension, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + EXTENSION &Extension + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Private IEs +-- +-- ************************************************************** + +M3AP-PRIVATE-IES ::= CLASS { + &id PrivateIE-ID, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Container for Protocol IEs +-- +-- ************************************************************** + +ProtocolIE-Container {M3AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-Single-Container {M3AP-PROTOCOL-IES : IEsSetParam} ::= + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-Field {M3AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE { + id M3AP-PROTOCOL-IES.&id ({IEsSetParam}), + criticality M3AP-PROTOCOL-IES.&criticality ({IEsSetParam}{@id}), + value M3AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Protocol IE Pairs +-- +-- ************************************************************** + +ProtocolIE-ContainerPair {M3AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-FieldPair {{IEsSetParam}} + +ProtocolIE-FieldPair {M3AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE { + id M3AP-PROTOCOL-IES-PAIR.&id ({IEsSetParam}), + firstCriticality M3AP-PROTOCOL-IES-PAIR.&firstCriticality ({IEsSetParam}{@id}), + firstValue M3AP-PROTOCOL-IES-PAIR.&FirstValue ({IEsSetParam}{@id}), + secondCriticality M3AP-PROTOCOL-IES-PAIR.&secondCriticality ({IEsSetParam}{@id}), + secondValue M3AP-PROTOCOL-IES-PAIR.&SecondValue ({IEsSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container Lists for Protocol IE Containers +-- +-- ************************************************************** + +ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, M3AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-Container {{IEsSetParam}} + +ProtocolIE-ContainerPairList {INTEGER : lowerBound, INTEGER : upperBound, M3AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-ContainerPair {{IEsSetParam}} + +-- ************************************************************** +-- +-- Container for Protocol Extensions +-- +-- ************************************************************** + +ProtocolExtensionContainer {M3AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= + SEQUENCE (SIZE (1..maxProtocolExtensions)) OF + ProtocolExtensionField {{ExtensionSetParam}} + +ProtocolExtensionField {M3AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE { + id M3AP-PROTOCOL-EXTENSION.&id ({ExtensionSetParam}), + criticality M3AP-PROTOCOL-EXTENSION.&criticality ({ExtensionSetParam}{@id}), + extensionValue M3AP-PROTOCOL-EXTENSION.&Extension ({ExtensionSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Private IEs +-- +-- ************************************************************** + +PrivateIE-Container {M3AP-PRIVATE-IES : IEsSetParam} ::= + SEQUENCE (SIZE (1..maxPrivateIEs)) OF + PrivateIE-Field {{IEsSetParam}} + +PrivateIE-Field {M3AP-PRIVATE-IES : IEsSetParam} ::= SEQUENCE { + id M3AP-PRIVATE-IES.&id ({IEsSetParam}), + criticality M3AP-PRIVATE-IES.&criticality ({IEsSetParam}{@id}), + value M3AP-PRIVATE-IES.&Value ({IEsSetParam}{@id}) +} + +END + +-- M3AP-Constants.asn +-- +-- 3GPP TS 36.444 V13.2.0 (2016-03) +-- http://www.3gpp.org/ftp/Specs/archive/36_series/36.444/36444-d20.zip +-- +-- 9.3.7 Constant Definitions +-- + +-- ************************************************************** +-- +-- Constant definitions +-- +-- ************************************************************** + +M3AP-Constants { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) m3ap (5) version1 (1) m3ap-Constants (4) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + ProcedureCode, + ProtocolIE-ID +FROM M3AP-CommonDataTypes; + +-- ************************************************************** +-- +-- Elementary Procedures +-- +-- ************************************************************** + +id-mBMSsessionStart ProcedureCode ::= 0 +id-mBMSsessionStop ProcedureCode ::= 1 +id-errorIndication ProcedureCode ::= 2 +id-privateMessage ProcedureCode ::= 3 +id-Reset ProcedureCode ::= 4 +id-mBMSsessionUpdate ProcedureCode ::= 5 +id-mCEConfigurationUpdate ProcedureCode ::= 6 +id-m3Setup ProcedureCode ::= 7 + + + +-- ************************************************************** +-- +-- Lists +-- +-- ************************************************************** + +maxnoofMBMSServiceAreaIdentitiesPerMCE INTEGER ::= 65536 +maxnooferrors INTEGER ::= 256 +maxNrOfIndividualM3ConnectionsToReset INTEGER ::= 256 +maxnoofCellsforMBMS INTEGER ::= 4096 + +-- ************************************************************** +-- +-- IEs +-- +-- ************************************************************** + +id-MME-MBMS-M3AP-ID ProtocolIE-ID ::= 0 +id-MCE-MBMS-M3AP-ID ProtocolIE-ID ::= 1 +id-TMGI ProtocolIE-ID ::= 2 +id-MBMS-Session-ID ProtocolIE-ID ::= 3 +id-MBMS-E-RAB-QoS-Parameters ProtocolIE-ID ::= 4 +id-MBMS-Session-Duration ProtocolIE-ID ::= 5 +id-MBMS-Service-Area ProtocolIE-ID ::= 6 +id-TNL-Information ProtocolIE-ID ::= 7 +id-CriticalityDiagnostics ProtocolIE-ID ::= 8 +id-Cause ProtocolIE-ID ::= 9 +id-MBMS-Service-Area-List ProtocolIE-ID ::= 10 +id-MBMS-Service-Area-List-Item ProtocolIE-ID ::= 11 +id-TimeToWait ProtocolIE-ID ::= 12 +id-ResetType ProtocolIE-ID ::= 13 +id-MBMS-Service-associatedLogicalM3-ConnectionItem ProtocolIE-ID ::= 14 +id-MBMS-Service-associatedLogicalM3-ConnectionListResAck ProtocolIE-ID ::= 15 +id-MinimumTimeToMBMSDataTransfer ProtocolIE-ID ::= 16 +id-AllocationAndRetentionPriority ProtocolIE-ID ::= 17 +id-Global-MCE-ID ProtocolIE-ID ::= 18 +id-MCEname ProtocolIE-ID ::= 19 +id-MBMSServiceAreaList ProtocolIE-ID ::= 20 +id-Time-ofMBMS-DataTransfer ProtocolIE-ID ::= 21 +id-Time-ofMBMS-DataStop ProtocolIE-ID ::= 22 +id-Reestablishment ProtocolIE-ID ::= 23 +id-Alternative-TNL-Information ProtocolIE-ID ::= 24 +id-MBMS-Cell-List ProtocolIE-ID ::= 25 +END diff --git a/openair3/M3AP/MESSAGES/ASN1/asn1tostruct.py b/openair3/M3AP/MESSAGES/ASN1/asn1tostruct.py new file mode 100644 index 0000000000..b5a141349b --- /dev/null +++ b/openair3/M3AP/MESSAGES/ASN1/asn1tostruct.py @@ -0,0 +1,732 @@ +import re, os, sys, string +import datetime +import getopt +import getpass + +version = "1.0.2" + +lines = "" +iesDefs = {} +ieofielist = {} +outdir = './' + +filenames = [] +verbosity = 0 +prefix = "" + +FAIL = '\033[91m' +WARN = '\033[93m' +ENDC = '\033[0m' + +fileprefix = "" +fileprefix_first_upper = "" + +def printFail(string): + sys.stderr.write(FAIL + string + ENDC + "\n") + +def printWarning(string): + print WARN + string + ENDC + +def printDebug(string): + if verbosity > 0: + print string + +def outputHeaderToFile(f, filename): + now = datetime.datetime.now() + f.write("""/* + * 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 + */ + +""") + f.write("/*******************************************************************************\n") + f.write(" * This file had been created by asn1tostruct.py script v%s\n" % (version)) + f.write(" * Please do not modify this file but regenerate it via script.\n") + f.write(" * Created on: %s by %s\n * from %s\n" % (str(now), getpass.getuser(), filenames)) + f.write(" ******************************************************************************/\n") + +def lowerFirstCamelWord(word): + """ puts the first word in a CamelCase Word in lowercase. + + I.e. CustomerID becomes customerID, XMLInfoTest becomes xmlInfoTest + """ + newstr = '' + swapped = word.swapcase() + idx = 0 + + # if it's all-caps, return an all-lowered version + lowered = word.lower() + + if swapped == lowered: + return lowered + + for c in swapped: + if c in string.lowercase: + newstr += c + idx += 1 + else: + break + if idx < 2: + newstr += word[idx:] + else: + newstr = newstr[:-1]+ word[idx-1:] + + return newstr + +def usage(): + print "Python parser for asn1 v%s" % (version) + print "Usage: python asn1tostruct.py [options]" + print "Available options:" + print "-d Enable script debug" + print "-f [file] Input file to parse" + print "-o [dir] Output files to given directory" + print "-h Print this help and return" + +try: + opts, args = getopt.getopt(sys.argv[1:], "df:ho:", ["debug", "file", "help", "outdir"]) +except getopt.GetoptError as err: + # print help information and exit: + usage() + sys.exit(2) + +for o, a in opts: + if o in ("-f", "--file"): + filenames.append(a) + if o in ("-d", "--debug"): + verbosity = 1 + if o in ("-o", "--outdir"): + outdir = a + if outdir.rfind('/') != len(outdir): + outdir += '/' + if o in ("-h", "--help"): + usage() + sys.exit(2) + +for filename in filenames: + file = open(filename, 'r') + for line in file: + # Removing any comment + if line.find('--') >= 0: + line = line[:line.find('--')] + # Removing any carriage return + lines += re.sub('\r', '', line) + + for m in re.findall(r'([a-zA-Z0-9-]+)\s*::=\s+SEQUENCE\s+\(\s*SIZE\s*\(\s*\d+\s*\.\.\s*[0-9a-zA-Z-]+\s*\)\s*\)\s*OF\s+[a-zA-Z-]+\s*\{\s*\{\s*([0-9a-zA-Z-]+)\s*\}\s*\}', lines, re.MULTILINE): + ieofielist[m[0]] = m[1] + for m in re.findall(r'([a-zA-Z0-9-]+)\s*::=\s+E-RAB-IE-ContainerList\s*\{\s*\{\s*([a-zA-Z0-9-]+)\s*\}\s*\}', lines, re.MULTILINE): + ieofielist[m[0]] = m[1] + + for i in re.findall(r'([a-zA-Z0-9-]+)\s+([A-Z0-9-]+)\s*::=\s*\{\s+([\,\|\{\}\t\n\.{3}\ \-a-zA-Z0-9]+)\s+}\n', lines, re.MULTILINE): + ies = [] + maxLength = 0 + # TODO: handle extensions + if i[1].find('EXTENSION') >= 0: + continue + if fileprefix == "": + fileprefix = i[1][:i[1].find('-')].lower() + for j in re.findall(r'\s*\{\s*([a-zA-Z0-9-\ \t]+)\s*\}\s*[\|,]*', i[2], re.MULTILINE): + for k in re.findall(r'ID\s*([a-zA-Z0-9\-]+)\s*CRITICALITY\s*([a-zA-Z0-9\-]+)\s+[A-Z]+\s+([a-zA-Z0-9\-]+)\s*PRESENCE\s*([a-zA-Z0-9\-]+)', j, re.MULTILINE): + printDebug("Got new ie for message " + i[0] + ": " + str(k)) + if len(k[2]) > maxLength: + maxLength = len(k[2]) + ies.append(k) + + if len(ies) > 0: + iesDefs[i[0]] = { "length": maxLength, "ies": ies } + else: + printWarning("Didn't find any information element for message: " + i[0]) + +if len(iesDefs) == 0: + printFail("No Information Element parsed, exiting") + sys.exit(0) + +fileprefix_first_upper = fileprefix[0].upper() + fileprefix[1:] + +f = open(outdir + fileprefix + '_ies_defs.h', 'w') +outputHeaderToFile(f, filename) +f.write("#include \"%s_common.h\"\n\n" % (fileprefix)) +f.write("#ifndef %s_IES_DEFS_H_\n#define %s_IES_DEFS_H_\n\n" % (fileprefix.upper(), fileprefix.upper())) +f.write("/* Define the version of script used to generate this file */\n") +f.write("#define %s_SCRIPT_VERSION (%s)\n\n" % (fileprefix.upper(), re.sub('\.', '', version))) + +for key in iesDefs: + + if key not in ieofielist.values(): + continue + + for (i, j) in ieofielist.items(): + if j == key: + break + + f.write("typedef struct %sIEs_s {\n" % (re.sub('-', '_', i))) + f.write(" A_SEQUENCE_OF(struct %s_s) %s;\n" % (re.sub('IEs', '', re.sub('-', '_', ieofielist[i])), lowerFirstCamelWord(re.sub('IEs', '', re.sub('-', '_', ieofielist[i]))))) + f.write("} %sIEs_t;\n\n" % (re.sub('-', '_', i))) + +for key in iesDefs: + keyupperunderscore = re.sub('-', '_', key.upper()) + keylowerunderscore = re.sub('-', '_', key.lower()) + shift = 0 + + if len(iesDefs[key]["ies"]) == 0: + continue + + # Presence mask + for ie in iesDefs[key]["ies"]: + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] == "optional" or ie[3] == "conditional": + f.write("#define {0:<{pad}} {1}\n".format("%s_%s_PRESENT" % (keyupperunderscore, ieupperunderscore), "(1 << %d)" % shift, + pad=iesDefs[key]["length"] + len(keyupperunderscore) + 9)) + shift += 1 + if (shift > 0): + f.write("\n") + + f.write("typedef struct %s_s {\n" % (re.sub('-', '_', key))) + if (shift > 0): + f.write(" {0:<{pad}} {1};\n".format("uint16_t", "presenceMask", pad=iesDefs[key]["length"] + 2)) + for ie in iesDefs[key]["ies"]: + ieunderscore = re.sub('-', '_', ie[2]) + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + if ie[2] in ieofielist: + f.write(" %sIEs_t %s;" % (re.sub('-', '_', ie[2]), ienameunderscore)) + else: + f.write(" {0:<{pad}} {1};".format("%s_t" % ieunderscore, ienameunderscore, pad=iesDefs[key]["length"] + 2)) + if ie[3] == "optional": + f.write(" ///< Optional field") + elif ie[3] == "conditional": + f.write(" ///< Conditional field") + f.write("\n") + + f.write("} %s_t;\n\n" % (re.sub('-', '_', key))) + +f.write("typedef struct %s_message_s {\n" % (fileprefix)) +f.write(" %s_ProcedureCode_t procedureCode;\n" % (fileprefix_first_upper)) +f.write(" %s_Criticality_t criticality;\n" % (fileprefix_first_upper)) +f.write(" uint8_t direction;\n") +f.write(" union {\n") + +messageList = iesDefs.keys() +messageList.sort() +for message in messageList: + if message in ieofielist.values(): + continue + if len(iesDefs[message]["ies"]) == 0: + continue + f.write(" %s_t %s;\n" % (re.sub('-', '_', message), lowerFirstCamelWord(re.sub('-', '_', message)))) +f.write(" } msg;\n") +f.write("} %s_message;\n\n" % (fileprefix)) + +for key in iesDefs: + if key in ieofielist.values(): + continue + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + keylowerunderscore = re.sub('-', '_', key.lower()) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + f.write("/* %s in iesDefs not in ieofielist.values() */\n" % (key)) + f.write("/** \\brief Decode function for %s ies.\n" % (key)) + if len(iesDefs[key]["ies"]) != 0: + f.write(" * \\param %s Pointer to ASN1 structure in which data will be stored\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" * \\param any_p Pointer to the ANY value to decode.\n") + f.write(" **/\n") + f.write("int %s_decode_%s(\n" % (fileprefix, keylowerunderscore)) + if len(iesDefs[key]["ies"]) != 0: + f.write(" %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" ANY_t *any_p);\n\n") + + if len(iesDefs[key]["ies"]) == 0: + continue + + f.write("/* %s in iesDefs not in ieofielist.values() */\n" % (key)) + f.write("/** \\brief Encode function for %s ies.\n" % (key)) + f.write(" * \\param %s Pointer to the ASN1 structure.\n" % (firstlower)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" **/\n") + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstlower)) + f.write(" %s_t *%s);\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + + +for key in iesDefs: + if key not in ieofielist.values(): + continue + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + f.write("/* %s in iesDefs in ieofielist.values() */\n" % (key)) + f.write("/** \\brief Encode function for %s ies.\n" % (key)) + f.write(" * \\param %s Pointer to the ASN1 structure.\n" % (firstlower)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" **/\n") + f.write("/* %s in iesDefs in ieofielist.values() */\n" % (key)) + f.write("int %s_encode_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstlower)) + f.write(" %sIEs_t *%sIEs);\n\n" % (asn1cStruct, firstlower)) + f.write("/** \\brief Decode function for %s ies.\n" % (key)) + f.write(" * \\param any_p Pointer to the ANY value to decode.\n") + f.write(" * \\param callback Callback function called when any_p is successfully decoded.\n") + f.write(" **/\n") + f.write("/* %s in iesDefs in ieofielist.values() */\n" % (key)) + f.write("int %s_decode_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" %sIEs_t *%sIEs,\n" % (asn1cStruct, firstlower)) + f.write(" %s_t *%s);\n\n" % (asn1cStruct, lowerFirstCamelWord(asn1cStruct))) + + + +for key in iesDefs: + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + if key in ieofielist.values(): + f.write("/** \\brief Display %s encapsulated IE using XER encoding.\n" % (asn1cStruct)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" * \\param file File descriptor to write output.\n") + f.write(" **/\n") + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('item', 'list', firstlower.lower()))) + f.write(" asn_app_consume_bytes_f *cb,\n") + f.write(" void *app_key,\n") + f.write(" %sIEs_t *%sIEs);\n\n" % (re.sub('item', 'list', asn1cStruct), firstlower)) + else: + f.write("/** \\brief Display %s message using XER encoding.\n" % (asn1cStruct)) + f.write(" * \\param message_p Pointer to root message.\n") + f.write(" * \\param file File descriptor to write output.\n") + f.write(" **/\n") + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" asn_app_consume_bytes_f *cb,\n") + f.write(" void *app_key,\n") + f.write(" %s_message *message_p);\n\n" % (fileprefix)) + +f.write("int %s_xer__print2sp(const void *buffer, size_t size, void *app_key);\n\n" % (fileprefix.lower())) +f.write("int %s_xer__print2fp(const void *buffer, size_t size, void *app_key);\n\n" % (fileprefix.lower())) +f.write("extern size_t %s_string_total_size;\n\n" % (fileprefix.lower())) +f.write("#endif /* %s_IES_DEFS_H_ */\n\n" % (fileprefix.upper())) + +#Generate Decode functions +f = open(outdir + fileprefix + '_decoder.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n\n" % (fileprefix, fileprefix)) +for key in iesDefs: + if key in ieofielist.values(): + continue + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + if asn1cStruct.rfind('_') == len(asn1cStruct) - 1: + asn1cStruct = asn1cStruct[:-1] + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + ielistname = re.sub('UE', 'ue', asn1cStruct) + ielistnamefirstlower = ielistname[:1].lower() + ielistname[1:] + asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:] + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + iesaccess = "" + if key not in ieofielist.values(): + iesaccess = "%s_ies." % (firstlower) + + f.write("int %s_decode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + if len(iesDefs[key]["ies"]) != 0: + f.write(" %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" ANY_t *any_p) {\n\n") + + f.write(" %s_t %s;\n %s_t *%s_p = &%s;\n" % (asn1cStruct, asn1cStructfirstlower, asn1cStruct, asn1cStructfirstlower, asn1cStructfirstlower)) + f.write(" int i, decoded = 0;\n") + if len(iesDefs[key]["ies"]) != 0: + f.write(" int tempDecoded = 0;\n") + + f.write(" assert(any_p != NULL);\n") + if len(iesDefs[key]["ies"]) != 0: + f.write(" assert(%s != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + + f.write(" %s_DEBUG(\"Decoding message %s (%%s:%%d)\\n\", __FILE__, __LINE__);\n\n" % (fileprefix.upper(), re.sub('-', '_', keyName))) + f.write(" ANY_to_type_aper(any_p, &asn_DEF_%s, (void**)&%s_p);\n\n" % (asn1cStruct, asn1cStructfirstlower)) + f.write(" for (i = 0; i < %s_p->%slist.count; i++) {\n" % (asn1cStructfirstlower, iesaccess)) + f.write(" %s_IE_t *ie_p;\n" % (fileprefix[0].upper() + fileprefix[1:])) + f.write(" ie_p = %s_p->%slist.array[i];\n" % (asn1cStructfirstlower, iesaccess)) + f.write(" switch(ie_p->id) {\n") + for ie in iesDefs[key]["ies"]: + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + ienameunderscorefirstlower = lowerFirstCamelWord(ienameunderscore) + ietypesubst = re.sub('-', '', ie[2]) + ietypeunderscore = re.sub('-', '_', ie[2]) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" case %s_ProtocolIE_ID_%s:\n" % (fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" {\n") + f.write(" %s_t *%s_p = NULL;\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + if ie[3] != "mandatory": + f.write(" %s->presenceMask |= %s_%s_PRESENT;\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore)) + f.write(" tempDecoded = ANY_to_type_aper(&ie_p->value, &asn_DEF_%s, (void**)&%s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (lowerFirstCamelWord(ietypesubst))) + f.write(" %s_ERROR(\"Decoding of IE %s failed\\n\");\n" % (fileprefix.upper(), ienameunderscore)) + f.write(" if (%s_p)\n" % (lowerFirstCamelWord(ietypesubst))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" decoded += tempDecoded;\n") + f.write(" if (asn1_xer_print)\n") + f.write(" xer_fprint(stdout, &asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + if ie[2] in ieofielist.keys(): + f.write(" if (%s_decode_%s(&%s->%s, %s_p) < 0) {\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" %s_ERROR(\"Decoding of encapsulated IE %s failed\\n\");\n" % (fileprefix.upper(), lowerFirstCamelWord(ietypesubst))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" }\n") + else: + f.write(" memcpy(&%s->%s, %s_p, sizeof(%s_t));\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore, lowerFirstCamelWord(ietypesubst), ietypeunderscore)) + #f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" } break;\n") + f.write(" default:\n") + f.write(" %s_ERROR(\"Unknown protocol IE id (%%d) for message %s\\n\", (int)ie_p->id);\n" % (fileprefix.upper(), re.sub('-', '_', structName.lower()))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return decoded;\n") + f.write("}\n\n") + +for key in iesDefs: + if key not in ieofielist.values(): + continue + + keyname = re.sub('IEs', '', re.sub('Item', 'List', key)) + + f.write("int %s_decode_%s(\n" % (fileprefix, re.sub('-', '_', keyname).lower())) + f.write(" %sIEs_t *%sIEs,\n" % (re.sub('-', '_', keyname), lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" %s_t *%s) {\n\n" % (re.sub('-', '_', keyname), lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" int i, decoded = 0;\n") + f.write(" int tempDecoded = 0;\n\n") + + f.write(" assert(%s != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))); + f.write(" assert(%sIEs != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))); + + f.write(" for (i = 0; i < %s->list.count; i++) {\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" %s_IE_t *ie_p = %s->list.array[i];\n" % (fileprefix[0].upper() + fileprefix[1:], lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" switch (ie_p->id) {\n") + for ie in iesDefs[key]["ies"]: + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + f.write(" case %s_ProtocolIE_ID_%s:\n" % (fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" {\n") + f.write(" %s_t *%s_p = NULL;\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" tempDecoded = ANY_to_type_aper(&ie_p->value, &asn_DEF_%s, (void**)&%s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" %s_ERROR(\"Decoding of IE %s for message %s failed\\n\");\n" % (fileprefix.upper(), ienameunderscore, re.sub('-', '_', keyname))) + f.write(" if (%s_p)\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + #f.write(" free(%s_p);\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" decoded += tempDecoded;\n") + f.write(" if (asn1_xer_print)\n") + f.write(" xer_fprint(stdout, &asn_DEF_%s, %s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" ASN_SEQUENCE_ADD(&%sIEs->%s, %s_p);\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)), + re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" } break;\n") + f.write(" default:\n") + f.write(" %s_ERROR(\"Unknown protocol IE id (%%d) for message %s\\n\", (int)ie_p->id);\n" % (fileprefix.upper(), re.sub('-', '_', structName.lower()))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return decoded;\n") + f.write("}\n\n") + + +#Generate IES Encode functions +f = open(outdir + fileprefix + '_encoder.c', 'w') +outputHeaderToFile(f,filename) +f.write("#include \"%s_common.h\"\n" % (fileprefix)) +f.write("#include \"%s_ies_defs.h\"\n\n" % (fileprefix)) +for key in iesDefs: + if key in ieofielist.values(): + continue + + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + if asn1cStruct.rfind('_') == len(asn1cStruct) - 1: + asn1cStruct = asn1cStruct[:-1] + asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:] + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + iesaccess = "" + if key not in ieofielist.values(): + iesaccess = "%s_ies." % (firstwordlower) + + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + # No IE to encode... + if len(iesDefs[key]["ies"]) == 0: + continue + + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstwordlower)) + f.write(" %s_t *%s) {\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + + f.write(" %s_IE_t *ie;\n\n" % (fileprefix_first_upper)) + + f.write(" assert(%s != NULL);\n" % (firstwordlower)); + f.write(" assert(%s != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))); + + for ie in iesDefs[key]["ies"]: + iename = re.sub('-', '_', re.sub('id-', '', ie[0])) + ienameunderscore = re.sub('-', '_', iename) + ienamefirstwordlower = lowerFirstCamelWord(iename) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + ietypeunderscore = re.sub('-', '_', ie[2]) + + if ie[3] != "mandatory": + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" if (%s->presenceMask & %s_%s_PRESENT) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore)) + #f.write(" == %s_%s_PRESENT) {\n" % (keyupperunderscore, ieupperunderscore)) + f.write(" if ((ie = %s_new_ie(%s_ProtocolIE_ID_%s,\n" % (fileprefix, fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" %s_Criticality_%s,\n" % (fileprefix_first_upper, ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + f.write(" &%s->%s)) == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->%slist, ie);\n" % (firstwordlower, iesaccess)) + f.write(" }\n\n") + else: + if ie[2] in ieofielist.keys(): + f.write(" %s_t %s;\n\n" % (ietypeunderscore, ienamefirstwordlower)) + f.write(" memset(&%s, 0, sizeof(%s_t));\n" % (ienamefirstwordlower, ietypeunderscore)) + f.write("\n") + f.write(" if (%s_encode_%s(&%s, &%s->%s) < 0) return -1;\n" % (fileprefix, ietypeunderscore.lower(), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" if ((ie = %s_new_ie(%s_ProtocolIE_ID_%s,\n" % (fileprefix, fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" %s_Criticality_%s,\n" % (fileprefix_first_upper, ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + if ie[2] in ieofielist.keys(): + f.write(" &%s)) == NULL) {\n" % (ienamefirstwordlower)) + else: + f.write(" &%s->%s)) == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->%slist, ie);\n\n" % (firstwordlower, iesaccess)) + if ie[2] in ieofielist.keys(): + f.write(" /* Free any dynamic allocation that is no more used */\n") + f.write(" ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_%s, &%s);\n\n" % (ietypeunderscore, ienamefirstwordlower)) + + f.write(" return 0;\n") + f.write("}\n\n") + +for (key, value) in iesDefs.items(): + if key not in ieofielist.values(): + continue + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + for (i, j) in ieofielist.items(): + if j == key: + break + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', i).lower())) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstwordlower)) + f.write(" %sIEs_t *%sIEs) {\n\n" % (re.sub('-', '_', i), lowerFirstCamelWord(re.sub('-', '_', i)))) + f.write(" int i;\n") + + f.write(" %s_IE_t *ie;\n\n" % (fileprefix_first_upper)) + + f.write(" assert(%s != NULL);\n" % (firstwordlower)); + f.write(" assert(%sIEs != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', i)))); + + f.write(" for (i = 0; i < %sIEs->%s.count; i++) {\n" % (firstwordlower, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" if ((ie = %s_new_ie(%s_ProtocolIE_ID_%s,\n" % (fileprefix, fileprefix_first_upper, re.sub('-', '_', ie[0]))) + f.write(" %s_Criticality_%s,\n" % (fileprefix_first_upper, ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + f.write(" %sIEs->%s.array[i])) == NULL) {\n" % (firstwordlower, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->list, ie);\n" % (firstwordlower)) + f.write(" }\n") + f.write(" return 0;\n") + f.write("}\n\n") + +#Generate xer print functions +f = open(outdir + fileprefix + '_xer_print.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include \n") +f.write("#include \n\n") +f.write("#include \n#include \n\n") +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n\n" % (fileprefix, fileprefix)) + +f.write("size_t %s_string_total_size = 0;\n\n" % (fileprefix.lower())) +f.write("""int +%s_xer__print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + +""" % (fileprefix.lower())) + +f.write("""int %s_xer__print2sp(const void *buffer, size_t size, void *app_key) { + char *string = (char *)app_key; + + /* Copy buffer to the formatted string */ + memcpy(&string[%s_string_total_size], buffer, size); + + %s_string_total_size += size; + + return 0; +} + +""" % (fileprefix.lower(), fileprefix.lower(), fileprefix.lower())) + +f.write("""static asn_enc_rval_t +xer_encode_local(asn_TYPE_descriptor_t *td, void *sptr, + asn_app_consume_bytes_f *cb, void *app_key, int indent) { + asn_enc_rval_t er, tmper; + const char *mname; + size_t mlen; + int xcan = 2; + + if(!td || !sptr) goto cb_failed; + + mname = td->xml_tag; + mlen = strlen(mname); + + ASN__TEXT_INDENT(0, indent); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = td->op->xer_encoder(td, sptr, indent + 1, XER_F_BASIC, cb, app_key); + if(tmper.encoded == -1) return tmper; + + ASN__CALLBACK3("\\n", xcan); + + er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} +""") + +for (key, value) in iesDefs.items(): + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + iesStructName = lowerFirstCamelWord(re.sub('-', '_', key)) + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + + if key in ieofielist.values(): + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('ies', '', re.sub('item', 'list', re.sub('-', '_', key).lower())))) + else: + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('ies', '', re.sub('-', '_', key).lower()))) + #f.write(" FILE *file,\n") + f.write(" asn_app_consume_bytes_f *cb,\n") + f.write(" void *app_key,\n") + if key in ieofielist.values(): + iesStructName = lowerFirstCamelWord(re.sub('Item', 'List', re.sub('-', '_', key))) + f.write(" %sIEs_t *%s) {\n\n" % (re.sub('IEs', '', re.sub('Item', 'List', re.sub('-', '_', key))), iesStructName)) + f.write(" int i;\n") + f.write(" asn_enc_rval_t er;\n") + else: + f.write(" %s_message *message_p)\n{\n" % (fileprefix)) + f.write(" %s_t *%s;\n" % (re.sub('-', '_', key), iesStructName)) + f.write(" asn_enc_rval_t er;\n") + #f.write(" void *app_key = (void *)file;\n") + #f.write(" asn_app_consume_bytes_f *cb = %s_xer__print2fp;\n\n" % (fileprefix.lower())) + + f.write(" %s = &message_p->msg.%s;\n\n" % (iesStructName, iesStructName)) + + if key in ieofielist.values(): + # Increase indentation level + f.write(" for (i = 0; i < %s->%s.count; i++) {\n" % (iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + #f.write(" xer_fprint(file, &asn_DEF_%s, %s->%s.array[i]);\n" % (ietypeunderscore, iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" er = xer_encode(&asn_DEF_%s, %s->%s.array[i], XER_F_BASIC, cb, app_key);\n" % (ietypeunderscore, iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" }\n") + else: + f.write(" cb(\"<%s-PDU>\\n\", %d, app_key);\n" % (key, len("<%s-PDU>\n" % (key)))) + f.write(" xer_encode_local(&asn_DEF_%s_Criticality, &message_p->criticality, cb, app_key, 1);\n" % fileprefix_first_upper) + f.write(" xer_encode_local(&asn_DEF_%s_ProcedureCode, &message_p->procedureCode, cb, app_key, 1);\n" % fileprefix_first_upper) + + f.write(" cb(\" <%s>\\n\", %d, app_key);\n" % (key, len(" <%s>\n" % (key)))) + + for ie in iesDefs[key]["ies"]: + iename = re.sub('-', '_', re.sub('id-', '', ie[0])) + ienameunderscore = re.sub('-', '_', iename) + ienamefirstwordlower = lowerFirstCamelWord(iename) + ietypeunderscore = re.sub('-', '_', ie[2]) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] != "mandatory": + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" if (%s->presenceMask & %s_%s_PRESENT)\n " % (iesStructName, keyupperunderscore, ieupperunderscore)) + + # Is it an encapsulated IE ? + if ie[2] in ieofielist.keys(): + f.write(" %s_xer_print_%s(cb, app_key, &%s->%s);\n" % (fileprefix, re.sub('ies', '', re.sub('-', '_', ie[2]).lower()), iesStructName, ienamefirstwordlower)) + else: + f.write(" xer_encode_local(&asn_DEF_%s, &%s->%s, cb, app_key, 2);\n" % (ietypeunderscore, iesStructName, ienamefirstwordlower)) + f.write(" cb(\" \\n\", %d, app_key);\n" % (key, len(" \n" % (key)))) + f.write(" cb(\"\\n\", %d, app_key);\n" % (key, len("\n" % (key)))) + + f.write(" ASN__ENCODED_OK(er);\n") + #if key not in ieofielist.values(): + #f.write("cb_failed:\n") + #f.write(" return er;\n") + f.write("}\n\n") + + +#Generate xer print functions +f = open(outdir + fileprefix + '_compare.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include \n") +f.write("#include \n\n") +f.write("#include \n#include \n\n") +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n" % (fileprefix, fileprefix)) +f.write("#include \"%s-ProtocolIE-ID.h\"\n\n" % (fileprefix_first_upper)) + + +for (key, value) in iesDefs.items(): + if key not in ieofielist.values(): + continue + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + for (i, j) in ieofielist.items(): + if j == key: + break + + f.write("extern asn_TYPE_descriptor_t asn_DEF_%s;\n" % (ietypeunderscore)) diff --git a/openair3/M3AP/m3ap_MCE.c b/openair3/M3AP/m3ap_MCE.c new file mode 100644 index 0000000000..232b0c0ece --- /dev/null +++ b/openair3/M3AP/m3ap_MCE.c @@ -0,0 +1,689 @@ +/* + * 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 m3ap_MCE.c + * \brief m3ap tasks for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include +#include +#include +#include + +#include "intertask_interface.h" + +#include "m3ap_MCE.h" +#include "m3ap_MCE_defs.h" +#include "m3ap_MCE_management_procedures.h" +#include "m3ap_MCE_handler.h" +//#include "m3ap_MCE_generate_messages.h" +#include "m3ap_common.h" +#include "m3ap_MCE_interface_management.h" +#include "m3ap_ids.h" +#include "m3ap_timers.h" + +#include "queue.h" +#include "assertions.h" +#include "conversions.h" + +struct m3ap_mce_map; +struct m3ap_MCE_data_s; + +m3ap_setup_req_t * m3ap_mce_data_g; + +RB_PROTOTYPE(m3ap_mce_map, m3ap_MCE_data_s, entry, m3ap_MCE_compare_assoc_id); + +static +void m3ap_MCE_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind); + +static +void m3ap_MCE_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp); + +static +void m3ap_MCE_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind); + +static +void m3ap_MCE_handle_register_MCE(instance_t instance, + m3ap_register_mce_req_t *m3ap_register_MME); +static +void m3ap_MCE_register_MCE(m3ap_MCE_instance_t *instance_p, + net_ip_address_t *target_MME_ip_addr, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t mce_port_for_M3C, + int multi_sd); + +//static +//void m3ap_eNB_handle_handover_req(instance_t instance, +// m3ap_handover_req_t *m3ap_handover_req); +// +//static +//void m3ap_eNB_handle_handover_req_ack(instance_t instance, +// m3ap_handover_req_ack_t *m3ap_handover_req_ack); +// +//static +//void m3ap_eNB_ue_context_release(instance_t instance, +// m3ap_ue_context_release_t *m3ap_ue_context_release); +// + +static +void m3ap_MCE_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) { + int result; + DevAssert(sctp_data_ind != NULL); + m3ap_MCE_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream, + sctp_data_ind->buffer, sctp_data_ind->buffer_length); + result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +} + +static +void m3ap_MCE_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { + m3ap_MCE_instance_t *instance_p; + m3ap_MCE_data_t *m3ap_mce_data_p; + DevAssert(sctp_new_association_resp != NULL); + //printf("m3ap_eNB_handle_sctp_association_resp at 1\n"); + //dump_trees(); + instance_p = m3ap_MCE_get_instance(instance); + DevAssert(instance_p != NULL); + + /* if the assoc_id is already known, it is certainly because an IND was received + * before. In this case, just update streams and return + */ + if (sctp_new_association_resp->assoc_id != -1) { + m3ap_mce_data_p = m3ap_get_MCE(instance_p, sctp_new_association_resp->assoc_id, + sctp_new_association_resp->ulp_cnx_id); + + if (m3ap_mce_data_p != NULL) { + /* some sanity check - to be refined at some point */ + if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + M3AP_ERROR("m3ap_mce_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n"); + abort(); + } + + m3ap_mce_data_p->in_streams = sctp_new_association_resp->in_streams; + m3ap_mce_data_p->out_streams = sctp_new_association_resp->out_streams; + return; + } + } + + m3ap_mce_data_p = m3ap_get_MCE(instance_p, -1, + sctp_new_association_resp->ulp_cnx_id); + DevAssert(m3ap_mce_data_p != NULL); + //printf("m3ap_MCE_handle_sctp_association_resp at 2\n"); + //dump_trees_m3(); + + if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + M3AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n", + sctp_new_association_resp->sctp_state, + instance, + sctp_new_association_resp->ulp_cnx_id); + //m3ap_handle_m3_setup_message(instance_p, m3ap_enb_data_p, + //sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); + return; + } + + //printf("m3ap_MCE_handle_sctp_association_resp at 3\n"); + //dump_trees_m3(); + /* Update parameters */ + m3ap_mce_data_p->assoc_id = sctp_new_association_resp->assoc_id; + m3ap_mce_data_p->in_streams = sctp_new_association_resp->in_streams; + m3ap_mce_data_p->out_streams = sctp_new_association_resp->out_streams; + //printf("m3ap_MCE_handle_sctp_association_resp at 4\n"); + //dump_trees_m3(); + + m3ap_mce_data_g->assoc_id = sctp_new_association_resp->assoc_id; + m3ap_mce_data_g->sctp_in_streams = sctp_new_association_resp->in_streams; + m3ap_mce_data_g->sctp_out_streams = sctp_new_association_resp->out_streams; + + /* Prepare new m3 Setup Request */ + //m3ap_eNB_generate_m3_setup_request(instance_p, m3ap_enb_data_p); + MCE_send_M3_SETUP_REQUEST(instance_p, m3ap_mce_data_p); +} + +static +void m3ap_MCE_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind) { + m3ap_MCE_instance_t *instance_p; + m3ap_MCE_data_t *m3ap_mce_data_p; + //printf("m3ap_MCE_handle_sctp_association_ind at 1 (called for instance %d)\n", instance); + //dump_trees_m3(); + DevAssert(sctp_new_association_ind != NULL); + instance_p = m3ap_MCE_get_instance(instance); + DevAssert(instance_p != NULL); + m3ap_mce_data_p = m3ap_get_MCE(instance_p, sctp_new_association_ind->assoc_id, -1); + + if (m3ap_mce_data_p != NULL) abort(); + + // DevAssert(m3ap_mce_data_p != NULL); + if (m3ap_mce_data_p == NULL) { + /* Create new MCE descriptor */ + m3ap_mce_data_p = calloc(1, sizeof(*m3ap_mce_data_p)); + DevAssert(m3ap_mce_data_p != NULL); + m3ap_mce_data_p->cnx_id = m3ap_MCE_fetch_add_global_cnx_id(); + m3ap_mce_data_p->m3ap_MCE_instance = instance_p; + /* Insert the new descriptor in list of known eNB + * but not yet associated. + */ + RB_INSERT(m3ap_mce_map, &instance_p->m3ap_mce_head, m3ap_mce_data_p); + m3ap_mce_data_p->state = M3AP_MCE_STATE_CONNECTED; + instance_p->m3_target_mme_nb++; + + if (instance_p->m3_target_mme_pending_nb > 0) { + instance_p->m3_target_mme_pending_nb--; + } + } else { + M3AP_WARN("m3ap_mce_data_p already exists\n"); + } + + //printf("m3ap_MCE_handle_sctp_association_ind at 2\n"); + //dump_trees_m3(); + /* Update parameters */ + m3ap_mce_data_p->assoc_id = sctp_new_association_ind->assoc_id; + m3ap_mce_data_p->in_streams = sctp_new_association_ind->in_streams; + m3ap_mce_data_p->out_streams = sctp_new_association_ind->out_streams; + //printf("m3ap_MCE_handle_sctp_association_ind at 3\n"); + //dump_trees_m3(); +} + +int m3ap_MCE_init_sctp (m3ap_MCE_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t mce_port_for_M3C) { + // Create and alloc new message + MessageDef *message; + sctp_init_t *sctp_init = NULL; + DevAssert(instance_p != NULL); + DevAssert(local_ip_addr != NULL); + message = itti_alloc_new_message (TASK_M3AP_MCE, SCTP_INIT_MSG_MULTI_REQ); + sctp_init = &message->ittiMsg.sctp_init_multi; + sctp_init->port = mce_port_for_M3C; + sctp_init->ppid = M3AP_SCTP_PPID; + sctp_init->ipv4 = 1; + sctp_init->ipv6 = 0; + sctp_init->nb_ipv4_addr = 1; +#if 0 + memcpy(&sctp_init->ipv4_address, + local_ip_addr, + sizeof(*local_ip_addr)); +#endif + sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address); + /* + * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * * * * Disable it for now. + */ + sctp_init->nb_ipv6_addr = 0; + sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1"; + return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message); +} + +static void m3ap_MCE_register_MCE(m3ap_MCE_instance_t *instance_p, + net_ip_address_t *target_MCE_ip_address, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t mce_port_for_M3C, + int multi_sd) { + MessageDef *message = NULL; + sctp_new_association_req_multi_t *sctp_new_association_req = NULL; + m3ap_MCE_data_t *m3ap_mce_data = NULL; + DevAssert(instance_p != NULL); + DevAssert(target_MCE_ip_address != NULL); + message = itti_alloc_new_message(TASK_M3AP_MCE, SCTP_NEW_ASSOCIATION_REQ_MULTI); + sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi; + sctp_new_association_req->port = mce_port_for_M3C; + sctp_new_association_req->ppid = M3AP_SCTP_PPID; + sctp_new_association_req->in_streams = in_streams; + sctp_new_association_req->out_streams = out_streams; + sctp_new_association_req->multi_sd = multi_sd; + memcpy(&sctp_new_association_req->remote_address, + target_MCE_ip_address, + sizeof(*target_MCE_ip_address)); + memcpy(&sctp_new_association_req->local_address, + local_ip_addr, + sizeof(*local_ip_addr)); + /* Create new MCE descriptor */ + m3ap_mce_data = calloc(1, sizeof(*m3ap_mce_data)); + DevAssert(m3ap_mce_data != NULL); + m3ap_mce_data->cnx_id = m3ap_MCE_fetch_add_global_cnx_id(); + sctp_new_association_req->ulp_cnx_id = m3ap_mce_data->cnx_id; + m3ap_mce_data->assoc_id = -1; + m3ap_mce_data->m3ap_MCE_instance = instance_p; + /* Insert the new descriptor in list of known eNB + * but not yet associated. + */ + + m3ap_mce_data_g = (m3ap_setup_req_t*)calloc(1,sizeof(m3ap_setup_req_t)); + + + + RB_INSERT(m3ap_mce_map, &instance_p->m3ap_mce_head, m3ap_mce_data); + m3ap_mce_data->state = M3AP_MCE_STATE_WAITING; + instance_p->m3_target_mme_nb ++; + instance_p->m3_target_mme_pending_nb ++; + itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message); +} + +static +void m3ap_MCE_handle_register_MCE(instance_t instance, + m3ap_register_mce_req_t *m3ap_register_MCE) { + m3ap_MCE_instance_t *new_instance; + DevAssert(m3ap_register_MCE != NULL); + /* Look if the provided instance already exists */ + new_instance = m3ap_MCE_get_instance(instance); + + if (new_instance != NULL) { + /* Checks if it is a retry on the same MCE */ + DevCheck(new_instance->MCE_id == m3ap_register_MCE->MCE_id, new_instance->MCE_id, m3ap_register_MCE->MCE_id, 0); + DevCheck(new_instance->cell_type == m3ap_register_MCE->cell_type, new_instance->cell_type, m3ap_register_MCE->cell_type, 0); + DevCheck(new_instance->tac == m3ap_register_MCE->tac, new_instance->tac, m3ap_register_MCE->tac, 0); + DevCheck(new_instance->mcc == m3ap_register_MCE->mcc, new_instance->mcc, m3ap_register_MCE->mcc, 0); + DevCheck(new_instance->mnc == m3ap_register_MCE->mnc, new_instance->mnc, m3ap_register_MCE->mnc, 0); + M3AP_WARN("MCE[%d] already registered\n", instance); + } else { + new_instance = calloc(1, sizeof(m3ap_MCE_instance_t)); + DevAssert(new_instance != NULL); + RB_INIT(&new_instance->m3ap_mce_head); + /* Copy usefull parameters */ + new_instance->instance = instance; + new_instance->MCE_name = m3ap_register_MCE->MCE_name; + new_instance->MCE_id = m3ap_register_MCE->MCE_id; + new_instance->cell_type = m3ap_register_MCE->cell_type; + new_instance->tac = m3ap_register_MCE->tac; + new_instance->mcc = m3ap_register_MCE->mcc; + new_instance->mnc = m3ap_register_MCE->mnc; + new_instance->mnc_digit_length = m3ap_register_MCE->mnc_digit_length; + new_instance->num_cc = m3ap_register_MCE->num_cc; + + m3ap_id_manager_init(&new_instance->id_manager); + m3ap_timers_init(&new_instance->timers, + m3ap_register_MCE->t_reloc_prep, + m3ap_register_MCE->tm3_reloc_overall); + + for (int i = 0; i< m3ap_register_MCE->num_cc; i++) { + new_instance->eutra_band[i] = m3ap_register_MCE->eutra_band[i]; + new_instance->downlink_frequency[i] = m3ap_register_MCE->downlink_frequency[i]; + new_instance->uplink_frequency_offset[i] = m3ap_register_MCE->uplink_frequency_offset[i]; + new_instance->Nid_cell[i] = m3ap_register_MCE->Nid_cell[i]; + new_instance->N_RB_DL[i] = m3ap_register_MCE->N_RB_DL[i]; + new_instance->frame_type[i] = m3ap_register_MCE->frame_type[i]; + new_instance->fdd_earfcn_DL[i] = m3ap_register_MCE->fdd_earfcn_DL[i]; + new_instance->fdd_earfcn_UL[i] = m3ap_register_MCE->fdd_earfcn_UL[i]; + } + + DevCheck(m3ap_register_MCE->nb_m3 <= M3AP_MAX_NB_MCE_IP_ADDRESS, + M3AP_MAX_NB_MCE_IP_ADDRESS, m3ap_register_MCE->nb_m3, 0); + memcpy(new_instance->target_mme_m3_ip_address, + m3ap_register_MCE->target_mme_m3_ip_address, + m3ap_register_MCE->nb_m3 * sizeof(net_ip_address_t)); + new_instance->nb_m3 = m3ap_register_MCE->nb_m3; + new_instance->mme_m3_ip_address = m3ap_register_MCE->mme_m3_ip_address; + new_instance->sctp_in_streams = m3ap_register_MCE->sctp_in_streams; + new_instance->sctp_out_streams = m3ap_register_MCE->sctp_out_streams; + new_instance->mce_port_for_M3C = m3ap_register_MCE->mme_port_for_M3C; + /* Add the new instance to the list of MCE (meaningfull in virtual mode) */ + m3ap_MCE_insert_new_instance(new_instance); + M3AP_INFO("Registered new MCE[%d] and %s MCE id %u\n", + instance, + m3ap_register_MCE->cell_type == CELL_MACRO_ENB ? "macro" : "home", + m3ap_register_MCE->MCE_id); + + + printf("ipv4_address %s\n",m3ap_register_MCE->mme_m3_ip_address.ipv4_address); + /* initiate the SCTP listener */ + if (m3ap_MCE_init_sctp(new_instance,&m3ap_register_MCE->mme_m3_ip_address,m3ap_register_MCE->mme_port_for_M3C) < 0 ) { + M3AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n"); + return; + } + + M3AP_INFO("MCE[%d] MCE id %u acting as a listner (server)\n", + instance, m3ap_register_MCE->MCE_id); + } +} + +static +void m3ap_MCE_handle_sctp_init_msg_multi_cnf( + instance_t instance_id, + sctp_init_msg_multi_cnf_t *m) { + m3ap_MCE_instance_t *instance; + int index; + DevAssert(m != NULL); + instance = m3ap_MCE_get_instance(instance_id); + DevAssert(instance != NULL); + instance->multi_sd = m->multi_sd; + + /* Exit if CNF message reports failure. + * Failure means multi_sd < 0. + */ + if (instance->multi_sd < 0) { + M3AP_ERROR("Error: be sure to properly configure M3 in your configuration file.\n"); + DevAssert(instance->multi_sd >= 0); + } + + /* Trying to connect to the provided list of MCE ip address */ + + for (index = 0; index < instance->nb_m3; index++) { + M3AP_INFO("MCE[%d] MCE id %u acting as an initiator (client)\n", + instance_id, instance->MCE_id); + m3ap_MCE_register_MCE(instance, + &instance->target_mme_m3_ip_address[index], + &instance->mme_m3_ip_address, + instance->sctp_in_streams, + instance->sctp_out_streams, + instance->mce_port_for_M3C, + instance->multi_sd); + } +} + +//static +//void m3ap_eNB_handle_handover_req(instance_t instance, +// m3ap_handover_req_t *m3ap_handover_req) +//{ +// m3ap_eNB_instance_t *instance_p; +// m3ap_eNB_data_t *target; +// m3ap_id_manager *id_manager; +// int ue_id; +// +// int target_pci = m3ap_handover_req->target_physCellId; +// +// instance_p = m3ap_eNB_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m3ap_is_eNB_pci_in_list(target_pci); +// DevAssert(target != NULL); +// +// /* allocate m3ap ID */ +// id_manager = &instance_p->id_manager; +// ue_id = m3ap_allocate_new_id(id_manager); +// if (ue_id == -1) { +// M3AP_ERROR("could not allocate a new M3AP UE ID\n"); +// /* TODO: cancel handover: send (to be defined) message to RRC */ +// exit(1); +// } +// /* id_source is ue_id, id_target is unknown yet */ +// m3ap_set_ids(id_manager, ue_id, m3ap_handover_req->rnti, ue_id, -1); +// m3ap_id_set_state(id_manager, ue_id, M2ID_STATE_SOURCE_PREPARE); +// m3ap_set_reloc_prep_timer(id_manager, ue_id, +// m3ap_timer_get_tti(&instance_p->timers)); +// m3ap_id_set_target(id_manager, ue_id, target); +// +// m3ap_eNB_generate_m3_handover_request(instance_p, target, m3ap_handover_req, ue_id); +//} + +//static +//void m3ap_eNB_handle_handover_req_ack(instance_t instance, +// m3ap_handover_req_ack_t *m3ap_handover_req_ack) +//{ +// /* TODO: remove this hack (the goal is to find the correct +// * eNodeB structure for the other end) - we need a proper way for RRC +// * and M3AP to identify eNodeBs +// * RRC knows about mod_id and M3AP knows about eNB_id (eNB_ID in +// * the configuration file) +// * as far as I understand.. CROUX +// */ +// m3ap_eNB_instance_t *instance_p; +// m3ap_eNB_data_t *target; +// int source_assoc_id = m3ap_handover_req_ack->source_assoc_id; +// int ue_id; +// int id_source; +// int id_target; +// +// instance_p = m3ap_eNB_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m3ap_get_eNB(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// /* rnti is a new information, save it */ +// ue_id = m3ap_handover_req_ack->m3_id_target; +// id_source = m3ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// m3ap_set_ids(&instance_p->id_manager, ue_id, m3ap_handover_req_ack->rnti, id_source, id_target); +// +// m3ap_eNB_generate_m3_handover_request_ack(instance_p, target, m3ap_handover_req_ack); +//} +// +//static +//void m3ap_eNB_ue_context_release(instance_t instance, +// m3ap_ue_context_release_t *m3ap_ue_context_release) +//{ +// m3ap_eNB_instance_t *instance_p; +// m3ap_eNB_data_t *target; +// int source_assoc_id = m3ap_ue_context_release->source_assoc_id; +// int ue_id; +// instance_p = m3ap_eNB_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m3ap_get_eNB(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// m3ap_eNB_generate_m3_ue_context_release(instance_p, target, m3ap_ue_context_release); +// +// /* free the M3AP UE ID */ +// ue_id = m3ap_find_id_from_rnti(&instance_p->id_manager, m3ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M3AP_ERROR("could not find UE %x\n", m3ap_ue_context_release->rnti); +// exit(1); +// } +// m3ap_release_id(&instance_p->id_manager, ue_id); +//} + +uint8_t m3ap_m3setup[] = { + 0x00, 0x07, 0x00, 0x23, 0x00, 0x00, 0x03, 0x00, + 0x12, 0x00, 0x07, 0x40, 0x55, 0xf5, 0x01, 0x00, + 0x25, 0x00, 0x00, 0x13, 0x40, 0x0a, 0x03, 0x80, + 0x4d, 0x33, 0x2d, 0x65, 0x4e, 0x42, 0x33, 0x37, + 0x00, 0x14, 0x00, 0x03, 0x01, 0x00, 0x01 +}; + +uint8_t m3ap_start[] = { + 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x07, 0x00, 0x55, 0xf5, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x0d, 0x60, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 0x01, + 0x7a, 0x00, 0x05, 0x00, 0x03, 0x07, 0x08, 0x00, + 0x00, 0x06, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, + 0x0e, 0x00, 0xe8, 0x0a, 0x0a, 0x0a, 0x00, 0x0a, + 0xc8, 0x0a, 0xfe, 0x00, 0x00, 0x00, 0x01 +}; + + +void *m3ap_MCE_task(void *arg) { + MessageDef *received_msg = NULL; + int result; + M3AP_DEBUG("Starting M3AP MCE layer\n"); + m3ap_MCE_prepare_internal_data(); + itti_mark_task_ready(TASK_M3AP_MCE); + + while (1) { + itti_receive_msg(TASK_M3AP_MCE, &received_msg); + + switch (ITTI_MSG_ID(received_msg)) { + case MESSAGE_TEST: +// LOG_W(M3AP,"MCE Received Test Message ... TODO\n"); +// //MessageDef * message_p = itti_alloc_new_message(TASK_M3AP, MESSAGE_TEST); +// //itti_send_msg_to_task(TASK_M2AP_ENB, 1/*ctxt_pP->module_id*/, message_p); +// +// asn_dec_rval_t dec_ret; +// +// +// uint8_t *buffer; +// uint32_t len; +// M3AP_M3AP_PDU_t pdu; +// memset(&pdu, 0, sizeof(pdu)); +// +// buffer = &m3ap_m3setup[0]; +// //buffer = &m3ap_start[0]; +// len=8*4+7; +// //len=8*9+7; +// +// //if (m3ap_decode_pdu(&pdu, buffer, len) < 0) { +// // LOG_E(M3AP, "Failed to decode PDU\n"); +// //re//turn -1; +// //} +// M3AP_M3AP_PDU_t *pdu2 = &pdu; +// dec_ret = aper_decode(NULL, +// &asn_DEF_M3AP_M3AP_PDU, +// (void **)&pdu2, +// buffer, +// len, +// 0, +// 0); +// +// LOG_W(M3AP,"Trying to print %d\n",(dec_ret.code == RC_OK)); +// xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, &pdu); +// LOG_W(M3AP,"Trying to print out \n"); + + break; + case TERMINATE_MESSAGE: + M3AP_WARN(" *** Exiting M3AP thread\n"); + itti_exit_task(); + break; + + case M3AP_SUBFRAME_PROCESS: + m3ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg)); + break; + + case M3AP_REGISTER_MCE_REQ: + LOG_I(M3AP,"MCE Received M3AP_REGISTER_MCE_REQ Message\n"); + + m3ap_MCE_handle_register_MCE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_REGISTER_MCE_REQ(received_msg)); + break; + + case M3AP_MBMS_SESSION_START_RESP: + LOG_I(M3AP,"MCE M3AP_MBMS_SESSION_START_RESP Message\n"); + MCE_send_MBMS_SESSION_START_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_MBMS_SESSION_START_RESP(received_msg)); + + break; + + case M3AP_MBMS_SESSION_STOP_RESP: + LOG_I(M3AP,"MCE M3AP_MBMS_SESSION_STOP_RESP Message\n"); + MCE_send_MBMS_SESSION_STOP_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_MBMS_SESSION_START_RESP(received_msg)); + + break; + + case M3AP_MBMS_SESSION_UPDATE_RESP: + LOG_I(M3AP,"MCE M3AP_MBMS_SESSION_UPDATE_RESP Message\n"); + //MCE_send_MBMS_SESSION_UPDATE_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + //&M3AP_MBMS_SESSION_START_RESP(received_msg)); + + break; + + +// case M3AP_HANDOVER_REQ: +// m3ap_eNB_handle_handover_req(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_HANDOVER_REQ(received_msg)); +// break; +// +// case M3AP_HANDOVER_REQ_ACK: +// m3ap_eNB_handle_handover_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_HANDOVER_REQ_ACK(received_msg)); +// break; +// +// case M3AP_UE_CONTEXT_RELEASE: +// m3ap_eNB_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_UE_CONTEXT_RELEASE(received_msg)); +// break; +// + case SCTP_INIT_MSG_MULTI_CNF: + LOG_D(M3AP,"MCE Received SCTP_INIT_MSG_MULTI_CNF Message\n"); + + m3ap_MCE_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_init_msg_multi_cnf); + break; + + case SCTP_NEW_ASSOCIATION_RESP: + LOG_D(M3AP,"MCE Received SCTP_NEW_ASSOCIATION_RESP Message\n"); + + m3ap_MCE_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_resp); + break; + + case SCTP_NEW_ASSOCIATION_IND: + LOG_D(M3AP,"MCE Received SCTP_NEW_ASSOCIATION Message\n"); + + m3ap_MCE_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_ind); + break; + + case SCTP_DATA_IND: + LOG_D(M3AP,"MCE Received SCTP_DATA_IND Message\n"); + + m3ap_MCE_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_data_ind); + break; + + default: + M3AP_ERROR("Received unhandled message: %d:%s\n", + ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + received_msg = NULL; + } + + return NULL; +} + +#include "common/config/config_userapi.h" + +int is_m3ap_MCE_enabled(void) +{ + static volatile int config_loaded = 0; + static volatile int enabled = 0; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + if (pthread_mutex_lock(&mutex)) goto mutex_error; + + if (config_loaded) { + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + return enabled; + } + + char *enable_m3 = NULL; + paramdef_t p[] = { + { "enable_mce_m3", "yes/no", 0, strptr:&enable_m3, defstrval:"", TYPE_STRING, 0 } + }; + + /* TODO: do it per module - we check only first MCE */ + config_get(p, sizeof(p)/sizeof(paramdef_t), "MCEs.[0]"); + if (enable_m3 != NULL && strcmp(enable_m3, "yes") == 0) + enabled = 1; + + config_loaded = 1; + + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + + return enabled; + +mutex_error: + LOG_E(M3AP, "mutex error\n"); + exit(1); +} diff --git a/openair3/M3AP/m3ap_MCE.h b/openair3/M3AP/m3ap_MCE.h new file mode 100644 index 0000000000..3a617776e3 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE.h @@ -0,0 +1,55 @@ +/* + * 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 m3ap_eNB.h + * \brief m3ap tasks for eNB + * \author Konstantinos Alexandris , Cedric Roux , Navid Nikaein + * \date 2018 + * \version 1.0 + */ + +#include +#include + +/** @defgroup _m3ap_impl_ M3AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef M3AP_MCE_H_ +#define M3AP_MCE_H_ + +#include "m3ap_MCE_defs.h" + + +int m3ap_MCE_init_sctp (m3ap_MCE_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t mce_port_for_M3C); + +void *m3ap_MCE_task(void *arg); + +int is_m3ap_MCE_enabled(void); + +#endif /* M3AP_H_ */ + +/** + * @} + */ diff --git a/openair3/M3AP/m3ap_MCE_defs.h b/openair3/M3AP/m3ap_MCE_defs.h new file mode 100644 index 0000000000..18ad70a408 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_defs.h @@ -0,0 +1,210 @@ +/* + * 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 m3ap_MCE_defs.h + * \brief m3ap struct definitions for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "queue.h" +#include "tree.h" + +#include "sctp_eNB_defs.h" + +#include "m3ap_ids.h" //looks X2AP specific for HO +#include "m3ap_timers.h" + +#ifndef M3AP_MCE_DEFS_H_ +#define M3AP_MCE_DEFS_H_ + +#define M3AP_MCE_NAME_LENGTH_MAX (150) + +typedef enum { + /* Disconnected state: initial state for any association. */ + M3AP_MCE_STATE_DISCONNECTED = 0x0, + + /* State waiting for m2 Setup response message if the target MCE accepts or + * M3 Setup failure if rejects the MCE. + */ + M3AP_MCE_STATE_WAITING = 0x1, + + /* The MCE is successfully connected to another MCE. */ + M3AP_MCE_STATE_CONNECTED = 0x2, + + /* M3AP is ready, and the MCE is successfully connected to another MCE. */ + M3AP_MCE_STATE_READY = 0x3, + + M3AP_MCE_STATE_OVERLOAD = 0x4, + + M3AP_MCE_STATE_RESETTING = 0x5, + + /* Max number of states available */ + M3AP_MCE_STATE_MAX, +} m3ap_MCE_state_t; + +/* Served PLMN identity element */ +/*struct plmn_identity_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + STAILQ_ENTRY(plmn_identity_s) next; +};*/ + +/* Served group id element */ +/*struct served_group_id_s { + uint16_t mce_group_id; + STAILQ_ENTRY(served_group_id_s) next; +};*/ + +/* Served enn code for a particular MCE */ +/*struct mce_code_s { + uint8_t mce_code; + STAILQ_ENTRY(mce_code_s) next; +};*/ + +struct m3ap_MCE_instance_s; + +/* This structure describes association of a MCE to another MCE */ +typedef struct m3ap_MCE_data_s { + /* MCE descriptors tree, ordered by sctp assoc id */ + RB_ENTRY(m3ap_MCE_data_s) entry; + + /* This is the optional name provided by the MME */ + char *MCE_name; + + /* target MCE ID */ + uint32_t MCE_id; + + /* Current MCE load information (if any). */ + //m3ap_load_state_t overload_state; + + /* Current MCE->MCE M3AP association state */ + m3ap_MCE_state_t state; + + /* Next usable stream for UE signalling */ + int32_t nextstream; + + /* Number of input/ouput streams */ + uint16_t in_streams; + uint16_t out_streams; + + /* Connexion id used between SCTP/M3AP */ + uint16_t cnx_id; + + /* SCTP association id */ + int32_t assoc_id; + + /* Nid cells */ + uint32_t Nid_cell[MAX_NUM_CCs]; + int num_cc; + + /* Only meaningfull in virtual mode */ + struct m3ap_MCE_instance_s *m3ap_MCE_instance; +} m3ap_MCE_data_t; + +typedef struct m3ap_MCE_instance_s { + /* used in simulation to store multiple MCE instances*/ + STAILQ_ENTRY(m3ap_MCE_instance_s) m3ap_MCE_entries; + + /* Number of target MCEs requested by MCE (tree size) */ + uint32_t m3_target_mme_nb; + /* Number of target MCEs for which association is pending */ + uint32_t m3_target_mme_pending_nb; + /* Number of target MCE successfully associated to MCE */ + uint32_t m3_target_mme_associated_nb; + /* Tree of M3AP MCE associations ordered by association ID */ + RB_HEAD(m3ap_mce_map, m3ap_MCE_data_s) m3ap_mce_head; + + /* Tree of UE ordered by MCE_ue_m3ap_id's */ + // RB_HEAD(m3ap_ue_map, m3ap_MCE_ue_context_s) m3ap_ue_head; + + /* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */ + instance_t instance; + + /* Displayable name of MCE */ + char *MCE_name; + + /* Unique MCE_id to identify the MCE within EPC. + * In our case the MCE is a macro MCE so the id will be 20 bits long. + * For Home MCE id, this field should be 28 bits long. + */ + uint32_t MCE_id; + /* The type of the cell */ + cell_type_t cell_type; + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + /* CC params */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + net_ip_address_t target_mme_m3_ip_address[M3AP_MAX_NB_MCE_IP_ADDRESS]; + uint8_t nb_m3; + net_ip_address_t mme_m3_ip_address; + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + uint32_t mce_port_for_M3C; + int multi_sd; + + m3ap_id_manager id_manager; + m3ap_timers_t timers; +} m3ap_MCE_instance_t; + +typedef struct { + /* List of served MCEs + * Only used for virtual mode + */ + STAILQ_HEAD(m3ap_MCE_instances_head_s, m3ap_MCE_instance_s) m3ap_MCE_instances_head; + /* Nb of registered MCEs */ + uint8_t nb_registered_MCEs; + + /* Generate a unique connexion id used between M3AP and SCTP */ + uint16_t global_cnx_id; +} m3ap_MCE_internal_data_t; + +int m3ap_MCE_compare_assoc_id(struct m3ap_MCE_data_s *p1, struct m3ap_MCE_data_s *p2); + +/* Generate the tree management functions */ +struct m3ap_MCE_map; +struct m3ap_MCE_data_s; +RB_PROTOTYPE(m3ap_MCE_map, m3ap_MCE_data_s, entry, m3ap_MCE_compare_assoc_id); + + +#endif /* M3AP_MCE_DEFS_H_ */ diff --git a/openair3/M3AP/m3ap_MCE_generate_messages.h b/openair3/M3AP/m3ap_MCE_generate_messages.h new file mode 100644 index 0000000000..0884e8216e --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_generate_messages.h @@ -0,0 +1,63 @@ +/* + * 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 m2ap_eNB_generate_messages.h + * \brief m2ap procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_ENB_GENERATE_MESSAGES_H_ +#define M2AP_ENB_GENERATE_MESSAGES_H_ + +#include "m2ap_eNB_defs.h" +#include "m2ap_common.h" + +int m2ap_eNB_generate_m2_setup_request(m2ap_eNB_instance_t *instance_p, + m2ap_eNB_data_t *m2ap_eNB_data_p); + +int m2ap_MCE_generate_m2_setup_response(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p); + +/*int m2ap_MCE_generate_m2_setup_failure(instance_t instance, + uint32_t assoc_id, + M2AP_Cause_PR cause_type, + long cause_value, + long time_to_wait);*/ + +int m2ap_eNB_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value); + +//int m2ap_eNB_generate_m2_handover_request (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id); +// +//int m2ap_eNB_generate_m2_handover_request_ack (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack); +// +//int m2ap_eNB_generate_m2_ue_context_release (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_ue_context_release_t *m2ap_ue_context_release); +// +//int m2ap_eNB_generate_m2_handover_cancel (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause); + +#endif /* M2AP_ENB_GENERATE_MESSAGES_H_ */ diff --git a/openair3/M3AP/m3ap_MCE_generate_messsages.c b/openair3/M3AP/m3ap_MCE_generate_messsages.c new file mode 100644 index 0000000000..8d8c7f3853 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_generate_messsages.c @@ -0,0 +1,808 @@ +/* + * 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 m2ap_eNB_generate_messages.c + * \brief m2ap procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include "intertask_interface.h" + +//#include "M2AP_LastVisitedCell-Item.h" + +#include "m2ap_common.h" +#include "m2ap_eNB.h" +#include "m2ap_eNB_generate_messages.h" +#include "m2ap_encoder.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +#include "m2ap_itti_messaging.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +int m2ap_eNB_generate_m2_setup_request( + m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p) +{ + module_id_t enb_mod_idP=0; + module_id_t du_mod_idP=0; + + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupRequest_t *out; + M2AP_M2SetupRequest_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + int i = 0; + int j = 0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M2AP_InitiatingMessage_t *)calloc(1, sizeof(M2AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_M2SetupRequest; + out = &pdu.choice.initiatingMessage.value.choice.M2SetupRequest; + + /* mandatory */ + /* c1. GlobalENB_ID (integer value) */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_GlobalENB_ID; + //ie->value.choice.GlobalENB_ID.eNB_ID = 1;//M2AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP); + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &ie->value.choice.GlobalENB_ID.pLMN_Identity); + ie->value.choice.GlobalENB_ID.eNB_ID.present = M2AP_ENB_ID_PR_macro_eNB_ID; + MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id, + &ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); + M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0], + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1], + ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + ///* mandatory */ + ///* c2. GNB_eNB_ID (integrer value) */ + //ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_gNB_eNB_ID; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequestIEs__value_PR_GNB_eNB_ID; + //asn_int642INTEGER(&ie->value.choice.GNB_eNB_ID, f1ap_du_data->gNB_eNB_id); + //ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional */ + /* c3. ENBname */ + if (m2ap_eNB_data_p->eNB_name != NULL) { + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENBname; + ie->criticality = M2AP_Criticality_ignore; + ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_ENBname; + //OCTET_STRING_fromBuf(&ie->value.choice.ENB_Name, m2ap_eNB_data_p->eNB_name, + //strlen(m2ap_eNB_data_p->eNB_name)); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* mandatory */ + /* c4. serverd cells list */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + ie->id = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_List; + ie->criticality = M2AP_Criticality_reject; + ie->value.present = M2AP_M2SetupRequest_Ies__value_PR_ENB_MBMS_Configuration_data_List; + + int num_mbms_available = 1;//m2ap_du_data->num_mbms_available; + LOG_D(M2AP, "num_mbms_available = %d \n", num_mbms_available); + + for (i=0; + iid = M2AP_ProtocolIE_ID_id_ENB_MBMS_Configuration_data_Item; + mbms_configuration_data_list_item_ies->criticality = M2AP_Criticality_reject; + mbms_configuration_data_list_item_ies->value.present = M2AP_ENB_MBMS_Configuration_data_ItemIEs__value_PR_ENB_MBMS_Configuration_data_Item; + + M2AP_ENB_MBMS_Configuration_data_Item_t *mbms_configuration_data_item; + mbms_configuration_data_item = &mbms_configuration_data_list_item_ies->value.choice.ENB_MBMS_Configuration_data_Item; + { + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &mbms_configuration_data_item->eCGI.pLMN_Identity); + MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0, + &mbms_configuration_data_item->eCGI.eUTRANcellIdentifier); + M2AP_MBMS_Service_Area_t * mbms_service_area; + mbms_service_area = (M2AP_MBMS_Service_Area_t*)calloc(1,sizeof(M2AP_MBMS_Service_Area_t)); + ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area); + + + } + + + //M2AP_ENB_MBMS_Configuration_data_Item_t mbms_configuration_data_item; + //memset((void *)&mbms_configuration_data_item, 0, sizeof(M2AP_ENB_MBMS_Configuration_data_Item_t)); + + //M2AP_ECGI_t eCGI; + //M2AP_PLMN_Identity_t pLMN_Identity; + //M2AP_EUTRANCellIdentifier_t eUTRANcellIdentifier + //M2AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea; + //M2AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList; + + + ASN_SEQUENCE_ADD(&ie->value.choice.ENB_MBMS_Configuration_data_List.list,mbms_configuration_data_list_item_ies); + + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + LOG_W(M2AP,"m2ap_eNB_data_p->assoc_id %d\n",m2ap_eNB_data_p->assoc_id); + /* encode */ + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M2AP, "Failed to encode M2 setup request\n"); + return -1; + } + + + LOG_W(M2AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M2AP_eNB, + // MSC_M2AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M2_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m2ap_eNB_data_p->ENBname); + + m2ap_eNB_itti_send_sctp_data_req(instance_p, m2ap_eNB_data_p->assoc_id, buffer, len, 0); + + return 0; + + +} + +//int m2ap_MCE_generate_m2_setup_response(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_M2SetupResponse_t *out; +// M2AP_M2SetupResponse_Ies_t *ie; +// //M2AP_PLMN_Identity_t *plmn; +// //ServedCells__Member *servedCellMember; +// //M2AP_GU_Group_ID_t *gu; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// /* Prepare the M2AP message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; +// pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; +// pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_M2SetupResponse; +// out = &pdu.choice.successfulOutcome.value.choice.M2SetupResponse; +// +// /* mandatory */ +// ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_GlobalENB_ID; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GlobalENB_ID; +// //MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// // &ie->value.choice.GlobalENB_ID.pLMN_Identity); +// //ie->value.choice.GlobalENB_ID.eNB_ID.present = M2AP_ENB_ID_PR_macro_eNB_ID; +// //MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id, +// // &ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID); +// //M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, +// // ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0], +// // ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1], +// // ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_ServedCells; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_ServedCells; +// //{ +// // for (int i = 0; inum_cc; i++){ +// // servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member)); +// // { +// // servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i]; +// +// // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// // &servedCellMember->servedCellInfo.cellId.pLMN_Identity); +// // MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0, +// // &servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier); +// +// // INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC); +// // plmn = (M2AP_PLMN_Identity_t *)calloc(1,sizeof(M2AP_PLMN_Identity_t)); +// // { +// // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); +// // ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn); +// // } +// +// // if (instance_p->frame_type[i] == FDD) { +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = M2AP_EUTRA_Mode_Info_PR_fDD; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; +// // switch (instance_p->N_RB_DL[i]) { +// // case 6: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; +// // break; +// // case 15: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; +// // break; +// // case 25: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; +// // break; +// // case 50: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; +// // break; +// // case 75: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; +// // break; +// // case 100: +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; +// // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; +// // break; +// // default: +// // AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); +// // break; +// // } +// // } +// // else { +// // AssertFatal(0,"M2Setupresponse not supported for TDD!"); +// // } +// // } +// // ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember); +// // } +// //} +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_GUGroupIDList; +// //ie->criticality = M2AP_Criticality_reject; +// //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GUGroupIDList; +// //{ +// // gu = (M2AP_GU_Group_ID_t *)calloc(1, sizeof(M2AP_GU_Group_ID_t)); +// // { +// // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// // &gu->pLMN_Identity); +// // //@TODO: consider to update this value +// // INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID); +// // } +// // ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu); +// //} +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode M2 setup response\n"); +// return -1; +// } +// +// m2ap_eNB_data_p->state = M2AP_ENB_STATE_READY; +// +// //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 M2Setup/successfulOutcome assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 0); +// +// return ret; +//} + +//int m2ap_MCE_generate_m2_setup_failure(instance_t instance, +// uint32_t assoc_id, +// M2AP_Cause_PR cause_type, +// long cause_value, +// long time_to_wait) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_M2SetupFailure_t *out; +// M2AP_M2SetupFailure_Ies_t *ie; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// /* Prepare the M2AP message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; +// pdu.choice.unsuccessfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; +// pdu.choice.unsuccessfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.unsuccessfulOutcome.value.present = M2AP_UnsuccessfulOutcome__value_PR_M2SetupFailure; +// out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure; +// +// /* mandatory */ +// ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_Cause; +// //ie->criticality = M2AP_Criticality_ignore; +// //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_Cause; +// +// //m2ap_eNB_set_cause (&ie->value.choice.Cause, cause_type, cause_value); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional: consider to handle this later */ +// ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); +// //ie->id = M2AP_ProtocolIE_ID_id_TimeToWait; +// //ie->criticality = M2AP_Criticality_ignore; +// //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_TimeToWait; +// +// //if (time_to_wait > -1) { +// // ie->value.choice.TimeToWait = time_to_wait; +// //} +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode M2 setup failure\n"); +// return -1; +// } +// +// //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, +// // MSC_M2AP_TARGET_ENB, NULL, 0, +// // "0 M2Setup/unsuccessfulOutcome assoc_id %u cause %u value %u", +// // assoc_id, cause_type, cause_value); +// +// m2ap_eNB_itti_send_sctp_data_req(instance, assoc_id, buffer, len, 0); +// +// return ret; +//} + +int m2ap_eNB_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value) +{ + + DevAssert (cause_p != NULL); + cause_p->present = cause_type; + + switch (cause_type) { + case M2AP_Cause_PR_radioNetwork: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_transport: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_protocol: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_misc: + cause_p->choice.misc = cause_value; + break; + + default: + return -1; + } + + return 0; +} + +//int m2ap_eNB_generate_m2_handover_request (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequest_t *out; +// M2AP_HandoverRequest_IEs_t *ie; +// M2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs; +// M2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item; +// M2AP_LastVisitedCell_Item_t *lastVisitedCell_Item; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverRequest; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverRequest; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_Cause; +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = M2AP_CauseRadioNetwork_handover_desirable_for_radio_reasons; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargetCell_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_ECGI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.ECGI.pLMN_Identity); +// MACRO_ENB_ID_TO_CELL_IDENTITY(m2ap_eNB_data_p->eNB_id, 0, &ie->value.choice.ECGI.eUTRANcellIdentifier); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_GUMMEI_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_GUMMEI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.GUMMEI.gU_Group_ID.pLMN_Identity); +// //@TODO: consider to update these values +// INT16_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_group_id, &ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID); +// MME_CODE_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_code, &ie->value.choice.GUMMEI.mME_Code); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_ContextInformation; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_ContextInformation; +// //@TODO: consider to update this value +// ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID = m2ap_handover_req->mme_ue_s1ap_id; +// +// KENB_STAR_TO_BIT_STRING(m2ap_handover_req->kenb,&ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star); +// +// if (m2ap_handover_req->kenb_ncc >=0) { // Check this condition +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = m2ap_handover_req->kenb_ncc; +// } +// else { +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = 1; +// } +// +// ENCRALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.encryption_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms); +// +// INTPROTALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.integrity_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms); +// +// //@TODO: update with proper UEAMPR +// UEAGMAXBITRTD_TO_ASN_PRIMITIVES(3L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink); +// UEAGMAXBITRTU_TO_ASN_PRIMITIVES(6L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateUplink); +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_ToBeSetup_ItemIEs = (M2AP_E_RABs_ToBeSetup_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_ToBeSetup_ItemIEs_t)); +// e_RABS_ToBeSetup_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_ToBeSetup_Item; +// e_RABS_ToBeSetup_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_ToBeSetup_ItemIEs->value.present = M2AP_E_RABs_ToBeSetup_ItemIEs__value_PR_E_RABs_ToBeSetup_Item; +// e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item; +// { +// e_RABs_ToBeSetup_Item->e_RAB_ID = m2ap_handover_req->e_rabs_tobesetup[i].e_rab_id; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI = m2ap_handover_req->e_rab_param[i].qos.qci; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.priority_level; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size = (uint8_t)(m2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.length/8); +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = m2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.length%8; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf = +// calloc(1,e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// memcpy (e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf, +// m2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.buffer, +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// INT32_TO_OCTET_STRING(m2ap_handover_req->e_rabs_tobesetup[i].gtp_teid,&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID); +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list, e_RABS_ToBeSetup_ItemIEs); +// } +// } +// +// OCTET_STRING_fromBuf(&ie->value.choice.UE_ContextInformation.rRC_Context, (char*) m2ap_handover_req->rrc_buffer, m2ap_handover_req->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_HistoryInformation; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_HistoryInformation; +// //@TODO: consider to update this value +// { +// lastVisitedCell_Item = (M2AP_LastVisitedCell_Item_t *)calloc(1, sizeof(M2AP_LastVisitedCell_Item_t)); +// lastVisitedCell_Item->present = M2AP_LastVisitedCell_Item_PR_e_UTRAN_Cell; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.pLMN_Identity); +// MACRO_ENB_ID_TO_CELL_IDENTITY(0, 0, &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.eUTRANcellIdentifier); +// lastVisitedCell_Item->choice.e_UTRAN_Cell.cellType.cell_Size = M2AP_Cell_Size_small; +// lastVisitedCell_Item->choice.e_UTRAN_Cell.time_UE_StayedInCell = 2; +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_HistoryInformation.list, lastVisitedCell_Item); +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover request\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2Handover/initiatingMessage assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_eNB_generate_m2_handover_request_ack (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequestAcknowledge_t *out; +// M2AP_HandoverRequestAcknowledge_IEs_t *ie; +// M2AP_E_RABs_Admitted_ItemIEs_t *e_RABS_Admitted_ItemIEs; +// M2AP_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// ue_id = m2ap_handover_req_ack->m2_id_target; +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; +// pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge; +// out = &pdu.choice.successfulOutcome.value.choice.HandoverRequestAcknowledge; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_List; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_E_RABs_Admitted_List; +// +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_Admitted_ItemIEs = (M2AP_E_RABs_Admitted_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_Admitted_ItemIEs_t)); +// e_RABS_Admitted_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_Item; +// e_RABS_Admitted_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_Admitted_ItemIEs->value.present = M2AP_E_RABs_Admitted_ItemIEs__value_PR_E_RABs_Admitted_Item; +// e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item; +// { +// e_RABs_Admitted_Item->e_RAB_ID = m2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id; +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs); +// } +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_TargeteNBtoSource_eNBTransparentContainer; +// +// OCTET_STRING_fromBuf(&ie->value.choice.TargeteNBtoSource_eNBTransparentContainer, (char*) m2ap_handover_req_ack->rrc_buffer, m2ap_handover_req_ack->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover response\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2Handover/successfulOutcome assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_eNB_generate_m2_ue_context_release (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, m2ap_ue_context_release_t *m2ap_ue_context_release) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_UEContextRelease_t *out; +// M2AP_UEContextRelease_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// ue_id = m2ap_find_id_from_rnti(&instance_p->id_manager, m2ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M2AP_ERROR("could not find UE %x\n", m2ap_ue_context_release->rnti); +// exit(1); +// } +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP ue context relase message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_uEContextRelease; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_UEContextRelease; +// out = &pdu.choice.initiatingMessage.value.choice.UEContextRelease; +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 UE Context Release\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2UEContextRelease/initiatingMessage assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_eNB_generate_m2_handover_cancel (m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *m2ap_eNB_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverCancel_t *out; +// M2AP_HandoverCancel_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_eNB_data_p != NULL); +// +// ue_id = m2_ue_id; +// id_source = ue_id; +// id_target = m2ap_id_get_id_target(&instance_p->id_manager, ue_id); +// +// /* Prepare the M2AP handover cancel message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverCancel; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverCancel; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverCancel; +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ +// if (id_target != -1) { +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_eNB_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_Cause; +// switch (cause) { +// case M2AP_T_RELOC_PREP_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_trelocprep_expiry; +// break; +// case M2AP_TX2_RELOC_OVERALL_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_tx2relocoverall_expiry; +// break; +// default: +// /* we can't come here */ +// M2AP_ERROR("unhandled cancel cause\n"); +// exit(1); +// } +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 Handover Cancel\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_ENB, MSC_M2AP_TARGET_ENB, NULL, 0, "0 X2HandoverCancel/initiatingMessage assoc_id %u", m2ap_eNB_data_p->assoc_id); +// +// m2ap_eNB_itti_send_sctp_data_req(instance_p->instance, m2ap_eNB_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} diff --git a/openair3/M3AP/m3ap_MCE_handler.c b/openair3/M3AP/m3ap_MCE_handler.c new file mode 100644 index 0000000000..e733af28db --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_handler.c @@ -0,0 +1,118 @@ +/* + * 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 m3ap_eNB_handler.c + * \brief m3ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "intertask_interface.h" + +#include "asn1_conversions.h" + +#include "m3ap_common.h" +#include "m3ap_MCE_defs.h" +#include "m3ap_handler.h" +#include "m3ap_decoder.h" +#include "m3ap_ids.h" + +//#include "m3ap_MCE_management_procedures.h" +#include "m3ap_MCE_generate_messages.h" + +//#include "m3ap_MME_interface_management.h" +#include "m3ap_MCE_interface_management.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +/* Handlers matrix. Only eNB related procedure present here */ +m3ap_MCE_message_decoded_callback m3ap_MCE_messages_callback[][3] = { + { MCE_handle_MBMS_SESSION_START_REQUEST, 0, 0 }, /* MBMSSessionStart */ + { MCE_handle_MBMS_SESSION_STOP_REQUEST, 0, 0 }, /* MBMSSessionStop */ + { 0, 0, 0 }, /* Error Indication */ + { 0, 0, 0 }, /* Reset */ + { 0, 0, 0 }, /* ??? */ + { MCE_handle_MBMS_SESSION_UPDATE_REQUEST, 0, 0 }, /* MBMSSessionUpdate */ + { 0, 0, 0 }, /* MCEConfigurationUpdate */ + { 0, MCE_handle_M3_SETUP_RESPONSE, 0 } /* M3 Setup */ +}; + +static char *m3ap_direction2String(int m3ap_dir) { +static char *m3ap_direction_String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; +return(m3ap_direction_String[m3ap_dir]); +} + + +int m3ap_MCE_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length) +{ + M3AP_M3AP_PDU_t pdu; + int ret; + + DevAssert(data != NULL); + + memset(&pdu, 0, sizeof(pdu)); + + if (m3ap_decode_pdu(&pdu, data, data_length) < 0) { + LOG_E(M3AP, "Failed to decode PDU\n"); + return -1; + } + + /* Checking procedure Code and direction of message */ + if (pdu.choice.initiatingMessage.procedureCode > sizeof(m3ap_MCE_messages_callback) / (3 * sizeof( + m3ap_message_decoded_callback)) + || (pdu.present > M3AP_M3AP_PDU_PR_unsuccessfulOutcome)) { + LOG_E(M3AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return -1; + } + + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (m3ap_MCE_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) { + LOG_E(M3AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, + m3ap_direction2String(pdu.present - 1)); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return -1; + } + + /* Calling the right handler */ + LOG_I(M3AP, "Calling handler with instance %d\n",instance); + ret = (*m3ap_MCE_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1]) + (instance, assoc_id, stream, &pdu); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return ret; +} + + diff --git a/openair3/M3AP/m3ap_MCE_handler.h b/openair3/M3AP/m3ap_MCE_handler.h new file mode 100644 index 0000000000..ce4997e80d --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_handler.h @@ -0,0 +1,43 @@ +/* + * 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 m2ap_handler.h + * \brief m2ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_MCE_HANDLERS_H_ +#define M2AP_MCE_HANDLERS_H_ + +#include "m2ap_MCE_defs.h" + +//void m3ap_handle_m2_setup_message(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown); + +//int m3ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + //const uint8_t * const data, const uint32_t data_length); + +int m3ap_MCE_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + + +#endif /* M2AP_MCE_HANDLERS_H_ */ diff --git a/openair3/M3AP/m3ap_MCE_interface_management.c b/openair3/M3AP/m3ap_MCE_interface_management.c new file mode 100644 index 0000000000..2694846526 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_interface_management.c @@ -0,0 +1,756 @@ +/* + * 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 m3ap_MCE_interface_management.c + * \brief m3ap interface management for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "intertask_interface.h" + +#include "m3ap_common.h" +#include "m3ap_MCE.h" +//#include "m3ap_MCE_generate_messages.h" +#include "m3ap_encoder.h" +#include "m3ap_decoder.h" +#include "m3ap_ids.h" + +#include "m3ap_MCE_interface_management.h" + + +#include "m3ap_itti_messaging.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + + +//#include "m3ap_common.h" +//#include "m3ap_encoder.h" +//#include "m3ap_decoder.h" +//#include "m3ap_itti_messaging.h" +//#include "m3ap_MCE_interface_management.h" +//#include "assertions.h" + +extern m3ap_setup_req_t * m3ap_mce_data_g; + + +int MCE_handle_MBMS_SESSION_START_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ +// LOG_W(M3AP, "MCE_handle_MBMS_SESSION_START_REQUEST assoc_id %d\n",assoc_id); +// + MessageDef *message_p; +// M3AP_SessionStartRequest_t *container; +// M3AP_SessionStartRequest_Ies_t *ie; +// int i = 0; +// +// DevAssert(pdu != NULL); +// +// container = &pdu->choice.initiatingMessage.value.choice.SessionStartRequest; + + message_p = itti_alloc_new_message(TASK_M3AP_MCE, M3AP_MBMS_SESSION_START_REQ); + +// +// /* M3 Setup Request == Non UE-related procedure -> stream 0 */ +// if (stream != 0) { +// LOG_W(M3AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", +// assoc_id, stream); +// } +// + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + +// if(1){ +// MCE_send_MBMS_SESSION_START_RESPONSE(instance,assoc_id); +// }else +// MCE_send_MBMS_SESSION_START_FAILURE(instance,assoc_id); + return 0; + +} + +int MCE_send_MBMS_SESSION_START_RESPONSE(instance_t instance, m3ap_session_start_resp_t * m3ap_session_start_resp){ + //AssertFatal(1==0,"Not implemented yet\n"); + +// module_id_t mce_mod_idP; +// module_id_t enb_mod_idP; +// +// // This should be fixed +// enb_mod_idP = (module_id_t)0; +// mce_mod_idP = (module_id_t)0; +// + M3AP_M3AP_PDU_t pdu; + M3AP_MBMSSessionStartResponse_t *out; + M3AP_MBMSSessionStartResponse_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M3AP_SuccessfulOutcome_t *)calloc(1, sizeof(M3AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M3AP_ProcedureCode_id_mBMSsessionStart; + pdu.choice.successfulOutcome.criticality = M3AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M3AP_SuccessfulOutcome__value_PR_MBMSSessionStartResponse; + out = &pdu.choice.successfulOutcome.value.choice.MBMSSessionStartResponse; + + + /* mandatory */ + /* c1. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStartResponse_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartResponse_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartResponse_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c1. MME_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStartResponse_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartResponse_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartResponse_IEs__value_PR_MME_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M3AP, "Failed to encode M3 SessionStart Response\n"); + return -1; + } +// +// +// LOG_W(M3AP,"pdu.present %d\n",pdu.present); +// // MSC_LOG_TX_MESSAGE( +// // MSC_M3AP_MCE, +// // MSC_M3AP_MCE, +// // (const char *)buffer, +// // len, +// // MSC_AS_TIME_FMT" M3_SETUP_REQUEST initiatingMessage MCEname %s", +// // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +// // m3ap_MCE_data_p->MCEname); +// + m3ap_MCE_itti_send_sctp_data_req(instance, m3ap_mce_data_g->assoc_id, buffer, len, 0); + return 0; +} + + +int MCE_send_MBMS_SESSION_START_FAILURE(instance_t instance, m3ap_session_start_failure_t * m3ap_session_start_failure){ +// module_id_t enb_mod_idP; +// module_id_t mce_mod_idP; +// +// // This should be fixed +// enb_mod_idP = (module_id_t)0; +// mce_mod_idP = (module_id_t)0; +// +// M3AP_M3AP_PDU_t pdu; +// M3AP_SessionStartFailure_t *out; +// M3AP_SessionStartFailure_Ies_t *ie; +// +// uint8_t *buffer; +// uint32_t len; +// +// /* Create */ +// /* 0. Message Type */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M3AP_M3AP_PDU_PR_unsuccessfulOutcome; +// //pdu.choice.unsuccessfulOutcome = (M3AP_UnsuccessfulOutcome_t *)calloc(1, sizeof(M3AP_UnsuccessfulOutcome_t)); +// pdu.choice.unsuccessfulOutcome.procedureCode = M3AP_ProcedureCode_id_sessionStart; +// pdu.choice.unsuccessfulOutcome.criticality = M3AP_Criticality_reject; +// pdu.choice.unsuccessfulOutcome.value.present = M3AP_UnsuccessfulOutcome__value_PR_SessionStartFailure; +// out = &pdu.choice.unsuccessfulOutcome.value.choice.SessionStartFailure; +// +// /* mandatory */ +// /* c1. Transaction ID (integer value)*/ +// // ie = (M3AP_M3SetupFailure_Ies_t *)calloc(1, sizeof(M3AP_M3SetupFailure_Ies_t)); +// // ie->id = M3AP_ProtocolIE_ID_id_GlobalMCE_ID; +// // ie->criticality = M3AP_Criticality_reject; +// // ie->value.present = M3AP_M3SetupFailure_Ies__value_PR_GlobalMCE_ID; +// // ie->value.choice.GlobalMCE_ID = M3AP_get_next_transaction_identifier(enb_mod_idP, mce_mod_idP); +// // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// /* c2. Cause */ +// ie = (M3AP_M3SetupFailure_Ies_t *)calloc(1, sizeof(M3AP_SessionStartFailure_Ies_t)); +// ie->id = M3AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M3AP_Criticality_ignore; +// ie->value.present = M3AP_SessionStartFailure_Ies__value_PR_Cause; +// ie->value.choice.Cause.present = M3AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = M3AP_CauseRadioNetwork_unspecified; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// +// /* encode */ +// if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// LOG_E(M3AP, "Failed to encode M3 setup request\n"); +// return -1; +// } +// +// //mce_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_enb->assoc_id, buffer, len, 0); +// m3ap_MCE_itti_send_sctp_data_req(instance,assoc_id,buffer,len,0); +// + + return 0; +} + +int MCE_handle_MBMS_SESSION_STOP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + + //AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M3AP, "MCE_handle_MBMS_SESSION_STOP_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M3AP_MBMSSessionStopRequest_t *container; + //M3AP_MBMSSessionStopRequest_IEs_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.MBMSSessionStopRequest; + + /* M3 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_W(M3AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + //if(1){ + //MCE_send_MBMS_SESSION_STOP_RESPONSE(instance,assoc_id); + //}else + //MCE_send_MBMS_SESSION_STOP_FAILURE(instance,assoc_id); + message_p = itti_alloc_new_message(TASK_M3AP_MCE, M3AP_MBMS_SESSION_STOP_REQ); + +// +// /* M3 Setup Request == Non UE-related procedure -> stream 0 */ +// if (stream != 0) { +// LOG_W(M3AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", +// assoc_id, stream); +// } +// + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + + return 0; + +} +int MCE_send_MBMS_SESSION_STOP_RESPONSE(instance_t instance, m3ap_session_start_resp_t * m3ap_session_start_resp){ +// module_id_t mce_mod_idP; +// module_id_t enb_mod_idP; +// +// // This should be fixed +// enb_mod_idP = (module_id_t)0; +// mce_mod_idP = (module_id_t)0; +// + M3AP_M3AP_PDU_t pdu; + M3AP_MBMSSessionStopResponse_t *out; + M3AP_MBMSSessionStopResponse_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M3AP_SuccessfulOutcome_t *)calloc(1, sizeof(M3AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M3AP_ProcedureCode_id_mBMSsessionStop; + pdu.choice.successfulOutcome.criticality = M3AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M3AP_SuccessfulOutcome__value_PR_MBMSSessionStopResponse; + out = &pdu.choice.successfulOutcome.value.choice.MBMSSessionStopResponse; + + + /* mandatory */ + /* c1. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStopResponse_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStopResponse_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStopResponse_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c1. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStopResponse_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStopResponse_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStopResponse_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M3AP, "Failed to encode M3 SessionStop Response\n"); + return -1; + } + + + LOG_D(M3AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M3AP_MCE, + // MSC_M3AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M3_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m3ap_MCE_data_p->MCEname); + + m3ap_MCE_itti_send_sctp_data_req(instance, m3ap_mce_data_g->assoc_id, buffer, len, 0); + return 0; +} + +/* + * Session Update + */ +int MCE_handle_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) +{ + //AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M3AP, "MCE_handle_MBMS_SESSION_UPDATE_REQUEST assoc_id %d\n",assoc_id); + + MessageDef *message_p; + //M3AP_MBMSSessionUpdateRequest_t *container; + //M3AP_MBMSSessionUpdateRequest_IEs_t *ie; + //int i = 0; + + DevAssert(pdu != NULL); + + //container = &pdu->choice.initiatingMessage.value.choice.MBMSSessionUpdateRequest; + + /* M3 Setup Request == Non UE-related procedure -> stream 0 */ + if (stream != 0) { + LOG_D(M3AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", + assoc_id, stream); + } + + //if(1){ + //MCE_send_MBMS_SESSION_STOP_RESPONSE(instance,assoc_id); + //}else + //MCE_send_MBMS_SESSION_STOP_FAILURE(instance,assoc_id); + message_p = itti_alloc_new_message(TASK_M3AP_MCE, M3AP_MBMS_SESSION_UPDATE_REQ); + +// +// /* M3 Setup Request == Non UE-related procedure -> stream 0 */ +// if (stream != 0) { +// LOG_W(M3AP, "[SCTP %d] Received MMBS session start request on stream != 0 (%d)\n", +// assoc_id, stream); +// } +// + + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); + + + + + return 0; +} + +int MCE_send_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, m3ap_mbms_session_update_resp_t * m3ap_mbms_session_update_resp){ + M3AP_M3AP_PDU_t pdu; + M3AP_MBMSSessionUpdateResponse_t *out; + M3AP_MBMSSessionUpdateResponse_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M3AP_SuccessfulOutcome_t *)calloc(1, sizeof(M3AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M3AP_ProcedureCode_id_mBMSsessionUpdate; + pdu.choice.successfulOutcome.criticality = M3AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M3AP_SuccessfulOutcome__value_PR_MBMSSessionUpdateResponse; + out = &pdu.choice.successfulOutcome.value.choice.MBMSSessionUpdateResponse; + + + /* mandatory */ + /* c1. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionUpdateResponse_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateResponse_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateResponse_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c1. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionUpdateResponse_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateResponse_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateResponse_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M3AP, "Failed to encode M3 SessionUpdate Response\n"); + return -1; + } + + + LOG_D(M3AP,"pdu.present %d\n",pdu.present); + // MSC_LOG_TX_MESSAGE( + // MSC_M3AP_MCE, + // MSC_M3AP_MCE, + // (const char *)buffer, + // len, + // MSC_AS_TIME_FMT" M3_SETUP_REQUEST initiatingMessage MCEname %s", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // m3ap_MCE_data_p->MCEname); + + m3ap_MCE_itti_send_sctp_data_req(instance, m3ap_mce_data_g->assoc_id, buffer, len, 0); + return 0; +} +int MCE_send_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, m3ap_mbms_session_update_failure_t * m3ap_mbms_session_update_failure){ + return 0; +} + +/* + M3 Setup +*/ + +//uint8_t m3ap_m3setup_message[] = {0x00,0x07,0x00,0x23,0x00,0x00,0x03,0x00,0x12,0x00,0x07,0x40,0x55,0xf5,0x01,0x00,0x25,0x00,0x00,0x13,0x40,0x0a,0x03,0x80,0x4d,0x33,0x2d,0x65,0x4e,0x42,0x33,0x37,0x00,0x14,0x00,0x03,0x01,0x00,0x01}; +uint8_t m3ap_m3setup_message[] = { + 0x00, 0x07, 0x00, 0x23, 0x00, 0x00, 0x03, 0x00, + 0x12, 0x00, 0x07, 0x40, 0x55, 0xf5, 0x01, 0x00, + 0x25, 0x00, 0x00, 0x13, 0x40, 0x0a, 0x03, 0x80, + 0x4d, 0x33, 0x2d, 0x65, 0x4e, 0x42, 0x33, 0x37, + 0x00, 0x14, 0x00, 0x03, 0x01, 0x00, 0x01 +}; + + +//uint8_t m3ap_start_message[] = { +// 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x07, 0x00, +// 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, +// 0x07, 0x00, 0x55, 0xf5, 0x01, 0x00, 0x00, 0x01, +// 0x00, 0x04, 0x00, 0x0d, 0x60, 0x01, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 0x01, +// 0x7a, 0x00, 0x05, 0x00, 0x03, 0x07, 0x08, 0x00, +// 0x00, 0x06, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, +// 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, +// 0x0e, 0x00, 0xe8, 0x0a, 0x0a, 0x0a, 0x00, 0x0a, +// 0xc8, 0x0a, 0xfe, 0x00, 0x00, 0x00, 0x01 +//}; +// +// SETUP REQUEST +int MCE_send_M3_SETUP_REQUEST(m3ap_MCE_instance_t *instance_p, m3ap_MCE_data_t *m3ap_MCE_data_p) { +// module_id_t enb_mod_idP=0; +// module_id_t du_mod_idP=0; +// + M3AP_M3AP_PDU_t pdu; + M3AP_M3SetupRequest_t *out; + M3AP_M3SetupRequestIEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + //int j = 0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_m3Setup; + pdu.choice.initiatingMessage.criticality = M3AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_M3SetupRequest; + out = &pdu.choice.initiatingMessage.value.choice.M3SetupRequest; + + /* mandatory */ + /* c1. GlobalMCE_ID (integer value) */ + ie = (M3AP_M3SetupRequestIEs_t *)calloc(1, sizeof(M3AP_M3SetupRequestIEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_Global_MCE_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_M3SetupRequestIEs__value_PR_Global_MCE_ID; + //ie->value.choice.GlobalMCE_ID.MCE_ID = 1;//M3AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP); + MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + &ie->value.choice.Global_MCE_ID.pLMN_Identity); + //ie->value.choice.Global_MCE_ID.MCE_ID.present = M3AP_MCE_ID_PR_macro_MCE_ID; + OCTET_STRING_fromBuf(&ie->value.choice.Global_MCE_ID.mCE_ID,"02",2); + + // MACRO_ENB_ID_TO_BIT_STRING(instance_p->MCE_id, + // &ie->value.choice.Global_MCE_ID.mCE_ID); + //M3AP_INFO("%d -> %02x%02x%02x\n", instance_p->MCE_id, + // ie->value.choice.Global_MCE_ID.mCE_ID.buf[0], + // ie->value.choice.Global_MCE_ID.mCE_ID.buf[1], + // ie->value.choice.Global_MCE_ID.mCE_ID.buf[2]); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// ///* mandatory */ +// ///* c2. GNB_MCE_ID (integrer value) */ +// //ie = (M3AP_M3SetupRequest_Ies_t *)calloc(1, sizeof(M3AP_M3SetupRequest_Ies_t)); +// //ie->id = M3AP_ProtocolIE_ID_id_gNB_MCE_ID; +// //ie->criticality = M3AP_Criticality_reject; +// //ie->value.present = M3AP_M3SetupRequestIEs__value_PR_GNB_MCE_ID; +// //asn_int642INTEGER(&ie->value.choice.GNB_MCE_ID, f1ap_du_data->gNB_MCE_id); +// //ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ + /* c3. MCEname */ + //m3ap_MCE_data_p->MCE_name="kk"; + if (m3ap_MCE_data_p->MCE_name != NULL) { + ie = (M3AP_M3SetupRequestIEs_t *)calloc(1, sizeof(M3AP_M3SetupRequestIEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCEname; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_M3SetupRequestIEs__value_PR_MCEname; + OCTET_STRING_fromBuf(&ie->value.choice.MCEname, m3ap_MCE_data_p->MCE_name, + strlen(m3ap_MCE_data_p->MCE_name)); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* mandatory */ //but removed from asn definition (optional) since it crashes when decoding ??????????? +// M3SetupRequestIEs M3AP-PROTOCOL-IES ::= { +// { ID id-Global-MCE-ID CRITICALITY reject TYPE Global-MCE-ID PRESENCE mandatory}| +// { ID id-MCEname CRITICALITY ignore TYPE MCEname PRESENCE optional}| +// { ID id-MBMSServiceAreaList CRITICALITY reject TYPE MBMSServiceAreaListItem PRESENCE mandatory}, --> optional ?????????? +// ... +// } + + + /* M3AP_MBMSServiceAreaListItem_t */ + ie = (M3AP_M3SetupRequestIEs_t *)calloc(1, sizeof(M3AP_M3SetupRequestIEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMSServiceAreaList; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_M3SetupRequestIEs__value_PR_MBMSServiceAreaListItem; + + //M3AP_MBMSServiceAreaListItem_t * m3ap_mbmsservicearealistitem = (M3AP_MBMSServiceAreaListItem_t*)calloc(1,sizeof(M3AP_MBMSServiceAreaListItem_t)); + + M3AP_MBMSServiceArea1_t * m3ap_mbmsservicearea1 = (M3AP_MBMSServiceArea1_t*)calloc(1,sizeof(M3AP_MBMSServiceArea1_t)); + + OCTET_STRING_fromBuf(m3ap_mbmsservicearea1,"02",2); + + //ASN_SEQUENCE_ADD(&m3ap_mbmsservicearealistitem->list,m3ap_mbmsservicearea1); + + //ASN_SEQUENCE_ADD(&ie->value.choice.MBMSServiceAreaListItem,m3ap_mbmsservicearealistitem); + //ASN_SEQUENCE_ADD(&ie->value.choice.MBMSServiceAreaListItem.list,m3ap_mbmsservicearealistitem); + ASN_SEQUENCE_ADD(&ie->value.choice.MBMSServiceAreaListItem.list,m3ap_mbmsservicearea1); + + //ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + +// +// /* mandatory */ +// /* c4. serverd cells list */ +// ie = (M3AP_M3SetupRequest_Ies_t *)calloc(1, sizeof(M3AP_M3SetupRequest_Ies_t)); +// ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_Configuration_data_List; +// ie->criticality = M3AP_Criticality_reject; +// ie->value.present = M3AP_M3SetupRequest_Ies__value_PR_MCE_MBMS_Configuration_data_List; +// +// int num_mbms_available = 1;//m3ap_du_data->num_mbms_available; +// LOG_D(M3AP, "num_mbms_available = %d \n", num_mbms_available); +// +// for (i=0; +// iid = M3AP_ProtocolIE_ID_id_MCE_MBMS_Configuration_data_Item; +// mbms_configuration_data_list_item_ies->criticality = M3AP_Criticality_reject; +// mbms_configuration_data_list_item_ies->value.present = M3AP_MCE_MBMS_Configuration_data_ItemIEs__value_PR_MCE_MBMS_Configuration_data_Item; +// +// M3AP_MCE_MBMS_Configuration_data_Item_t *mbms_configuration_data_item; +// mbms_configuration_data_item = &mbms_configuration_data_list_item_ies->value.choice.MCE_MBMS_Configuration_data_Item; +// { +// /* M3AP_ECGI_t eCGI */ +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &mbms_configuration_data_item->eCGI.pLMN_Identity); +// MACRO_MCE_ID_TO_CELL_IDENTITY(instance_p->MCE_id,0, +// &mbms_configuration_data_item->eCGI.eUTRANcellIdentifier); +// /* M3AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea */ +// mbms_configuration_data_item->mbsfnSynchronisationArea=10000; //? long +// /* M3AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList */ +// M3AP_MBMS_Service_Area_t * mbms_service_area,*mbms_service_area2; +// mbms_service_area = (M3AP_MBMS_Service_Area_t*)calloc(1,sizeof(M3AP_MBMS_Service_Area_t)); +// mbms_service_area2 = (M3AP_MBMS_Service_Area_t*)calloc(1,sizeof(M3AP_MBMS_Service_Area_t)); +// //memset(mbms_service_area,0,sizeof(OCTET_STRING_t)); +// OCTET_STRING_fromBuf(mbms_service_area,"01",2); +// ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area); +// OCTET_STRING_fromBuf(mbms_service_area2,"02",2); +// ASN_SEQUENCE_ADD(&mbms_configuration_data_item->mbmsServiceAreaList.list,mbms_service_area2); +// +// +// } +// +// +// //M3AP_MCE_MBMS_Configuration_data_Item_t mbms_configuration_data_item; +// //memset((void *)&mbms_configuration_data_item, 0, sizeof(M3AP_MCE_MBMS_Configuration_data_Item_t)); +// +// //M3AP_ECGI_t eCGI; +// //M3AP_PLMN_Identity_t pLMN_Identity; +// //M3AP_EUTRANCellIdentifier_t eUTRANcellIdentifier +// //M3AP_MBSFN_SynchronisationArea_ID_t mbsfnSynchronisationArea; +// //M3AP_MBMS_Service_Area_ID_List_t mbmsServiceAreaList; +// +// +// ASN_SEQUENCE_ADD(&ie->value.choice.MCE_MBMS_Configuration_data_List.list,mbms_configuration_data_list_item_ies); +// +// } +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// LOG_W(M3AP,"m3ap_MCE_data_p->assoc_id %d\n",m3ap_MCE_data_p->assoc_id); +// /* encode */ + +// xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, &pdu); +// xer_fprint(stdout, &asn_DEF_M3AP_M3SetupRequest, &pdu.choice.initiatingMessage.value.choice.M3SetupRequest); +// xer_fprint(stdout, &asn_DEF_M3AP_M3SetupRequest, out); + + if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M3AP, "Failed to encode M3 setup request\n"); + return -1; + } + + /* buffer = &m3ap_start_message[0]; + len=8*9+7; + + buffer = &m3ap_m3setup_message[0]; + len=8*4+7; */ +// +// +// LOG_W(M3AP,"pdu.present %d\n",pdu.present); +// // MSC_LOG_TX_MESSAGE( +// // MSC_M3AP_MCE, +// // MSC_M3AP_MCE, +// // (const char *)buffer, +// // len, +// // MSC_AS_TIME_FMT" M3_SETUP_REQUEST initiatingMessage MCEname %s", +// // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +// // m3ap_MCE_data_p->MCEname); +// +// +//// buffer = &bytes[0]; +//// len = 40; +//// +//// for(int i=0; i < len; i++ ) +//// printf("%02X",buffer[i]); +//// printf("\n"); +//// + +// M3AP_M3AP_PDU_t pdu2; +// +// memset(&pdu2, 0, sizeof(pdu2)); +// +// for( i=0; i < len; i++) +// printf("%02X",buffer[i]); +// printf("\n"); +// +// if (m3ap_decode_pdu(&pdu2, buffer, len) < 0) { +// LOG_E(M3AP, "Failed to decode PDU\n"); +// //return -1; +// } +// + + //printf("m3ap_MCE_data_p->assoc_id %d\n",m3ap_MCE_data_p->assoc_id); + m3ap_MCE_itti_send_sctp_data_req(instance_p->instance, m3ap_MCE_data_p->assoc_id, buffer, len, 0); + + return 0; +} + + + +int MCE_handle_M3_SETUP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) +{ + + LOG_D(M3AP, "MCE_handle_M3_SETUP_RESPONSE\n"); + + AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome, + "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M3AP_ProcedureCode_id_m3Setup, + "pdu->choice.successfulOutcome.procedureCode != M3AP_ProcedureCode_id_M3Setup\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M3AP_Criticality_reject, + "pdu->choice.successfulOutcome.criticality != M3AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M3AP_SuccessfulOutcome__value_PR_M3SetupResponse, + "pdu->choice.successfulOutcome.value.present != M3AP_SuccessfulOutcome__value_PR_M3SetupResponse\n"); + + //M3AP_M3SetupResponse_t *in = &pdu->choice.successfulOutcome.value.choice.M3SetupResponse; + + + //M3AP_M3SetupResponseIEs_t *ie; + //int GlobalMCE_ID = -1; + //int num_cells_to_activate = 0; + //M3AP_Cells_to_be_Activated_List_Item_t *cell; + + MessageDef *msg_p = itti_alloc_new_message (TASK_M3AP_MCE, M3AP_SETUP_RESP); + + // LOG_D(M3AP, "M3AP: M3Setup-Resp: protocolIEs.list.count %d\n", + // in->protocolIEs.list.count); + // for (int i=0;i < in->protocolIEs.list.count; i++) { + // ie = in->protocolIEs.list.array[i]; + // } + //AssertFatal(GlobalMCE_ID!=-1,"GlobalMCE_ID was not sent\n"); + //AssertFatal(num_cells_to_activate>0,"No cells activated\n"); + //M3AP_SETUP_RESP (msg_p).num_cells_to_activate = num_cells_to_activate; + + //for (int i=0;i 0, "System Information %d is missing",i); + + //MSC_LOG_RX_MESSAGE( + // MSC_M3AP_MCE, + // MSC_M3AP_CU, + // 0, + // 0, + // MSC_AS_TIME_FMT" MCE_handle_M3_SETUP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + //LOG_D(M3AP, "Sending M3AP_SETUP_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n", + // assoc_id,MCE_MOMCELE_ID_TO_INSTANCE(assoc_id)); + itti_send_msg_to_task(TASK_MCE_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + return 0; +} + +// SETUP FAILURE +int MCE_handle_M3_SETUP_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) { + LOG_E(M3AP, "MCE_handle_M3_SETUP_FAILURE\n"); + return 0; +} + + + + + diff --git a/openair3/M3AP/m3ap_MCE_interface_management.h b/openair3/M3AP/m3ap_MCE_interface_management.h new file mode 100644 index 0000000000..76e13bb8d8 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_interface_management.h @@ -0,0 +1,119 @@ +/* + * 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 m3ap_MCE_interface_management.h + * \brief m3ap interface management for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#ifndef M3AP_MCE_INTERFACE_MANAGEMENT_H_ +#define M3AP_MCE_INTERFACE_MANAGEMENT_H_ + +/* + * Session Start + */ + +int MCE_handle_MBMS_SESSION_START_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); +int MCE_send_MBMS_SESSION_START_RESPONSE(instance_t instance, m3ap_session_start_resp_t * m3ap_session_start_resp); +int MCE_send_MBMS_SESSION_START_FAILURE(instance_t instance, m3ap_session_start_failure_t * m3ap_session_start_failure); + +/* + * Session Stop + */ + +int MCE_handle_MBMS_SESSION_STOP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +/* + * Session Update + */ +int MCE_handle_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +int MCE_send_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, m3ap_mbms_session_update_resp_t * m3ap_mbms_session_update_resp); +int MCE_send_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, m3ap_mbms_session_update_failure_t * m3ap_mbms_session_update_failure); + + + + + + + +int MCE_send_MBMS_SESSION_STOP_RESPONSE(instance_t instance, m3ap_session_start_resp_t * m3ap_session_start_resp); + +/* + * Reset + */ +int MCE_handle_RESET(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); +int MCE_send_RESET_ACKKNOWLEDGE(instance_t instance, M3AP_ResetAcknowledge_t *ResetAcknowledge); +int MCE_send_RESET(instance_t instance, M3AP_Reset_t *Reset); +int MCE_handle_RESET_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +/* + * M3AP Setup + */ +int MCE_send_M3_SETUP_REQUEST( m3ap_MCE_instance_t *instance_p, m3ap_MCE_data_t *m3ap_MCE_data_p); + +int MCE_handle_M3_SETUP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +int MCE_handle_M3_SETUP_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +/* + * Error Indication + */ +int MCE_send_ERROR_INDICATION(instance_t instance, M3AP_M3AP_PDU_t *pdu_p); +int MCE_handle_ERROR_INDICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + + + + +#endif /* M3AP_MCE_INTERFACE_MANAGEMENT_H_ */ + + + diff --git a/openair3/M3AP/m3ap_MCE_management_procedures.c b/openair3/M3AP/m3ap_MCE_management_procedures.c new file mode 100644 index 0000000000..32901ca869 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_management_procedures.c @@ -0,0 +1,257 @@ +/* + * 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 m3ap_MCE_management_procedures.c + * \brief m3ap tasks for MCE + * \author Javier Morgade + * \date 2018 + * \version 1.0 + */ + +#include +#include +#include + +#include "intertask_interface.h" + +#include "assertions.h" +#include "conversions.h" + +#include "m3ap_common.h" +#include "m3ap_MCE_defs.h" +#include "m3ap_MCE.h" + + +#define M3AP_DEBUG_LIST +#ifdef M3AP_DEBUG_LIST +# define M3AP_MCE_LIST_OUT(x, args...) M3AP_DEBUG("[MCE]%*s"x"\n", 4*indent, "", ##args) +#else +# define M3AP_MCE_LIST_OUT(x, args...) +#endif + +static int indent = 0; + + +m3ap_MCE_internal_data_t m3ap_MCE_internal_data; + +RB_GENERATE(m3ap_mce_map, m3ap_MCE_data_s, entry, m3ap_MCE_compare_assoc_id); + +int m3ap_MCE_compare_assoc_id( + struct m3ap_MCE_data_s *p1, struct m3ap_MCE_data_s *p2) +{ + if (p1->assoc_id == -1) { + if (p1->cnx_id < p2->cnx_id) { + return -1; + } + + if (p1->cnx_id > p2->cnx_id) { + return 1; + } + } else { + if (p1->assoc_id < p2->assoc_id) { + return -1; + } + + if (p1->assoc_id > p2->assoc_id) { + return 1; + } + } + + /* Matching reference */ + return 0; +} + +uint16_t m3ap_MCE_fetch_add_global_cnx_id(void) +{ + return ++m3ap_MCE_internal_data.global_cnx_id; +} + +void m3ap_MCE_prepare_internal_data(void) +{ + memset(&m3ap_MCE_internal_data, 0, sizeof(m3ap_MCE_internal_data)); + STAILQ_INIT(&m3ap_MCE_internal_data.m3ap_MCE_instances_head); +} + +void m3ap_MCE_insert_new_instance(m3ap_MCE_instance_t *new_instance_p) +{ + DevAssert(new_instance_p != NULL); + + STAILQ_INSERT_TAIL(&m3ap_MCE_internal_data.m3ap_MCE_instances_head, + new_instance_p, m3ap_MCE_entries); +} + +void dump_tree_m3(m3ap_MCE_data_t *t) +{ + if (t == NULL) return; + printf("-----------------------\n"); + printf("MCE id %d %s\n", t->MCE_id, t->MCE_name); + printf("state %d\n", t->state); + printf("nextstream %d\n", t->nextstream); + printf("in_streams %d out_streams %d\n", t->in_streams, t->out_streams); + printf("cnx_id %d assoc_id %d\n", t->cnx_id, t->assoc_id); + dump_tree_m3(t->entry.rbe_left); + dump_tree_m3(t->entry.rbe_right); +} + +void dump_trees_m3(void) +{ +m3ap_MCE_instance_t *zz; +STAILQ_FOREACH(zz, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, + m3ap_MCE_entries) { +printf("here comes the tree (instance %d):\n---------------------------------------------\n", zz->instance); +dump_tree_m3(zz->m3ap_mce_head.rbh_root); +printf("---------------------------------------------\n"); +} +} + +struct m3ap_MCE_data_s *m3ap_get_MCE(m3ap_MCE_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id) +{ + struct m3ap_MCE_data_s temp; + struct m3ap_MCE_data_s *found; + +//printf("m3ap_get_MCE at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id); +//dump_trees_m3(); + + memset(&temp, 0, sizeof(struct m3ap_MCE_data_s)); + + temp.assoc_id = assoc_id; + temp.cnx_id = cnx_id; + + if (instance_p == NULL) { + STAILQ_FOREACH(instance_p, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, + m3ap_MCE_entries) { + found = RB_FIND(m3ap_mce_map, &instance_p->m3ap_mce_head, &temp); + + if (found != NULL) { + return found; + } + } + } else { + return RB_FIND(m3ap_mce_map, &instance_p->m3ap_mce_head, &temp); + } + + return NULL; +} + + +m3ap_MCE_instance_t *m3ap_MCE_get_instance(instance_t instance) +{ + m3ap_MCE_instance_t *temp = NULL; + + STAILQ_FOREACH(temp, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, + m3ap_MCE_entries) { + if (temp->instance == instance) { + /* Matching occurence */ + return temp; + } + } + + return NULL; +} + +/// utility functions + +void m3ap_dump_MCE (m3ap_MCE_data_t * MCE_ref); + +void +m3ap_dump_MCE_list (void) { + m3ap_MCE_instance_t *inst = NULL; + struct m3ap_MCE_data_s *found = NULL; + struct m3ap_MCE_data_s temp; + + memset(&temp, 0, sizeof(struct m3ap_MCE_data_s)); + + STAILQ_FOREACH (inst, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, m3ap_MCE_entries) { + found = RB_FIND(m3ap_mce_map, &inst->m3ap_mce_head, &temp); + m3ap_dump_MCE (found); + } +} + +void m3ap_dump_MCE (m3ap_MCE_data_t * MCE_ref) { + + if (MCE_ref == NULL) { + return; + } + + M3AP_MCE_LIST_OUT (""); + M3AP_MCE_LIST_OUT ("MCE name: %s", MCE_ref->MCE_name == NULL ? "not present" : MCE_ref->MCE_name); + M3AP_MCE_LIST_OUT ("MCE STATE: %07x", MCE_ref->state); + M3AP_MCE_LIST_OUT ("MCE ID: %07x", MCE_ref->MCE_id); + indent++; + M3AP_MCE_LIST_OUT ("SCTP cnx id: %d", MCE_ref->cnx_id); + M3AP_MCE_LIST_OUT ("SCTP assoc id: %d", MCE_ref->assoc_id); + M3AP_MCE_LIST_OUT ("SCTP instreams: %d", MCE_ref->in_streams); + M3AP_MCE_LIST_OUT ("SCTP outstreams: %d", MCE_ref->out_streams); + indent--; +} + +m3ap_MCE_data_t * m3ap_is_MCE_pci_in_list (const uint32_t pci) +{ + m3ap_MCE_instance_t *inst; + struct m3ap_MCE_data_s *elm; + + STAILQ_FOREACH(inst, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, m3ap_MCE_entries) { + RB_FOREACH(elm, m3ap_mce_map, &inst->m3ap_mce_head) { + for (int i = 0; inum_cc; i++) { + if (elm->Nid_cell[i] == pci) { + return elm; + } + } + } + } + return NULL; +} + +m3ap_MCE_data_t * m3ap_is_MCE_id_in_list (const uint32_t MCE_id) +{ + m3ap_MCE_instance_t *inst; + struct m3ap_MCE_data_s *elm; + + STAILQ_FOREACH(inst, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, m3ap_MCE_entries) { + RB_FOREACH(elm, m3ap_mce_map, &inst->m3ap_mce_head) { + if (elm->MCE_id == MCE_id) + return elm; + } + } + return NULL; +} + +m3ap_MCE_data_t * m3ap_is_MCE_assoc_id_in_list (const uint32_t sctp_assoc_id) +{ + m3ap_MCE_instance_t *inst; + struct m3ap_MCE_data_s *found; + struct m3ap_MCE_data_s temp; + + temp.assoc_id = sctp_assoc_id; + temp.cnx_id = -1; + + STAILQ_FOREACH(inst, &m3ap_MCE_internal_data.m3ap_MCE_instances_head, m3ap_MCE_entries) { + found = RB_FIND(m3ap_mce_map, &inst->m3ap_mce_head, &temp); + if (found != NULL){ + if (found->assoc_id == sctp_assoc_id) { + return found; + } + } + } + return NULL; +} diff --git a/openair3/M3AP/m3ap_MCE_management_procedures.h b/openair3/M3AP/m3ap_MCE_management_procedures.h new file mode 100644 index 0000000000..2d18df8c26 --- /dev/null +++ b/openair3/M3AP/m3ap_MCE_management_procedures.h @@ -0,0 +1,53 @@ +/* + * 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 m3ap_MCE_management_procedures.h + * \brief m3ap tasks for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M3AP_MCE_MANAGEMENT_PROCEDURES_H_ +#define M3AP_MCE_MANAGEMENT_PROCEDURES_H + +void m3ap_MCE_prepare_internal_data(void); + +void dump_trees_m3(void); + +void m3ap_MCE_insert_new_instance(m3ap_MCE_instance_t *new_instance_p); + +m3ap_MCE_instance_t *m3ap_MCE_get_instance(uint8_t mod_id); + +uint16_t m3ap_MCE_fetch_add_global_cnx_id(void); + + +m3ap_MCE_data_t* m3ap_is_MCE_id_in_list(uint32_t MCE_id); + +m3ap_MCE_data_t* m3ap_is_MCE_assoc_id_in_list(uint32_t sctp_assoc_id); + +m3ap_MCE_data_t* m3ap_is_MCE_pci_in_list (const uint32_t pci); + +struct m3ap_MCE_data_s *m3ap_get_MCE(m3ap_MCE_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id); + +#endif /* M3AP_MCE_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair3/M3AP/m3ap_MME.c b/openair3/M3AP/m3ap_MME.c new file mode 100644 index 0000000000..fbfe6e1327 --- /dev/null +++ b/openair3/M3AP/m3ap_MME.c @@ -0,0 +1,730 @@ +/* + * 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 m3ap_MME.c + * \brief m3ap tasks for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include +#include +#include +#include + +#include "intertask_interface.h" + +#include "m3ap_MME.h" +#include "m3ap_MME_defs.h" +#include "m3ap_MME_management_procedures.h" +#include "m3ap_MME_handler.h" +//#include "m3ap_MME_generate_messages.h" +#include "m3ap_common.h" +#include "m3ap_MME_interface_management.h" +#include "m3ap_ids.h" +#include "m3ap_timers.h" + +#include "queue.h" +#include "assertions.h" +#include "conversions.h" + +struct m3ap_mme_map; +struct m3ap_MME_data_s; + +m3ap_setup_req_t *m3ap_mme_data_from_mce; + +RB_PROTOTYPE(m3ap_mme_map, m3ap_MME_data_s, entry, m3ap_MME_compare_assoc_id); + +static +void m3ap_MME_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind); + +static +void m3ap_MME_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp); + +static +void m3ap_MME_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind); + +//static +//void m3ap_MME_handle_register_MME(instance_t instance, +// m3ap_register_mce_req_t *m3ap_register_MME); +static +void m3ap_MME_register_MME(m3ap_MME_instance_t *instance_p, + net_ip_address_t *target_MME_ip_addr, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t mme_port_for_M3C, + int multi_sd); + +//static +//void m3ap_MME_handle_handover_req(instance_t instance, +// m3ap_handover_req_t *m3ap_handover_req); +// +//static +//void m3ap_MME_handle_handover_req_ack(instance_t instance, +// m3ap_handover_req_ack_t *m3ap_handover_req_ack); +// +//static +//void m3ap_MME_ue_context_release(instance_t instance, +// m3ap_ue_context_release_t *m3ap_ue_context_release); +// + +static +void m3ap_MME_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) { + int result; + DevAssert(sctp_data_ind != NULL); + m3ap_MME_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream, + sctp_data_ind->buffer, sctp_data_ind->buffer_length); + result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +} + +static +void m3ap_MME_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { + + DevAssert(sctp_new_association_resp != NULL); + + if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + LOG_W(M3AP, "Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n", + sctp_new_association_resp->sctp_state, + instance, + sctp_new_association_resp->ulp_cnx_id); + + if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) + //proto_agent_stop(instance); + //f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); + return; // exit -1 for debugging + } + + // go to an init func + m3ap_mme_data_from_mce = (m3ap_setup_req_t *)calloc(1, sizeof(m3ap_setup_req_t)); + // save the assoc id + m3ap_mme_data_from_mce->assoc_id = sctp_new_association_resp->assoc_id; + m3ap_mme_data_from_mce->sctp_in_streams = sctp_new_association_resp->in_streams; + m3ap_mme_data_from_mce->sctp_out_streams = sctp_new_association_resp->out_streams; + + + + // m3ap_MME_instance_t *instance_p; + // m3ap_MME_data_t *m3ap_mme_data_p; + // DevAssert(sctp_new_association_resp != NULL); + // printf("m3ap_MME_handle_sctp_association_resp at 1\n"); + // dump_mme_trees_m3(); + // instance_p = instance;//m3ap_MME_get_instance(instance); + // DevAssert(instance_p != NULL); + + // /* if the assoc_id is already known, it is certainly because an IND was received + // * before. In this case, just update streams and return + // */ + // if (sctp_new_association_resp->assoc_id != -1) { + // m3ap_mme_data_p = m3ap_get_MME(instance_p, sctp_new_association_resp->assoc_id, + // sctp_new_association_resp->ulp_cnx_id); + + // if (m3ap_mme_data_p != NULL) { + // /* some sanity check - to be refined at some point */ + // if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + // M3AP_ERROR("m3ap_mme_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n"); + // abort(); + // } + + // m3ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams; + // m3ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams; + // return; + // } + // } + + // m3ap_mme_data_p = m3ap_get_MME(instance_p, -1, + // sctp_new_association_resp->ulp_cnx_id); + // DevAssert(m3ap_mme_data_p != NULL); + // printf("m3ap_MME_handle_sctp_association_resp at 2\n"); + // dump_mme_trees_m3(); + + // if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { + // M3AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n", + // sctp_new_association_resp->sctp_state, + // instance, + // sctp_new_association_resp->ulp_cnx_id); + // //m3ap_eNB_handle_m3_setup_message(instance_p, m3ap_mme_data_p, + // //sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); + // return; + // } + + // printf("m3ap_MME_handle_sctp_association_resp at 3\n"); + // dump_mme_trees_m3(); + // /* Update parameters */ + // m3ap_mme_data_p->assoc_id = sctp_new_association_resp->assoc_id; + // m3ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams; + // m3ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams; + // printf("m3ap_MME_handle_sctp_association_resp at 4\n"); + // dump_mme_trees_m3(); + // /* Prepare new m3 Setup Request */ + // //m3ap_MME_generate_m3_setup_request(instance_p, m3ap_mme_data_p); +} + +static +void m3ap_MME_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind) { + //m3ap_MME_instance_t *instance_p; + //m3ap_MME_data_t *m3ap_mme_data_p; + //printf("m3ap_MME_handle_sctp_association_ind at 1 (called for instance %d)\n", instance); + ///dump_mme_trees_m3(); + ///DevAssert(sctp_new_association_ind != NULL); + ///instance_p = instance;//m3ap_MME_get_instance(instance); + ///DevAssert(instance_p != NULL); + ///m3ap_mme_data_p = m3ap_get_MME(instance_p, sctp_new_association_ind->assoc_id, -1); + + ///if (m3ap_mme_data_p != NULL) abort(); + + ///// DevAssert(m3ap_enb_data_p != NULL); + ///if (m3ap_mme_data_p == NULL) { + /// /* Create new MME descriptor */ + /// m3ap_mme_data_p = calloc(1, sizeof(*m3ap_mme_data_p)); + /// DevAssert(m3ap_mme_data_p != NULL); + /// m3ap_mme_data_p->cnx_id = m3ap_MME_fetch_add_global_cnx_id(); + /// m3ap_mme_data_p->m3ap_MME_instance = instance_p; + /// /* Insert the new descriptor in list of known MME + /// * but not yet associated. + /// */ + /// RB_INSERT(m3ap_mme_map, &instance_p->m3ap_mme_head, m3ap_mme_data_p); + /// m3ap_mme_data_p->state = M3AP_MME_STATE_CONNECTED; + /// instance_p->m3_target_mme_nb++; + + /// if (instance_p->m3_target_mme_pending_nb > 0) { + /// instance_p->m3_target_mme_pending_nb--; + /// } + ///} else { + /// M3AP_WARN("m3ap_mme_data_p already exists\n"); + ///} + + ///printf("m3ap_MME_handle_sctp_association_ind at 2\n"); + ///dump_mme_trees_m3(); + ////* Update parameters */ + ///m3ap_mme_data_p->assoc_id = sctp_new_association_ind->assoc_id; + ///m3ap_mme_data_p->in_streams = sctp_new_association_ind->in_streams; + ///m3ap_mme_data_p->out_streams = sctp_new_association_ind->out_streams; + ///printf("m3ap_MME_handle_sctp_association_ind at 3\n"); + ///dump_mme_trees_m3(); +} + +int m3ap_MME_init_sctp (m3ap_MME_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t mme_port_for_M3C) { + // Create and alloc new message + MessageDef *message; + sctp_init_t *sctp_init = NULL; + DevAssert(instance_p != NULL); + DevAssert(local_ip_addr != NULL); + message = itti_alloc_new_message (TASK_M3AP_MME, SCTP_INIT_MSG_MULTI_REQ); + sctp_init = &message->ittiMsg.sctp_init_multi; + sctp_init->port = mme_port_for_M3C; + sctp_init->ppid = M3AP_SCTP_PPID; + sctp_init->ipv4 = 1; + sctp_init->ipv6 = 0; + sctp_init->nb_ipv4_addr = 1; +#if 0 + memcpy(&sctp_init->ipv4_address, + local_ip_addr, + sizeof(*local_ip_addr)); +#endif + sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address); + /* + * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * * * * Disable it for now. + */ + sctp_init->nb_ipv6_addr = 0; + sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1"; + return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message); +} + +static void m3ap_MME_register_MME(m3ap_MME_instance_t *instance_p, + net_ip_address_t *target_MME_ip_address, + net_ip_address_t *local_ip_addr, + uint16_t in_streams, + uint16_t out_streams, + uint32_t mme_port_for_M3C, + int multi_sd) { + // MessageDef *message = NULL; + // sctp_new_association_req_multi_t *sctp_new_association_req = NULL; + // m3ap_MME_data_t *m3ap_mme_data = NULL; + // DevAssert(instance_p != NULL); + // DevAssert(target_MME_ip_address != NULL); + // message = itti_alloc_new_message(TASK_M3AP_MME, SCTP_NEW_ASSOCIATION_REQ_MULTI); + // sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi; + // sctp_new_association_req->port = mme_port_for_M3C; + // sctp_new_association_req->ppid = M3AP_SCTP_PPID; + // sctp_new_association_req->in_streams = in_streams; + // sctp_new_association_req->out_streams = out_streams; + // sctp_new_association_req->multi_sd = multi_sd; + // memcpy(&sctp_new_association_req->remote_address, + // target_MME_ip_address, + // sizeof(*target_MME_ip_address)); + // memcpy(&sctp_new_association_req->local_address, + // local_ip_addr, + // sizeof(*local_ip_addr)); + // /* Create new MME descriptor */ + // m3ap_mme_data = calloc(1, sizeof(*m3ap_mme_data)); + // DevAssert(m3ap_mme_data != NULL); + // m3ap_mme_data->cnx_id = m3ap_MME_fetch_add_global_cnx_id(); + // sctp_new_association_req->ulp_cnx_id = m3ap_mme_data->cnx_id; + // m3ap_mme_data->assoc_id = -1; + // m3ap_mme_data->m3ap_MME_instance = instance_p; + // /* Insert the new descriptor in list of known MME + // * but not yet associated. + // */ + // RB_INSERT(m3ap_mme_map, &instance_p->m3ap_mme_head, m3ap_mme_data); + // m3ap_mme_data->state = M3AP_MME_STATE_WAITING; + // instance_p->m3_target_mme_nb ++; + // instance_p->m3_target_mme_pending_nb ++; + // itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message); +} + +//static +//void m3ap_MME_handle_register_MME(instance_t instance, +// m3ap_register_mce_req_t *m3ap_register_MME) { +// m3ap_MME_instance_t *new_instance; +// DevAssert(m3ap_register_MME != NULL); +// /* Look if the provided instance already exists */ +// new_instance = m3ap_MME_get_instance(instance); +// +// if (new_instance != NULL) { +// /* Checks if it is a retry on the same MME */ +// DevCheck(new_instance->MME_id == m3ap_register_MME->MME_id, new_instance->MME_id, m3ap_register_MME->MME_id, 0); +// DevCheck(new_instance->cell_type == m3ap_register_MME->cell_type, new_instance->cell_type, m3ap_register_MME->cell_type, 0); +// DevCheck(new_instance->tac == m3ap_register_MME->tac, new_instance->tac, m3ap_register_MME->tac, 0); +// DevCheck(new_instance->mcc == m3ap_register_MME->mcc, new_instance->mcc, m3ap_register_MME->mcc, 0); +// DevCheck(new_instance->mnc == m3ap_register_MME->mnc, new_instance->mnc, m3ap_register_MME->mnc, 0); +// M3AP_WARN("MME[%d] already registered\n", instance); +// } else { +// new_instance = calloc(1, sizeof(m3ap_MME_instance_t)); +// DevAssert(new_instance != NULL); +// RB_INIT(&new_instance->m3ap_mme_head); +// /* Copy usefull parameters */ +// new_instance->instance = instance; +// new_instance->MME_name = m3ap_register_MME->MME_name; +// new_instance->MME_id = m3ap_register_MME->MME_id; +// new_instance->cell_type = m3ap_register_MME->cell_type; +// new_instance->tac = m3ap_register_MME->tac; +// new_instance->mcc = m3ap_register_MME->mcc; +// new_instance->mnc = m3ap_register_MME->mnc; +// new_instance->mnc_digit_length = m3ap_register_MME->mnc_digit_length; +// new_instance->num_cc = m3ap_register_MME->num_cc; +// +// m3ap_id_manager_init(&new_instance->id_manager); +// m3ap_timers_init(&new_instance->timers, +// m3ap_register_MME->t_reloc_prep, +// m3ap_register_MME->tm3_reloc_overall); +// +// for (int i = 0; i< m3ap_register_MME->num_cc; i++) { +// new_instance->eutra_band[i] = m3ap_register_MME->eutra_band[i]; +// new_instance->downlink_frequency[i] = m3ap_register_MME->downlink_frequency[i]; +// new_instance->uplink_frequency_offset[i] = m3ap_register_MME->uplink_frequency_offset[i]; +// new_instance->Nid_cell[i] = m3ap_register_MME->Nid_cell[i]; +// new_instance->N_RB_DL[i] = m3ap_register_MME->N_RB_DL[i]; +// new_instance->frame_type[i] = m3ap_register_MME->frame_type[i]; +// new_instance->fdd_earfcn_DL[i] = m3ap_register_MME->fdd_earfcn_DL[i]; +// new_instance->fdd_earfcn_UL[i] = m3ap_register_MME->fdd_earfcn_UL[i]; +// } +// +// DevCheck(m3ap_register_MME->nb_m3 <= M3AP_MAX_NB_MME_IP_ADDRESS, +// M3AP_MAX_NB_MME_IP_ADDRESS, m3ap_register_MME->nb_m3, 0); +// memcpy(new_instance->target_mme_m3_ip_address, +// m3ap_register_MME->target_mme_m3_ip_address, +// m3ap_register_MME->nb_m3 * sizeof(net_ip_address_t)); +// new_instance->nb_m3 = m3ap_register_MME->nb_m3; +// new_instance->mme_m3_ip_address = m3ap_register_MME->mme_m3_ip_address; +// new_instance->sctp_in_streams = m3ap_register_MME->sctp_in_streams; +// new_instance->sctp_out_streams = m3ap_register_MME->sctp_out_streams; +// new_instance->mme_port_for_M3C = m3ap_register_MME->mme_port_for_M3C; +// /* Add the new instance to the list of MME (meaningfull in virtual mode) */ +// m3ap_MME_insert_new_instance(new_instance); +// M3AP_INFO("Registered new MME[%d] and %s MME id %u\n", +// instance, +// m3ap_register_MME->cell_type == CELL_MACRO_ENB ? "macro" : "home", +// m3ap_register_MME->MME_id); +// +// /* initiate the SCTP listener */ +// if (m3ap_MME_init_sctp(new_instance,&m3ap_register_MME->mme_m3_ip_address,m3ap_register_MME->mme_port_for_M3C) < 0 ) { +// M3AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n"); +// return; +// } +// +// M3AP_INFO("MME[%d] MME id %u acting as a listner (server)\n", +// instance, m3ap_register_MME->MME_id); +// } +//} + +static +void m3ap_MME_handle_sctp_init_msg_multi_cnf( + instance_t instance_id, + sctp_init_msg_multi_cnf_t *m) { + m3ap_MME_instance_t *instance; + int index; + DevAssert(m != NULL); + instance = m3ap_MME_get_instance(instance_id); + DevAssert(instance != NULL); + instance->multi_sd = m->multi_sd; + + /* Exit if CNF message reports failure. + * Failure means multi_sd < 0. + */ + if (instance->multi_sd < 0) { + M3AP_ERROR("Error: be sure to properly configure M2 in your configuration file.\n"); + DevAssert(instance->multi_sd >= 0); + } + + /* Trying to connect to the provided list of MME ip address */ + + for (index = 0; index < instance->nb_m3; index++) { + M3AP_INFO("MME[%d] MME id %u acting as an initiator (client)\n", + instance_id, instance->MME_id); + m3ap_MME_register_MME(instance, + &instance->target_mme_m3_ip_address[index], + &instance->mme_m3_ip_address, + instance->sctp_in_streams, + instance->sctp_out_streams, + instance->mme_port_for_M3C, + instance->multi_sd); + } +} + +//static +//void m3ap_MME_handle_handover_req(instance_t instance, +// m3ap_handover_req_t *m3ap_handover_req) +//{ +// m3ap_MME_instance_t *instance_p; +// m3ap_MME_data_t *target; +// m3ap_id_manager *id_manager; +// int ue_id; +// +// int target_pci = m3ap_handover_req->target_physCellId; +// +// instance_p = m3ap_MME_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m3ap_is_MME_pci_in_list(target_pci); +// DevAssert(target != NULL); +// +// /* allocate m3ap ID */ +// id_manager = &instance_p->id_manager; +// ue_id = m3ap_allocate_new_id(id_manager); +// if (ue_id == -1) { +// M3AP_ERROR("could not allocate a new M3AP UE ID\n"); +// /* TODO: cancel handover: send (to be defined) message to RRC */ +// exit(1); +// } +// /* id_source is ue_id, id_target is unknown yet */ +// m3ap_set_ids(id_manager, ue_id, m3ap_handover_req->rnti, ue_id, -1); +// m3ap_id_set_state(id_manager, ue_id, M2ID_STATE_SOURCE_PREPARE); +// m3ap_set_reloc_prep_timer(id_manager, ue_id, +// m3ap_timer_get_tti(&instance_p->timers)); +// m3ap_id_set_target(id_manager, ue_id, target); +// +// m3ap_MME_generate_m3_handover_request(instance_p, target, m3ap_handover_req, ue_id); +//} + +//static +//void m3ap_MME_handle_handover_req_ack(instance_t instance, +// m3ap_handover_req_ack_t *m3ap_handover_req_ack) +//{ +// /* TODO: remove this hack (the goal is to find the correct +// * eNodeB structure for the other end) - we need a proper way for RRC +// * and M3AP to identify eNodeBs +// * RRC knows about mod_id and M3AP knows about MME_id (MME_ID in +// * the configuration file) +// * as far as I understand.. CROUX +// */ +// m3ap_MME_instance_t *instance_p; +// m3ap_MME_data_t *target; +// int source_assoc_id = m3ap_handover_req_ack->source_assoc_id; +// int ue_id; +// int id_source; +// int id_target; +// +// instance_p = m3ap_MME_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m3ap_get_MME(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// /* rnti is a new information, save it */ +// ue_id = m3ap_handover_req_ack->m3_id_target; +// id_source = m3ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// m3ap_set_ids(&instance_p->id_manager, ue_id, m3ap_handover_req_ack->rnti, id_source, id_target); +// +// m3ap_MME_generate_m3_handover_request_ack(instance_p, target, m3ap_handover_req_ack); +//} +// +//static +//void m3ap_MME_ue_context_release(instance_t instance, +// m3ap_ue_context_release_t *m3ap_ue_context_release) +//{ +// m3ap_MME_instance_t *instance_p; +// m3ap_MME_data_t *target; +// int source_assoc_id = m3ap_ue_context_release->source_assoc_id; +// int ue_id; +// instance_p = m3ap_MME_get_instance(instance); +// DevAssert(instance_p != NULL); +// +// target = m3ap_get_MME(NULL, source_assoc_id, 0); +// DevAssert(target != NULL); +// +// m3ap_MME_generate_m3_ue_context_release(instance_p, target, m3ap_ue_context_release); +// +// /* free the M3AP UE ID */ +// ue_id = m3ap_find_id_from_rnti(&instance_p->id_manager, m3ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M3AP_ERROR("could not find UE %x\n", m3ap_ue_context_release->rnti); +// exit(1); +// } +// m3ap_release_id(&instance_p->id_manager, ue_id); +//} + +void MME_task_send_sctp_init_req(instance_t enb_id, m3ap_mme_sctp_req_t * m3ap_mme_sctp_req) { + // 1. get the itti msg, and retrive the enb_id from the message + // 2. use RC.rrc[enb_id] to fill the sctp_init_t with the ip, port + // 3. creat an itti message to init + + MessageDef *message_p = NULL; + + message_p = itti_alloc_new_message (TASK_M3AP_MME, SCTP_INIT_MSG); +if(m3ap_mme_sctp_req==NULL) { + LOG_I(M3AP, "M3AP_SCTP_REQ(create socket)\n"); + message_p->ittiMsg.sctp_init.port = M3AP_PORT_NUMBER; + message_p->ittiMsg.sctp_init.ppid = M3AP_SCTP_PPID; + message_p->ittiMsg.sctp_init.ipv4 = 1; + message_p->ittiMsg.sctp_init.ipv6 = 0; + message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1; + //message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr); + message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr("127.0.0.8"); + +}else{ + + LOG_I(M3AP, "M3AP_SCTP_REQ(create socket) %s\n",m3ap_mme_sctp_req->mme_m3_ip_address.ipv4_address); + message_p->ittiMsg.sctp_init.port = m3ap_mme_sctp_req->mme_port_for_M3C; + message_p->ittiMsg.sctp_init.ppid = M3AP_SCTP_PPID; + message_p->ittiMsg.sctp_init.ipv4 = 1; + message_p->ittiMsg.sctp_init.ipv6 = 0; + message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1; + //message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr); + message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(m3ap_mme_sctp_req->mme_m3_ip_address.ipv4_address); + } + + /* + * SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * * * * Disable it for now. + */ + message_p->ittiMsg.sctp_init.nb_ipv6_addr = 0; + message_p->ittiMsg.sctp_init.ipv6_address[0] = "0:0:0:0:0:0:0:1"; + + itti_send_msg_to_task(TASK_SCTP, enb_id, message_p); +} + +void *m3ap_MME_task(void *arg) { + MessageDef *received_msg = NULL; + int result; + M3AP_DEBUG("Starting M3AP layer\n"); + m3ap_MME_prepare_internal_data(); + itti_mark_task_ready(TASK_M3AP_MME); + + //MME_task_send_sctp_init_req(0,NULL); + + + while (1) { + itti_receive_msg(TASK_M3AP_MME, &received_msg); + + switch (ITTI_MSG_ID(received_msg)) { + case MESSAGE_TEST: + LOG_W(M3AP,"MME Received MESSAGE_TEST Message\n"); + //MessageDef * message_p = itti_alloc_new_message(TASK_M3AP_MME, MESSAGE_TEST); + //itti_send_msg_to_task(TASK_M3AP, 1/*ctxt_pP->module_id*/, message_p); + break; + case TERMINATE_MESSAGE: + M3AP_WARN(" *** Exiting M3AP thread\n"); + itti_exit_task(); + break; + +// case M3AP_SUBFRAME_PROCESS: +// m3ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg)); +// break; +// +// case M3AP_REGISTER_MME_REQ: +// LOG_W(M3AP,"MME Received M3AP_REGISTER_MME_REQ Message\n"); +// m3ap_MME_handle_register_MME(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_REGISTER_MME_REQ(received_msg)); +// break; +// + + case M3AP_MME_SCTP_REQ: + MME_task_send_sctp_init_req(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_MME_SCTP_REQ(received_msg)); + break; + + case M3AP_SETUP_RESP: + LOG_I(M3AP,"MME Received M3AP_SETUP_RESP Message\n"); + MME_send_M3_SETUP_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_SETUP_RESP(received_msg)); + break; +// break; +// +// case M3AP_SETUP_FAILURE: +// LOG_W(M3AP,"MME Received M3AP_SETUP_FAILURE Message\n"); +// MME_send_M2_SETUP_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_SETUP_FAILURE(received_msg)); +// break; +// +// case M3AP_MBMS_SCHEDULING_INFORMATION: +// LOG_W(M3AP,"MME Received M3AP_MBMS_SCHEDULING_INFORMATION Message\n"); +// MME_send_MBMS_SCHEDULING_INFORMATION(0, +// &M3AP_MBMS_SCHEDULING_INFORMATION(received_msg)); +// + case M3AP_MBMS_SESSION_START_REQ: + LOG_I(M3AP,"MME Received M3AP_MBMS_SESSION_START_REQ Message\n"); + MME_send_MBMS_SESSION_START_REQUEST(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_MBMS_SESSION_START_REQ(received_msg)); + break; +// + case M3AP_MBMS_SESSION_STOP_REQ: + LOG_I(M3AP,"MME Received M3AP_MBMS_SESSION_STOP_REQ Message\n"); + MME_send_MBMS_SESSION_STOP_REQUEST(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &M3AP_MBMS_SESSION_STOP_REQ(received_msg)); + break; +// + case M3AP_MBMS_SESSION_UPDATE_REQ: + LOG_I(M3AP,"MME Received M3AP_MBMS_SESSION_UPDATE_REQ Message\n"); + // MME_send_MBMS_SESSION_UPDATE_REQUEST(ITTI_MESSAGE_GET_INSTANCE(received_msg), + // &M3AP_MBMS_SESSION_UPDATE_REQ(received_msg)); + break; +// +// case M3AP_RESET: +// LOG_W(M3AP,"MME Received M3AP_RESET Message\n"); +// MME_send_RESET(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_RESET(received_msg)); +// break; +// +// case M3AP_ENB_CONFIGURATION_UPDATE_ACK: +// LOG_W(M3AP,"MME Received M3AP_ENB_CONFIGURATION_UPDATE_ACK Message\n"); +// MME_send_ENB_CONFIGURATION_UPDATE_ACKNOWLEDGE(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_ENB_CONFIGURATION_UPDATE_ACK(received_msg)); +// break; +// +// case M3AP_ENB_CONFIGURATION_UPDATE_FAILURE: +// LOG_W(M3AP,"MME Received M3AP_ENB_CONFIGURATION_UPDATE_FAILURE Message\n"); +// MME_send_ENB_CONFIGURATION_UPDATE_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_ENB_CONFIGURATION_UPDATE_FAILURE(received_msg))// break; +// +// +// case M3AP_MME_CONFIGURATION_UPDATE: +// LOG_W(M3AP,"MME Received M3AP_MME_CONFIGURATION_UPDATE Message\n"); +// MME_send_MME_CONFIGURATION_UPDATE(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_MME_CONFIGURATION_UPDATE(received_msg)); +// break; +// + +// case M3AP_HANDOVER_REQ: +// m3ap_MME_handle_handover_req(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_HANDOVER_REQ(received_msg)); +// break; +// +// case M3AP_HANDOVER_REQ_ACK: +// m3ap_MME_handle_handover_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_HANDOVER_REQ_ACK(received_msg)); +// break; +// +// case M3AP_UE_CONTEXT_RELEASE: +// m3ap_MME_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg), +// &M3AP_UE_CONTEXT_RELEASE(received_msg)); +// break; +// + case SCTP_INIT_MSG_MULTI_CNF: + LOG_E(M3AP,"MME Received SCTP_INIT_MSG_MULTI_CNF Message ... shoudn't be happening ... it doesn't at leaast with M2AP_MCEC\n"); + m3ap_MME_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_init_msg_multi_cnf); + break; + + case SCTP_NEW_ASSOCIATION_RESP: + LOG_D(M3AP,"MME Received SCTP_NEW_ASSOCIATION_RESP Message\n"); + m3ap_MME_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_resp); + break; + + case SCTP_NEW_ASSOCIATION_IND: + LOG_D(M3AP,"MME Received SCTP_NEW_ASSOCIATION Message\n"); + m3ap_MME_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_new_association_ind); + break; + + case SCTP_DATA_IND: + LOG_D(M3AP,"MME Received SCTP_DATA_IND Message\n"); + m3ap_MME_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &received_msg->ittiMsg.sctp_data_ind); + break; + + default: + M3AP_ERROR("MME Received unhandled message: %d:%s\n", + ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + received_msg = NULL; + } + + return NULL; +} + +#include "common/config/config_userapi.h" + +int is_m3ap_MME_enabled(void) +{ + static volatile int config_loaded = 0; + static volatile int enabled = 0; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + if (pthread_mutex_lock(&mutex)) goto mutex_error; + + if (config_loaded) { + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + return enabled; + } + + char *enable_m3 = NULL; + paramdef_t p[] = { + { "enable_mme_m3", "yes/no", 0, strptr:&enable_m3, defstrval:"", TYPE_STRING, 0 } + }; + + /* TODO: do it per module - we check only first MME */ + config_get(p, sizeof(p)/sizeof(paramdef_t), "MMEs.[0]"); + if (enable_m3 != NULL && strcmp(enable_m3, "yes") == 0) + enabled = 1; + + config_loaded = 1; + + if (pthread_mutex_unlock(&mutex)) goto mutex_error; + + return enabled; + +mutex_error: + LOG_E(M3AP, "mutex error\n"); + exit(1); +} diff --git a/openair3/M3AP/m3ap_MME.h b/openair3/M3AP/m3ap_MME.h new file mode 100644 index 0000000000..f5d1b158e4 --- /dev/null +++ b/openair3/M3AP/m3ap_MME.h @@ -0,0 +1,55 @@ +/* + * 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 m3ap_MME.h + * \brief m3ap tasks for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include + +/** @defgroup _m3ap_impl_ M3AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef M3AP_MME_H_ +#define M3AP_MME_H_ + +#include "m3ap_MME_defs.h" + + +int m3ap_MME_init_sctp (m3ap_MME_instance_t *instance_p, + net_ip_address_t *local_ip_addr, + uint32_t enb_port_for_M3C); + +void *m3ap_MME_task(void *arg); + +int is_m3ap_MME_enabled(void); + +#endif /* M3AP_MCE_H_ */ + +/** + * @} + */ diff --git a/openair3/M3AP/m3ap_MME_defs.h b/openair3/M3AP/m3ap_MME_defs.h new file mode 100644 index 0000000000..3b5725655d --- /dev/null +++ b/openair3/M3AP/m3ap_MME_defs.h @@ -0,0 +1,210 @@ +/* + * 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 m3ap_MME_defs.h + * \brief m2ap struct definitions for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "queue.h" +#include "tree.h" + +#include "sctp_eNB_defs.h" + +#include "m3ap_ids.h" //looks X2AP specific for HO +#include "m3ap_timers.h" + +#ifndef M3AP_MME_DEFS_H_ +#define M3AP_MME_DEFS_H_ + +#define M3AP_MME_NAME_LENGTH_MAX (150) + +typedef enum { + /* Disconnected state: initial state for any association. */ + M3AP_MME_STATE_DISCONNECTED = 0x0, + + /* State waiting for m2 Setup response message if the target MME accepts or + * M2 Setup failure if rejects the MME. + */ + M3AP_MME_STATE_WAITING = 0x1, + + /* The MME is successfully connected to another MME. */ + M3AP_MME_STATE_CONNECTED = 0x2, + + /* M3AP is ready, and the MME is successfully connected to another MME. */ + M3AP_MME_STATE_READY = 0x3, + + M3AP_MME_STATE_OVERLOAD = 0x4, + + M3AP_MME_STATE_RESETTING = 0x5, + + /* Max number of states available */ + M3AP_MME_STATE_MAX, +} m3ap_MME_state_t; + +/* Served PLMN identity element */ +/*struct plmn_identity_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + STAILQ_ENTRY(plmn_identity_s) next; +};*/ + +/* Served group id element */ +/*struct served_group_id_s { + uint16_t mce_group_id; + STAILQ_ENTRY(served_group_id_s) next; +};*/ + +/* Served enn code for a particular MME */ +/*struct mce_code_s { + uint8_t mce_code; + STAILQ_ENTRY(mce_code_s) next; +};*/ + +struct m3ap_MME_instance_s; + +/* This structure describes association of a MME to another MME */ +typedef struct m3ap_MME_data_s { + /* MME descriptors tree, ordered by sctp assoc id */ + RB_ENTRY(m3ap_MME_data_s) entry; + + /* This is the optional name provided by the MME */ + char *MME_name; + + /* target MME ID */ + uint32_t MME_id; + + /* Current MME load information (if any). */ + //m3ap_load_state_t overload_state; + + /* Current MME->MME M3AP association state */ + m3ap_MME_state_t state; + + /* Next usable stream for UE signalling */ + int32_t nextstream; + + /* Number of input/ouput streams */ + uint16_t in_streams; + uint16_t out_streams; + + /* Connexion id used between SCTP/M3AP */ + uint16_t cnx_id; + + /* SCTP association id */ + int32_t assoc_id; + + /* Nid cells */ + uint32_t Nid_cell[MAX_NUM_CCs]; + int num_cc; + + /* Only meaningfull in virtual mode */ + struct m3ap_MME_instance_s *m3ap_MME_instance; +} m3ap_MME_data_t; + +typedef struct m3ap_MME_instance_s { + /* used in simulation to store multiple MME instances*/ + STAILQ_ENTRY(m3ap_MME_instance_s) m3ap_MME_entries; + + /* Number of target MMEs requested by MME (tree size) */ + uint32_t m2_target_mce_nb; + /* Number of target MMEs for which association is pending */ + uint32_t m2_target_mce_pending_nb; + /* Number of target MME successfully associated to MME */ + uint32_t m2_target_mce_associated_nb; + /* Tree of M3AP MME associations ordered by association ID */ + RB_HEAD(m3ap_mme_map, m3ap_MME_data_s) m3ap_mme_head; + + /* Tree of UE ordered by MME_ue_m3ap_id's */ + // RB_HEAD(m3ap_ue_map, m3ap_MME_ue_context_s) m3ap_ue_head; + + /* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */ + instance_t instance; + + /* Displayable name of MME */ + char *MME_name; + + /* Unique MME_id to identify the MME within EPC. + * In our case the MME is a macro MME so the id will be 20 bits long. + * For Home MME id, this field should be 28 bits long. + */ + uint32_t MME_id; + /* The type of the cell */ + cell_type_t cell_type; + + /* Tracking area code */ + uint16_t tac; + + /* Mobile Country Code + * Mobile Network Code + */ + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + + /* CC params */ + int16_t eutra_band[MAX_NUM_CCs]; + uint32_t downlink_frequency[MAX_NUM_CCs]; + int32_t uplink_frequency_offset[MAX_NUM_CCs]; + uint32_t Nid_cell[MAX_NUM_CCs]; + int16_t N_RB_DL[MAX_NUM_CCs]; + lte_frame_type_t frame_type[MAX_NUM_CCs]; + uint32_t fdd_earfcn_DL[MAX_NUM_CCs]; + uint32_t fdd_earfcn_UL[MAX_NUM_CCs]; + int num_cc; + + net_ip_address_t target_mme_m3_ip_address[M3AP_MAX_NB_MME_IP_ADDRESS]; + uint8_t nb_m3; + net_ip_address_t mme_m3_ip_address; + uint16_t sctp_in_streams; + uint16_t sctp_out_streams; + uint32_t mme_port_for_M3C; + int multi_sd; + + m3ap_id_manager id_manager; + m3ap_timers_t timers; +} m3ap_MME_instance_t; + +typedef struct { + /* List of served MMEs + * Only used for virtual mode + */ + STAILQ_HEAD(m3ap_MME_instances_head_s, m3ap_MME_instance_s) m3ap_MME_instances_head; + /* Nb of registered MMEs */ + uint8_t nb_registered_MMEs; + + /* Generate a unique connexion id used between M3AP and SCTP */ + uint16_t global_cnx_id; +} m3ap_MME_internal_data_t; + +int m3ap_MME_compare_assoc_id(struct m3ap_MME_data_s *p1, struct m3ap_MME_data_s *p2); + +/* Generate the tree management functions */ +struct m3ap_MME_map; +struct m3ap_MME_data_s; +RB_PROTOTYPE(m3ap_MME_map, m3ap_MME_data_s, entry, m3ap_MME_compare_assoc_id); + + +#endif /* M3AP_MME_DEFS_H_ */ diff --git a/openair3/M3AP/m3ap_MME_generate_messages.c b/openair3/M3AP/m3ap_MME_generate_messages.c new file mode 100644 index 0000000000..a28097cf1a --- /dev/null +++ b/openair3/M3AP/m3ap_MME_generate_messages.c @@ -0,0 +1,804 @@ +/* + * 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 m2ap_MCE_generate_messages.c + * \brief m2ap procedures for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include "intertask_interface.h" + +//#include "M2AP_LastVisitedCell-Item.h" + +#include "m2ap_common.h" +#include "m2ap_MCE.h" +#include "m2ap_MCE_generate_messages.h" +#include "m2ap_encoder.h" +#include "m2ap_decoder.h" +#include "m2ap_ids.h" + +#include "m2ap_itti_messaging.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +int m2ap_MCE_generate_m2_setup_request( + m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p) +{ + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupRequest_t *out; + M2AP_M2SetupRequest_Ies_t *ie; + //M2AP_PLMN_Identity_t *plmn; + //ServedCells__Member *servedCellMember; + //M2AP_GU_Group_ID_t *gu; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + DevAssert(instance_p != NULL); + DevAssert(m2ap_MCE_data_p != NULL); + + m2ap_MCE_data_p->state = M2AP_MCE_STATE_WAITING; + + /* Prepare the M2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_M2SetupRequest; + out = &pdu.choice.initiatingMessage.value.choice.M2SetupRequest; + + /* mandatory */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GlobalMCE_ID; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequest_IEs__value_PR_GlobalMCE_ID; + //MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &ie->value.choice.GlobalMCE_ID.pLMN_Identity); + //ie->value.choice.GlobalMCE_ID.MCE_ID.present = M2AP_MCE_ID_PR_macro_MCE_ID; + //MACRO_MCE_ID_TO_BIT_STRING(instance_p->MCE_id, + // &ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID); + //M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->MCE_id, + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[0], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[1], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[2]); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_ServedCells; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequest_IEs__value_PR_ServedCells; + //{ + // for (int i = 0; inum_cc; i++){ + // servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member)); + // { + // servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i]; + + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &servedCellMember->servedCellInfo.cellId.pLMN_Identity); + // MACRO_MCE_ID_TO_CELL_IDENTITY(instance_p->MCE_id,0, + // &servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier); + + // INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC); + // plmn = (M2AP_PLMN_Identity_t *)calloc(1,sizeof(M2AP_PLMN_Identity_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); + // ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn); + // } + + // if (instance_p->frame_type[i] == FDD) { + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = M2AP_EUTRA_Mode_Info_PR_fDD; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; + // switch (instance_p->N_RB_DL[i]) { + // case 6: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // break; + // case 15: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // break; + // case 25: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // break; + // case 50: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // break; + // case 75: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // break; + // case 100: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // break; + // default: + // AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); + // break; + // } + // } + // else { + // AssertFatal(0,"M2Setuprequest not supported for TDD!"); + // } + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember); + // } + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupRequest_Ies_t *)calloc(1, sizeof(M2AP_M2SetupRequest_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GUGroupIDList; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupRequest_IEs__value_PR_GUGroupIDList; + //{ + // gu = (M2AP_GU_Group_ID_t *)calloc(1, sizeof(M2AP_GU_Group_ID_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &gu->pLMN_Identity); + // //@TODO: consider to update this value + // INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID); + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu); + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + M2AP_ERROR("Failed to encode M2 setup request\n"); + return -1; + } + + //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 M2Setup/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); + + m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 0); + + return ret; +} + +int m2ap_MCE_generate_m2_setup_response(m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p) +{ + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupResponse_t *out; + M2AP_M2SetupResponse_Ies_t *ie; + //M2AP_PLMN_Identity_t *plmn; + //ServedCells__Member *servedCellMember; + //M2AP_GU_Group_ID_t *gu; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + DevAssert(instance_p != NULL); + DevAssert(m2ap_MCE_data_p != NULL); + + /* Prepare the M2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_M2SetupResponse; + out = &pdu.choice.successfulOutcome.value.choice.M2SetupResponse; + + /* mandatory */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GlobalMCE_ID; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GlobalMCE_ID; + //MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &ie->value.choice.GlobalMCE_ID.pLMN_Identity); + //ie->value.choice.GlobalMCE_ID.MCE_ID.present = M2AP_MCE_ID_PR_macro_MCE_ID; + //MACRO_MCE_ID_TO_BIT_STRING(instance_p->MCE_id, + // &ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID); + //M2AP_INFO("%d -> %02x%02x%02x\n", instance_p->MCE_id, + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[0], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[1], + // ie->value.choice.GlobalMCE_ID.MCE_ID.choice.macro_MCE_ID.buf[2]); + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_ServedCells; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_ServedCells; + //{ + // for (int i = 0; inum_cc; i++){ + // servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member)); + // { + // servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i]; + + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &servedCellMember->servedCellInfo.cellId.pLMN_Identity); + // MACRO_MCE_ID_TO_CELL_IDENTITY(instance_p->MCE_id,0, + // &servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier); + + // INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC); + // plmn = (M2AP_PLMN_Identity_t *)calloc(1,sizeof(M2AP_PLMN_Identity_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn); + // ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn); + // } + + // if (instance_p->frame_type[i] == FDD) { + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = M2AP_EUTRA_Mode_Info_PR_fDD; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i]; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i]; + // switch (instance_p->N_RB_DL[i]) { + // case 6: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw6; + // break; + // case 15: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw15; + // break; + // case 25: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw25; + // break; + // case 50: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw50; + // break; + // case 75: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw75; + // break; + // case 100: + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = M2AP_Transmission_Bandwidth_bw100; + // break; + // default: + // AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL"); + // break; + // } + // } + // else { + // AssertFatal(0,"M2Setupresponse not supported for TDD!"); + // } + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember); + // } + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + ie = (M2AP_M2SetupResponse_Ies_t *)calloc(1, sizeof(M2AP_M2SetupResponse_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_GUGroupIDList; + //ie->criticality = M2AP_Criticality_reject; + //ie->value.present = M2AP_M2SetupResponse_IEs__value_PR_GUGroupIDList; + //{ + // gu = (M2AP_GU_Group_ID_t *)calloc(1, sizeof(M2AP_GU_Group_ID_t)); + // { + // MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, + // &gu->pLMN_Identity); + // //@TODO: consider to update this value + // INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID); + // } + // ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu); + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + M2AP_ERROR("Failed to encode M2 setup response\n"); + return -1; + } + + m2ap_MCE_data_p->state = M2AP_MCE_STATE_READY; + + //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 M2Setup/successfulOutcome assoc_id %u", m2ap_MCE_data_p->assoc_id); + + m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 0); + + return ret; +} + +int m2ap_MCE_generate_m2_setup_failure(instance_t instance, + uint32_t assoc_id, + M2AP_Cause_PR cause_type, + long cause_value, + long time_to_wait) +{ + M2AP_M2AP_PDU_t pdu; + M2AP_M2SetupFailure_t *out; + M2AP_M2SetupFailure_Ies_t *ie; + + uint8_t *buffer; + uint32_t len; + int ret = 0; + + /* Prepare the M2AP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M2AP_M2AP_PDU_PR_unsuccessfulOutcome; + pdu.choice.unsuccessfulOutcome.procedureCode = M2AP_ProcedureCode_id_m2Setup; + pdu.choice.unsuccessfulOutcome.criticality = M2AP_Criticality_reject; + pdu.choice.unsuccessfulOutcome.value.present = M2AP_UnsuccessfulOutcome__value_PR_M2SetupFailure; + out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure; + + /* mandatory */ + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_Cause; + //ie->criticality = M2AP_Criticality_ignore; + //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_Cause; + + //m2ap_MCE_set_cause (&ie->value.choice.Cause, cause_type, cause_value); + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* optional: consider to handle this later */ + ie = (M2AP_M2SetupFailure_Ies_t *)calloc(1, sizeof(M2AP_M2SetupFailure_Ies_t)); + //ie->id = M2AP_ProtocolIE_ID_id_TimeToWait; + //ie->criticality = M2AP_Criticality_ignore; + //ie->value.present = M2AP_M2SetupFailure_IEs__value_PR_TimeToWait; + + //if (time_to_wait > -1) { + // ie->value.choice.TimeToWait = time_to_wait; + //} + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + if (m2ap_encode_pdu(&pdu, &buffer, &len) < 0) { + M2AP_ERROR("Failed to encode M2 setup failure\n"); + return -1; + } + + //MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, + // MSC_M2AP_TARGET_MCE, NULL, 0, + // "0 M2Setup/unsuccessfulOutcome assoc_id %u cause %u value %u", + // assoc_id, cause_type, cause_value); + + m2ap_MCE_itti_send_sctp_data_req(instance, assoc_id, buffer, len, 0); + + return ret; +} + +int m2ap_MCE_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value) +{ + + DevAssert (cause_p != NULL); + cause_p->present = cause_type; + + switch (cause_type) { + case M2AP_Cause_PR_radioNetwork: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_transport: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_protocol: + cause_p->choice.misc = cause_value; + break; + + case M2AP_Cause_PR_misc: + cause_p->choice.misc = cause_value; + break; + + default: + return -1; + } + + return 0; +} + +//int m2ap_MCE_generate_m2_handover_request (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequest_t *out; +// M2AP_HandoverRequest_IEs_t *ie; +// M2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs; +// M2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item; +// M2AP_LastVisitedCell_Item_t *lastVisitedCell_Item; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_reject; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverRequest; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverRequest; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_Cause; +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = M2AP_CauseRadioNetwork_handover_desirable_for_radio_reasons; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargetCell_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_ECGI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.ECGI.pLMN_Identity); +// MACRO_MCE_ID_TO_CELL_IDENTITY(m2ap_MCE_data_p->MCE_id, 0, &ie->value.choice.ECGI.eUTRANcellIdentifier); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_GUMMEI_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_GUMMEI; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &ie->value.choice.GUMMEI.gU_Group_ID.pLMN_Identity); +// //@TODO: consider to update these values +// INT16_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_group_id, &ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID); +// MME_CODE_TO_OCTET_STRING(m2ap_handover_req->ue_gummei.mme_code, &ie->value.choice.GUMMEI.mME_Code); +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_ContextInformation; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_ContextInformation; +// //@TODO: consider to update this value +// ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID = m2ap_handover_req->mme_ue_s1ap_id; +// +// KMCE_STAR_TO_BIT_STRING(m2ap_handover_req->kenb,&ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star); +// +// if (m2ap_handover_req->kenb_ncc >=0) { // Check this condition +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = m2ap_handover_req->kenb_ncc; +// } +// else { +// ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = 1; +// } +// +// ENCRALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.encryption_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms); +// +// INTPROTALG_TO_BIT_STRING(m2ap_handover_req->security_capabilities.integrity_algorithms, +// &ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms); +// +// //@TODO: update with proper UEAMPR +// UEAGMAXBITRTD_TO_ASN_PRIMITIVES(3L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink); +// UEAGMAXBITRTU_TO_ASN_PRIMITIVES(6L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateUplink); +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_ToBeSetup_ItemIEs = (M2AP_E_RABs_ToBeSetup_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_ToBeSetup_ItemIEs_t)); +// e_RABS_ToBeSetup_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_ToBeSetup_Item; +// e_RABS_ToBeSetup_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_ToBeSetup_ItemIEs->value.present = M2AP_E_RABs_ToBeSetup_ItemIEs__value_PR_E_RABs_ToBeSetup_Item; +// e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item; +// { +// e_RABs_ToBeSetup_Item->e_RAB_ID = m2ap_handover_req->e_rabs_tobesetup[i].e_rab_id; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI = m2ap_handover_req->e_rab_param[i].qos.qci; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.priority_level; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability; +// e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = m2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size = (uint8_t)(m2ap_handover_req->e_rabs_tobesetup[i].MCE_addr.length/8); +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = m2ap_handover_req->e_rabs_tobesetup[i].MCE_addr.length%8; +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf = +// calloc(1,e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// memcpy (e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf, +// m2ap_handover_req->e_rabs_tobesetup[i].MCE_addr.buffer, +// e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size); +// +// INT32_TO_OCTET_STRING(m2ap_handover_req->e_rabs_tobesetup[i].gtp_teid,&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID); +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list, e_RABS_ToBeSetup_ItemIEs); +// } +// } +// +// OCTET_STRING_fromBuf(&ie->value.choice.UE_ContextInformation.rRC_Context, (char*) m2ap_handover_req->rrc_buffer, m2ap_handover_req->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequest_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_UE_HistoryInformation; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequest_IEs__value_PR_UE_HistoryInformation; +// //@TODO: consider to update this value +// { +// lastVisitedCell_Item = (M2AP_LastVisitedCell_Item_t *)calloc(1, sizeof(M2AP_LastVisitedCell_Item_t)); +// lastVisitedCell_Item->present = M2AP_LastVisitedCell_Item_PR_e_UTRAN_Cell; +// MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, +// &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.pLMN_Identity); +// MACRO_MCE_ID_TO_CELL_IDENTITY(0, 0, &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.eUTRANcellIdentifier); +// lastVisitedCell_Item->choice.e_UTRAN_Cell.cellType.cell_Size = M2AP_Cell_Size_small; +// lastVisitedCell_Item->choice.e_UTRAN_Cell.time_UE_StayedInCell = 2; +// ASN_SEQUENCE_ADD(&ie->value.choice.UE_HistoryInformation.list, lastVisitedCell_Item); +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover request\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2Handover/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_MCE_generate_m2_handover_request_ack (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverRequestAcknowledge_t *out; +// M2AP_HandoverRequestAcknowledge_IEs_t *ie; +// M2AP_E_RABs_Admitted_ItemIEs_t *e_RABS_Admitted_ItemIEs; +// M2AP_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// ue_id = m2ap_handover_req_ack->m2_id_target; +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP handover message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_successfulOutcome; +// pdu.choice.successfulOutcome.procedureCode = M2AP_ProcedureCode_id_handoverPreparation; +// pdu.choice.successfulOutcome.criticality = M2AP_Criticality_reject; +// pdu.choice.successfulOutcome.value.present = M2AP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge; +// out = &pdu.choice.successfulOutcome.value.choice.HandoverRequestAcknowledge; +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_List; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_E_RABs_Admitted_List; +// +// { +// for (int i=0;inb_e_rabs_tobesetup;i++) { +// e_RABS_Admitted_ItemIEs = (M2AP_E_RABs_Admitted_ItemIEs_t *)calloc(1,sizeof(M2AP_E_RABs_Admitted_ItemIEs_t)); +// e_RABS_Admitted_ItemIEs->id = M2AP_ProtocolIE_ID_id_E_RABs_Admitted_Item; +// e_RABS_Admitted_ItemIEs->criticality = M2AP_Criticality_ignore; +// e_RABS_Admitted_ItemIEs->value.present = M2AP_E_RABs_Admitted_ItemIEs__value_PR_E_RABs_Admitted_Item; +// e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item; +// { +// e_RABs_Admitted_Item->e_RAB_ID = m2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id; +// } +// ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs); +// } +// } +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(M2AP_HandoverRequestAcknowledge_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_TargetMCEtoSource_MCETransparentContainer; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverRequestAcknowledge_IEs__value_PR_TargetMCEtoSource_MCETransparentContainer; +// +// OCTET_STRING_fromBuf(&ie->value.choice.TargetMCEtoSource_MCETransparentContainer, (char*) m2ap_handover_req_ack->rrc_buffer, m2ap_handover_req_ack->rrc_buffer_size); +// +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 handover response\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2Handover/successfulOutcome assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_MCE_generate_m2_ue_context_release (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, m2ap_ue_context_release_t *m2ap_ue_context_release) +//{ +// +// M2AP_M2AP_PDU_t pdu; +// M2AP_UEContextRelease_t *out; +// M2AP_UEContextRelease_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// ue_id = m2ap_find_id_from_rnti(&instance_p->id_manager, m2ap_ue_context_release->rnti); +// if (ue_id == -1) { +// M2AP_ERROR("could not find UE %x\n", m2ap_ue_context_release->rnti); +// exit(1); +// } +// id_source = m2ap_id_get_id_source(&instance_p->id_manager, ue_id); +// id_target = ue_id; +// +// /* Prepare the M2AP ue context relase message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_uEContextRelease; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_UEContextRelease; +// out = &pdu.choice.initiatingMessage.value.choice.UEContextRelease; +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// ie = (M2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(M2AP_UEContextRelease_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_UEContextRelease_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 UE Context Release\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2UEContextRelease/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} +// +//int m2ap_MCE_generate_m2_handover_cancel (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause) +//{ +// M2AP_M2AP_PDU_t pdu; +// M2AP_HandoverCancel_t *out; +// M2AP_HandoverCancel_IEs_t *ie; +// int ue_id; +// int id_source; +// int id_target; +// +// uint8_t *buffer; +// uint32_t len; +// int ret = 0; +// +// DevAssert(instance_p != NULL); +// DevAssert(m2ap_MCE_data_p != NULL); +// +// ue_id = m2_ue_id; +// id_source = ue_id; +// id_target = m2ap_id_get_id_target(&instance_p->id_manager, ue_id); +// +// /* Prepare the M2AP handover cancel message to encode */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M2AP_M2AP_PDU_PR_initiatingMessage; +// pdu.choice.initiatingMessage.procedureCode = M2AP_ProcedureCode_id_handoverCancel; +// pdu.choice.initiatingMessage.criticality = M2AP_Criticality_ignore; +// pdu.choice.initiatingMessage.value.present = M2AP_InitiatingMessage__value_PR_HandoverCancel; +// out = &pdu.choice.initiatingMessage.value.choice.HandoverCancel; +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Old_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_reject; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID; +// ie->value.choice.UE_M2AP_ID = id_source; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ +// if (id_target != -1) { +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_New_MCE_UE_M2AP_ID; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_UE_M2AP_ID_1; +// ie->value.choice.UE_M2AP_ID_1 = id_target; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* mandatory */ +// ie = (M2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(M2AP_HandoverCancel_IEs_t)); +// ie->id = M2AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M2AP_Criticality_ignore; +// ie->value.present = M2AP_HandoverCancel_IEs__value_PR_Cause; +// switch (cause) { +// case M2AP_T_RELOC_PREP_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_trelocprep_expiry; +// break; +// case M2AP_TX2_RELOC_OVERALL_TIMEOUT: +// ie->value.choice.Cause.present = M2AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = +// M2AP_CauseRadioNetwork_tx2relocoverall_expiry; +// break; +// default: +// /* we can't come here */ +// M2AP_ERROR("unhandled cancel cause\n"); +// exit(1); +// } +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// if (m2ap_MCE_encode_pdu(&pdu, &buffer, &len) < 0) { +// M2AP_ERROR("Failed to encode X2 Handover Cancel\n"); +// abort(); +// return -1; +// } +// +// MSC_LOG_TX_MESSAGE (MSC_M2AP_SRC_MCE, MSC_M2AP_TARGET_MCE, NULL, 0, "0 X2HandoverCancel/initiatingMessage assoc_id %u", m2ap_MCE_data_p->assoc_id); +// +// m2ap_MCE_itti_send_sctp_data_req(instance_p->instance, m2ap_MCE_data_p->assoc_id, buffer, len, 1); +// +// return ret; +//} diff --git a/openair3/M3AP/m3ap_MME_generate_messages.h b/openair3/M3AP/m3ap_MME_generate_messages.h new file mode 100644 index 0000000000..1632dc807a --- /dev/null +++ b/openair3/M3AP/m3ap_MME_generate_messages.h @@ -0,0 +1,63 @@ +/* + * 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 m2ap_MCE_generate_messages.h + * \brief m2ap procedures for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_MCE_GENERATE_MESSAGES_H_ +#define M2AP_MCE_GENERATE_MESSAGES_H_ + +#include "m2ap_MCE_defs.h" +#include "m2ap_common.h" + +int m2ap_MCE_generate_m2_setup_request(m2ap_MCE_instance_t *instance_p, + m2ap_MCE_data_t *m2ap_MCE_data_p); + +int m2ap_MCE_generate_m2_setup_response(m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p); + +int m2ap_MCE_generate_m2_setup_failure(instance_t instance, + uint32_t assoc_id, + M2AP_Cause_PR cause_type, + long cause_value, + long time_to_wait); + +int m2ap_MCE_set_cause (M2AP_Cause_t * cause_p, + M2AP_Cause_PR cause_type, + long cause_value); + +//int m2ap_MCE_generate_m2_handover_request (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_t *m2ap_handover_req, int ue_id); +// +//int m2ap_MCE_generate_m2_handover_request_ack (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_handover_req_ack_t *m2ap_handover_req_ack); +// +//int m2ap_MCE_generate_m2_ue_context_release (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// m2ap_ue_context_release_t *m2ap_ue_context_release); +// +//int m2ap_MCE_generate_m2_handover_cancel (m2ap_MCE_instance_t *instance_p, m2ap_MCE_data_t *m2ap_MCE_data_p, +// int m2_ue_id, +// m2ap_handover_cancel_cause_t cause); + +#endif /* M2AP_MCE_GENERATE_MESSAGES_H_ */ diff --git a/openair3/M3AP/m3ap_MME_handler.c b/openair3/M3AP/m3ap_MME_handler.c new file mode 100644 index 0000000000..9af8cbe14f --- /dev/null +++ b/openair3/M3AP/m3ap_MME_handler.c @@ -0,0 +1,118 @@ +/* + * 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 m3ap_eNB_handler.c + * \brief m3ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "intertask_interface.h" + +#include "asn1_conversions.h" + +#include "m3ap_common.h" +#include "m3ap_MME_defs.h" +#include "m3ap_handler.h" +#include "m3ap_decoder.h" +#include "m3ap_ids.h" + +#include "m3ap_MME_management_procedures.h" +//#include "m3ap_MCE_generate_messages.h" + +#include "m3ap_MME_interface_management.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +/* Handlers matrix. Only eNB related procedure present here */ +m3ap_MCE_message_decoded_callback m3ap_MME_messages_callback[][3] = { + { 0, MME_handle_MBMS_SESSION_START_RESPONSE, 0 }, /* MBMSSessionStart */ + { 0, MME_handle_MBMS_SESSION_STOP_RESPONSE, 0 }, /* MBMSSessionStop */ + { 0, 0, 0 }, /* Error Indication */ + { 0, 0, 0 }, /* Reset */ + { 0, 0, 0 }, /* ??? */ + { 0, MME_handle_MBMS_SESSION_UPDATE_RESPONSE, 0 }, /* MBMSSessionUpdate */ + { 0, 0, 0 }, /* MCEConfigurationUpdate */ + { MME_handle_M3_SETUP_REQUEST, 0, 0 } /* M3 Setup */ +}; + +static char *m3ap_direction2String(int m3ap_dir) { +static char *m3ap_direction_String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; +return(m3ap_direction_String[m3ap_dir]); +} + + +int m3ap_MME_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length) +{ + M3AP_M3AP_PDU_t pdu; + int ret; + + DevAssert(data != NULL); + + memset(&pdu, 0, sizeof(pdu)); + + + if (m3ap_decode_pdu(&pdu, data, data_length) < 0) { + LOG_E(M3AP, "Failed to decode PDU\n"); + return -1; + } + + /* Checking procedure Code and direction of message */ + if (pdu.choice.initiatingMessage.procedureCode > sizeof(m3ap_MME_messages_callback) / (3 * sizeof( + m3ap_message_decoded_callback)) + || (pdu.present > M3AP_M3AP_PDU_PR_unsuccessfulOutcome)) { + LOG_E(M3AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return -1; + } + + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (m3ap_MME_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) { + LOG_E(M3AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, + m3ap_direction2String(pdu.present - 1)); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return -1; + } + + /* Calling the right handler */ + LOG_I(M3AP, "Calling handler with instance %d\n",instance); + ret = (*m3ap_MME_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1]) + (instance, assoc_id, stream, &pdu); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return ret; +} + + diff --git a/openair3/M3AP/m3ap_MME_handler.h b/openair3/M3AP/m3ap_MME_handler.h new file mode 100644 index 0000000000..feabfe256c --- /dev/null +++ b/openair3/M3AP/m3ap_MME_handler.h @@ -0,0 +1,43 @@ +/* + * 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 m3ap_handler.h + * \brief m3ap handler procedures for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M3AP_MME_HANDLERS_H_ +#define M3AP_MME_HANDLERS_H_ + +#include "m3ap_MME_defs.h" + +//void m3ap_handle_m2_setup_message(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown); + +//int m3ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + //const uint8_t * const data, const uint32_t data_length); + +int m3ap_MME_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + + +#endif /* M3AP_MME_HANDLERS_H_ */ diff --git a/openair3/M3AP/m3ap_MME_interface_management.c b/openair3/M3AP/m3ap_MME_interface_management.c new file mode 100644 index 0000000000..e5cb03cf26 --- /dev/null +++ b/openair3/M3AP/m3ap_MME_interface_management.c @@ -0,0 +1,1162 @@ +/* + * 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 m3ap_MME_interface_management.c + * \brief m3ap interface management for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "m3ap_common.h" +#include "m3ap_encoder.h" +#include "m3ap_decoder.h" +#include "m3ap_itti_messaging.h" +#include "m3ap_MME_interface_management.h" + +#include "conversions.h" + +#include "M3AP_ECGI.h" + +extern m3ap_setup_req_t *m3ap_mme_data_from_mce; + + + +uint8_t m3ap_start_message[] = { + 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x07, 0x00, 0x55, 0xf5, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x0d, 0x60, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 0x01, + 0x7a, 0x00, 0x05, 0x00, 0x03, 0x07, 0x08, 0x00, + 0x00, 0x06, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, + 0x0e, 0x00, 0xe8, 0x0a, 0x0a, 0x0a, 0x00, 0x0a, + 0xc8, 0x0a, 0xfe, 0x00, 0x00, 0x00, 0x01 +}; + + +/* + * MBMS Session start + */ +int MME_send_MBMS_SESSION_START_REQUEST(instance_t instance/*, uint32_t assoc_id*/,m3ap_session_start_req_t* m3ap_session_start_req){ + + //AssertFatal(1==0,"Not implemented yet\n"); + + //module_id_t enb_mod_idP=0; + //module_id_t du_mod_idP=0; + + M3AP_M3AP_PDU_t pdu; + M3AP_MBMSSessionStartRequest_t *out; + M3AP_MBMSSessionStartRequest_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i=0; + //int j=0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_mBMSsessionStart; + pdu.choice.initiatingMessage.criticality = M3AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_MBMSSessionStartRequest; + out = &pdu.choice.initiatingMessage.value.choice.MBMSSessionStartRequest; + + /* mandatory */ + /* c1. MME_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MME_MBMS_M3AP_ID; + //ie->value.choice.MME_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. TMGI */ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_TMGI; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_TMGI; + M3AP_TMGI_t *tmgi = &ie->value.choice.TMGI; + { + MCC_MNC_TO_PLMNID(0,0,3,&tmgi->pLMNidentity); + uint8_t TMGI[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(&tmgi->serviceID,(const char*)&TMGI[2],3); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* optional */ + /* c2. MBMS_Session_ID */ + if(0){ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Session_ID; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Session_ID; + //M3AP_MBMS_Session_ID_t * mbms_session_id = &ie->value.choice.MBMS_Session_ID; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + /* mandatory */ + /* c2. MBMS_E_RAB_QoS_Parameters */ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_E_RAB_QoS_Parameters; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_E_RAB_QoS_Parameters; + M3AP_MBMS_E_RAB_QoS_Parameters_t * mbms_e_rab_qos_parameters = &ie->value.choice.MBMS_E_RAB_QoS_Parameters; + { + //M3AP_QCI_t * qci = &mbms_e_rab_qos_parameters->qCI; //long + mbms_e_rab_qos_parameters->qCI = 1; + //struct M3AP_GBR_QosInformation *gbrQosInformation; /* OPTIONAL */ + } + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ + /* c2. MBMS_Session_Duration */ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Session_Duration; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Session_Duration; + M3AP_MBMS_Session_Duration_t * mbms_session_duration = &ie->value.choice.MBMS_Session_Duration; + { + uint8_t duration[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(mbms_session_duration,(const char*)&duration[2],3); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ + /* c2 MBMS_Service_Area */ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Service_Area; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Service_Area; + M3AP_MBMS_Service_Area_t * mbms_service_area = &ie->value.choice.MBMS_Service_Area; + { + uint8_t duration[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(mbms_service_area,(const char*)&duration[2],1); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ + /* c2 MinimumTimeToMBMSDataTransfer */ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MinimumTimeToMBMSDataTransfer; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MinimumTimeToMBMSDataTransfer; + M3AP_MinimumTimeToMBMSDataTransfer_t * minimumtimetombmsdatatransfer = &ie->value.choice.MinimumTimeToMBMSDataTransfer; + { + uint8_t duration[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(minimumtimetombmsdatatransfer,(const char*)&duration[2],1); + } + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ + /* c2 TNL_Information */ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_TNL_Information; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_TNL_Information; + M3AP_TNL_Information_t * tnl_information = &ie->value.choice.TNL_Information; + { + //OCTET_STRING_fromBuf(&tnl_information->iPMCAddress,"1204",strlen("1234")); + //OCTET_STRING_fromBuf(&tnl_information->iPSourceAddress,"1204",strlen("1234")); + //OCTET_STRING_fromBuf(&tnl_information->gTP_DLTEID,"1204",strlen("1234")); + uint32_t gtp_dlteid = 1; + GTP_TEID_TO_ASN1(gtp_dlteid,&tnl_information->gTP_DLTEID); + //tnl_information->iPMCAddress.buf = calloc(4,sizeof(uint8_t)); + //tnl_information->iPMCAddress.buf[0] + //tnl_information->iPMCAddress.buf[1] + //tnl_information->iPMCAddress.buf[2] + //tnl_information->iPMCAddress.buf[3] + //tnl_information->iPMCAddress.buf.size = 4; + uint32_t ip= (224<<24) | (0) << 16 | (0) << 8 | (2); + INT32_TO_OCTET_STRING(ip,&tnl_information->iPMCAddress); + ip= (224<<24) | (0) << 16 | (0) << 8 | (2); + INT32_TO_OCTET_STRING(ip,&tnl_information->iPSourceAddress); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* optional */ + /* c2 Time_ofMBMS_DataTransfer */ + if(0){ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_Time_ofMBMS_DataTransfer; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_Absolute_Time_ofMBMS_Data; + //M3AP_Absolute_Time_ofMBMS_Data_t * absolute_time_ofmbms_data = &ie->value.choice.Absolute_Time_ofMBMS_Data; + //{ + //char duration[5] = {4,3,2,1,0}; + //OCTET_STRING_fromBuf(absolute_time_ofmbms_data,(const char*)&duration[2],3); + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + /* optional */ + /* c2 MBMS_Cell_List */ + if(0){ + ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Cell_List; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Cell_List; + M3AP_MBMS_Cell_List_t * mbms_cell_list = &ie->value.choice.MBMS_Cell_List; + M3AP_ECGI_t * ecgi = (M3AP_ECGI_t*)calloc(1,sizeof(M3AP_ECGI_t)); + { + //MCC_MNC_TO_PLMNID(0,0,3,ecgi->pLMN_Identity); + //MACRO_ENB_ID_TO_CELL_IDENTITY(1,0,ecgi->eUTRANcellIdentifier); + ASN_SEQUENCE_ADD(&mbms_cell_list->list,ecgi); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* encode */ + if (m3ap_encode_pdu(&pdu,&buffer,&len) < 0){ + return -1; + } + + +// buffer = &m3ap_start_message[0]; +// len=8*9+7; +// + m3ap_MME_itti_send_sctp_data_req(instance, m3ap_mme_data_from_mce->assoc_id, buffer, len, 0); + + return 0; + +} + +int MME_handle_MBMS_SESSION_START_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ +// AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M3AP, "MME_handle_MBMS_SESSION_START_RESPONSE\n"); + + AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome, + "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M3AP_ProcedureCode_id_mBMSsessionStart, + "pdu->choice.successfulOutcome->procedureCode != M3AP_ProcedureCode_id_sessionStart\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M3AP_Criticality_reject, + "pdu->choice.successfulOutcome->criticality != M3AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M3AP_SuccessfulOutcome__value_PR_MBMSSessionStartResponse, + "pdu->choice.successfulOutcome.value.present != M3AP_SuccessfulOutcome__value_PR_MBMSSessionStartResponse\n"); + + + M3AP_MBMSSessionStartResponse_t *in = &pdu->choice.successfulOutcome.value.choice.MBMSSessionStartResponse; + M3AP_MBMSSessionStartResponse_IEs_t *ie; + int MME_MBMS_M3AP_ID=-1; + int MCE_MBMS_M3AP_ID=-1; + + + MessageDef *msg_g = itti_alloc_new_message(TASK_M3AP_MME,M3AP_MBMS_SESSION_START_RESP); //TODO + + LOG_D(M3AP, "M3AP: SessionStart-Resp: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (int i=0;i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID: + AssertFatal(ie->criticality == M3AP_Criticality_reject, + "ie->criticality != M3AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M3AP_MBMSSessionStartResponse_IEs__value_PR_MME_MBMS_M3AP_ID, + "ie->value.present != M3AP_sessionStartResponse_IEs__value_PR_MME_MBMS_M3AP_ID\n"); + MME_MBMS_M3AP_ID=ie->value.choice.MME_MBMS_M3AP_ID; + LOG_D(M3AP, "M3AP: SessionStart-Resp: MME_MBMS_M3AP_ID %d\n", + MME_MBMS_M3AP_ID); + break; + case M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID: + AssertFatal(ie->criticality == M3AP_Criticality_reject, + "ie->criticality != M3AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M3AP_MBMSSessionStartResponse_IEs__value_PR_MCE_MBMS_M3AP_ID, + "ie->value.present != M3AP_sessionStartResponse_IEs__value_PR_MCE_MBMS_M3AP_ID\n"); + MCE_MBMS_M3AP_ID=ie->value.choice.MCE_MBMS_M3AP_ID; + LOG_D(M3AP, "M3AP: SessionStart-Resp: MCE_MBMS_M3AP_ID %d\n", + MCE_MBMS_M3AP_ID); + break; + } + } + + //AssertFatal(MME_MBMS_M3AP_ID!=-1,"MME_MBMS_M3AP_ID was not sent\n"); + //AssertFatal(MCE_MBMS_M3AP_ID!=-1,"MCE_MBMS_M3AP_ID was not sent\n"); + ////M3AP_SESSION_START_RESP(msg_p). +//// MSC_LOG_RX_MESSAGE( +//// MSC_M3AP_MME, +//// MSC_M3AP_MCE, + // //return 0; +//// 0, +//// 0, +//// MSC_AS_TIME_FMT" MME_handle_M2_SESSION_START_RESPONSE successfulOutcome assoc_id %d", +//// 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +//// assoc_id); +//// + // LOG_W(M3AP, "Sending M3AP_SESSION_START_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id)); + itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g); + return 0; + +} +int MME_handle_MBMS_SESSION_START_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + +/* + * MBMS Session stop + */ +int MME_send_MBMS_SESSION_STOP_REQUEST(instance_t instance, m3ap_session_stop_req_t* m3ap_session_stop_req){ + + + // module_id_t enb_mod_idP=0; + // module_id_t du_mod_idP=0; + + M3AP_M3AP_PDU_t pdu; + M3AP_MBMSSessionStopRequest_t *out; + M3AP_MBMSSessionStopRequest_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i=0; + //int j=0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_mBMSsessionStop; + pdu.choice.initiatingMessage.criticality = M3AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_MBMSSessionStopRequest; + out = &pdu.choice.initiatingMessage.value.choice.MBMSSessionStopRequest; + + /* mandatory */ + /* c1. MME_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStopRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStopRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStopRequest_IEs__value_PR_MME_MBMS_M3AP_ID; + //ie->value.choice.MME_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionStopRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStopRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionStopRequest_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + + /* encode */ + if (m3ap_encode_pdu(&pdu,&buffer,&len) < 0){ + return -1; + } + + //MME_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_mce->assoid,buffer,len,0); + m3ap_MME_itti_send_sctp_data_req(instance, m3ap_mme_data_from_mce->assoc_id,buffer,len,0); + return 0; + + + +} + +int MME_handle_MBMS_SESSION_STOP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + //AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M3AP, "eNB_handle_MBMS_SESSION_STOP_RESPONSE\n"); + + AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome, + "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M3AP_ProcedureCode_id_mBMSsessionStop, + "pdu->choice.successfulOutcome->procedureCode != M3AP_ProcedureCode_id_sessionStop\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M3AP_Criticality_reject, + "pdu->choice.successfulOutcome->criticality != M3AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M3AP_SuccessfulOutcome__value_PR_MBMSSessionStopResponse, + "pdu->choice.successfulOutcome->value.present != M3AP_SuccessfulOutcome__value_PR_MBMSSessionStopResponse\n"); + + + M3AP_MBMSSessionStopResponse_t *in = &pdu->choice.successfulOutcome.value.choice.MBMSSessionStopResponse; + M3AP_MBMSSessionStopResponse_IEs_t *ie; + int MME_MBMS_M3AP_ID=-1; + int MCE_MBMS_M3AP_ID=-1; + + + MessageDef *msg_g = itti_alloc_new_message(TASK_M3AP_MME,M3AP_MBMS_SESSION_STOP_RESP); //TODO + + LOG_D(M3AP, "M3AP: MBMSSessionStop-Resp: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (int i=0;i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID: + AssertFatal(ie->criticality == M3AP_Criticality_reject, + "ie->criticality != M3AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M3AP_MBMSSessionStopResponse_IEs__value_PR_MME_MBMS_M3AP_ID, + "ie->value.present != M3AP_MBMSStopResponse_IEs__value_PR_MME_MBMS_M3AP_ID\n"); + MME_MBMS_M3AP_ID=ie->value.choice.MME_MBMS_M3AP_ID; + LOG_D(M3AP, "M3AP: MBMSSessionStop-Resp: MME_MBMS_M3AP_ID %d\n", + MME_MBMS_M3AP_ID); + break; + case M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID: + AssertFatal(ie->criticality == M3AP_Criticality_reject, + "ie->criticality != M3AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M3AP_MBMSSessionStopResponse_IEs__value_PR_MCE_MBMS_M3AP_ID, + "ie->value.present != M3AP_MBMSStopResponse_IEs__value_PR_MCE_MBMS_M3AP_ID\n"); + MCE_MBMS_M3AP_ID=ie->value.choice.MCE_MBMS_M3AP_ID; + LOG_D(M3AP, "M3AP: MBMSSessionStop-Resp: MCE_MBMS_M3AP_ID %d\n", + MCE_MBMS_M3AP_ID); + break; + } + } + + //AssertFatal(MME_MBMS_M3AP_ID!=-1,"MME_MBMS_M3AP_ID was not sent\n"); + //AssertFatal(MCE_MBMS_M3AP_ID!=-1,"MCE_MBMS_M3AP_ID was not sent\n"); + // M3AP_SESSION_STOP_RESP(msg_p). + // MSC_LOG_RX_MESSAGE( + // MSC_M3AP_MME, + // MSC_M3AP_MCE, + // 0, + // 0, + // MSC_AS_TIME_FMT" MME_handle_M2_SESSION_STOP_RESPONSE successfulOutcome assoc_id %d", + // 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + // assoc_id); + + // LOG_D(M3AP, "Sending M3AP_SESSION_START_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n", + // assoc_id,MCE_MODULE_ID_TO_INSTANCE(assoc_id)); + itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g); +// // + return 0; +} + + + +int MME_handle_MBMS_SESSION_STOP_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + + + + +/* + * Reset + */ + +int MME_send_RESET(instance_t instance, m3ap_reset_t * m3ap_reset) { + AssertFatal(1==0,"Not implemented yet\n"); + //M3AP_Reset_t Reset; + +} + + +int MME_handle_RESET_ACKKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) { + AssertFatal(1==0,"Not implemented yet\n"); + +} + +int MME_handle_RESET(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) { + AssertFatal(1==0,"Not implemented yet\n"); +} + +int MME_send_RESET_ACKNOWLEDGE(instance_t instance, M3AP_ResetAcknowledge_t *ResetAcknowledge) { + AssertFatal(1==0,"Not implemented yet\n"); +} + +/* + * M3 Setup + */ +int MME_handle_M3_SETUP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) +{ + LOG_D(M2AP, "MCE_handle_M3_SETUP_REQUEST assoc_id %d\n",assoc_id); + + //AssertFatal(1==0,"Not implemented yet\n"); +// LOG_W(M3AP, "MME_handle_M3_SETUP_REQUEST assoc_id %d\n",assoc_id); +// + MessageDef *message_p; +// M3AP_M3SetupRequest_t *container; +// M3AP_M3SetupRequestIEs_t *ie; +// int i = 0,j=0; +// +// DevAssert(pdu != NULL); +// +// container = &pdu->choice.initiatingMessage.value.choice.M3SetupRequest; +// +// /* M3 Setup Request == Non UE-related procedure -> stream 0 */ +// if (stream != 0) { +// LOG_W(M3AP, "[SCTP %d] Received m3 setup request on stream != 0 (%d)\n", +// assoc_id, stream); +// } +// + message_p = itti_alloc_new_message(TASK_M3AP_MME, M3AP_SETUP_REQ); + //printf("M3AP_SETUP_REQ(message_p).assoc_id %d\n",M3AP_SETUP_REQ(message_p).assoc_id); +// +// /* assoc_id */ + M3AP_SETUP_REQ(message_p).assoc_id = assoc_id; +// +// /* GlobalMCE_id */ +// // this function exits if the ie is mandatory +// M3AP_FIND_PROTOCOLIE_BY_ID(M3AP_M3SetupRequestIEs_t, ie, container, +// M3AP_ProtocolIE_ID_id_Global_MCE_ID, true); +// asn_INTEGER2ulong(&ie->value.choice.GlobalMCE_ID, &M3AP_SETUP_REQ(message_p).GlobalMCE_ID); +// LOG_W(M3AP, "M3AP_SETUP_REQ(message_p).GlobalMCE_ID %lu \n", M3AP_SETUP_REQ(message_p).GlobalMCE_ID); +// +// /* MCE_name */ +// M3AP_FIND_PROTOCOLIE_BY_ID(M3AP_M3SetupRequestIEs_t, ie, container, +// M3AP_ProtocolIE_ID_id_MCEname, true); +// M3AP_SETUP_REQ(message_p).MCEname = calloc(ie->value.choice.MCEname.size + 1, sizeof(char)); +// memcpy(M3AP_SETUP_REQ(message_p).MCEname, ie->value.choice.MCEname.buf, +// ie->value.choice.MCEname.size); +// +// /* Convert the mme name to a printable string */ +// M3AP_SETUP_REQ(message_p).MCEname[ie->value.choice.MCEname.size] = '\0'; +// LOG_W(M3AP, "M3AP_SETUP_REQ(message_p).gNB_DU_name %s \n", M3AP_SETUP_REQ(message_p).MCEname); +// /* MCE_MBMS_Configuration_data_List */ +// M3AP_FIND_PROTOCOLIE_BY_ID(M3AP_M3SetupRequestIEs_t, ie, container, +// M3AP_ProtocolIE_ID_id_MCE_MBMS_Configuration_data_List, true); +// M3AP_SETUP_REQ(message_p).num_mbms_available = ie->value.choice.MCE_MBMS_Configuration_data_List.list.count; +// LOG_W(M3AP, "M3AP_SETUP_REQ(message_p).num_mbms_available %d \n", +// M3AP_SETUP_REQ(message_p).num_mbms_available); +// int num_mbms_available = M3AP_SETUP_REQ(message_p).num_mbms_available; +// for (i=0; ivalue.choice.MCE_MBMS_Configuration_data_List.list.array[i])->value.choice.MCE_MBMS_Configuration_data_Item); +// /* eCGI */ +// //mbms_configuration_item_p->eCGI ... (M3AP_ECGI_t) +// +// OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->eCGI.pLMN_Identity),M3AP_SETUP_REQ(message_p).plmn_identity[i]); +// //OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->eCGI.eUTRANcellIdentifier),M3AP_SETUP_REQ(message_p).eutran_cell_identifier[i]); +// /* mbsfnSynchronisationArea */ +// //mbms_configuration_item_p->mbsfnSynchronisationArea ... (M3AP_MBSFN_SynchronisationArea_ID_t) +// +// M3AP_SETUP_REQ(message_p).mbsfn_synchronization_area[i]=mbms_configuration_item_p->mbsfnSynchronisationArea; +// /* mbmsServiceAreaList */ +// //mbms_configuration_item_p->mbmsServiceAreaList ... (M3AP_MBMS_Service_Area_ID_List_t) +// for(j=0;j<1;j++){ +// //OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->mbmsServiceAreaList.list.array[j]), M3AP_SETUP_REQ(message_p).service_area_id[i][j]); +// } +// +// } +// +//// /* tac */ +//// OCTET_STRING_TO_INT16(&(served_celles_item_p->served_Cell_Information.fiveGS_TAC), M3AP_SETUP_REQ(message_p).tac[i]); +//// LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).tac[%d] %d \n", +//// i, M3AP_SETUP_REQ(message_p).tac[i]); +//// +//// /* - nRCGI */ +//// TBCD_TO_MCC_MNC(&(served_celles_item_p->served_Cell_Information.nRCGI.pLMN_Identity), M3AP_SETUP_REQ(message_p).mcc[i], +//// M3AP_SETUP_REQ(message_p).mnc[i], +//// M3AP_SETUP_REQ(message_p).mnc_digit_length[i]); +//// +//// +//// // NR cellID +//// BIT_STRING_TO_NR_CELL_IDENTITY(&served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity, +//// M3AP_SETUP_REQ(message_p).nr_cellid[i]); +//// LOG_D(M3AP, "[SCTP %d] Received nRCGI: MCC %d, MNC %d, CELL_ID %llu\n", assoc_id, +//// M3AP_SETUP_REQ(message_p).mcc[i], +//// M3AP_SETUP_REQ(message_p).mnc[i], +//// (long long unsigned int)M3AP_SETUP_REQ(message_p).nr_cellid[i]); +//// LOG_D(M3AP, "nr_cellId : %x %x %x %x %x\n", +//// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[0], +//// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[1], +//// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[2], +//// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[3], +//// served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[4]); +//// /* - nRPCI */ +//// M3AP_SETUP_REQ(message_p).nr_pci[i] = served_celles_item_p->served_Cell_Information.nRPCI; +//// LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).nr_pci[%d] %d \n", +//// i, M3AP_SETUP_REQ(message_p).nr_pci[i]); +//// +//// // System Information +//// /* mib */ +//// M3AP_SETUP_REQ(message_p).mib[i] = calloc(served_celles_item_p->gNB_DU_System_Information->mIB_message.size + 1, sizeof(char)); +//// memcpy(M3AP_SETUP_REQ(message_p).mib[i], served_celles_item_p->gNB_DU_System_Information->mIB_message.buf, +//// served_celles_item_p->gNB_DU_System_Information->mIB_message.size); +//// /* Convert the mme name to a printable string */ +//// M3AP_SETUP_REQ(message_p).mib[i][served_celles_item_p->gNB_DU_System_Information->mIB_message.size] = '\0'; +//// M3AP_SETUP_REQ(message_p).mib_length[i] = served_celles_item_p->gNB_DU_System_Information->mIB_message.size; +//// LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).mib[%d] %s , len = %d \n", +//// i, M3AP_SETUP_REQ(message_p).mib[i], M3AP_SETUP_REQ(message_p).mib_length[i]); +//// +//// /* sib1 */ +//// M3AP_SETUP_REQ(message_p).sib1[i] = calloc(served_celles_item_p->gNB_DU_System_Information->sIB1_message.size + 1, sizeof(char)); +//// memcpy(M3AP_SETUP_REQ(message_p).sib1[i], served_celles_item_p->gNB_DU_System_Information->sIB1_message.buf, +//// served_celles_item_p->gNB_DU_System_Information->sIB1_message.size); +//// /* Convert the mme name to a printable string */ +//// M3AP_SETUP_REQ(message_p).sib1[i][served_celles_item_p->gNB_DU_System_Information->sIB1_message.size] = '\0'; +//// M3AP_SETUP_REQ(message_p).sib1_length[i] = served_celles_item_p->gNB_DU_System_Information->sIB1_message.size; +//// LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).sib1[%d] %s , len = %d \n", +//// i, M3AP_SETUP_REQ(message_p).sib1[i], M3AP_SETUP_REQ(message_p).sib1_length[i]); +//// } +// +// + //printf("m3ap_mme_data_from_mce->assoc_id %d %d\n",m3ap_mme_data_from_mce->assoc_id,assoc_id); + *m3ap_mme_data_from_mce = M3AP_SETUP_REQ(message_p); + //printf("m3ap_mme_data_from_mce->assoc_id %d %d\n",m3ap_mme_data_from_mce->assoc_id,assoc_id); +// +//// MSC_LOG_TX_MESSAGE( +//// MSC_M3AP_MME, +//// MSC_RRC_MCE, +//// 0, +//// 0, +//// MSC_AS_TIME_FMT" MME_handle_M3_SETUP_REQUEST", +//// 0,0//MSC_AS_TIME_ARGS(ctxt_pP), +//// ); +//// + itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p); +// if (num_mbms_available > 0) { +// itti_send_msg_to_task(TASK_MME_APP, MCE_MODULE_ID_TO_INSTANCE(instance), message_p); +// } else { +// //MME_send_M3_SETUP_FAILURE(instance); +// return -1; +// } +//// return 0; +// //TEST POINT MME -> eNB +// if(1){ +// printf("instance %d\n",instance); +// //MME_send_M3_SETUP_RESPONSE(instance,assoc_id,m3ap_mce_data_from_enb->assoc_id); +// //MME_send_MBMS_SESSION_START_REQUEST(instance,assoc_id); +// //MME_send_MBMS_SESSION_STOP_REQUEST(instance,assoc_id); +// //MME_send_MBMS_SCHEDULING_INFORMATION(instance,assoc_id,NULL); //TODO +// } +// else +// MME_send_M3_SETUP_FAILURE(instance,assoc_id); +// + return 0; +} + +int MME_send_M3_SETUP_RESPONSE(instance_t instance, /*uint32_t assoc_id,*/ + m3ap_setup_resp_t *m3ap_setup_resp) { + M3AP_M3AP_PDU_t pdu; + M3AP_M3SetupResponse_t *out; + M3AP_M3SetupResponseIEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i = 0; + + /* Create */ + /* 0. Message Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_successfulOutcome; + //pdu.choice.successfulOutcome = (M3AP_SuccessfulOutcome_t *)calloc(1, sizeof(M3AP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome.procedureCode = M3AP_ProcedureCode_id_m3Setup; + pdu.choice.successfulOutcome.criticality = M3AP_Criticality_reject; + pdu.choice.successfulOutcome.value.present = M3AP_SuccessfulOutcome__value_PR_M3SetupResponse; + out = &pdu.choice.successfulOutcome.value.choice.M3SetupResponse; + + /* mandatory */ + /* c4. CriticalityDiagnostics*/ + if (0) { + ie = (M3AP_M3SetupResponseIEs_t *)calloc(1, sizeof(M3AP_M3SetupResponseIEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_CriticalityDiagnostics; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_M3SetupFailureIEs__value_PR_CriticalityDiagnostics; + ie->value.choice.CriticalityDiagnostics.procedureCode = (M3AP_ProcedureCode_t *)calloc(1, sizeof(M3AP_ProcedureCode_t)); + *ie->value.choice.CriticalityDiagnostics.procedureCode = M3AP_ProcedureCode_id_m3Setup; + ie->value.choice.CriticalityDiagnostics.triggeringMessage = (M3AP_TriggeringMessage_t *)calloc(1, sizeof(M3AP_TriggeringMessage_t)); + *ie->value.choice.CriticalityDiagnostics.triggeringMessage = M3AP_TriggeringMessage_initiating_message; + ie->value.choice.CriticalityDiagnostics.procedureCriticality = (M3AP_Criticality_t *)calloc(1, sizeof(M3AP_Criticality_t)); + *ie->value.choice.CriticalityDiagnostics.procedureCriticality = M3AP_Criticality_reject; + //ie->value.choice.CriticalityDiagnostics.transactionID = (M2AP_TransactionID_t *)calloc(1, sizeof(M3AP_TransactionID_t)); + //*ie->value.choice.CriticalityDiagnostics.transactionID = 0; + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* encode */ + if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { + LOG_E(M3AP, "Failed to encode M3 response\n"); + return -1; + } + + //printf(",m3ap_mme_data_from_mce->assoc_id %d\n",m3ap_mme_data_from_mce->assoc_id); + + m3ap_MME_itti_send_sctp_data_req(instance,m3ap_mme_data_from_mce->assoc_id,buffer,len,0); + + return 0; +} + +int MME_send_M3_SETUP_FAILURE(instance_t instance,m3ap_setup_failure_t* m3ap_setup_failure) { + AssertFatal(1==0,"Not implemented yet\n"); + +// module_id_t enb_mod_idP; +// module_id_t mce_mod_idP; +// +// // This should be fixed +// enb_mod_idP = (module_id_t)0; +// mce_mod_idP = (module_id_t)0; +// +// M3AP_M3AP_PDU_t pdu; +// M3AP_M3SetupFailure_t *out; +// M3AP_M3SetupFailureIEs_t *ie; +// +// uint8_t *buffer; +// uint32_t len; +// +// /* Create */ +// /* 0. Message Type */ +// memset(&pdu, 0, sizeof(pdu)); +// pdu.present = M3AP_M3AP_PDU_PR_unsuccessfulOutcome; +// //pdu.choice.unsuccessfulOutcome = (M3AP_UnsuccessfulOutcome_t *)calloc(1, sizeof(M3AP_UnsuccessfulOutcome_t)); +// pdu.choice.unsuccessfulOutcome.procedureCode = M3AP_ProcedureCode_id_m3Setup; +// pdu.choice.unsuccessfulOutcome.criticality = M3AP_Criticality_reject; +// pdu.choice.unsuccessfulOutcome.value.present = M3AP_UnsuccessfulOutcome__value_PR_M2SetupFailure; +// out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure; +// +// /* mandatory */ +// /* c1. Transaction ID (integer value)*/ +// // ie = (M3AP_M3SetupFailure_Ies_t *)calloc(1, sizeof(M3AP_M3SetupFailure_Ies_t)); +// // ie->id = M3AP_ProtocolIE_ID_id_GlobalMCE_ID; +// // ie->criticality = M3AP_Criticality_reject; +// // ie->value.present = M3AP_M3SetupFailure_Ies__value_PR_GlobalMCE_ID; +// // ie->value.choice.GlobalMCE_ID = M3AP_get_next_transaction_identifier(enb_mod_idP, mce_mod_idP); +// // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* mandatory */ +// /* c2. Cause */ +// ie = (M3AP_M3SetupFailureIEs_t *)calloc(1, sizeof(M3AP_M3SetupFailureIEs_t)); +// ie->id = M3AP_ProtocolIE_ID_id_Cause; +// ie->criticality = M3AP_Criticality_ignore; +// ie->value.present = M3AP_M3SetupFailure_Ies__value_PR_Cause; +// ie->value.choice.Cause.present = M3AP_Cause_PR_radioNetwork; +// ie->value.choice.Cause.choice.radioNetwork = M3AP_CauseRadioNetwork_unspecified; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// +// /* optional */ +// /* c3. TimeToWait */ +// if (0) { +// ie = (M3AP_M3SetupFailureIEs_t *)calloc(1, sizeof(M3AP_M3SetupFailureIEs_t)); +// ie->id = M3AP_ProtocolIE_ID_id_TimeToWait; +// ie->criticality = M3AP_Criticality_ignore; +// ie->value.present = M3AP_M3SetupFailure_Ies__value_PR_TimeToWait; +// ie->value.choice.TimeToWait = M3AP_TimeToWait_v10s; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* optional */ +// /* c4. CriticalityDiagnostics*/ +// if (0) { +// ie = (M3AP_M3SetupFailureIEs_t *)calloc(1, sizeof(M3AP_M3SetupFailureIEs_t)); +// ie->id = M3AP_ProtocolIE_ID_id_CriticalityDiagnostics; +// ie->criticality = M3AP_Criticality_ignore; +// ie->value.present = M3AP_M3SetupFailure_Ies__value_PR_CriticalityDiagnostics; +// ie->value.choice.CriticalityDiagnostics.procedureCode = (M3AP_ProcedureCode_t *)calloc(1, sizeof(M3AP_ProcedureCode_t)); +// *ie->value.choice.CriticalityDiagnostics.procedureCode = M3AP_ProcedureCode_id_m3Setup; +// ie->value.choice.CriticalityDiagnostics.triggeringMessage = (M3AP_TriggeringMessage_t *)calloc(1, sizeof(M3AP_TriggeringMessage_t)); +// *ie->value.choice.CriticalityDiagnostics.triggeringMessage = M3AP_TriggeringMessage_initiating_message; +// ie->value.choice.CriticalityDiagnostics.procedureCriticality = (M3AP_Criticality_t *)calloc(1, sizeof(M3AP_Criticality_t)); +// *ie->value.choice.CriticalityDiagnostics.procedureCriticality = M3AP_Criticality_reject; +// //ie->value.choice.CriticalityDiagnostics.transactionID = (M3AP_TransactionID_t *)calloc(1, sizeof(M3AP_TransactionID_t)); +// //*ie->value.choice.CriticalityDiagnostics.transactionID = 0; +// ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); +// } +// +// /* encode */ +// if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) { +// LOG_E(M3AP, "Failed to encode M2 setup request\n"); +// return -1; +// } +// +// //mce_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_enb->assoc_id, buffer, len, 0); +// m3ap_MME_itti_send_sctp_data_req(instance,m3ap_mme_data_from_mce->assoc_id,buffer,len,0); + + return 0; +} + +/* + * MME Configuration Update + */ + + +int MME_handle_MME_CONFIGURATION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + + +int MME_handle_MME_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + + +/* + * MCE Configuration Update + */ + + +int MME_handle_MCE_CONFIGURATION_UPDATE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + + + + + + +/* + * Error Indication + */ + +int MME_handle_ERROR_INDICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu) { + AssertFatal(1==0,"Not implemented yet\n"); + + +} + +int MME_send_ERROR_INDICATION(instance_t instance, M3AP_ErrorIndication_t *ErrorIndication) { + AssertFatal(1==0,"Not implemented yet\n"); +} + + + + +/* + * Session Update Request + */ +int MME_send_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, m3ap_mbms_session_update_req_t * m3ap_mbms_session_update_req){ + M3AP_M3AP_PDU_t pdu; + M3AP_MBMSSessionUpdateRequest_t *out; + M3AP_MBMSSessionUpdateRequest_IEs_t *ie; + + uint8_t *buffer; + uint32_t len; + //int i=0; + //int j=0; + + /* Create */ + /* 0. pdu Type */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage; + //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_mBMSsessionUpdate; + pdu.choice.initiatingMessage.criticality = M3AP_Criticality_reject; + pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_MBMSSessionUpdateRequest; + out = &pdu.choice.initiatingMessage.value.choice.MBMSSessionUpdateRequest; + + /* mandatory */ + /* c1. MME_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MME_MBMS_M3AP_ID; + //ie->value.choice.MME_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. MCE_MBMS_M3AP_ID (integer value) */ //long + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MCE_MBMS_M3AP_ID; + //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //? + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + + /* mandatory */ + /* c2. TMGI */ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_TMGI; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_TMGI; + M3AP_TMGI_t *tmgi = &ie->value.choice.TMGI; + { + MCC_MNC_TO_PLMNID(0,0,3,&tmgi->pLMNidentity); + uint8_t TMGI[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(&tmgi->serviceID,(const char*)&TMGI[2],3); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* optional */ + /* c2. MBMS_Session_ID */ + if(0){ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Session_ID; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Session_ID; + //M3AP_MBMS_Session_ID_t * mbms_session_id = &ie->value.choice.MBMS_Session_ID; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + /* mandatory */ + /* c2. MBMS_E_RAB_QoS_Parameters */ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_E_RAB_QoS_Parameters; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_E_RAB_QoS_Parameters; + M3AP_MBMS_E_RAB_QoS_Parameters_t * mbms_e_rab_qos_parameters = &ie->value.choice.MBMS_E_RAB_QoS_Parameters; + { + //M3AP_QCI_t * qci = &mbms_e_rab_qos_parameters->qCI; //long + mbms_e_rab_qos_parameters->qCI=1; + //struct M3AP_GBR_QosInformation *gbrQosInformation; /* OPTIONAL */ + } + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* mandatory */ + /* c2. MBMS_Session_Duration */ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Session_Duration; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Session_Duration; + M3AP_MBMS_Session_Duration_t * mbms_session_duration = &ie->value.choice.MBMS_Session_Duration; + { + uint8_t duration[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(mbms_session_duration,(const char*)&duration[2],3); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* optional */ + /* c2 MBMS_Service_Area */ + if(0){ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Service_Area; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Service_Area; + //M3AP_MBMS_Service_Area_t * mbms_service_area = &ie->value.choice.MBMS_Service_Area; + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + /* mandatory */ + /* c2 MinimumTimeToMBMSDataTransfer */ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MinimumTimeToMBMSDataTransfer; + ie->criticality = M3AP_Criticality_reject; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MinimumTimeToMBMSDataTransfer; + M3AP_MinimumTimeToMBMSDataTransfer_t * minimumtimetombmsdatatransfer = &ie->value.choice.MinimumTimeToMBMSDataTransfer; + { + uint8_t duration[5] = {4,3,2,1,0}; + OCTET_STRING_fromBuf(minimumtimetombmsdatatransfer,(const char*)&duration[2],1); + } + + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + /* optional */ + /* c2 TNL_Information */ + if(0){ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_TNL_Information; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_TNL_Information; + M3AP_TNL_Information_t * tnl_information = &ie->value.choice.TNL_Information; + { + OCTET_STRING_fromBuf(&tnl_information->iPMCAddress,"1204",strlen("1234")); + OCTET_STRING_fromBuf(&tnl_information->iPSourceAddress,"1204",strlen("1234")); + OCTET_STRING_fromBuf(&tnl_information->gTP_DLTEID,"1204",strlen("1234")); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + /* optional */ + /* c2 Time_ofMBMS_DataTransfer */ + if(0){ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_Time_ofMBMS_DataTransfer; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_Absolute_Time_ofMBMS_Data; + //M3AP_Absolute_Time_ofMBMS_Data_t * absolute_time_ofmbms_data = &ie->value.choice.Absolute_Time_ofMBMS_Data; + //{ + //char duration[5] = {4,3,2,1,0}; + //OCTET_STRING_fromBuf(absolute_time_ofmbms_data,(const char*)&duration[2],3); + //} + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + /* optional */ + /* c2 MBMS_Cell_List */ + if(0){ + ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t)); + ie->id = M3AP_ProtocolIE_ID_id_MBMS_Cell_List; + ie->criticality = M3AP_Criticality_ignore; + ie->value.present = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Cell_List; + M3AP_MBMS_Cell_List_t * mbms_cell_list = &ie->value.choice.MBMS_Cell_List; + M3AP_ECGI_t * ecgi = (M3AP_ECGI_t*)calloc(1,sizeof(M3AP_ECGI_t)); + { + //MCC_MNC_TO_PLMNID(0,0,3,ecgi->pLMN_Identity); + //MACRO_ENB_ID_TO_CELL_IDENTITY(1,0,ecgi->eUTRANcellIdentifier); + ASN_SEQUENCE_ADD(&mbms_cell_list->list,ecgi); + } + ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie); + } + + /* encode */ + if (m3ap_encode_pdu(&pdu,&buffer,&len) < 0){ + return -1; + } + + //MME_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_mce->assoid,buffer,len,0); + m3ap_MME_itti_send_sctp_data_req(instance, m3ap_mme_data_from_mce->assoc_id,buffer,len,0); + return 0; + + + +} + + + +int MME_handle_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + //AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(M3AP, "MME_handle_MBMS_SESSION_UPDATE_RESPONSE\n"); + + AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome, + "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n"); + AssertFatal(pdu->choice.successfulOutcome.procedureCode == M3AP_ProcedureCode_id_mBMSsessionUpdate, + "pdu->choice.successfulOutcome->procedureCode != M3AP_ProcedureCode_id_sessionUpdate\n"); + AssertFatal(pdu->choice.successfulOutcome.criticality == M3AP_Criticality_reject, + "pdu->choice.successfulOutcome->criticality != M3AP_Criticality_reject\n"); + AssertFatal(pdu->choice.successfulOutcome.value.present == M3AP_SuccessfulOutcome__value_PR_MBMSSessionUpdateResponse, + "pdu->choice.successfulOutcome.value.present != M3AP_SuccessfulOutcome__value_PR_MBMSSessionUpdateResponse\n"); + + + M3AP_MBMSSessionUpdateResponse_t *in = &pdu->choice.successfulOutcome.value.choice.MBMSSessionUpdateResponse; + M3AP_MBMSSessionUpdateResponse_IEs_t *ie; + int MME_MBMS_M3AP_ID=-1; + int MCE_MBMS_M3AP_ID=-1; + + + MessageDef *msg_g = itti_alloc_new_message(TASK_M3AP_MME,M3AP_MBMS_SESSION_UPDATE_RESP); //TODO + + LOG_D(M3AP, "M3AP: SessionUpdate-Resp: protocolIEs.list.count %d\n", + in->protocolIEs.list.count); + for (int i=0;i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID: + AssertFatal(ie->criticality == M3AP_Criticality_reject, + "ie->criticality != M3AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M3AP_MBMSSessionUpdateResponse_IEs__value_PR_MME_MBMS_M3AP_ID, + "ie->value.present != M3AP_sessionUpdateResponse_IEs__value_PR_MME_MBMS_M3AP_ID\n"); + MME_MBMS_M3AP_ID=ie->value.choice.MME_MBMS_M3AP_ID; + LOG_D(M3AP, "M3AP: SessionUpdate-Resp: MME_MBMS_M3AP_ID %d\n", + MME_MBMS_M3AP_ID); + break; + case M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID: + AssertFatal(ie->criticality == M3AP_Criticality_reject, + "ie->criticality != M3AP_Criticality_reject\n"); + AssertFatal(ie->value.present == M3AP_MBMSSessionUpdateResponse_IEs__value_PR_MCE_MBMS_M3AP_ID, + "ie->value.present != M3AP_sessionUpdateResponse_IEs__value_PR_MCE_MBMS_M3AP_ID\n"); + MCE_MBMS_M3AP_ID=ie->value.choice.MCE_MBMS_M3AP_ID; + LOG_D(M3AP, "M3AP: SessionUpdate-Resp: MCE_MBMS_M3AP_ID %d\n", + MCE_MBMS_M3AP_ID); + break; + } + } + + //AssertFatal(MME_MBMS_M3AP_ID!=-1,"MME_MBMS_M3AP_ID was not sent\n"); + //AssertFatal(MCE_MBMS_M3AP_ID!=-1,"MCE_MBMS_M3AP_ID was not sent\n"); + ////M3AP_SESSION_START_RESP(msg_p). +//// MSC_LOG_RX_MESSAGE( +//// MSC_M3AP_MME, +//// MSC_M3AP_MCE, + // //return 0; +//// 0, +//// 0, +//// MSC_AS_TIME_FMT" MME_handle_M2_SESSION_START_RESPONSE successfulOutcome assoc_id %d", +//// 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), +//// assoc_id); +//// + // LOG_W(M3AP, "Sending M3AP_SESSION_START_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n", + // assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id)); + itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g); + + return 0; + +} + + + +int MME_handle_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + + + +int MME_handle_MBMS_SERVICE_COUNTING_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); +} + + + +int MME_handle_MBMS_SESSION_COUNTING_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + +/* + * Service Counting Results Report + */ + +int MME_handle_MBMS_SESSION_COUNTING_RESULTS_REPORT(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + +/* + * Overload Notification + */ +int MME_handle_MBMS_OVERLOAD_NOTIFICATION(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu){ + AssertFatal(1==0,"Not implemented yet\n"); + +} + + + + diff --git a/openair3/M3AP/m3ap_MME_interface_management.h b/openair3/M3AP/m3ap_MME_interface_management.h new file mode 100644 index 0000000000..d3765182ce --- /dev/null +++ b/openair3/M3AP/m3ap_MME_interface_management.h @@ -0,0 +1,111 @@ +/* + * 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 m3ap_MME_interface_management.h + * \brief m3ap interface management for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#ifndef M3AP_MME_INTERFACE_MANAGEMENT_H_ +#define M3AP_MME_INTERFACE_MANAGEMENT_H_ +/* + * MBMS Session start + */ +int MME_send_MBMS_SESSION_START_REQUEST(instance_t instance/*, + uint32_t assoc_id*/,m3ap_session_start_req_t* m3ap_session_start_req); +int MME_handle_MBMS_SESSION_START_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +int MME_handle_MBMS_SESSION_START_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); +/* + * MBMS Session stop + */ +int MME_send_MBMS_SESSION_STOP_REQUEST(instance_t instance, + m3ap_session_stop_req_t* m3ap_session_stop_req); + +int MME_handle_MBMS_SESSION_STOP_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +/* + * Update + */ +int MME_handle_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +int MME_handle_MBMS_SESSION_UPDATE_FAILURE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + + + +/* + * Reset + */ +int MME_send_RESET(instance_t instance, m3ap_reset_t * m3ap_reset); + +int MME_handle_RESET_ACKKNOWLEDGE(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +int MME_handle_RESET(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); +int MME_send_RESET_ACKNOWLEDGE(instance_t instance, M3AP_ResetAcknowledge_t *ResetAcknowledge); + +/* + * M3AP Setup + */ +int MME_handle_M3_SETUP_REQUEST(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +int MME_send_M3_SETUP_RESPONSE(instance_t instance,/*uint32_t assoc_id,*/ m3ap_setup_resp_t *m3ap_setup_resp); + +int MME_send_M3_SETUP_FAILURE(instance_t instance, /*uint32_t assoc_id*/ m3ap_setup_failure_t * m3ap_setup_failure); + + + + + + +#endif /* M3AP_MME_INTERFACE_MANAGEMENT_H_ */ + + + diff --git a/openair3/M3AP/m3ap_MME_management_procedures.c b/openair3/M3AP/m3ap_MME_management_procedures.c new file mode 100644 index 0000000000..11d2924249 --- /dev/null +++ b/openair3/M3AP/m3ap_MME_management_procedures.c @@ -0,0 +1,257 @@ +/* + * 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 m3ap_MME_management_procedures.c + * \brief m3ap tasks for MME + * \author Javier Morgade + * \date 2018 + * \version 1.0 + */ + +#include +#include +#include + +#include "intertask_interface.h" + +#include "assertions.h" +#include "conversions.h" + +#include "m3ap_common.h" +#include "m3ap_MME_defs.h" +#include "m3ap_MME.h" + + +#define M3AP_DEBUG_LIST +#ifdef M3AP_DEBUG_LIST +# define M3AP_MME_LIST_OUT(x, args...) M3AP_DEBUG("[MME]%*s"x"\n", 4*indent, "", ##args) +#else +# define M3AP_MME_LIST_OUT(x, args...) +#endif + +static int indent = 0; + + +m3ap_MME_internal_data_t m3ap_MME_internal_data; + +RB_GENERATE(m3ap_mme_map, m3ap_MME_data_s, entry, m3ap_MME_compare_assoc_id); + +int m3ap_MME_compare_assoc_id( + struct m3ap_MME_data_s *p1, struct m3ap_MME_data_s *p2) +{ + if (p1->assoc_id == -1) { + if (p1->cnx_id < p2->cnx_id) { + return -1; + } + + if (p1->cnx_id > p2->cnx_id) { + return 1; + } + } else { + if (p1->assoc_id < p2->assoc_id) { + return -1; + } + + if (p1->assoc_id > p2->assoc_id) { + return 1; + } + } + + /* Matching reference */ + return 0; +} + +uint16_t m3ap_MME_fetch_add_global_cnx_id(void) +{ + return ++m3ap_MME_internal_data.global_cnx_id; +} + +void m3ap_MME_prepare_internal_data(void) +{ + memset(&m3ap_MME_internal_data, 0, sizeof(m3ap_MME_internal_data)); + STAILQ_INIT(&m3ap_MME_internal_data.m3ap_MME_instances_head); +} + +void m3ap_MME_insert_new_instance(m3ap_MME_instance_t *new_instance_p) +{ + DevAssert(new_instance_p != NULL); + + STAILQ_INSERT_TAIL(&m3ap_MME_internal_data.m3ap_MME_instances_head, + new_instance_p, m3ap_MME_entries); +} + +void dump_mme_tree_m2(m3ap_MME_data_t *t) +{ + if (t == NULL) return; + printf("-----------------------\n"); + printf("MME id %d %s\n", t->MME_id, t->MME_name); + printf("state %d\n", t->state); + printf("nextstream %d\n", t->nextstream); + printf("in_streams %d out_streams %d\n", t->in_streams, t->out_streams); + printf("cnx_id %d assoc_id %d\n", t->cnx_id, t->assoc_id); + dump_mme_tree_m2(t->entry.rbe_left); + dump_mme_tree_m2(t->entry.rbe_right); +} + +void dump_mme_trees_m2(void) +{ +m3ap_MME_instance_t *zz; +STAILQ_FOREACH(zz, &m3ap_MME_internal_data.m3ap_MME_instances_head, + m3ap_MME_entries) { +printf("here comes the tree (instance %d):\n---------------------------------------------\n", zz->instance); +dump_mme_tree_m2(zz->m3ap_mme_head.rbh_root); +printf("---------------------------------------------\n"); +} +} + +struct m3ap_MME_data_s *m3ap_get_MME(m3ap_MME_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id) +{ + struct m3ap_MME_data_s temp; + struct m3ap_MME_data_s *found; + +printf("m3ap_get_MME at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id); +dump_mme_trees_m2(); + + memset(&temp, 0, sizeof(struct m3ap_MME_data_s)); + + temp.assoc_id = assoc_id; + temp.cnx_id = cnx_id; + + if (instance_p == NULL) { + STAILQ_FOREACH(instance_p, &m3ap_MME_internal_data.m3ap_MME_instances_head, + m3ap_MME_entries) { + found = RB_FIND(m3ap_mme_map, &instance_p->m3ap_mme_head, &temp); + + if (found != NULL) { + return found; + } + } + } else { + return RB_FIND(m3ap_mme_map, &instance_p->m3ap_mme_head, &temp); + } + + return NULL; +} + + +m3ap_MME_instance_t *m3ap_MME_get_instance(instance_t instance) +{ + m3ap_MME_instance_t *temp = NULL; + + STAILQ_FOREACH(temp, &m3ap_MME_internal_data.m3ap_MME_instances_head, + m3ap_MME_entries) { + if (temp->instance == instance) { + /* Matching occurence */ + return temp; + } + } + + return NULL; +} + +/// utility functions + +void m3ap_dump_MME (m3ap_MME_data_t * MME_ref); + +void +m3ap_dump_MME_list (void) { + m3ap_MME_instance_t *inst = NULL; + struct m3ap_MME_data_s *found = NULL; + struct m3ap_MME_data_s temp; + + memset(&temp, 0, sizeof(struct m3ap_MME_data_s)); + + STAILQ_FOREACH (inst, &m3ap_MME_internal_data.m3ap_MME_instances_head, m3ap_MME_entries) { + found = RB_FIND(m3ap_mme_map, &inst->m3ap_mme_head, &temp); + m3ap_dump_MME (found); + } +} + +void m3ap_dump_MME (m3ap_MME_data_t * MME_ref) { + + if (MME_ref == NULL) { + return; + } + + M3AP_MME_LIST_OUT (""); + M3AP_MME_LIST_OUT ("MME name: %s", MME_ref->MME_name == NULL ? "not present" : MME_ref->MME_name); + M3AP_MME_LIST_OUT ("MME STATE: %07x", MME_ref->state); + M3AP_MME_LIST_OUT ("MME ID: %07x", MME_ref->MME_id); + indent++; + M3AP_MME_LIST_OUT ("SCTP cnx id: %d", MME_ref->cnx_id); + M3AP_MME_LIST_OUT ("SCTP assoc id: %d", MME_ref->assoc_id); + M3AP_MME_LIST_OUT ("SCTP instreams: %d", MME_ref->in_streams); + M3AP_MME_LIST_OUT ("SCTP outstreams: %d", MME_ref->out_streams); + indent--; +} + +m3ap_MME_data_t * m3ap_is_MME_pci_in_list (const uint32_t pci) +{ + m3ap_MME_instance_t *inst; + struct m3ap_MME_data_s *elm; + + STAILQ_FOREACH(inst, &m3ap_MME_internal_data.m3ap_MME_instances_head, m3ap_MME_entries) { + RB_FOREACH(elm, m3ap_mme_map, &inst->m3ap_mme_head) { + for (int i = 0; inum_cc; i++) { + if (elm->Nid_cell[i] == pci) { + return elm; + } + } + } + } + return NULL; +} + +m3ap_MME_data_t * m3ap_is_MME_id_in_list (const uint32_t MME_id) +{ + m3ap_MME_instance_t *inst; + struct m3ap_MME_data_s *elm; + + STAILQ_FOREACH(inst, &m3ap_MME_internal_data.m3ap_MME_instances_head, m3ap_MME_entries) { + RB_FOREACH(elm, m3ap_mme_map, &inst->m3ap_mme_head) { + if (elm->MME_id == MME_id) + return elm; + } + } + return NULL; +} + +m3ap_MME_data_t * m3ap_is_MME_assoc_id_in_list (const uint32_t sctp_assoc_id) +{ + m3ap_MME_instance_t *inst; + struct m3ap_MME_data_s *found; + struct m3ap_MME_data_s temp; + + temp.assoc_id = sctp_assoc_id; + temp.cnx_id = -1; + + STAILQ_FOREACH(inst, &m3ap_MME_internal_data.m3ap_MME_instances_head, m3ap_MME_entries) { + found = RB_FIND(m3ap_mme_map, &inst->m3ap_mme_head, &temp); + if (found != NULL){ + if (found->assoc_id == sctp_assoc_id) { + return found; + } + } + } + return NULL; +} diff --git a/openair3/M3AP/m3ap_MME_management_procedures.h b/openair3/M3AP/m3ap_MME_management_procedures.h new file mode 100644 index 0000000000..e966ee1f17 --- /dev/null +++ b/openair3/M3AP/m3ap_MME_management_procedures.h @@ -0,0 +1,54 @@ +/* + * 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 m3ap_eNB_management_procedures.h + * \brief m3ap tasks for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M3AP_MME_MANAGEMENT_PROCEDURES_H_ +#define M3AP_MME_MANAGEMENT_PROCEDURES_H + +void m3ap_MME_prepare_internal_data(void); + +void dump_trees_m2(void); + +void m3ap_MME_insert_new_instance(m3ap_MME_instance_t *new_instance_p); + +m3ap_MME_instance_t *m3ap_MME_get_instance(uint8_t mod_id); + +uint16_t m3ap_MME_fetch_add_global_cnx_id(void); + +void m3ap_MME_prepare_internal_data(void); + +m3ap_MME_data_t* m3ap_is_MME_id_in_list(uint32_t MME_id); + +m3ap_MME_data_t* m3ap_is_MME_assoc_id_in_list(uint32_t sctp_assoc_id); + +m3ap_MME_data_t* m3ap_is_MME_pci_in_list (const uint32_t pci); + +struct m3ap_MME_data_s *m3ap_get_MME(m3ap_MME_instance_t *instance_p, + int32_t assoc_id, + uint16_t cnx_id); + +#endif /* M3AP_MME_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair3/M3AP/m3ap_common.c b/openair3/M3AP/m3ap_common.c new file mode 100644 index 0000000000..5501997638 --- /dev/null +++ b/openair3/M3AP/m3ap_common.c @@ -0,0 +1,124 @@ +/* + * 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 m3ap_common.c + * \brief m3ap procedures for both eNB and MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "m3ap_common.h" +#include "M3AP_M3AP-PDU.h" + +int asn_debug = 0; +int asn1_xer_print = 0; + +#if defined(EMIT_ASN_DEBUG_EXTERN) +inline void ASN_DEBUG(const char *fmt, ...) +{ + if (asn_debug) { + int adi = asn_debug_indent; + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "[ASN1]"); + + while(adi--) fprintf(stderr, " "); + + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + } +} +#endif + +ssize_t m3ap_generate_initiating_message( + uint8_t **buffer, + uint32_t *length, + M3AP_ProcedureCode_t procedureCode, + M3AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + M3AP_M3AP_PDU_t pdu; + ssize_t encoded; + memset(&pdu, 0, sizeof(M3AP_M3AP_PDU_t)); + pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = procedureCode; + pdu.choice.initiatingMessage.criticality = criticality; + ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_M3AP_M3AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + return encoded; +} + + +ssize_t m3ap_generate_unsuccessfull_outcome( + uint8_t **buffer, + uint32_t *length, + M3AP_ProcedureCode_t procedureCode, + M3AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + M3AP_M3AP_PDU_t pdu; + ssize_t encoded; + memset(&pdu, 0, sizeof(M3AP_M3AP_PDU_t)); + pdu.present = M3AP_M3AP_PDU_PR_unsuccessfulOutcome; + pdu.choice.successfulOutcome.procedureCode = procedureCode; + pdu.choice.successfulOutcome.criticality = criticality; + ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_M3AP_M3AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + return encoded; +} + +void m3ap_handle_criticality(M3AP_Criticality_t criticality) +{ + +} + diff --git a/openair3/M3AP/m3ap_common.h b/openair3/M3AP/m3ap_common.h new file mode 100644 index 0000000000..7f68510314 --- /dev/null +++ b/openair3/M3AP/m3ap_common.h @@ -0,0 +1,175 @@ +/* + * 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 + */ + +#if HAVE_CONFIG_H_ +# include "config.h" +#endif + +#include "M3AP_ProtocolIE-Field.h" +#include "M3AP_M3AP-PDU.h" +#include "M3AP_InitiatingMessage.h" +#include "M3AP_SuccessfulOutcome.h" +#include "M3AP_UnsuccessfulOutcome.h" +#include "M3AP_ProtocolIE-FieldPair.h" +#include "M3AP_ProtocolIE-ContainerPair.h" +#include "M3AP_ProtocolExtensionField.h" +#include "M3AP_ProtocolExtensionContainer.h" +#include "M3AP_asn_constant.h" +#include "intertask_interface.h" + +#ifndef M3AP_COMMON_H_ +#define M3AP_COMMON_H_ + +/** @defgroup _m3ap_impl_ M3AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +/* Checking version of ASN1C compiler */ +#if (ASN1C_ENVIRONMENT_VERSION < 923) +# error "You are compiling m3ap with the wrong version of ASN1C" +#endif + +#ifndef M3AP_PORT +# define M3AP_PORT 36444 +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +extern int asn1_xer_print; + +#if defined(ENB_MODE) +# include "common/utils/LOG/log.h" +# include "m3ap_default_values.h" +# define M3AP_INFO(x, args...) LOG_I(M3AP, x, ##args) +# define M3AP_ERROR(x, args...) LOG_E(M3AP, x, ##args) +# define M3AP_WARN(x, args...) LOG_W(M3AP, x, ##args) +# define M3AP_DEBUG(x, args...) LOG_D(M3AP, x, ##args) +#else +# define M3AP_INFO(x, args...) do { fprintf(stdout, "[M3AP][I]"x, ##args); } while(0) +# define M3AP_ERROR(x, args...) do { fprintf(stdout, "[M3AP][E]"x, ##args); } while(0) +# define M3AP_WARN(x, args...) do { fprintf(stdout, "[M3AP][W]"x, ##args); } while(0) +# define M3AP_DEBUG(x, args...) do { fprintf(stdout, "[M3AP][D]"x, ##args); } while(0) +#endif + +#define M3AP_FIND_PROTOCOLIE_BY_ID(IE_TYPE, ie, container, IE_ID, mandatory) \ + do {\ + IE_TYPE **ptr; \ + ie = NULL; \ + for (ptr = container->protocolIEs.list.array; \ + ptr < &container->protocolIEs.list.array[container->protocolIEs.list.count]; \ + ptr++) { \ + if((*ptr)->id == IE_ID) { \ + ie = *ptr; \ + break; \ + } \ + } \ + if (mandatory) DevAssert(ie != NULL); \ + } while(0) + +/** \brief Function callback prototype. + **/ +typedef int (*m3ap_message_decoded_callback)( + instance_t instance, + uint32_t assocId, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + + +/** \brief Function callback prototype. + **/ +typedef int (*m3ap_MCE_message_decoded_callback)( + instance_t instance, + uint32_t assocId, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + +/** \brief Function callback prototype. + **/ +typedef int (*m3ap_MME_message_decoded_callback)( + instance_t instance, + uint32_t assocId, + uint32_t stream, + M3AP_M3AP_PDU_t *pdu); + + + +/** \brief Encode a successfull outcome message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t m3ap_generate_successfull_outcome( + uint8_t **buffer, + uint32_t *length, + M3AP_ProcedureCode_t procedureCode, + M3AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Encode an initiating message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t m3ap_generate_initiating_message( + uint8_t **buffer, + uint32_t *length, + M3AP_ProcedureCode_t procedureCode, + M3AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Encode an unsuccessfull outcome message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t m3ap_generate_unsuccessfull_outcome( + uint8_t **buffer, + uint32_t *length, + M3AP_ProcedureCode_t procedureCode, + M3AP_Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Handle criticality + \param criticality Criticality of the IE + @returns void + **/ +void m3ap_handle_criticality(M3AP_Criticality_t criticality); + +#endif /* M3AP_COMMON_H_ */ diff --git a/openair3/M3AP/m3ap_decoder.c b/openair3/M3AP/m3ap_decoder.c new file mode 100644 index 0000000000..cee0a5ff41 --- /dev/null +++ b/openair3/M3AP/m3ap_decoder.c @@ -0,0 +1,217 @@ +/* + * 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 m3ap_decoder.c + * \brief m3ap decoder procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "assertions.h" +#include "intertask_interface.h" +#include "m3ap_common.h" +#include "m3ap_decoder.h" + +static int m3ap_decode_initiating_message(M3AP_M3AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + switch(pdu->choice.initiatingMessage.procedureCode) { + case M3AP_ProcedureCode_id_mBMSsessionStart: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mBMSsessionStop: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_errorIndication: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_privateMessage: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_Reset: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mBMSsessionUpdate: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mCEConfigurationUpdate: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_m3Setup: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + default: + M3AP_ERROR("Unknown procedure ID (%d) for initiating message\n", + (int)pdu->choice.initiatingMessage.procedureCode); + AssertFatal( 0, "Unknown procedure ID (%d) for initiating message\n", + (int)pdu->choice.initiatingMessage.procedureCode); + return -1; + } + + return 0; + +} + + +static int m3ap_decode_successful_outcome(M3AP_M3AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + switch(pdu->choice.successfulOutcome.procedureCode) { + case M3AP_ProcedureCode_id_mBMSsessionStart: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_successfuloutcome_message!\n"); + break; + case M3AP_ProcedureCode_id_mBMSsessionStop: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_succesfuloutcome_message!\n"); + break; + case M3AP_ProcedureCode_id_errorIndication: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_privateMessage: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_Reset: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mBMSsessionUpdate: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mCEConfigurationUpdate: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_m3Setup: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_succesfuloutcome_message!\n"); + break; + default: + M3AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n", + (int)pdu->choice.successfulOutcome.procedureCode); + return -1; + } + + return 0; +} + +static int m3ap_decode_unsuccessful_outcome(M3AP_M3AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + switch(pdu->choice.unsuccessfulOutcome.procedureCode) { + case M3AP_ProcedureCode_id_mBMSsessionStart: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mBMSsessionStop: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_errorIndication: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_privateMessage: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_Reset: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mBMSsessionUpdate: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_mCEConfigurationUpdate: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + case M3AP_ProcedureCode_id_m3Setup: + //asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_M3AP_M3AP_PDU, pdu); + M3AP_INFO("m3ap__decode_initiating_message!\n"); + break; + default: + M3AP_ERROR("Unknown procedure ID (%d) for unsuccessfull outcome message\n", + (int)pdu->choice.unsuccessfulOutcome.procedureCode); + return -1; + } + + return 0; +} + +int m3ap_decode_pdu(M3AP_M3AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length) +{ + asn_dec_rval_t dec_ret; + + DevAssert(buffer != NULL); + + dec_ret = aper_decode(NULL, + &asn_DEF_M3AP_M3AP_PDU, + (void **)&pdu, + buffer, + length, + 0, + 0); + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, pdu); + } + + if (dec_ret.code != RC_OK) { + M3AP_ERROR("Failed to decode pdu\n"); + return -1; + } + + switch(pdu->present) { + case M3AP_M3AP_PDU_PR_initiatingMessage: + return m3ap_decode_initiating_message(pdu); + + case M3AP_M3AP_PDU_PR_successfulOutcome: + return m3ap_decode_successful_outcome(pdu); + + case M3AP_M3AP_PDU_PR_unsuccessfulOutcome: + return m3ap_decode_unsuccessful_outcome(pdu); + + default: + M3AP_DEBUG("Unknown presence (%d) or not implemented\n", (int)pdu->present); + break; + } + + + return -1; +} diff --git a/openair3/M3AP/m3ap_decoder.h b/openair3/M3AP/m3ap_decoder.h new file mode 100644 index 0000000000..6d228a1ceb --- /dev/null +++ b/openair3/M3AP/m3ap_decoder.h @@ -0,0 +1,35 @@ +/* + * 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 m3ap_decoder.h + * \brief m3ap decoder procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M3AP_DECODER_H_ +#define M3AP_DECODER_H_ + +int m3ap_decode_pdu(M3AP_M3AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length) +__attribute__ ((warn_unused_result)); + +#endif /* M3AP_DECODER_H_ */ diff --git a/openair3/M3AP/m3ap_default_values.h b/openair3/M3AP/m3ap_default_values.h new file mode 100644 index 0000000000..79c78d5b96 --- /dev/null +++ b/openair3/M3AP/m3ap_default_values.h @@ -0,0 +1,47 @@ +/* + * 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 m3ap_default_values.h + * \brief default values for m3ap procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + * \company Vicomtech + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#ifndef M3AP_DEFAULT_VALUES_H_ +#define M3AP_DEFAULT_VALUES_H_ + +#define ENB_TAC (1) +#define ENB_MCC (208) +#define ENB_MNC (92) + +#define ENB_NAME "Eurecom ENB" +#define ENB_NAME_FORMAT (ENB_NAME" %u") + +#define M3AP_PORT_NUMBER (36444) +#define M3AP_SCTP_PPID (44) + +#endif /* M3AP_DEFAULT_VALUES_H_ */ + diff --git a/openair3/M3AP/m3ap_encoder.c b/openair3/M3AP/m3ap_encoder.c new file mode 100644 index 0000000000..2e1cbf80af --- /dev/null +++ b/openair3/M3AP/m3ap_encoder.c @@ -0,0 +1,61 @@ +/* + * 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 m3ap_encoder.c + * \brief m3ap encoder procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include +#include +#include + +#include "assertions.h" +#include "conversions.h" +#include "intertask_interface.h" +#include "m3ap_common.h" +#include "m3ap_encoder.h" + +int m3ap_encode_pdu(M3AP_M3AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) +{ + ssize_t encoded; + + DevAssert(pdu != NULL); + DevAssert(buffer != NULL); + DevAssert(len != NULL); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)pdu); + } + + encoded = aper_encode_to_new_buffer(&asn_DEF_M3AP_M3AP_PDU, 0, pdu, (void **)buffer); + + if (encoded < 0) { + return -1; + } + + *len = encoded; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, pdu); + return encoded; +} diff --git a/openair3/M3AP/m3ap_encoder.h b/openair3/M3AP/m3ap_encoder.h new file mode 100644 index 0000000000..db444a611e --- /dev/null +++ b/openair3/M3AP/m3ap_encoder.h @@ -0,0 +1,35 @@ +/* + * 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 m3ap_encoder.h + * \brief m3ap encoder procedures + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M3AP_ENCODER_H_ +#define M3AP_ENCODER_H_ + +int m3ap_encode_pdu(M3AP_M3AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) +__attribute__ ((warn_unused_result)); + +#endif /* M3AP_ENCODER_H_ */ diff --git a/openair3/M3AP/m3ap_handler.c b/openair3/M3AP/m3ap_handler.c new file mode 100644 index 0000000000..832aa0dbac --- /dev/null +++ b/openair3/M3AP/m3ap_handler.c @@ -0,0 +1,123 @@ +/* + * 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 m3ap_eNB_handler.c + * \brief m3ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include + +#include "intertask_interface.h" + +#include "asn1_conversions.h" + +#include "m3ap_common.h" +#include "m3ap_MCE_defs.h" +#include "m3ap_handler.h" +#include "m3ap_decoder.h" +#include "m3ap_ids.h" + +#include "m3ap_MCE_management_procedures.h" +//#include "m3ap_MCE_generate_messages.h" + +#include "m3ap_MME_interface_management.h" +#include "m3ap_MCE_interface_management.h" + +#include "msc.h" +#include "assertions.h" +#include "conversions.h" + +/* Handlers matrix. Only eNB related procedure present here */ +m3ap_message_decoded_callback m3ap_messages_callback[][3] = { + { MCE_handle_MBMS_SESSION_START_REQUEST, MME_handle_MBMS_SESSION_START_RESPONSE, 0 }, /* MBMSSessionStart */ + { MCE_handle_MBMS_SESSION_STOP_REQUEST, MME_handle_MBMS_SESSION_STOP_RESPONSE, 0 }, /* MBMSSessionStop */ + { 0, 0, 0 }, /* Error Indication */ + { 0, 0, 0 }, /* Reset */ + { 0, 0, 0 }, /* ??? */ + { MCE_handle_MBMS_SESSION_UPDATE_REQUEST, MME_handle_MBMS_SESSION_UPDATE_RESPONSE, 0 }, /* MBMSSessionUpdate */ + { 0, 0, 0 }, /* MCEConfigurationUpdate */ + { MME_handle_M3_SETUP_REQUEST, MCE_handle_M3_SETUP_RESPONSE, 0 } /* M3 Setup */ +}; + +char *m3ap_direction2String(int m3ap_dir) { +static char *m3ap_direction_String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; +return(m3ap_direction_String[m3ap_dir]); +} + + +int m3ap_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length) +{ + M3AP_M3AP_PDU_t pdu; + int ret; + + DevAssert(data != NULL); + + memset(&pdu, 0, sizeof(pdu)); + + int i=0; + for( i=0; i < data_length; i++) + printf("%02X",data[i]); + printf("\n"); + + if (m3ap_decode_pdu(&pdu, data, data_length) < 0) { + LOG_E(M3AP, "Failed to decode PDU\n"); + return -1; + } + + /* Checking procedure Code and direction of message */ + if (pdu.choice.initiatingMessage.procedureCode > sizeof(m3ap_messages_callback) / (3 * sizeof( + m3ap_message_decoded_callback)) + || (pdu.present > M3AP_M3AP_PDU_PR_unsuccessfulOutcome)) { + LOG_E(M3AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return -1; + } + + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (m3ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) { + LOG_E(M3AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", + assoc_id, pdu.choice.initiatingMessage.procedureCode, + m3ap_direction2String(pdu.present - 1)); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return -1; + } + + /* Calling the right handler */ + LOG_I(M3AP, "Calling handler with instance %d\n",instance); + ret = (*m3ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1]) + (instance, assoc_id, stream, &pdu); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_M3AP_M3AP_PDU, &pdu); + return ret; +} + + diff --git a/openair3/M3AP/m3ap_handler.h b/openair3/M3AP/m3ap_handler.h new file mode 100644 index 0000000000..4b01307807 --- /dev/null +++ b/openair3/M3AP/m3ap_handler.h @@ -0,0 +1,43 @@ +/* + * 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 m2ap_handler.h + * \brief m2ap handler procedures for eNB + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M2AP_MCE_OLD_HANDLERS_H_ +#define M2AP_MCE_OLD_HANDLERS_H_ + +#include "m2ap_eNB_defs.h" + +//void m3ap_handle_m2_setup_message(m2ap_eNB_instance_t *instance_p, m2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown); + +//int m3ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + //const uint8_t * const data, const uint32_t data_length); + +int m3ap_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream, + const uint8_t * const data, const uint32_t data_length); + + +#endif /* M2AP_MCE_HANDLERS_H_ */ diff --git a/openair3/M3AP/m3ap_ids.c b/openair3/M3AP/m3ap_ids.c new file mode 100644 index 0000000000..8e0a9f2106 --- /dev/null +++ b/openair3/M3AP/m3ap_ids.c @@ -0,0 +1,128 @@ +/* + * 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 "m3ap_ids.h" + +#include + +void m3ap_id_manager_init(m3ap_id_manager *m) +{ + int i; + memset(m, 0, sizeof(m3ap_id_manager)); + for (i = 0; i < M3AP_MAX_IDS; i++) + m->ids[i].rnti = -1; +} + +int m3ap_allocate_new_id(m3ap_id_manager *m) +{ + int i; + for (i = 0; i < M3AP_MAX_IDS; i++) + if (m->ids[i].rnti == -1) { + m->ids[i].rnti = 0; + m->ids[i].id_source = -1; + m->ids[i].id_target = -1; + return i; + } + return -1; +} + +void m3ap_release_id(m3ap_id_manager *m, int id) +{ + m->ids[id].rnti = -1; +} + +int m3ap_find_id(m3ap_id_manager *m, int id_source, int id_target) +{ + int i; + for (i = 0; i < M3AP_MAX_IDS; i++) + if (m->ids[i].rnti != -1 && + m->ids[i].id_source == id_source && + m->ids[i].id_target == id_target) + return i; + return -1; +} + +int m3ap_find_id_from_id_source(m3ap_id_manager *m, int id_source) +{ + int i; + for (i = 0; i < M3AP_MAX_IDS; i++) + if (m->ids[i].rnti != -1 && + m->ids[i].id_source == id_source) + return i; + return -1; +} + +int m3ap_find_id_from_rnti(m3ap_id_manager *m, int rnti) +{ + int i; + for (i = 0; i < M3AP_MAX_IDS; i++) + if (m->ids[i].rnti == rnti) + return i; + return -1; +} + +void m3ap_set_ids(m3ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target) +{ + m->ids[ue_id].rnti = rnti; + m->ids[ue_id].id_source = id_source; + m->ids[ue_id].id_target = id_target; +} + +/* real type of target is m3ap_eNB_data_t * */ +void m3ap_id_set_target(m3ap_id_manager *m, int ue_id, void *target) +{ + m->ids[ue_id].target = target; +} + +void m3ap_id_set_state(m3ap_id_manager *m, int ue_id, m3id_state_t state) +{ + m->ids[ue_id].state = state; +} + +void m3ap_set_reloc_prep_timer(m3ap_id_manager *m, int ue_id, uint64_t time) +{ + m->ids[ue_id].t_reloc_prep_start = time; +} + +void m3ap_set_reloc_overall_timer(m3ap_id_manager *m, int ue_id, uint64_t time) +{ + m->ids[ue_id].tm3_reloc_overall_start = time; +} + +int m3ap_id_get_id_source(m3ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].id_source; +} + +int m3ap_id_get_id_target(m3ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].id_target; +} + +int m3ap_id_get_rnti(m3ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].rnti; +} + +void *m3ap_id_get_target(m3ap_id_manager *m, int ue_id) +{ + return m->ids[ue_id].target; +} diff --git a/openair3/M3AP/m3ap_ids.h b/openair3/M3AP/m3ap_ids.h new file mode 100644 index 0000000000..bc5a3c3898 --- /dev/null +++ b/openair3/M3AP/m3ap_ids.h @@ -0,0 +1,80 @@ +/* + * 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 + */ + +#ifndef M3AP_IDS_H_ +#define M3AP_IDS_H_ + +#include + +/* maximum number of simultaneous handovers, do not set too high */ +#define M3AP_MAX_IDS 16 + +/* + * state: + * - when starting handover in source, UE is in state M3ID_STATE_SOURCE_PREPARE + * - after receiving HO_ack in source, UE is in state M3ID_STATE_SOURCE_OVERALL + * - in target, UE is in state X2ID_STATE_TARGET + * The state is used to check timers. + */ +typedef enum { + M3ID_STATE_SOURCE_PREPARE, + M3ID_STATE_SOURCE_OVERALL, + M3ID_STATE_TARGET +} m3id_state_t; + +typedef struct { + int rnti; /* -1 when free */ + int id_source; + int id_target; + + /* the target eNB. Real type is m3ap_eNB_data_t * */ + void *target; + + /* state: needed to check timers */ + m3id_state_t state; + + /* timers */ + uint64_t t_reloc_prep_start; + uint64_t tm3_reloc_overall_start; +} m3ap_id; + +typedef struct { + m3ap_id ids[M3AP_MAX_IDS]; +} m3ap_id_manager; + +void m3ap_id_manager_init(m3ap_id_manager *m); +int m3ap_allocate_new_id(m3ap_id_manager *m); +void m3ap_release_id(m3ap_id_manager *m, int id); +int m3ap_find_id(m3ap_id_manager *, int id_source, int id_target); +int m3ap_find_id_from_id_source(m3ap_id_manager *, int id_source); +int m3ap_find_id_from_rnti(m3ap_id_manager *, int rnti); +void m3ap_set_ids(m3ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target); +void m3ap_id_set_state(m3ap_id_manager *m, int ue_id, m3id_state_t state); +/* real type of target is m3ap_eNB_data_t * */ +void m3ap_id_set_target(m3ap_id_manager *m, int ue_id, void *target); +void m3ap_set_reloc_prep_timer(m3ap_id_manager *m, int ue_id, uint64_t time); +void m3ap_set_reloc_overall_timer(m3ap_id_manager *m, int ue_id, uint64_t time); +int m3ap_id_get_id_source(m3ap_id_manager *m, int ue_id); +int m3ap_id_get_id_target(m3ap_id_manager *m, int ue_id); +int m3ap_id_get_rnti(m3ap_id_manager *m, int ue_id); +void *m3ap_id_get_target(m3ap_id_manager *m, int ue_id); + +#endif /* M3AP_IDS_H_ */ diff --git a/openair3/M3AP/m3ap_itti_messaging.c b/openair3/M3AP/m3ap_itti_messaging.c new file mode 100644 index 0000000000..b906747640 --- /dev/null +++ b/openair3/M3AP/m3ap_itti_messaging.c @@ -0,0 +1,96 @@ +/* + * 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 m3ap_MCE_itti_messaging.c + * \brief m3ap tasks for MCE + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#include "intertask_interface.h" + +#include "m3ap_itti_messaging.h" + +void m3ap_MCE_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream) +{ + MessageDef *message_p; + sctp_data_req_t *sctp_data_req; + + message_p = itti_alloc_new_message(TASK_M3AP_MCE, SCTP_DATA_REQ); + + sctp_data_req = &message_p->ittiMsg.sctp_data_req; + + sctp_data_req->assoc_id = assoc_id; + sctp_data_req->buffer = buffer; + sctp_data_req->buffer_length = buffer_length; + sctp_data_req->stream = stream; + + //LOG_W(M3AP,"assoc_id %d, stream %d\n",assoc_id,stream); + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} + + +void m3ap_MCE_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id) +{ + MessageDef *message_p = NULL; + sctp_close_association_t *sctp_close_association_p = NULL; + + message_p = itti_alloc_new_message(TASK_M3AP_MCE, SCTP_CLOSE_ASSOCIATION); + sctp_close_association_p = &message_p->ittiMsg.sctp_close_association; + sctp_close_association_p->assoc_id = assoc_id; + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} + + +void m3ap_MME_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream) +{ + MessageDef *message_p; + sctp_data_req_t *sctp_data_req; + + message_p = itti_alloc_new_message(TASK_M3AP_MME, SCTP_DATA_REQ); + + sctp_data_req = &message_p->ittiMsg.sctp_data_req; + + sctp_data_req->assoc_id = assoc_id; + sctp_data_req->buffer = buffer; + sctp_data_req->buffer_length = buffer_length; + sctp_data_req->stream = stream; + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} + + +void m3ap_MME_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id) +{ + MessageDef *message_p = NULL; + sctp_close_association_t *sctp_close_association_p = NULL; + + message_p = itti_alloc_new_message(TASK_M3AP_MME, SCTP_CLOSE_ASSOCIATION); + sctp_close_association_p = &message_p->ittiMsg.sctp_close_association; + sctp_close_association_p->assoc_id = assoc_id; + + itti_send_msg_to_task(TASK_SCTP, instance, message_p); +} diff --git a/openair3/M3AP/m3ap_itti_messaging.h b/openair3/M3AP/m3ap_itti_messaging.h new file mode 100644 index 0000000000..8a4069da9b --- /dev/null +++ b/openair3/M3AP/m3ap_itti_messaging.h @@ -0,0 +1,48 @@ +/* + * 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 m3ap_itti_messaging.h + * \brief m3ap tasks for MME + * \author Javier Morgade + * \date 2019 + * \version 0.1 + */ + +#ifndef M3AP_MCE_ITTI_MESSAGING_H_ +#define M3AP_MCE_ITTI_MESSAGING_H_ + +void m3ap_MCE_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream); + + +void m3ap_MCE_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id); + + +void m3ap_MME_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer, + uint32_t buffer_length, uint16_t stream); + + +void m3ap_MME_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id); + + + + +#endif /* M3AP_MCE_ITTI_MESSAGING_H_ */ diff --git a/openair3/M3AP/m3ap_timers.c b/openair3/M3AP/m3ap_timers.c new file mode 100644 index 0000000000..39498cc8eb --- /dev/null +++ b/openair3/M3AP/m3ap_timers.c @@ -0,0 +1,105 @@ +/* + * 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 "m3ap_timers.h" +#include "assertions.h" +#include "PHY/defs_common.h" /* TODO: try to not include this */ +#include "m3ap_messages_types.h" +#include "m3ap_MCE_defs.h" +#include "m3ap_ids.h" +#include "m3ap_MCE_management_procedures.h" +//#include "m3ap_eNB_generate_messages.h" + +void m3ap_timers_init(m3ap_timers_t *t, int t_reloc_prep, int tm3_reloc_overall) +{ + t->tti = 0; + t->t_reloc_prep = t_reloc_prep; + t->tm3_reloc_overall = tm3_reloc_overall; +} + +void m3ap_check_timers(instance_t instance) +{ + //m3ap_eNB_instance_t *instance_p; + //m3ap_timers_t *t; + //m3ap_id_manager *m; + //int i; + //m3ap_handover_cancel_cause_t cause; + //void *target; + //MessageDef *msg; + //int m2_ongoing; + + //instance_p = m3ap_eNB_get_instance(instance); + //DevAssert(instance_p != NULL); + + //t = &instance_p->timers; + //m = &instance_p->id_manager; + + ///* increment subframe count */ + //t->tti++; + + //m2_ongoing = 0; + + //for (i = 0; i < M3AP_MAX_IDS; i++) { + // if (m->ids[i].rnti == -1) continue; + // m2_ongoing++; + + // if (m->ids[i].state == M2ID_STATE_SOURCE_PREPARE && + // t->tti > m->ids[i].t_reloc_prep_start + t->t_reloc_prep) { + // LOG_I(M3AP, "M2 timeout reloc prep\n"); + // /* t_reloc_prep timed out */ + // cause = M3AP_T_RELOC_PREP_TIMEOUT; + // goto timeout; + // } + + // if (m->ids[i].state == M2ID_STATE_SOURCE_OVERALL && + // t->tti > m->ids[i].tm2_reloc_overall_start + t->tm2_reloc_overall) { + // LOG_I(M3AP, "M2 timeout reloc overall\n"); + // /* tm2_reloc_overall timed out */ + // cause = M3AP_TM2_RELOC_OVERALL_TIMEOUT; + // goto timeout; + // } + + // /* no timeout -> check next UE */ + // continue; + + // timeout: + // /* inform target about timeout */ + // target = m3ap_id_get_target(m, i); + // m3ap_eNB_generate_m2_handover_cancel(instance_p, target, i, cause); + + // /* inform RRC of cancellation */ + // msg = itti_alloc_new_message(TASK_M3AP, M3AP_HANDOVER_CANCEL); + // M3AP_HANDOVER_CANCEL(msg).rnti = m3ap_id_get_rnti(m, i); + // M3AP_HANDOVER_CANCEL(msg).cause = cause; + // itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg); + + // /* remove UE from M3AP */ + // m3ap_release_id(m, i); + //} + + //if (m2_ongoing && t->tti % 1000 == 0) + // LOG_I(M3AP, "M2 has %d process ongoing\n", m2_ongoing); +} + +uint64_t m3ap_timer_get_tti(m3ap_timers_t *t) +{ + return t->tti; +} diff --git a/openair3/M3AP/m3ap_timers.h b/openair3/M3AP/m3ap_timers.h new file mode 100644 index 0000000000..95dcbfc9d9 --- /dev/null +++ b/openair3/M3AP/m3ap_timers.h @@ -0,0 +1,45 @@ +/* + * 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 + */ + +#ifndef M3AP_TIMERS_H_ +#define M3AP_TIMERS_H_ + +#include +#include "platform_types.h" + +typedef struct { + /* incremented every TTI (every millisecond when in realtime). + * Used to check timers. + * 64 bits gives us more than 500 million years of (realtime) processing. + * It should be enough. + */ + uint64_t tti; + + /* timer values (unit: TTI, ie. millisecond when in realtime) */ + int t_reloc_prep; + int tm3_reloc_overall; +} m3ap_timers_t; + +void m3ap_timers_init(m3ap_timers_t *t, int t_reloc_prep, int tm3_reloc_overall); +void m3ap_check_timers(instance_t instance); +uint64_t m3ap_timer_get_tti(m3ap_timers_t *t); + +#endif /* M3AP_TIMERS_H_ */ diff --git a/openair3/MME_APP/enb_paramdef_mme.h b/openair3/MME_APP/enb_paramdef_mme.h new file mode 100644 index 0000000000..3d65036553 --- /dev/null +++ b/openair3/MME_APP/enb_paramdef_mme.h @@ -0,0 +1,174 @@ +/* + * 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 openair2/ENB_APP/enb_paramdef_mce.h + * \brief definition of configuration parameters for MME modules + * \author Javier MORGADE + * \date 2019 + * \version 0.1 + * \company VICOMTECH Spain + * \email: javier.morgade@ieee.org + * \note + * \warning + */ + +#include "common/config/config_paramdesc.h" +#include "RRC_paramsvalues.h" + +#define ENB_CONFIG_STRING_MME_PARAMETERS "mme_parameters" +//#define ENB_CONFIG_STRING_SCHEDULING_INFO_BR "scheduling_info_br" +//#define ENB_CONFIG_STRING_RSRP_RANGE_LIST "rsrp_range_list" +//#define ENB_CONFIG_STRING_PRACH_CONFIG_COMMON_V1310 "prach_ConfigCommon_v1310" +//#define ENB_CONFIG_STRING_MPDCCH_START_SF_CSS_RA_R13 "mpdcch_startSF_CSS_RA_r13" +//#define ENB_CONFIG_STRING_MPDCCH_START_SF_CSS_RA_R13_VAL "mpdcch_startSF_CSS_RA_r13_val" +//#define ENB_CONFIG_STRING_PRACH_HOPPING_OFFSET_R13 "prach_HoppingOffset_r13" +//#define ENB_CONFIG_STRING_SCHEDULING_INFO_SIB1_BR_R13 "schedulingInfoSIB1_BR_r13" +//#define ENB_CONFIG_STRING_CELL_SELECTION_INFO_CE_R13 "cellSelectionInfoCE_r13" +//#define ENB_CONFIG_STRING_Q_RX_LEV_MIN_CE_R13 "q_RxLevMinCE_r13" +//#define ENB_CONFIG_STRING_BANDWIDTH_REDUCED_ACCESS_RELATED_INFO_R13 "bandwidthReducedAccessRelatedInfo_r13" +//#define ENB_CONFIG_STRING_SI_WINDOW_LENGTH_BR_R13 "si_WindowLength_BR_r13" +//#define ENB_CONFIG_STRING_SI_REPETITION_PATTERN_R13 "si_RepetitionPattern_r13" +//#define ENB_CONFIG_STRING_FDD_DOWNLINK_OR_TDD_SUBFRAME_BITMAP_BR_R13 "fdd_DownlinkOrTddSubframeBitmapBR_r13" +//#define ENB_CONFIG_STRING_FDD_DOWNLINK_OR_TDD_SUBFRAME_BITMAP_BR_VAL_R13 "fdd_DownlinkOrTddSubframeBitmapBR_val_r13" +//#define ENB_CONFIG_STRING_START_SYMBOL_BR_R13 "startSymbolBR_r13" +//#define ENB_CONFIG_STRING_SI_HOPPING_CONFIG_COMMON_R13 "si_HoppingConfigCommon_r13" +//#define ENB_CONFIG_STRING_SI_VALIDITY_TIME_R13 "si_ValidityTime_r13" +//#define ENB_CONFIG_STRING_FREQ_HOPPING_PARAMETERS_DL_R13 "freqHoppingParametersDL_r13" +//#define ENB_CONFIG_STRING_MPDCCH_PDSCH_HOPPING_NB_R13 "mpdcch_pdsch_HoppingNB_r13" +//#define ENB_CONFIG_STRING_INTERVAL_DL_HOPPING_CONFIG_COMMON_MODE_A_R13 "interval_DLHoppingConfigCommonModeA_r13" +//#define ENB_CONFIG_STRING_INTERVAL_DL_HOPPING_CONFIG_COMMON_MODE_A_R13_VAL "interval_DLHoppingConfigCommonModeA_r13_val" +//#define ENB_CONFIG_STRING_INTERVAL_DL_HOPPING_CONFIG_COMMON_MODE_B_R13 "interval_DLHoppingConfigCommonModeB_r13" +//#define ENB_CONFIG_STRING_INTERVAL_DL_HOPPING_CONFIG_COMMON_MODE_B_R13_VAL "interval_DLHoppingConfigCommonModeB_r13_val" +//#define ENB_CONFIG_STRING_MPDCCH_PDSCH_HOPPING_OFFSET_R13 "mpdcch_pdsch_HoppingOffset_r13" +//#define ENB_CONFIG_STRING_PREAMBLE_TRANSMAX_CE_R13 "preamble_TransMax_ce_r13" +//#define ENB_CONFIG_STRING_PREAMBLE_TRANSMAX_CE_R13_VAL "preamble_TransMax_ce_r13_val" +//#define ENB_CONFIG_STRING_PDSCH_MAX_NUM_REPETITION_CE_MODE_A_R13 "pdsch_maxNumRepetitionCEmodeA_r13" +//#define ENB_CONFIG_STRING_PDSCH_MAX_NUM_REPETITION_CE_MODE_B_R13 "pdsch_maxNumRepetitionCEmodeB_r13" +//#define ENB_CONFIG_STRING_PUSCH_MAX_NUM_REPETITION_CE_MODE_A_R13 "pusch_maxNumRepetitionCEmodeA_r13" +//#define ENB_CONFIG_STRING_PUSCH_MAX_NUM_REPETITION_CE_MODE_B_R13 "pusch_maxNumRepetitionCEmodeB_r13" +//#define ENB_CONFIG_STRING_PUSCH_HOPPING_OFFSET_V1310 "pusch_HoppingOffset_v1310" +//#define ENB_CONFIG_STRING_SYSTEM_INFO_VALUE_TAG_LIST "system_info_value_tag_SI" +//#define ENB_CONFIG_STRING_FIRST_PREAMBLE_R13 "firstPreamble_r13" +//#define ENB_CONFIG_STRING_LAST_PREAMBLE_R13 "lastPreamble_r13" +//#define ENB_CONFIG_STRING_RA_RESPONSE_WINDOW_SIZE_R13 "ra_ResponseWindowSize_r13" +//#define ENB_CONFIG_STRING_MAC_CONTENTION_RESOLUTION_TIMER_R13 "mac_ContentionResolutionTimer_r13" +//#define ENB_CONFIG_STRING_RAR_HOPPING_CONFIG_R13 "rar_HoppingConfig_r13" +//#define ENB_CONFIG_STRING_RACH_CE_LEVELINFOLIST_R13 "rach_CE_LevelInfoList_r13" +//#define ENB_CONFIG_STRING_PRACH_CONFIG_INDEX_BR "prach_config_index_br" +//#define ENB_CONFIG_STRING_PRACH_FREQ_OFFSET_BR "prach_freq_offset_br" +//#define ENB_CONFIG_STRING_PRACH_STARTING_SUBFRAME_R13 "prach_StartingSubframe_r13" +//#define ENB_CONFIG_STRING_MAX_NUM_PER_PREAMBLE_ATTEMPT_CE_R13 "maxNumPreambleAttemptCE_r13" +//#define ENB_CONFIG_STRING_NUM_REPETITION_PER_PREAMBLE_ATTEMPT_R13 "numRepetitionPerPreambleAttempt_r13" +//#define ENB_CONFIG_STRING_MPDCCH_NUM_REPETITION_RA_R13 "mpdcch_NumRepetition_RA_r13" +//#define ENB_CONFIG_STRING_PRACH_HOPPING_CONFIG_R13 "prach_HoppingConfig_r13" +//#define ENB_CONFIG_SRING_MAX_AVAILABLE_NARROW_BAND "max_available_narrow_band" +//#define ENB_CONFIG_STRING_PRACH_PARAMETERS_CE_R13 "prach_parameters_ce_r13" +//#define ENB_CONFIG_STRING_PUCCH_INFO_VALUE "pucch_info_value" +//#define ENB_CONFIG_STRING_N1PUCCH_AN_INFOLIST_R13 "n1PUCCH_AN_InfoList_r13" +//#define ENB_CONFIG_STRING_PCCH_CONFIG_V1310 "pcch_config_v1310" +//#define ENB_CONFIG_STRING_PAGING_NARROWBANDS_R13 "paging_narrowbands_r13" +//#define ENB_CONFIG_STRING_MPDCCH_NUMREPETITION_PAGING_R13 "mpdcch_numrepetition_paging_r13" +//#define ENB_CONFIG_STRING_NB_V1310 "nb_v1310" +//#define ENB_CONFIG_STRING_SIB2_FREQ_HOPPINGPARAMETERS_R13 "sib2_freq_hoppingParameters_r13" + +typedef struct ccparams_MME_s { + /// indicator that eMTC is configured for this cell + int32_t MME_configured; + // /// the SIB2 parameters for eMTC SIB2 + // ccparams_lte_t ccparams; + // int si_Narrowband_r13; + // int si_TBS_r13; + // int systemInfoValueTagSi_r13; + // int firstPreamble_r13; + // int lastPreamble_r13; + // int ra_ResponseWindowSize_r13; + // int mac_ContentionResolutionTimer_r13; + // int rar_HoppingConfig_r13; + // int rsrp_range_br; + // int prach_config_index_br; + // int prach_freq_offset_br; + // int prach_StartingSubframe_r13; + // int maxNumPreambleAttemptCE_r13; + // int numRepetitionPerPreambleAttempt_r13; + // int mpdcch_NumRepetition_RA_r13; + // int prach_HoppingConfig_r13; + // int *maxavailablenarrowband; + // int pucch_info_value; + // int paging_narrowbands_r13; + // int mpdcch_numrepetition_paging_r13; + // int nb_v1310; + // char *pucch_NumRepetitionCE_Msg4_Level0_r13; + // char *pucch_NumRepetitionCE_Msg4_Level1_r13; + // char *pucch_NumRepetitionCE_Msg4_Level2_r13; + // char *pucch_NumRepetitionCE_Msg4_Level3_r13; + // int sib2_mpdcch_pdsch_hoppingNB_r13; + // char *sib2_interval_DLHoppingConfigCommonModeA_r13; + // int sib2_interval_DLHoppingConfigCommonModeA_r13_val; + // char *sib2_interval_DLHoppingConfigCommonModeB_r13; + // int sib2_interval_DLHoppingConfigCommonModeB_r13_val; + // char *sib2_interval_ULHoppingConfigCommonModeA_r13; + // int sib2_interval_ULHoppingConfigCommonModeA_r13_val; + // char *sib2_interval_ULHoppingConfigCommonModeB_r13; + // int sib2_interval_ULHoppingConfigCommonModeB_r13_val; + // int sib2_mpdcch_pdsch_hoppingOffset_r13; + // int pusch_HoppingOffset_v1310; + // int hyperSFN_r13; + // int eDRX_Allowed_r13; + // int q_RxLevMinCE_r13; + // int q_QualMinRSRQ_CE_r13; + // char *si_WindowLength_BR_r13; + // char *si_RepetitionPattern_r13; + // int startSymbolBR_r13; + // char *si_HoppingConfigCommon_r13; + // char *si_ValidityTime_r13; + // char *mpdcch_pdsch_HoppingNB_r13; + // int interval_DLHoppingConfigCommonModeA_r13_val; + // int interval_DLHoppingConfigCommonModeB_r13_val; + // int mpdcch_pdsch_HoppingOffset_r13; + // char *preambleTransMax_CE_r13; + // int prach_HoppingOffset_r13; + // int schedulingInfoSIB1_BR_r13; + // int64_t fdd_DownlinkOrTddSubframeBitmapBR_val_r13; + // char *cellSelectionInfoCE_r13; + // char *bandwidthReducedAccessRelatedInfo_r13; + // char *fdd_DownlinkOrTddSubframeBitmapBR_r13; + // char *fdd_UplinkSubframeBitmapBR_r13; + // char *freqHoppingParametersDL_r13; + // char *interval_DLHoppingConfigCommonModeA_r13; + // char *interval_DLHoppingConfigCommonModeB_r13; + // char *prach_ConfigCommon_v1310; + // char *mpdcch_startSF_CSS_RA_r13; + // char *mpdcch_startSF_CSS_RA_r13_val; + // char *pdsch_maxNumRepetitionCEmodeA_r13; + // char *pdsch_maxNumRepetitionCEmodeB_r13; + // char *pusch_maxNumRepetitionCEmodeA_r13; + // char *pusch_maxNumRepetitionCEmodeB_r13; +} ccparams_MME_t; + + +#define MMEPARAMS_DESC(MMEconfig) { \ + {"MME_configured", NULL, 0, iptr:&MMEconfig->MME_configured, defintval:0, TYPE_UINT, 0} \ +} + +#define MMEPARAMS_CHECK { \ + { .s5= {NULL }} \ +} + diff --git a/openair3/MME_APP/mme_app.c b/openair3/MME_APP/mme_app.c new file mode 100644 index 0000000000..534aec8b34 --- /dev/null +++ b/openair3/MME_APP/mme_app.c @@ -0,0 +1,580 @@ +/* + * 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 + */ + +/* + mme_app.c + ------------------- + AUTHOR : Javier Morgade + COMPANY : VICOMTECH Spain + EMAIL : javier.morgade@ieee.org +*/ + +#include +#include + +#include "mme_app.h" +#include "mme_config.h" +#include "assertions.h" +#include "common/ran_context.h" +#include "targets/RT/USER/lte-softmodem.h" + +#include "common/utils/LOG/log.h" + +# include "intertask_interface.h" +# include "s1ap_eNB.h" +# include "sctp_eNB_task.h" +# include "gtpv1u_eNB_task.h" +# include "flexran_agent.h" + +# include "x2ap_eNB.h" +# include "x2ap_messages_types.h" +# include "m2ap_eNB.h" +# include "m3ap_MME.h" +# include "m2ap_messages_types.h" +//# include "m3ap_eNB.h" +# include "m3ap_messages_types.h" +# define X2AP_ENB_REGISTER_RETRY_DELAY 10 + +#include "openair1/PHY/INIT/phy_init.h" +extern unsigned char NB_MCE_INST; + +extern RAN_CONTEXT_t RC; + +# define MCE_REGISTER_RETRY_DELAY 10 + +#include "targets/RT/USER/lte-softmodem.h" + + + + +/*------------------------------------------------------------------------------*/ + +//static uint32_t MCE_app_register(ngran_node_t node_type,uint32_t mce_id_start, uint32_t mce_id_end) { +// uint32_t mce_id; +// MessageDef *msg_p; +// uint32_t register_mce_pending = 0; +// +// for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { +// { +// // M3AP registration +// /* note: there is an implicit relationship between the data structure and the message name */ +// msg_p = itti_alloc_new_message (TASK_MME_APP, M3AP_REGISTER_MCE_REQ); +// //RCconfig_S1(msg_p, mce_id); +// +// //if (mce_id == 0) +// //RCconfig_gtpu(); +// +// //LOG_I(MME_APP,"default drx %d\n",((M3AP_REGISTER_MCE_REQ(msg_p)).default_drx)); +// +// LOG_I(ENB_APP,"[MCE %d] MCE_app_register via M3AP for instance %d\n", mce_id, ENB_MODULE_ID_TO_INSTANCE(mce_id)); +// itti_send_msg_to_task (TASK_M3AP, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); +// +// //if (NODE_IS_DU(node_type)) { // F1AP registration +// // // configure F1AP here for F1C +// // LOG_I(ENB_APP,"ngran_eNB_DU: Allocating ITTI message for F1AP_SETUP_REQ\n"); +// // msg_p = itti_alloc_new_message (TASK_ENB_APP, F1AP_SETUP_REQ); +// // RCconfig_DU_F1(msg_p, enb_id); +// +// // LOG_I(ENB_APP,"[eNB %d] eNB_app_register via F1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id)); +// // itti_send_msg_to_task (TASK_DU_F1, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); +// // // configure GTPu here for F1U +// //} +// //else { // S1AP registration +// // /* note: there is an implicit relationship between the data structure and the message name */ +// // msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ); +// // RCconfig_S1(msg_p, enb_id); +// +// // if (enb_id == 0) RCconfig_gtpu(); +// +// // LOG_I(ENB_APP,"default drx %d\n",((S1AP_REGISTER_ENB_REQ(msg_p)).default_drx)); +// +// // LOG_I(ENB_APP,"[eNB %d] eNB_app_register via S1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id)); +// // itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); +// //} +// +// register_mce_pending++; +// } +// } +// +// return register_mce_pending; +//} + + +/*------------------------------------------------------------------------------*/ +//static uint32_t MCE_app_register_x2(uint32_t mce_id_start, uint32_t mce_id_end) { +// uint32_t mce_id; +// MessageDef *msg_p; +// uint32_t register_mce_m2_pending = 0; +// +// for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { +// { +// msg_p = itti_alloc_new_message (TASK_ENB_APP, X2AP_REGISTER_ENB_REQ); +// RCconfig_X2(msg_p, mce_id); +// itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); +// register_mce_x2_pending++; +// } +// } +// +// return register_mce_x2_pending; +//} + +/*------------------------------------------------------------------------------*/ +//static uint32_t MCE_app_register_m2(uint32_t mce_id_start, uint32_t mce_id_end) { +// uint32_t mce_id; +// MessageDef *msg_p; +// uint32_t register_mce_m2_pending = 0; +// +// LOG_W(MME_APP,"Register ..."); +// for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) { +// { +// // LOG_W(MME_APP,"Register commes inside ...\n"); +// msg_p = itti_alloc_new_message (TASK_MME_APP, M2AP_REGISTER_MCE_REQ); +// //RCconfig_M2_MCE(msg_p, mce_id); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p); +// // LOG_W(MME_APP,"Register sent ...\n"); +// register_mce_m2_pending++; +// } +// } +// +// return register_mce_m2_pending; +//} +// +// +// +static uint32_t MME_app_handle_m3ap_setup_req(instance_t instance){ + + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MME_APP, M3AP_SETUP_RESP); + itti_send_msg_to_task (TASK_M3AP_MME, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} +static uint32_t MME_app_handle_m3ap_session_start_resp(instance_t instance){ + + + return 0; +} +// +//static uint32_t MME_app_handle_m3ap_session_stop_resp(instance_t instance){ +// +// +// return 0; +//} + + + +// +//static uint32_t MCE_app_send_m2ap_mbms_scheduling_information(instance_t instance){ +// +// uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MME_APP, M2AP_MBMS_SCHEDULING_INFORMATION); +// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} +// +static uint32_t MME_app_send_m3ap_session_start_req(instance_t instance){ + + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MME_APP, M3AP_MBMS_SESSION_START_REQ); + itti_send_msg_to_task (TASK_M3AP_MME, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} +//static uint32_t MME_app_send_m3ap_session_stop_req(instance_t instance){ +// +// //uint32_t mce_id=0; +// MessageDef *msg_p; +// msg_p = itti_alloc_new_message (TASK_MME_APP, M3AP_MBMS_SESSION_STOP_REQ); +// itti_send_msg_to_task (TASK_M3AP_MME, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); +// +// return 0; +//} +static uint32_t MME_app_send_m3ap_session_update_req(instance_t instance){ + + //uint32_t mce_id=0; + MessageDef *msg_p; + msg_p = itti_alloc_new_message (TASK_MME_APP, M3AP_MBMS_SESSION_UPDATE_REQ); + itti_send_msg_to_task (TASK_M3AP_MME, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p); + + return 0; +} +/*------------------------------------------------------------------------------*/ +void *MME_app_task(void *args_p) { + //uint32_t mce_nb = RC.nb_inst; + //uint32_t mce_id_start = 0; + //uint32_t mce_id_end = mce_id_start + mce_nb; + //uint32_t register_mce_pending=0; + //uint32_t registered_mce=0; + //long mce_register_retry_timer_id; + //uint32_t m2_register_mce_pending = 0; + // uint32_t x2_registered_mce = 0; + // long x2_mce_register_retry_timer_id; + // uint32_t m2_register_mce_pending = 0; + // uint32_t m2_registered_mce = 0; + // long m2_mce_register_retry_timer_id; + long m3_mme_register_session_start_timer_id; + MessageDef *msg_p = NULL; + instance_t instance; + int result; + /* for no gcc warnings */ + (void)instance; + itti_mark_task_ready (TASK_MME_APP); + + /* Try to register each MCE */ + // This assumes that node_type of all RRC instances is the same + if (EPC_MODE_ENABLED) { + //register_mce_pending = MCE_app_register(RC.rrc[0]->node_type, mce_id_start, mce_id_end); + } + + /* Try to register each MCE with each other */ + // if (is_x2ap_enabled() && !NODE_IS_DU(RC.rrc[0]->node_type)) { + // x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end); + // } + if ( is_m3ap_MME_enabled() ){ + RCconfig_MME(); + } + // /* Try to register each MCE with MCE each other */ + //if (is_m3ap_MME_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) { + //m2_register_mce_pending = MCE_app_register_m2 (mce_id_start, mce_id_end); + //} + + do { + // Wait for a message + itti_receive_msg (TASK_MME_APP, &msg_p); + instance = ITTI_MSG_INSTANCE (msg_p); + + switch (ITTI_MSG_ID(msg_p)) { + case TERMINATE_MESSAGE: + LOG_W(MME_APP, " *** Exiting MME_APP thread\n"); + itti_exit_task (); + break; + + case MESSAGE_TEST: + LOG_I(MME_APP, "MME_APP Received %s\n", ITTI_MSG_NAME(msg_p)); + break; + + case SOFT_RESTART_MESSAGE: + //handle_reconfiguration(instance); + break; + + case M3AP_REGISTER_MCE_CNF: //M3AP_REGISTER_MCE_CNF debería + //AssertFatal(!NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received S1AP_REGISTER_ENB_CNF\n"); + // if (EPC_MODE_ENABLED) { + // LOG_I(MME_APP, "[MCE %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p), + // M3AP_REGISTER_MCE_CNF(msg_p).nb_mme); + // DevAssert(register_mce_pending > 0); + // register_mce_pending--; + + // /* Check if at least MCE is registered with one MME */ + // if (M3AP_REGISTER_MCE_CNF(msg_p).nb_mme > 0) { + // registered_mce++; + // } + + // /* Check if all register MCE requests have been processed */ + // if (register_mce_pending == 0) { + // if (registered_mce == mce_nb) { + // /* If all MCE are registered, start L2L1 task */ + // // MessageDef *msg_init_p; + // // msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE); + // // itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); + // } else { + // LOG_W(MME_APP, " %d MCE not associated with a MME, retrying registration in %d seconds ...\n", + // mce_nb - registered_mce, MCE_REGISTER_RETRY_DELAY); + + // /* Restart the MCE registration process in MCE_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (MCE_REGISTER_RETRY_DELAY, 0, TASK_MME_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + // NULL, &mce_register_retry_timer_id) < 0) { + // LOG_E(MME_APP, " Can not start MCE register retry timer, use \"sleep\" instead!\n"); + // sleep(MCE_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // registered_mce = 0; + // register_mce_pending = MCE_app_register (RC.rrc[0]->node_type,mce_id_start, mce_id_end); + // } + // } + // } + // } /* if (EPC_MODE_ENABLED) */ + + break; + + // case M3AP_SETUP_RESP: + // //AssertFatal(NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received F1AP_REGISTER_ENB_CNF in CU/MCE\n"); + + // //LOG_I(MME_APP, "Received %s: associated ngran_MCE_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p), + // //F1AP_SETUP_RESP(msg_p).gNB_CU_name,F1AP_SETUP_RESP(msg_p).num_cells_to_activate); + // + // //handle_f1ap_setup_resp(&F1AP_SETUP_RESP(msg_p)); + // handle_m3ap_setup_resp(&M3AP_SETUP_RESP(msg_p)); + + // DevAssert(register_mce_pending > 0); + // register_mce_pending--; + + // /* Check if at least MCE is registered with one MME */ + // //if (M3AP_SETUP_RESP(msg_p).num_cells_to_activate > 0) { + // // registered_enb++; + // //} + + // /* Check if all register MCE requests have been processed */ + // if (register_mce_pending == 0) { + // if (registered_mce == mce_nb) { + // /* If all MCE cells are registered, start L2L1 task */ + // MessageDef *msg_init_p; + + // //msg_init_p = itti_alloc_new_message (TASK_MME_APP, INITIALIZE_MESSAGE); + // //itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); + + // } else { + // LOG_W(MME_APP, " %d MCE not associated with a MME, retrying registration in %d seconds ...\n", + // mce_nb - registered_mce, MCE_REGISTER_RETRY_DELAY); + + // /* Restart the MCE registration process in MCE_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (MCE_REGISTER_RETRY_DELAY, 0, TASK_MME_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, + // NULL, &mce_register_retry_timer_id) < 0) { + // LOG_E(ENB_APP, " Can not start MCE register retry timer, use \"sleep\" instead!\n"); + + // sleep(MCE_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // registered_mce = 0; + // register_mce_pending = MCE_app_register (RC.rrc[0]->node_type,mce_id_start, mce_id_end);//, enb_properties_p); + // } + // } + // } + + // break; + + case M3AP_DEREGISTERED_MCE_IND: //M3AP_DEREGISTERED_MCE_IND debería + if (EPC_MODE_ENABLED) { + LOG_W(MME_APP, "[MCE %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p), + M3AP_DEREGISTERED_MCE_IND(msg_p).nb_mme); + /* TODO handle recovering of registration */ + } + + break; + + case TIMER_HAS_EXPIRED: + //if (EPC_MODE_ENABLED) { + // LOG_I(MME_APP, " Received %s: timer_id %ld\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id); + + // if (TIMER_HAS_EXPIRED (msg_p).timer_id == mce_register_retry_timer_id) { + // /* Restart the registration process */ + // registered_mce = 0; + // //register_mce_pending = MCE_app_register (RC.rrc[0]->node_type, mce_id_start, mce_id_end); + // } + + // //if (TIMER_HAS_EXPIRED (msg_p).timer_id == x2_mce_register_retry_timer_id) { + // // /* Restart the registration process */ + // // x2_registered_mce = 0; + // // x2_register_mce_pending = MCE_app_register_x2 (mce_id_start, mce_id_end); + // //} + //} /* if (EPC_MODE_ENABLED) */ + if(TIMER_HAS_EXPIRED(msg_p).timer_id == m3_mme_register_session_start_timer_id){ + MME_app_send_m3ap_session_start_req(0); + } + + break; + + // case X2AP_DEREGISTERED_ENB_IND: + // LOG_W(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // X2AP_DEREGISTERED_ENB_IND(msg_p).nb_x2); + // /* TODO handle recovering of registration */ + // break; + + // case X2AP_REGISTER_ENB_CNF: + // LOG_I(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // X2AP_REGISTER_ENB_CNF(msg_p).nb_x2); + // DevAssert(x2_register_enb_pending > 0); + // x2_register_enb_pending--; + + // /* Check if at least MCE is registered with one target MCE */ + // if (X2AP_REGISTER_ENB_CNF(msg_p).nb_x2 > 0) { + // x2_registered_enb++; + // } + + // /* Check if all register MCE requests have been processed */ + // if (x2_register_enb_pending == 0) { + // if (x2_registered_enb == enb_nb) { + // /* If all MCE are registered, start RRC HO task */ + // } else { + // uint32_t x2_not_associated = enb_nb - x2_registered_enb; + // LOG_W(ENB_APP, " %d MCE %s not associated with the target\n", + // x2_not_associated, x2_not_associated > 1 ? "are" : "is"); + + // // timer to retry + // /* Restart the MCE registration process in ENB_REGISTER_RETRY_DELAY seconds */ + // if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, + // INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL, + // &x2_enb_register_retry_timer_id) < 0) { + // LOG_E(ENB_APP, " Can not start MCE X2AP register: retry timer, use \"sleep\" instead!\n"); + // sleep(X2AP_ENB_REGISTER_RETRY_DELAY); + // /* Restart the registration process */ + // x2_registered_enb = 0; + // x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end); + // } + // } + // } + + // break; + + // case M2AP_DEREGISTERED_ENB_IND: + // LOG_W(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // M2AP_DEREGISTERED_ENB_IND(msg_p).nb_m2); + // /* TODO handle recovering of registration */ + // break; + + // case M2AP_REGISTER_ENB_CNF: + // LOG_I(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p), + // M2AP_REGISTER_ENB_CNF(msg_p).nb_m2); + // DevAssert(m2_register_enb_pending > 0); + // m2_register_enb_pending--; + + // /* Check if at least MCE is registered with one target MCE */ + // if (M2AP_REGISTER_ENB_CNF(msg_p).nb_m2 > 0) { + // m2_registered_enb++; + // } + + // /* Check if all register MCE requests have been processed */ + // if (m2_register_enb_pending == 0) { + // if (m2_registered_enb == enb_nb) { + // /* If all MCE are registered, start RRC HO task */ + // } else { + // uint32_t m2_not_associated = enb_nb - m2_registered_enb; + // LOG_W(ENB_APP, " %d MCE %s not associated with the target\n", + // m2_not_associated, m2_not_associated > 1 ? "are" : "is"); + + // // timer to retry + // /* Restart the MCE registration process in ENB_REGISTER_RETRY_DELAY seconds */ + // //if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, + // // INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL, + // // &x2_enb_register_retry_timer_id) < 0) { + // // LOG_E(ENB_APP, " Can not start MCE X2AP register: retry timer, use \"sleep\" instead!\n"); + // // sleep(X2AP_ENB_REGISTER_RETRY_DELAY); + // // /* Restart the registration process */ + // // x2_registered_enb = 0; + // // x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end); + // //} + // } + // } + + // break; + case M3AP_RESET: + LOG_I(MME_APP,"Received M3AP_RESET message %s\n",ITTI_MSG_NAME(msg_p)); + break; + + case M3AP_SETUP_REQ: + LOG_I(MME_APP,"Received M3AP_REQ message %s\n",ITTI_MSG_NAME(msg_p)); + MME_app_handle_m3ap_setup_req(0); + if(timer_setup(1,0,TASK_MME_APP,INSTANCE_DEFAULT,TIMER_ONE_SHOT,NULL,&m3_mme_register_session_start_timer_id)<0){ + } + //MME_app_send_m3ap_session_start_req(0); + break; + + case M3AP_MBMS_SESSION_START_RESP: + LOG_I(MME_APP,"Received M3AP_MBMS_SESSION_START_RESP message %s\n",ITTI_MSG_NAME(msg_p)); + MME_app_handle_m3ap_session_start_resp(0); + //MME_app_send_m3ap_session_stop_req(0); + break; + + case M3AP_MBMS_SESSION_STOP_RESP: + LOG_I(MME_APP,"Received M3AP_MBMS_SESSION_STOP_RESP message %s\n",ITTI_MSG_NAME(msg_p)); + MME_app_send_m3ap_session_update_req(0); + break; + + case M3AP_MBMS_SESSION_UPDATE_RESP: + LOG_I(MME_APP,"Received M3AP_MBMS_SESSION_UPDATE_RESP message %s\n",ITTI_MSG_NAME(msg_p)); + // trigger something new here !!!!!! + break; + + case M3AP_MBMS_SESSION_UPDATE_FAILURE: + LOG_I(MME_APP,"Received M3AP_MBMS_SESSION_UPDATE_FAILURE message %s\n",ITTI_MSG_NAME(msg_p)); + break; + + case M3AP_MCE_CONFIGURATION_UPDATE: + LOG_I(MME_APP,"Received M3AP_MCE_CONFIGURATION_UPDATE message %s\n",ITTI_MSG_NAME(msg_p)); + break; + + default: + LOG_E(MME_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while (1); + + return NULL; +} + +//void handle_reconfiguration(module_id_t mod_id) { +// struct timespec start, end; +// clock_gettime(CLOCK_MONOTONIC, &start); +// flexran_agent_info_t *flexran = RC.flexran[mod_id]; +// LOG_I(ENB_APP, "lte-softmodem soft-restart requested\n"); +// +// if (ENB_WAIT == flexran->node_ctrl_state) { +// /* this is already waiting, just release */ +// pthread_mutex_lock(&flexran->mutex_node_ctrl); +// flexran->node_ctrl_state = ENB_NORMAL_OPERATION; +// pthread_mutex_unlock(&flexran->mutex_node_ctrl); +// pthread_cond_signal(&flexran->cond_node_ctrl); +// return; +// } +// +// if (stop_L1L2(mod_id) < 0) { +// LOG_E(ENB_APP, "can not stop lte-softmodem, aborting restart\n"); +// return; +// } +// +// /* node_ctrl_state should have value ENB_MAKE_WAIT only if this method is not +// * executed by the FlexRAN thread */ +// if (ENB_MAKE_WAIT == flexran->node_ctrl_state) { +// LOG_I(ENB_APP, " * MCE %d: Waiting for FlexRAN RTController command *\n", mod_id); +// pthread_mutex_lock(&flexran->mutex_node_ctrl); +// flexran->node_ctrl_state = ENB_WAIT; +// +// while (ENB_NORMAL_OPERATION != flexran->node_ctrl_state) +// pthread_cond_wait(&flexran->cond_node_ctrl, &flexran->mutex_node_ctrl); +// +// pthread_mutex_unlock(&flexran->mutex_node_ctrl); +// } +// +// if (restart_L1L2(mod_id) < 0) { +// LOG_E(ENB_APP, "can not restart, killing lte-softmodem\n"); +// exit_fun("can not restart L1L2, killing lte-softmodem"); +// return; +// } +// +// clock_gettime(CLOCK_MONOTONIC, &end); +// end.tv_sec -= start.tv_sec; +// +// if (end.tv_nsec >= start.tv_nsec) { +// end.tv_nsec -= start.tv_nsec; +// } else { +// end.tv_sec -= 1; +// end.tv_nsec = end.tv_nsec - start.tv_nsec + 1000000000; +// } +// +// LOG_I(ENB_APP, "lte-softmodem restart succeeded in %ld.%ld s\n", end.tv_sec, end.tv_nsec / 1000000); +//} + + diff --git a/openair3/MME_APP/mme_app.h b/openair3/MME_APP/mme_app.h new file mode 100644 index 0000000000..796bfa796c --- /dev/null +++ b/openair3/MME_APP/mme_app.h @@ -0,0 +1,41 @@ +/* + * 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 + */ + +/* + mme_app.h + ------------------- + AUTHOR : Javier Morgade + COMPANY : VICOMTECH Spain + EMAIL : javier.morgade@ieee.org +*/ + +#ifndef MME_APP_H_ +#define MME_APP_H_ + +#include +#include "platform_types.h" + + +void *MME_app_task(void *args_p); + +//void handle_reconfiguration(module_id_t mod_id); + +#endif /* MME_APP_H_ */ diff --git a/openair3/MME_APP/mme_config.c b/openair3/MME_APP/mme_config.c new file mode 100644 index 0000000000..04dba67567 --- /dev/null +++ b/openair3/MME_APP/mme_config.c @@ -0,0 +1,111 @@ +/* + * 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 + */ + +/* + mme_config.c + ------------------- + AUTHOR : Javier Morgade + COMPANY : VICOMTECH, Spain + EMAIL : javier.morgade@ieee.org +*/ + +#include +#include + +#include "common/utils/LOG/log.h" +#include "assertions.h" +#include "mme_config.h" +#include "UTIL/OTG/otg.h" +#include "UTIL/OTG/otg_externs.h" +#include "intertask_interface.h" +#include "s1ap_eNB.h" +#include "sctp_eNB_task.h" +#include "common/ran_context.h" +#include "sctp_default_values.h" +#include "LTE_SystemInformationBlockType2.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" +#include "PHY/phy_extern.h" +#include "PHY/INIT/phy_init.h" +#include "targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" +#include "nfapi_vnf.h" +#include "nfapi_pnf.h" + +#include "L1_paramdef.h" +#include "MACRLC_paramdef.h" +#include "common/config/config_userapi.h" +#include "RRC_config_tools.h" +#include "enb_paramdef.h" +#include "proto_agent.h" + +int RCconfig_MME(void ) { + //int num_enbs = 0; + //char *enb_interface_name_for_S1U = NULL; + char *mme_interface_name_for_m3_mce = NULL; + //char *enb_ipv4_address_for_S1U = NULL; + char *mme_ipv4_address_for_m3c = NULL; + //uint32_t enb_port_for_S1U = 0; + uint32_t mme_port_for_m3c = 0; + char *address = NULL; + char *cidr = NULL; + //char gtpupath[MAX_OPTNAME_SIZE*2 + 8]; + char mmepath[MAX_OPTNAME_SIZE*2 + 8]; + //paramdef_t ENBSParams[] = ENBSPARAMS_DESC; + //paramdef_t GTPUParams[] = GTPUPARAMS_DESC; + + paramdef_t MMEParams[] = MME_NETPARAMS_DESC; + + ///* get number of active eNodeBs */ + //config_get( ENBSParams,sizeof(ENBSParams)/sizeof(paramdef_t),NULL); + //num_enbs = ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt; + //AssertFatal (num_enbs >0, + // "Failed to parse config file no active eNodeBs in %s \n", ENB_CONFIG_STRING_ACTIVE_ENBS); + //sprintf(gtpupath,"%s.[%i].%s",ENB_CONFIG_STRING_ENB_LIST,0,ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + sprintf(mmepath,"%s.[%i].%s","MMEs",0,MME_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + //config_get( GTPUParams,sizeof(GTPUParams)/sizeof(paramdef_t),gtpupath); + config_get(MMEParams,sizeof(MMEParams)/sizeof(paramdef_t),mmepath); + //cidr = enb_ipv4_address_for_S1U; + cidr = mme_ipv4_address_for_m3c; + address = strtok(cidr, "/"); + + //LOG_W(MME_APP,"cidr %s\n",cidr); + //LOG_W(MME_APP,"address %s\n",address); + //LOG_W(MME_APP,"mme_interface_name_for_m3_mce %s\n",mme_interface_name_for_m3_mce); + //LOG_W(MME_APP,"mme_ipv4_address_for_m3c %s\n",mme_ipv4_address_for_m3c); + //LOG_W(MME_APP,"mme_port_for_m3c %d\n",mme_port_for_m3c); + + if (address) { + MessageDef *message; + AssertFatal((message = itti_alloc_new_message(TASK_MME_APP, M3AP_MME_SCTP_REQ))!=NULL,""); + M3AP_MME_SCTP_REQ (message).mme_m3_ip_address.ipv6 = 0; + M3AP_MME_SCTP_REQ (message).mme_m3_ip_address.ipv4 = 1; + strcpy( M3AP_MME_SCTP_REQ (message).mme_m3_ip_address.ipv4_address, address); + LOG_I(MME_APP,"Configuring M3_C address : %s\n",address/*,M3AP_MME_SCTP_REQ(message).mme_m3_ip_address*/); + M3AP_MME_SCTP_REQ(message).mme_port_for_M3C = mme_port_for_m3c; + itti_send_msg_to_task (TASK_M3AP_MME, 0, message); // data model is wrong: gtpu doesn't have enb_id (or module_id) + } else + LOG_E(MCE_APP,"invalid address for M2AP\n"); + + + + return 0; +} + diff --git a/openair3/MME_APP/mme_config.h b/openair3/MME_APP/mme_config.h new file mode 100644 index 0000000000..4371ad55f6 --- /dev/null +++ b/openair3/MME_APP/mme_config.h @@ -0,0 +1,52 @@ +/* + * 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 + */ + +/* + mme_config.h + AUTHOR : Javier Morgade + COMPANY : Vicomtech, Spain + EMAIL : javier.morgade@ieee.org +*/ + +#ifndef MME_CONFIG_H_ +#define MME_CONFIG_H_ +#include +#include +#include +#include + +#include "commonDef.h" +#include "platform_types.h" +#include "platform_constants.h" +#include "PHY/impl_defs_top.h" +#include "PHY/defs_eNB.h" +#include "s1ap_messages_types.h" +#include "f1ap_messages_types.h" +#include "LTE_SystemInformationBlockType2.h" +#include "rrc_messages_types.h" +#include "RRC/LTE/rrc_defs.h" +#include +#include "enb_paramdef.h" + +int RCconfig_MME(void); + +#endif /* MME_CONFIG_H_ */ +/** @} */ diff --git a/openair3/NAS/COMMON/UTIL/nas_log.h b/openair3/NAS/COMMON/UTIL/nas_log.h index b41e34c51b..d1531fa6db 100644 --- a/openair3/NAS/COMMON/UTIL/nas_log.h +++ b/openair3/NAS/COMMON/UTIL/nas_log.h @@ -95,14 +95,15 @@ typedef enum { /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #ifdef LOG_E # define LOG_TRACE(s, x, args...) \ do { \ switch (s) { \ - case ERROR: LOG_E(NAS, " %s:%d " x "\n", __FILE__, __LINE__, ##args); break; \ - case WARNING: LOG_W(NAS, " %s:%d " x "\n", __FILE__, __LINE__, ##args); break; \ - case INFO: LOG_I(NAS, " %s:%d " x "\n", __FILE__, __LINE__, ##args); break; \ - default: LOG_D(NAS, " %s:%d " x "\n", __FILE__, __LINE__, ##args); break; \ + case ERROR: LOG_E(NAS, " %s:%d " x "\n", __FILENAME__, __LINE__, ##args); break; \ + case WARNING: LOG_W(NAS, " %s:%d " x "\n", __FILENAME__, __LINE__, ##args); break; \ + case INFO: LOG_I(NAS, " %s:%d " x "\n", __FILENAME__, __LINE__, ##args); break; \ + default: LOG_D(NAS, " %s:%d " x "\n", __FILENAME__, __LINE__, ##args); break; \ } \ } while (0) diff --git a/openair3/NAS/COMMON/UTIL/nas_timer.c b/openair3/NAS/COMMON/UTIL/nas_timer.c index 7ddcb61d1d..9ccca12520 100644 --- a/openair3/NAS/COMMON/UTIL/nas_timer.c +++ b/openair3/NAS/COMMON/UTIL/nas_timer.c @@ -43,13 +43,7 @@ Description Timer utilities #include // memset #include // malloc, free #include // setitimer - -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#else -# include -# include // clock_gettime -#endif +#include "intertask_interface.h" #include "nas_timer.h" #include "commonDef.h" #include "msc.h" @@ -69,11 +63,7 @@ Description Timer utilities * value when the timer entry was allocated. */ typedef struct { -#if defined(ENABLE_ITTI) - long timer_id; /* Timer id returned by the timer API from ITTI */ -#else - pthread_t pid; /* Thread identifier of the callback */ -#endif +long timer_id; /* Timer id returned by the timer API from ITTI */ struct timeval itv; /* Initial interval timer value */ struct timeval tv; /* Interval timer value */ @@ -105,10 +95,6 @@ typedef struct { #define TIMER_DATABASE_SIZE 256 timer_queue_t tq[TIMER_DATABASE_SIZE]; timer_queue_t *head;/* Pointer to the first timer entry to be fired */ - -#if !defined(ENABLE_ITTI) - pthread_mutex_t mutex; -#endif } nas_timer_database_t; /* @@ -118,25 +104,15 @@ static nas_timer_database_t _nas_timer_db = { 0, {}, NULL -#if !defined(ENABLE_ITTI) - , PTHREAD_MUTEX_INITIALIZER -#endif }; -#if defined(ENABLE_ITTI) #define nas_timer_lock_db() #define nas_timer_unlock_db() -#else -#define nas_timer_lock_db() pthread_mutex_lock(&_nas_timer_db.mutex) -#define nas_timer_unlock_db() pthread_mutex_unlock(&_nas_timer_db.mutex) -#endif /* * The handler executed whenever the system timer expires */ -#if !defined(ENABLE_ITTI) -static void _nas_timer_handler(int signal); -#endif + /* * ----------------------------------------------------------------------------- @@ -191,33 +167,6 @@ int nas_timer_init(void) /* Initialize the timer database */ _nas_timer_db_init(); -#if !defined(ENABLE_ITTI) - /* Setup the timer database handler */ - struct sigaction act; - - (void) memset (&act, 0, sizeof (act)); - (void) sigfillset (&act.sa_mask); - (void) sigdelset (&act.sa_mask, SIGHUP); - (void) sigdelset (&act.sa_mask, SIGINT); - (void) sigdelset (&act.sa_mask, SIGTERM); - (void) sigdelset (&act.sa_mask, SIGILL); - (void) sigdelset (&act.sa_mask, SIGTRAP); - (void) sigdelset (&act.sa_mask, SIGIOT); -# ifndef LINUX - (void) sigdelset (&act.sa_mask, SIGEMT); -# endif - (void) sigdelset (&act.sa_mask, SIGFPE); - (void) sigdelset (&act.sa_mask, SIGBUS); - (void) sigdelset (&act.sa_mask, SIGSEGV); - (void) sigdelset (&act.sa_mask, SIGSYS); - - act.sa_handler = _nas_timer_handler; - - if ( sigaction (SIGALRM, &act, 0) < 0 ) { - return (RETURNerror); - } - -#endif return (RETURNok); } @@ -243,10 +192,8 @@ int nas_timer_start(long sec, nas_timer_callback_t cb, void *args) { int id; nas_timer_entry_t *te; -#if defined(ENABLE_ITTI) int ret; long timer_id; -#endif /* Do not start null timer */ if (sec == 0) { @@ -270,7 +217,6 @@ int nas_timer_start(long sec, nas_timer_callback_t cb, void *args) /* Insert the new entry into the timer queue */ _nas_timer_db_insert_entry(id, te); -#if defined(ENABLE_ITTI) # if defined(NAS_MME) ret = timer_setup(sec, 0, TASK_NAS_MME, INSTANCE_DEFAULT, TIMER_PERIODIC, args, &timer_id); # else @@ -280,10 +226,7 @@ int nas_timer_start(long sec, nas_timer_callback_t cb, void *args) if (ret == -1) { return NAS_TIMER_INACTIVE_ID; } - te->timer_id = timer_id; -#endif - return (id); } @@ -309,11 +252,7 @@ int nas_timer_stop(int id) nas_timer_entry_t *entry; /* Remove the entry from the timer queue */ entry = _nas_timer_db_remove_entry(id); -#if defined(ENABLE_ITTI) timer_remove(entry->timer_id); -#else - (void)entry; -#endif /* Delete the timer entry */ _nas_timer_db_delete_entry(id); return (NAS_TIMER_INACTIVE_ID); @@ -380,7 +319,7 @@ int nas_timer_restart(int id) ** Others: _nas_timer_db ** ** ** ***************************************************************************/ -#if defined(ENABLE_ITTI) + void nas_timer_handle_signal_expiry(long timer_id, void *arg_p) { /* Get the timer entry for which the system timer expired */ @@ -388,25 +327,7 @@ void nas_timer_handle_signal_expiry(long timer_id, void *arg_p) te->cb(te->args); } -#else -static void _nas_timer_handler(int signal) -{ - /* At least one timer has been started */ - assert( (_nas_timer_db.head != NULL) && (_nas_timer_db.head->entry != NULL) ); - /* Get the timer entry for which the system timer expired */ - nas_timer_entry_t *te = _nas_timer_db.head->entry; - - threadCreate (&te->pid, te->cb, te->args, "nas-timer", -1, OAI_PRIORITY_RT_LOW); - - void *result = NULL; - (void) pthread_join(te->pid, &result); - - if (result) { - free(result); - } -} -#endif /* * ----------------------------------------------------------------------------- @@ -605,17 +526,7 @@ static void _nas_timer_db_insert_entry(int id, nas_timer_entry_t *te) restart = _nas_timer_db_insert(&_nas_timer_db.tq[id]); nas_timer_unlock_db(); -#if !defined(ENABLE_ITTI) - - if (restart) { - /* The new entry is the first entry of the list; - * restart the system timer */ - setitimer(ITIMER_REAL, &it, 0); - } - -#else (void)(restart); -#endif } static int _nas_timer_db_insert(timer_queue_t *entry) @@ -704,21 +615,8 @@ static nas_timer_entry_t *_nas_timer_db_remove_entry(int id) tv.tv_usec = ts.tv_nsec/1000; /* tv = tv - time() */ rc = _nas_timer_sub(&_nas_timer_db.head->entry->tv, &tv, &it.it_value); - -#if defined(ENABLE_ITTI) timer_remove(_nas_timer_db.head->entry->timer_id); (void) (rc); -#else - - if (rc < 0) { - /* The system timer should have already expired */ - _nas_timer_handler(SIGALRM); - } else { - /* Restart the system timer */ - setitimer(ITIMER_REAL, &it, 0); - } - -#endif } /* Return a pointer to the removed entry */ @@ -749,17 +647,6 @@ static int _nas_timer_db_remove(timer_queue_t *entry) /* Other timers are scheduled to expire */ return TRUE; } - -#if !defined(ENABLE_ITTI) - { - /* No more timer is scheduled to expire; stop the system timer */ - struct itimerval it; - it.it_interval.tv_sec = it.it_interval.tv_usec = 0; - it.it_value.tv_sec = it.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &it, 0); - return FALSE; - } -#endif } /* The entry was NOT the first entry of the list */ diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index 7bdd21572e..67bfaf784e 100644 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -286,7 +286,7 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, user->emm_data->security->selected_algorithms.encryption = seea; user->emm_data->security->selected_algorithms.integrity = seia; #if defined(NAS_BUILT_IN_UE) - nas_itti_kenb_refresh_req(security_data->kenb.value); + nas_itti_kenb_refresh_req(security_data->kenb.value, user->ueid); #endif } diff --git a/openair3/NAS/UE/ESM/PdnConnectivity.c b/openair3/NAS/UE/ESM/PdnConnectivity.c index 48730f2ca9..3b5bad7529 100644 --- a/openair3/NAS/UE/ESM/PdnConnectivity.c +++ b/openair3/NAS/UE/ESM/PdnConnectivity.c @@ -61,9 +61,7 @@ Description Defines the PDN connectivity ESM procedure executed by the #include "emm_sap.h" -#if defined(ENABLE_ITTI) # include "assertions.h" -#endif /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c index 7fe1435960..7b9a1be422 100644 --- a/openair3/NAS/UE/UEprocess.c +++ b/openair3/NAS/UE/UEprocess.c @@ -188,17 +188,16 @@ int main(int argc, const char *argv[]) /**************************************************************************** ** ** - ** Name: _nas_user_mngr() ** + ** Name: _nas_user_mngr() ** ** ** ** Description: Manages the connection endpoint use to communicate with ** - ** the user application layer ** + ** the user application layer ** ** ** - ** Inputs: fd: The descriptor of the user connection end- ** - ** point ** - ** Others: None ** + ** Inputs: fd: The descriptor of the user connection end-point ** + ** Others: None ** ** ** - ** Outputs: Return: None ** - ** Others: None ** + ** Outputs: Return: None ** + ** Others: None ** ** ** ***************************************************************************/ static void *_nas_user_mngr(void *args) @@ -227,17 +226,16 @@ static void *_nas_user_mngr(void *args) /**************************************************************************** ** ** - ** Name: _nas_network_mngr() ** + ** Name: _nas_network_mngr() ** ** ** ** Description: Manages the connection endpoint use to communicate with ** - ** the network sublayer ** + ** the network sublayer ** ** ** - ** Inputs: fd: The descriptor of the network connection ** - ** endpoint ** - ** Others: None ** + ** Inputs: fd: The descriptor of the network connection endpoint ** + ** Others: None ** ** ** - ** Outputs: Return: None ** - ** Others: None ** + ** Outputs: Return: None ** + ** Others: None ** ** ** ***************************************************************************/ static void *_nas_network_mngr(void *args) @@ -302,16 +300,16 @@ static void *_nas_network_mngr(void *args) /**************************************************************************** ** ** - ** Name: _nas_set_signal_handler() ** + ** Name: _nas_set_signal_handler() ** ** ** ** Description: Set up a signal handler ** ** ** - ** Inputs: signal: Signal number ** - ** handler: Signal handler ** - ** Others: None ** + ** Inputs: signal: Signal number ** + ** handler: Signal handler ** + ** Others: None ** ** ** - ** Outputs: Return: RETURNerror, RETURNok ** - ** Others: None ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** ** ** ***************************************************************************/ static int _nas_set_signal_handler(int signal, void (handler)(int)) @@ -351,15 +349,15 @@ static int _nas_set_signal_handler(int signal, void (handler)(int)) /**************************************************************************** ** ** - ** Name: _nas_signal_handler() ** + ** Name: _nas_signal_handler() ** ** ** ** Description: Signal handler ** ** ** - ** Inputs: signal: Signal number ** - ** Others: None ** + ** Inputs: signal: Signal number ** + ** Others: None ** ** ** - ** Outputs: Return: None ** - ** Others: None ** + ** Outputs: Return: None ** + ** Others: None ** ** ** ***************************************************************************/ static void _nas_signal_handler(int signal) @@ -377,16 +375,16 @@ static void _nas_signal_handler(int signal) /**************************************************************************** ** ** - ** Name: _nas_clean() ** + ** Name: _nas_clean() ** ** ** ** Description: Performs termination cleanup ** ** ** - ** Inputs: usr_fd: User's connection file descriptor ** - ** net_fd: Network's connection file descriptor ** - ** Others: None ** + ** Inputs: usr_fd: User's connection file descriptor ** + ** net_fd: Network's connection file descriptor ** + ** Others: None ** ** ** - ** Outputs: Return: None ** - ** Others: None ** + ** Outputs: Return: None ** + ** Others: None ** ** ** ***************************************************************************/ static void _nas_clean(user_api_id_t *user_api_id, int net_fd) diff --git a/openair3/NAS/UE/nas_itti_messaging.c b/openair3/NAS/UE/nas_itti_messaging.c index 55566700d7..885ebbdd81 100644 --- a/openair3/NAS/UE/nas_itti_messaging.c +++ b/openair3/NAS/UE/nas_itti_messaging.c @@ -100,7 +100,7 @@ int nas_itti_protected_msg(const char *buffer, const nas_message_t *msg, const i extern unsigned char NB_eNB_INST; -int nas_itti_kenb_refresh_req(const Byte_t kenb[32]) { +int nas_itti_kenb_refresh_req(const Byte_t kenb[32], int user_id) { MessageDef *message_p; message_p = itti_alloc_new_message(TASK_NAS_UE, NAS_KENB_REFRESH_REQ); memcpy(NAS_KENB_REFRESH_REQ(message_p).kenb, kenb, sizeof(NAS_KENB_REFRESH_REQ(message_p).kenb)); @@ -125,7 +125,7 @@ int nas_itti_kenb_refresh_req(const Byte_t kenb[32]) { kenb[20], kenb[21], kenb[22], kenb[23], kenb[24], kenb[25], kenb[26], kenb[27], kenb[28], kenb[29], kenb[30], kenb[31]); - return itti_send_msg_to_task(TASK_RRC_UE, NB_eNB_INST + 0 /* TODO to be virtualized */, message_p); + return itti_send_msg_to_task(TASK_RRC_UE, NB_eNB_INST + user_id, message_p); } int nas_itti_cell_info_req(const plmn_t plmnID, const Byte_t rat, int user_id) { diff --git a/openair3/NAS/UE/nas_itti_messaging.h b/openair3/NAS/UE/nas_itti_messaging.h index d958317e5a..967bbb3059 100644 --- a/openair3/NAS/UE/nas_itti_messaging.h +++ b/openair3/NAS/UE/nas_itti_messaging.h @@ -48,7 +48,7 @@ int nas_itti_protected_msg( # if defined(NAS_BUILT_IN_UE) -int nas_itti_kenb_refresh_req(const Byte_t kenb[32]); +int nas_itti_kenb_refresh_req(const Byte_t kenb[32], int user_id); int nas_itti_cell_info_req(const plmn_t plmnID, const Byte_t rat, int user_id); diff --git a/openair3/NAS/UE/nas_network.c b/openair3/NAS/UE/nas_network.c index f7a292df3f..f8abba4900 100644 --- a/openair3/NAS/UE/nas_network.c +++ b/openair3/NAS/UE/nas_network.c @@ -59,16 +59,16 @@ Description NAS procedure functions triggered by the network /**************************************************************************** ** ** - ** Name: nas_network_initialize() ** + ** Name: nas_network_initialize() ** ** ** ** Description: Initializes network internal data ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: None ** - ** Return: None ** - ** Others: None ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** ** ** ***************************************************************************/ void nas_network_initialize(void) @@ -80,16 +80,16 @@ void nas_network_initialize(void) /**************************************************************************** ** ** - ** Name: nas_network_cleanup() ** + ** Name: nas_network_cleanup() ** ** ** ** Description: Performs clean up procedure before the system is shutdown ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: None ** - ** Return: None ** - ** Others: None ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** ** ** ***************************************************************************/ void nas_network_cleanup(nas_user_t *user) @@ -103,20 +103,20 @@ void nas_network_cleanup(nas_user_t *user) /**************************************************************************** ** ** - ** Name: nas_network_process_data() ** + ** Name: nas_network_process_data() ** ** ** ** Description: Process Access Stratum messages received from the network ** - ** and call applicable NAS procedure function. ** + ** and call applicable NAS procedure function. ** ** ** - ** Inputs: msg_id: AS message identifier ** - ** data: Generic pointer to data structure that has ** - ** to be processed ** - ** Others: None ** + ** Inputs: msg_id: AS message identifier ** + ** data: Generic pointer to data structure that has ** + ** to be processed ** + ** Others: None ** ** ** - ** Outputs: None ** - ** Return: RETURNok if the message has been success- ** - ** fully processed; RETURNerror otherwise ** - ** Others: None ** + ** Outputs: None ** + ** Return: RETURNok if the message has been success- ** + ** fully processed; RETURNerror otherwise ** + ** Others: None ** ** ** ***************************************************************************/ int nas_network_process_data(nas_user_t *user, int msg_id, const void *data) @@ -173,7 +173,7 @@ int nas_network_process_data(nas_user_t *user, int msg_id, const void *data) } case AS_NAS_RELEASE_IND: - /* Received NAS signalling connection releaase indication */ + /* Received NAS signalling connection release indication */ rc = nas_proc_release_ind(user, msg->msg.nas_release_ind.cause); break; diff --git a/openair3/NAS/UE/nas_parser.c b/openair3/NAS/UE/nas_parser.c index d62ebc3529..beba47f64a 100644 --- a/openair3/NAS/UE/nas_parser.c +++ b/openair3/NAS/UE/nas_parser.c @@ -54,7 +54,7 @@ Description NAS command line parser * Identifiers of the NAS command line options */ enum { - NAS_PARSER_UE_ID, /* User Equipement Identifier */ + NAS_PARSER_UE_ID, /* User Equipment Identifier */ NAS_PARSER_TRACE_LEVEL, /* Logging trace level */ NAS_PARSER_USER_HOST, /* User app layer's hostname */ NAS_PARSER_NETWORK_HOST, /* Network layer's hostname */ @@ -118,17 +118,16 @@ static int atohex(const char *a_char); /**************************************************************************** ** ** - ** Name: nas_parser_print_usage() ** + ** Name: nas_parser_print_usage() ** ** ** ** Description: Displays the command line options used to run the NAS ** - ** process and the firmware version defined at compilation ** - ** time ** + ** process and the firmware version defined at compilation time ** ** ** - ** Inputs: version: Firmware version ** - ** Others: None ** + ** Inputs: version: Firmware version ** + ** Others: None ** ** ** - ** Outputs: Return: None ** - ** Others: None ** + ** Outputs: Return: None ** + ** Others: None ** ** ** ***************************************************************************/ void nas_parser_print_usage(const char *version) @@ -139,16 +138,16 @@ void nas_parser_print_usage(const char *version) /**************************************************************************** ** ** - ** Name: nas_parser_get_options() ** + ** Name: nas_parser_get_options() ** ** ** ** Description: Gets the command line options used to run the NAS process ** ** ** - ** Inputs: argc: Number of options ** - ** argv: Pointer to the list of options ** - ** Others: None ** + ** Inputs: argc: Number of options ** + ** argv: Pointer to the list of options ** + ** Others: None ** ** ** - ** Outputs: Return: RETURNerror, RETURNok ** - ** Others: None ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** ** ** ***************************************************************************/ int nas_parser_get_options(int argc, const char **argv) @@ -158,16 +157,16 @@ int nas_parser_get_options(int argc, const char **argv) /**************************************************************************** ** ** - ** Name: nas_parser_get_nb_options() ** + ** Name: nas_parser_get_nb_options() ** ** ** ** Description: Returns the number of the command line options used to ** - ** run the NAS process ** + ** run the NAS process ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Number of command line options ** - ** Others: None ** + ** Outputs: Return: Number of command line options ** + ** Others: None ** ** ** ***************************************************************************/ int nas_parser_get_nb_options(void) @@ -177,15 +176,15 @@ int nas_parser_get_nb_options(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_trace_level() ** + ** Name: nas_parser_get_trace_level() ** ** ** ** Description: Returns the value of the logging trace level ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the logging trace level ** - ** Others: None ** + ** Outputs: Return: Value of the logging trace level ** + ** Others: None ** ** ** ***************************************************************************/ int nas_parser_get_trace_level(void) @@ -195,15 +194,15 @@ int nas_parser_get_trace_level(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_network_host() ** + ** Name: nas_parser_get_network_host() ** ** ** ** Description: Returns the value of the network layer hostname ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the network layer hostname ** - ** Others: None ** + ** Outputs: Return: Value of the network layer hostname ** + ** Others: None ** ** ** ***************************************************************************/ const char *nas_parser_get_network_host(void) @@ -213,15 +212,15 @@ const char *nas_parser_get_network_host(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_network_port() ** + ** Name: nas_parser_get_network_port() ** ** ** ** Description: Returns the value of the network layer port number ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the network layer port number ** - ** Others: None ** + ** Outputs: Return: Value of the network layer port number ** + ** Others: None ** ** ** ***************************************************************************/ const char *nas_parser_get_network_port(void) @@ -231,15 +230,15 @@ const char *nas_parser_get_network_port(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_ueid() ** + ** Name: nas_parser_get_ueid() ** ** ** ** Description: Returns the value of the UE identifier option ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the UE identifier option ** - ** Others: None ** + ** Outputs: Return: Value of the UE identifier option ** + ** Others: None ** ** ** ***************************************************************************/ int nas_parser_get_ueid(void) @@ -249,15 +248,15 @@ int nas_parser_get_ueid(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_user_host() ** + ** Name: nas_parser_get_user_host() ** ** ** ** Description: Returns the value of the user application layer hostname ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the user app layer hostname ** - ** Others: None ** + ** Outputs: Return: Value of the user app layer hostname ** + ** Others: None ** ** ** ***************************************************************************/ const char *nas_parser_get_user_host(void) @@ -267,16 +266,16 @@ const char *nas_parser_get_user_host(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_user_port() ** + ** Name: nas_parser_get_user_port() ** ** ** ** Description: Returns the value of the user application layer port ** - ** number ** + ** number ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the user app layer port number ** - ** Others: None ** + ** Outputs: Return: Value of the user app layer port number ** + ** Others: None ** ** ** ***************************************************************************/ const char *nas_parser_get_user_port(void) @@ -286,15 +285,15 @@ const char *nas_parser_get_user_port(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_device_path() ** + ** Name: nas_parser_get_device_path() ** ** ** ** Description: Returns the value of the device pathname ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the device pathname ** - ** Others: None ** + ** Outputs: Return: Value of the device pathname ** + ** Others: None ** ** ** ***************************************************************************/ const char *nas_parser_get_device_path(void) @@ -304,15 +303,15 @@ const char *nas_parser_get_device_path(void) /**************************************************************************** ** ** - ** Name: nas_parser_get_device_params() ** + ** Name: nas_parser_get_device_params() ** ** ** ** Description: Returns the value of the device attribute parameters ** ** ** - ** Inputs: None ** - ** Others: None ** + ** Inputs: None ** + ** Others: None ** ** ** - ** Outputs: Return: Value of the device attribute parameters ** - ** Others: None ** + ** Outputs: Return: Value of the device attribute parameters ** + ** Others: None ** ** ** ***************************************************************************/ const char *nas_parser_get_device_params(void) diff --git a/openair3/NAS/UE/nas_ue_task.c b/openair3/NAS/UE/nas_ue_task.c index 6df6666638..d712a7b7f0 100644 --- a/openair3/NAS/UE/nas_ue_task.c +++ b/openair3/NAS/UE/nas_ue_task.c @@ -20,7 +20,6 @@ */ #include "utils.h" -#if defined(ENABLE_ITTI) # include "assertions.h" # include "intertask_interface.h" # include "nas_ue_task.h" @@ -301,4 +300,3 @@ char *make_port_str_from_ueid(const char *base_port_str, int ueid) { return itoa(port); } -#endif diff --git a/openair3/NAS/UE/nas_ue_task.h b/openair3/NAS/UE/nas_ue_task.h index c9890719cb..5615f366b7 100644 --- a/openair3/NAS/UE/nas_ue_task.h +++ b/openair3/NAS/UE/nas_ue_task.h @@ -33,8 +33,6 @@ typedef struct { nas_user_t *find_user_from_fd(nas_user_container_t *users, int fd); -# if defined(ENABLE_ITTI) void *nas_ue_task(void *args_p); -# endif #endif /* NAS_TASK_H_ */ diff --git a/openair3/S1AP/s1ap_eNB.c b/openair3/S1AP/s1ap_eNB.c index 03e6273d1b..3592cf80a1 100644 --- a/openair3/S1AP/s1ap_eNB.c +++ b/openair3/S1AP/s1ap_eNB.c @@ -124,7 +124,9 @@ static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p, sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id; s1ap_mme_data_p->assoc_id = -1; s1ap_mme_data_p->broadcast_plmn_num = broadcast_plmn_num; - + memcpy(&s1ap_mme_data_p->mme_s1_ip, + mme_ip_address, + sizeof(*mme_ip_address)); for (int i = 0; i < broadcast_plmn_num; ++i) s1ap_mme_data_p->broadcast_plmn_index[i] = broadcast_plmn_index[i]; @@ -193,6 +195,10 @@ void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t * new_instance->eNB_id = s1ap_register_eNB->eNB_id; new_instance->cell_type = s1ap_register_eNB->cell_type; new_instance->tac = s1ap_register_eNB->tac; + + memcpy(&new_instance->eNB_s1_ip, + &s1ap_register_eNB->enb_ip_address, + sizeof(s1ap_register_eNB->enb_ip_address)); for (int i = 0; i < s1ap_register_eNB->num_plmn; i++) { new_instance->mcc[i] = s1ap_register_eNB->mcc[i]; diff --git a/openair3/S1AP/s1ap_eNB_defs.h b/openair3/S1AP/s1ap_eNB_defs.h index 5bffa0df0c..d4bc6cfc0f 100644 --- a/openair3/S1AP/s1ap_eNB_defs.h +++ b/openair3/S1AP/s1ap_eNB_defs.h @@ -124,6 +124,9 @@ typedef struct s1ap_eNB_mme_data_s { /* This is the optional name provided by the MME */ char *mme_name; + /* MME S1AP IP address */ + net_ip_address_t mme_s1_ip; + /* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max * number of 8 RATs but in our case only one is used. The LTE related pool * configuration is included on the first place in the list. @@ -200,6 +203,9 @@ typedef struct s1ap_eNB_instance_s { /* Tracking area code */ uint16_t tac; + /* eNB S1AP IP address */ + net_ip_address_t eNB_s1_ip; + /* Mobile Country Code * Mobile Network Code */ diff --git a/openair3/S1AP/s1ap_eNB_nas_procedures.c b/openair3/S1AP/s1ap_eNB_nas_procedures.c index b87bd7144a..d271ddf6ba 100644 --- a/openair3/S1AP/s1ap_eNB_nas_procedures.c +++ b/openair3/S1AP/s1ap_eNB_nas_procedures.c @@ -1468,7 +1468,7 @@ int s1ap_eNB_path_switch_req(instance_t instance, break; } } while(1); - + ue_context_p->mme_ue_s1ap_id = path_switch_req_p->mme_ue_s1ap_id; /* Prepare the S1AP message to encode */ diff --git a/openair3/SCTP/sctp_common.c b/openair3/SCTP/sctp_common.c index 55a2943924..66ffbec18a 100644 --- a/openair3/SCTP/sctp_common.c +++ b/openair3/SCTP/sctp_common.c @@ -41,7 +41,7 @@ #include "sctp_common.h" /* Pre-bind socket options configuration. - * See http://linux.die.net/man/7/sctp for more informations on these options. + * See http://linux.die.net/man/7/sctp for more information on these options. */ int sctp_set_init_opt(int sd, uint16_t instreams, uint16_t outstreams, uint16_t max_attempts, uint16_t init_timeout) diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h index e39a841d96..d28c9acccb 100644 --- a/openair3/UTILS/conversions.h +++ b/openair3/UTILS/conversions.h @@ -116,8 +116,14 @@ do { \ #define INT16_TO_OCTET_STRING(x, aSN) \ do { \ (aSN)->buf = calloc(2, sizeof(uint8_t)); \ - (aSN)->size = 2; \ - INT16_TO_BUFFER(x, (aSN)->buf); \ + INT16_TO_BUFFER(x, ((aSN)->buf)); \ + (aSN)->size = 2; \ +} while(0) + +#define INT16_TO_BIT_STRING(x, aSN) \ +do { \ + INT16_TO_OCTET_STRING(x, aSN); \ + (aSN)->bits_unused = 0; \ } while(0) #define INT8_TO_OCTET_STRING(x, aSN) \ diff --git a/svn2git/README.txt b/svn2git/README.txt deleted file mode 100644 index ef20ceebf0..0000000000 --- a/svn2git/README.txt +++ /dev/null @@ -1,64 +0,0 @@ -This file describes briefly the steps that were carried out to migrate from *PUBLIC* OAI SVN repo (http://svn.eurecom.fr/openair4G/trunk) to the gitlab repo (git@gitlab.eurecom.fr:oai/openairinterface5G.git). In order to reduce the size of repository, we have only included SVN commits from r4000 up till now. None of branches/tags are migrated from SVN Repository to Git. - -1. The steps to migrate from SVN to Git were carried out using the instructions/script here, https://www.atlassian.com/git/tutorials/migrating-overview - -2. Currently, the repository is public during the "transition period" for everyone to get used to the repository. During the "transition period", we will check in changes only to SVN and synchronize SVN to Git repository once everyday. At the end of "transition period", we will mark SVN repo as read-only and Git repository will be the default working repository. Currently, the "transition period" is set to 1 month until 15 July. However, this date might be changed based on the feedback from the community.There are brief instructions to explain this workflow here, https://www.atlassian.com/git/tutorials/migrating-overview/. - -3. The author list file is located in authors.txt in the main working directory. This file was extracted from SVN logs, but is modified for name and email addresses. - -4. Add a certificate from gitlab.eurecom.fr to your Ubuntu 14.04 installation (you need to be root user) - a) echo -n | openssl s_client -showcerts -connect gitlab.eurecom.fr:443 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /usr/local/share/ca-certificates/gitlab_eurecom_fr.crt - b)update-ca-certificates - -5. Git one time configuration with your name/email address. - git config --global user.name "Your Name" - git config --global user.email "Your email address" - -6. In order to checkout the Git repository (for OAI Users without login to gitlab server) - a) export GIT_SSL_NO_VERIFY=1; git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git (without certificate installation in step 4) - b) git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git (If certificate is installed in step 4) - -6. In order to checkout the Git repository (for OAI Developers/admins with login to gitlab server). Please send email to openair_tech@eurecom.fr to be added to the repository as a developer). If you do not have account on gitlab.eurecom.fr, please register yourself to gitlab.eurecom.fr. - - a) Checkout with using ssh keys: - You will need to put your ssh keys in https://gitlab.eurecom.fr/profile/keys to access to the git repo (only important for users who want to commit to the repository). Once that is done, checkout the git repository using: - git clone git@gitlab.eurecom.fr:oai/openairinterface5g.git - - b) Checkout with user name/password prompt: - - git clone https://YOUR_USERNAME@gitlab.eurecom.fr/oai/openairinterface5g.git - - - -Migration Instructions from SVN->Git in Detail (Not important for OAI Developer Community): -Assuming you are in svn2git directory. - -wget https://bitbucket.org/atlassian/svn-migration-scripts/downloads/svn-migration-scripts.jar -java -jar ./svn-migration-scripts.jar verify -java -jar ./svn-migration-scripts.jar authors http://svn.eurecom.fr/openair4G > authors.txt -git svn clone -r4000:HEAD --authors-file=./svn2git/authors.txt http://svn.eurecom.fr/openair4G/trunk oaiRepoData1 >& log_svn_clone1.out - -(Assuming you have added your ssh keys in https://gitlab.eurecom.fr/profile/keys) -//One time git configuration of user name/email address -git config --global user.name "Replace_With_Your_Name" -git config --global user.email "Replace_With_Your_Email_address" - -git remote add origin git@gitlab.eurecom.fr:oai/openairinterface5g.git - -git push -u origin --all -git push --tags - -Steps to synchronize on calisson (to be carried out periodically) -cd ~rohit/GitMigration/GitRepoNew/oaiRepoData1/svn2git -git config -l -git config --global user.name "Replace_With_Your_Name" -git config --global user.email "Replace_With_Your_Email_address" -./check_diff_author.sh #There should be no difference in author list file -git remote set-url origin https://kaltenbe@gitlab.eurecom.fr/oai/openairinterface5g.git -git svn fetch #--authors-file=./authors.txt (Make sure that there are no new authors since the last migration, else this will result in errors) -git svn rebase -git push -u origin --all -git push --tags - - - diff --git a/svn2git/authors.txt b/svn2git/authors.txt deleted file mode 100644 index 8bf7dbed0e..0000000000 --- a/svn2git/authors.txt +++ /dev/null @@ -1,86 +0,0 @@ -agostini = agostini -alexandr = alexandr -ambe = Anne Ambe -anouar = Hicham Anouar -antonb = antonb -apostolaras = Apostolos Apostolaras -arvanita = Arvanita -atsan = Emre Atsan -auberts = auberts -benromdh = benromdh -besnier = Joelle Besnier -bhamri = Bhamri -bohge = Mathias Bohge -brizzola = brizzola -byiringi = Byiringi -cerdan = Cerdan -cirkic = Cirkic -demiray = demiray -ferreira = Ferreira -fkalten = fkalten -fotimeli = Fotimeli -foubert = Philippe Foubert -gangakhe = Gangakhe -gangula = gangula -garcial = garcial -gauthier = Lionel Gauthier -ghaddab = ghaddab -ghaffar = ghaffar -guibene = guibene -guptar = Rohit Gupta -haerri = Haerri -hafsaoui = Hafsaoui -hao = hao -hashmat = hashmat -hrizi = hrizi -hu = hu -huang = Huang -iacobelli = Lorenzo Iacobelli -ihmig = ihmig -jdagres = jdagres -jiangx = jiangx -kaltenbe = Florian Kaltenberger -knopp = Raymond Knopp -kortke = kortke -kouassi = kouassi -laklii = laklii -latif = latif -libchaber = libchaber -linhuang = linhuang -lukashov = lukashov -maatalla = maatalla -maurel = maurel -mayani = mayani -merz = Ruben Merz -mlaner = mlaner -mosli = mosli -navid = Navid Nikaein -nguyenhn = nguyenhn -nguyennd = nguyennd -nikaeinn = Navid Nikaein < -oai_user1 = oai_user1 -ouni = ouni -paranche = paranche -pburlot = pburlot -qi = qi -renwanz = renwanz -roux = Cedric Roux -sait = sait -sorby = sorby -steinicke = steinicke -thomas = thomas -thomasl = thomasl -tonelli = tonelli -unlu = unlu -ustun = ustun -villa = villa -wagner = wagner -wangl = wangl -wetterwa = wetterwa -wewior = wewior -winckel = winckel -xuhl = xuhl -yannan = yannan -yilmaz = yilmaz -zayen = zayen -zhou = zhou diff --git a/svn2git/authors_original.txt b/svn2git/authors_original.txt deleted file mode 100644 index 7e239ce955..0000000000 --- a/svn2git/authors_original.txt +++ /dev/null @@ -1,45 +0,0 @@ -agostini = Agostini -alexandr = Alexandr -ambe = Anne Ambe -anouar = Hicham Anouar -apostolaras = Apostolos Apostolaras -arvanita = Arvanita -atsan = Emre Atsan -besnier = Joelle Besnier -bhamri = Bhamri -bohge = Mathias Bohge -byiringi = Byiringi -cerdan = Cerdan -cirkic = Cirkic -ferreira = Ferreira -fotimeli = Fotimeli -foubert = Philippe Foubert -gangakhe = Gangakhe -gangula = gangula -gauthier = Lionel Gauthier -haerri = Haerri -hafsaoui = Hafsaoui -huang = Huang -iacobelli = Lorenzo Iacobelli -ihmig = Ihmig -jiangx = Jiangx -kaltenbe = Florian Kaltenberger -knopp = Raymond Knopp -lukashov = Lukashov -navid = Navid Nikaein -nguyenhn = Nguyenhn -nguyennd = Nguyennd -nikaeinn = nikaeinn -oai_user1 = oai_user1 -ouni = Ouni -paranche = paranche -qi = qi -roux = Cedric Roux -sait = sait -sorby = sorby -thomas = thomas -unlu = unlu -wagner = wagner -yilmaz = yilmaz -zayen = zayen - diff --git a/svn2git/authors_original_java_output.txt b/svn2git/authors_original_java_output.txt deleted file mode 100644 index ca00a069c8..0000000000 --- a/svn2git/authors_original_java_output.txt +++ /dev/null @@ -1,86 +0,0 @@ -agostini = agostini -alexandr = alexandr -ambe = ambe -anouar = anouar -antonb = antonb -apostolaras = apostolaras -arvanita = arvanita -atsan = atsan -auberts = auberts -benromdh = benromdh -besnier = besnier -bhamri = bhamri -bohge = bohge -brizzola = brizzola -byiringi = byiringi -cerdan = cerdan -cirkic = cirkic -demiray = demiray -ferreira = ferreira -fkalten = fkalten -fotimeli = fotimeli -foubert = foubert -gangakhe = gangakhe -gangula = gangula -garcial = garcial -gauthier = gauthier -ghaddab = ghaddab -ghaffar = ghaffar -guibene = guibene -guptar = guptar -haerri = haerri -hafsaoui = hafsaoui -hao = hao -hashmat = hashmat -hrizi = hrizi -hu = hu -huang = huang -iacobelli = iacobelli -ihmig = ihmig -jdagres = jdagres -jiangx = jiangx -kaltenbe = kaltenbe -knopp = knopp -kortke = kortke -kouassi = kouassi -laklii = laklii -latif = latif -libchaber = libchaber -linhuang = linhuang -lukashov = lukashov -maatalla = maatalla -maurel = maurel -mayani = mayani -merz = merz -mlaner = mlaner -mosli = mosli -navid = navid -nguyenhn = nguyenhn -nguyennd = nguyennd -nikaeinn = nikaeinn -oai_user1 = oai_user1 -ouni = ouni -paranche = paranche -pburlot = pburlot -qi = qi -renwanz = renwanz -roux = roux -sait = sait -sorby = sorby -steinicke = steinicke -thomas = thomas -thomasl = thomasl -tonelli = tonelli -unlu = unlu -ustun = ustun -villa = villa -wagner = wagner -wangl = wangl -wetterwa = wetterwa -wewior = wewior -winckel = winckel -xuhl = xuhl -yannan = yannan -yilmaz = yilmaz -zayen = zayen -zhou = zhou diff --git a/svn2git/check_diff_author.sh b/svn2git/check_diff_author.sh deleted file mode 100755 index 7d55cfe9a5..0000000000 --- a/svn2git/check_diff_author.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -#The following script checks if the author list changed since the last commits in svn. If it finds difference in author names, then we need to add the author names manually in authors.txt - -wget https://bitbucket.org/atlassian/svn-migration-scripts/downloads/svn-migration-scripts.jar -java -jar ./svn-migration-scripts.jar verify -java -jar ./svn-migration-scripts.jar authors http://svn.eurecom.fr/openair4G > /tmp/authors.txt -diff /tmp/authors.txt ./authors_original_java_output.txt diff --git a/svn2git/git-author-rewrite.sh b/svn2git/git-author-rewrite.sh deleted file mode 100755 index b959db6b2e..0000000000 --- a/svn2git/git-author-rewrite.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -#Script to change author name/email address in git. It throws errors/warnings during the migration -#Copied from, https://help.github.com/articles/changing-author-info/ - -git filter-branch --env-filter ' - -OLD_EMAIL="your-old-email@example.com" -CORRECT_NAME="Your Correct Name" -CORRECT_EMAIL="your-correct-email@example.com" - -if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ] -then - export GIT_COMMITTER_NAME="$CORRECT_NAME" - export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL" -fi -if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ] -then - export GIT_AUTHOR_NAME="$CORRECT_NAME" - export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL" -fi -' --tag-name-filter cat -- --branches --tags - diff --git a/targets/ARCH/ADRV9371_ZC706/SYRTEM_IQ_uninstall_previous_SW.sh b/targets/ARCH/ADRV9371_ZC706/SYRTEM_IQ_uninstall_previous_SW.sh index 6651a3beb8..e0d5289f00 100755 --- a/targets/ARCH/ADRV9371_ZC706/SYRTEM_IQ_uninstall_previous_SW.sh +++ b/targets/ARCH/ADRV9371_ZC706/SYRTEM_IQ_uninstall_previous_SW.sh @@ -4,7 +4,7 @@ MODULE="riffa" KERNEL_VERSION=$(uname -r) RHR=/etc/redhat-release -sudo apt-get install -y --allow-unauthenticated linux-headers-`uname -r` +sudo apt-get install -y linux-headers-`uname -r` if lsmod | grep "$MODULE" &> /dev/null ; then echo "Previous SYRIQ is loaded!" diff --git a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c index f6ac1fc6e1..c4e593ca92 100644 --- a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c +++ b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c @@ -1147,7 +1147,6 @@ int device_init(openair0_device *device, device->trx_set_gains_func = trx_brf_set_gains; device->openair0_cfg = openair0_cfg; device->priv = (void *)brf; - device->uhd_set_thread_priority = NULL; calibrate_rf(device); diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index 16b86cfd64..3066f0906f 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -37,53 +37,27 @@ #include #include "common_lib.h" +#include "assertions.h" #include "common/utils/load_module_shlib.h" #include "common/utils/LOG/log.h" #include "targets/RT/USER/lte-softmodem.h" +char *get_devname(int devtype) { +char *devnames[MAX_RF_DEV_TYPE]=DEVTYPE_NAMES; + if (devtype < MAX_RF_DEV_TYPE && devtype !=MIN_RF_DEV_TYPE ) + return devnames[devtype]; + return "none"; +} + int set_device(openair0_device *device) { - switch (device->type) { - case EXMIMO_DEV: - LOG_I(HW,"[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case USRP_B200_DEV: - LOG_I(HW,"[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case USRP_X300_DEV: - LOG_I(HW,"[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case BLADERF_DEV: - LOG_I(HW,"[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case LMSSDR_DEV: - LOG_I(HW,"[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case IRIS_DEV: - LOG_I(HW,"[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case ADRV9371_ZC706_DEV: - LOG_I(HW,"[%s] has loaded ADRV9371_ZC706 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case UEDv2_DEV: - LOG_I(HW,"[%s] has loaded UEDv2 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - case NONE_DEV: - LOG_I(HW,"[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); - break; - - default: + char *devname = get_devname(device->type); + if (strcmp(devname,"none") != 0) { + LOG_I(HW,"[%s] has loaded %s device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"),devname); + } else { LOG_E(HW,"[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); return -1; - } + } return 0; } @@ -108,7 +82,7 @@ int set_transport(openair0_device *device) } typedef int(*devfunc_t)(openair0_device *, openair0_config_t *, eth_params_t *); -//loader_shlibfunc_t shlib_fdesc[2]; + /* look for the interface library and load it */ int load_lib(openair0_device *device, @@ -118,31 +92,44 @@ int load_lib(openair0_device *device, { loader_shlibfunc_t shlib_fdesc[1]; int ret=0; - char *libname; - if ( IS_SOFTMODEM_BASICSIM ) { - libname=OAI_BASICSIM_LIBNAME; + char *deflibname=OAI_RF_LIBNAME; + + openair0_cfg->recplay_mode = read_recplayconfig(&(openair0_cfg->recplay_conf),&(device->recplay_state)); + + if ( openair0_cfg->recplay_mode == RECPLAY_REPLAYMODE ) { + deflibname=OAI_IQPLAYER_LIBNAME; + shlib_fdesc[0].fname="device_init"; + set_softmodem_optmask(SOFTMODEM_RECPLAY_BIT); // softmodem has to know we use the iqplayer to workaround randomized algorithms + } else if ( IS_SOFTMODEM_BASICSIM ) { + deflibname=OAI_BASICSIM_LIBNAME; shlib_fdesc[0].fname="device_init"; } else if (IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) { - libname=OAI_RFSIM_LIBNAME; + deflibname=OAI_RFSIM_LIBNAME; shlib_fdesc[0].fname="device_init"; } else if (flag == RAU_LOCAL_RADIO_HEAD) { if (IS_SOFTMODEM_RFSIM) - libname="rfsimulator"; + deflibname="rfsimulator"; else - libname=OAI_RF_LIBNAME; + deflibname=OAI_RF_LIBNAME; shlib_fdesc[0].fname="device_init"; } else { - libname=OAI_TP_LIBNAME; + deflibname=OAI_TP_LIBNAME; shlib_fdesc[0].fname="transport_init"; } - ret=load_module_shlib(libname,shlib_fdesc,1,NULL); + + char *devname=NULL; + paramdef_t device_params[]=DEVICE_PARAMS_DESC ; + int numparams = sizeof(device_params)/sizeof(paramdef_t); + int devname_pidx = config_paramidx_fromname(device_params,numparams, CONFIG_DEVICEOPT_NAME); + device_params[devname_pidx].defstrval=deflibname; + + config_get(device_params,numparams,DEVICE_SECTION); + + ret=load_module_shlib(devname,shlib_fdesc,1,NULL); + AssertFatal( (ret >= 0), + "Library %s couldn't be loaded\n",devname); - if (ret < 0) { - LOG_E(HW,"Library %s couldn't be loaded\n",libname); - } else { - ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg); - } - return ret; + return ((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg); } diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 7052d6d40b..ecadb68c0c 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -35,15 +35,19 @@ #include #include #include +#include "record_player.h" -/* name of shared library implementing the radio front end */ +/* default name of shared library implementing the radio front end */ #define OAI_RF_LIBNAME "oai_device" /* name of shared library implementing the transport */ #define OAI_TP_LIBNAME "oai_transpro" -/* name of shared library implementing the basic/rf simulator */ +/* name of shared library implementing the rf simulator */ #define OAI_RFSIM_LIBNAME "rfsimulator" -/* name of shared library implementing the basic/rf simulator */ +/* name of shared library implementing the basic simulator */ #define OAI_BASICSIM_LIBNAME "tcp_bridge_oai" +/* name of shared library implementing the iq player */ +#define OAI_IQPLAYER_LIBNAME "oai_iqplayer" + /* flags for BBU to determine whether the attached radio head is local or remote */ #define RAU_LOCAL_RADIO_HEAD 0 #define RAU_REMOTE_RADIO_HEAD 1 @@ -56,7 +60,7 @@ typedef int64_t openair0_timestamp; typedef volatile int64_t openair0_vtimestamp; -/*!\brief structrue holds the parameters to configure USRP devices*/ +/*!\brief structure holds the parameters to configure USRP devices*/ typedef struct openair0_device_t openair0_device; //#define USRP_GAIN_OFFSET (56.0) // 86 calibrated for USRP B210 @ 2.6 GHz to get equivalent RS EPRE in OAI to SMBV100 output @@ -101,7 +105,7 @@ typedef enum { UEDv2_DEV, MAX_RF_DEV_TYPE } dev_type_t; - +#define DEVTYPE_NAMES {"","EXMIMO","USRP B200","USRP X300","BLADERF","LMSSDR","IRIS","No HW","ADRV9371_ZC706","UEDv2"} /*!\brief transport protocol types */ typedef enum { @@ -145,6 +149,7 @@ typedef enum { gpsdo=2 } clock_source_t; + /*! \brief RF frontend parameters set by application */ typedef struct { //! Module ID for this configuration @@ -219,15 +224,9 @@ typedef struct { char *my_addr; //! local port number for Ethernet interface (eNB/BBU, UE) unsigned int my_port; -#if defined(USRP_REC_PLAY) - unsigned short sf_mode; // 1=record, 2=replay - char sf_filename[1024]; // subframes file path - unsigned int sf_max; // max number of recorded subframes - unsigned int sf_loops; // number of loops in replay mode - unsigned int sf_read_delay; // read delay in replay mode - unsigned int sf_write_delay; // write delay in replay mode - unsigned int eth_mtu; // ethernet MTU -#endif + //! record player configuration, definition in record_player.h + uint32_t recplay_mode; + recplay_conf_t *recplay_conf; //! number of samples per tti unsigned int samples_per_tti; //! the sample rate for receive. @@ -287,7 +286,7 @@ struct openair0_device_t { /*!brief Type of this device */ dev_type_t type; - /*!brief Transport protocol type that the device suppports (in case I/Q samples need to be transported) */ + /*!brief Transport protocol type that the device supports (in case I/Q samples need to be transported) */ transport_type_t transp_type; /*!brief Type of the device's host (RAU/RRU) */ @@ -298,7 +297,8 @@ struct openair0_device_t { /* !brief ETH params set by application */ eth_params_t *eth_params; - + //! record player data, definition in record_player.h + recplay_state_t *recplay_state; /* !brief Indicates if device already initialized */ int is_init; @@ -400,10 +400,6 @@ struct openair0_device_t { * \param arg pointer to capabilities or configuration */ void (*configure_rru)(int idx, void *arg); - - /*! \brief set UHD thread priority - */ - void (*uhd_set_thread_priority)(void); }; /* type of device init function, implemented in shared lib */ @@ -447,11 +443,31 @@ typedef struct { #define OPTION_LZ4 0x00000001 // LZ4 compression (option_value is set to compressed size) + #ifdef __cplusplus extern "C" { #endif + +#define DEVICE_SECTION "device" +#define CONFIG_HLP_DEVICE "Identifies the oai device (the interface to RF) to use, the shared lib \"lib_.so\" will be loaded" + +#define CONFIG_DEVICEOPT_NAME "name" + +/* inclusion for device configuration */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* config parameters for oai device */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define DEVICE_PARAMS_DESC {\ + { CONFIG_DEVICEOPT_NAME, CONFIG_HLP_DEVICE, 0, strptr:&devname, defstrval:NULL, TYPE_STRING, 0}\ +} + + + +/*! \brief get device name from device type */ +char *get_devname(int devtype); /*! \brief Initialize openair RF target. It returns 0 if OK */ int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg); /*! \brief Initialize transport protocol . It returns 0 if OK */ @@ -469,6 +485,11 @@ openair0_timestamp get_usrp_time(openair0_device *device); * \returns 0 in success */ int openair0_set_rx_frequencies(openair0_device *device, openair0_config_t *openair0_cfg); +/*! \brief read the iq record/player configuration */ +extern int read_recplayconfig(recplay_conf_t **recplay_conf, recplay_state_t **recplay_state); +/*! \brief store recorded iqs from memory to file. */ +extern void iqrecorder_end(openair0_device *device); + #define gettid() syscall(__NR_gettid) /*@}*/ diff --git a/targets/ARCH/COMMON/record_player.c b/targets/ARCH/COMMON/record_player.c new file mode 100644 index 0000000000..2dcd61e479 --- /dev/null +++ b/targets/ARCH/COMMON/record_player.c @@ -0,0 +1,115 @@ +/* + * 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 + */ + +/** record_player.c + * + * \author: Nokia bellLabs B. Mongazon F. Taburet + * + */ + +#include +#include +#include +#include +#include +#include "common/utils/LOG/log.h" +#include "assertions.h" +#include "common_lib.h" +#include "record_player.h" + +/*! \brief read the oai recorder or player configuration, called from common device code + * \param recplay_conf: store parameters + * recplay_state: store recorder or player data while the device runs + */ +int read_recplayconfig(recplay_conf_t **recplay_conf, recplay_state_t **recplay_state) { + unsigned int u_sf_record = 0; // record mode + unsigned int u_sf_replay = 0; // replay mode + *recplay_conf = calloc(sizeof(recplay_conf_t),1); + paramdef_t device_recplay_params[]=DEVICE_RECPLAY_PARAMS_DESC ; + config_get(device_recplay_params,sizeof(device_recplay_params)/sizeof(paramdef_t),DEVICE_RECPLAY_SECTION); + + if (u_sf_record || u_sf_replay ) { + struct sysinfo systeminfo; + *recplay_state = calloc(sizeof(recplay_state_t),1); + + if ( *recplay_state == NULL) { + LOG_E(HW,"calloc error in %s\n", __FILE__); + return -1; + } + + // Use mmap for IQ files for systems with less than 6GB total RAM + sysinfo(&systeminfo); + + if (systeminfo.totalram < 6144000000) { + (*recplay_state)->use_mmap = 0; + } else { + (*recplay_state)->use_mmap = 1; + } + } else { /* record player enabled */ + free(*recplay_conf); + *recplay_conf=NULL; + } + + if (u_sf_replay == 1) return RECPLAY_REPLAYMODE; + else if (u_sf_record == 1) return RECPLAY_RECORDMODE; + + return 0; +} + +/*! \brief Terminate operation of the oai iq recorder. to be called by any device + * used in record mode + * \param device, the hardware used + */ +void iqrecorder_end(openair0_device *device) { + if (device->recplay_state != NULL) { // subframes store + iqfile_header_t fh = {device->type,device->openair0_cfg->tx_sample_advance, device->openair0_cfg->rx_bw,OAIIQFILE_ID}; + recplay_state_t *rs = device->recplay_state; + recplay_conf_t *rc = device->openair0_cfg[0].recplay_conf; + rs->pFile = fopen (rc->u_sf_filename,"wb+"); + + if (rs->pFile == NULL) { + LOG_E(HW,"Cannot open %s\n", rc->u_sf_filename); + } else { + unsigned int i = 0; + unsigned int modu = 0; + + if ((modu = rs->nb_samples % 10) != 0) { + rs->nb_samples -= modu; // store entire number of frames + } + + LOG_I(HW,"Writing file header to %s \n", rc->u_sf_filename ); + fwrite(&fh, sizeof(fh), 1, rs->pFile); + LOG_UI(HW,"Writing %u subframes to %s \n",rs->nb_samples, rc->u_sf_filename ); + + for (i = 0; i < rs->nb_samples; i++) { + fwrite(rs->ms_sample+i, sizeof(unsigned char), sizeof(iqrec_t), rs->pFile); + } + + fclose (rs->pFile); + LOG_UI(HW,"File %s closed\n",rc->u_sf_filename ); + } + + if (rs->ms_sample != NULL) { + free((void *)rs->ms_sample); + rs->ms_sample = NULL; + } + } +} \ No newline at end of file diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h b/targets/ARCH/COMMON/record_player.h similarity index 69% rename from targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h rename to targets/ARCH/COMMON/record_player.h index d29cf41db2..500acdd709 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h +++ b/targets/ARCH/COMMON/record_player.h @@ -1,5 +1,5 @@ -#ifndef __USRP_LIB_H -#define __USRP_LIB_H +#ifndef __RECORD_PLAYER_H +#define __RECORD_PLAYER_H /* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with @@ -21,7 +21,7 @@ * contact@openairinterface.org */ -/** usrp_lib.h +/** targets/ARCH/COMMON/record-player.h * * \author: bruno.mongazon-cazavet@nokia-bell-labs.com */ @@ -37,19 +37,6 @@ extern "C" { #endif -#define CONFIG_OPT_RECPLAY "enable_recplay" - -#define CONFIG_HLP_RECPLAY "Allow record player" -#define USRP_SECTION "device.usrp" -/* inclusion for device configuration */ -/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* command line parameters for USRP record/playback */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define USRP_DEVICE_PARAMS_DESC { \ - {CONFIG_OPT_RECPLAY, CONFIG_HLP_RECPLAY, PARAMFLAG_BOOL, uptr:&enable_recplay, defuintval:0, TYPE_UINT, 0} \ - } - /* inclusions for record player */ #define RECPLAY_DISABLED 0 @@ -59,6 +46,15 @@ extern "C" #define BELL_LABS_IQ_HEADER 0xabababababababab #define BELL_LABS_IQ_PER_SF 7680 // Up to 5MHz bw for now #define BELL_LABS_IQ_BYTES_PER_SF (BELL_LABS_IQ_PER_SF * 4) + +#define OAIIQFILE_ID "OIQF" +typedef struct { + uint64_t devtype; + uint64_t tx_sample_advance; + double bw; + char oaiid[4]; +} iqfile_header_t; + typedef struct { int64_t header; int64_t ts; @@ -75,8 +71,8 @@ typedef struct { /* help strings definition for config options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ #define CONFIG_HLP_SF_FILE "Path of the file used for subframes record or replay" -#define CONFIG_HLP_SF_REC "Record subframes from USRP driver into a file for later replay" -#define CONFIG_HLP_SF_REP "Replay subframes into USRP driver from a file" +#define CONFIG_HLP_SF_REC "Record subframes from device driver into a file for later replay" +#define CONFIG_HLP_SF_REP "Replay subframes from a file using the oai replay driver" #define CONFIG_HLP_SF_MAX "Maximum count of subframes to be recorded in subframe file" #define CONFIG_HLP_SF_LOOPS "Number of loops to replay of the entire subframes file" #define CONFIG_HLP_SF_RDELAY "Delay in microseconds to read a subframe in replay mode" @@ -91,41 +87,43 @@ typedef struct { #define CONFIG_OPT_SF_RDELAY "subframes-read-delay" #define CONFIG_OPT_SF_WDELAY "subframes-write-delay" -#define USRP_RECPLAY_SECTION "device.recplay" +#define DEVICE_RECPLAY_SECTION "device.recplay" /* For information only - the macro is not usable in C++ */ /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* command line parameters for USRP record/playback */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define USRP_RECPLAY_PARAMS_DESC { \ - {CONFIG_OPT_SF_FILE, CONFIG_HLP_SF_FILE, 0, strptr:(char **)((*recplay_state)->u_sf_filename), defstrval:DEF_SF_FILE, TYPE_STRING, 1024}, \ - {CONFIG_OPT_SF_REC, CONFIG_HLP_SF_REC, PARAMFLAG_BOOL, uptr:&(u_sf_record), defuintval:0, TYPE_UINT, 0}, \ - {CONFIG_OPT_SF_REP, CONFIG_HLP_SF_REP, PARAMFLAG_BOOL, uptr:&(u_sf_replay), defuintval:0, TYPE_UINT, 0}, \ - {CONFIG_OPT_SF_MAX, CONFIG_HLP_SF_MAX, 0, uptr:&((*recplay_state)->u_sf_max), defintval:DEF_NB_SF, TYPE_UINT, 0}, \ - {CONFIG_OPT_SF_LOOPS, CONFIG_HLP_SF_LOOPS, 0, uptr:&((*recplay_state)->u_sf_loops), defintval:DEF_SF_NB_LOOP, TYPE_UINT, 0}, \ - {CONFIG_OPT_SF_RDELAY, CONFIG_HLP_SF_RDELAY, 0, uptr:&((*recplay_state)->u_sf_read_delay), defintval:DEF_SF_DELAY_READ, TYPE_UINT, 0}, \ - {CONFIG_OPT_SF_WDELAY, CONFIG_HLP_SF_WDELAY, 0, uptr:&((*recplay_state)->u_sf_write_delay), defintval:DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \ - }/*! \brief USRP Configuration and state */ - +#define DEVICE_RECPLAY_PARAMS_DESC { \ + {CONFIG_OPT_SF_FILE, CONFIG_HLP_SF_FILE, 0, strptr:(char **)((*recplay_conf)->u_sf_filename), defstrval:DEF_SF_FILE, TYPE_STRING, 1024}, \ + {CONFIG_OPT_SF_REC, CONFIG_HLP_SF_REC, PARAMFLAG_BOOL, uptr:&(u_sf_record), defuintval:0, TYPE_UINT, 0}, \ + {CONFIG_OPT_SF_REP, CONFIG_HLP_SF_REP, PARAMFLAG_BOOL, uptr:&(u_sf_replay), defuintval:0, TYPE_UINT, 0}, \ + {CONFIG_OPT_SF_MAX, CONFIG_HLP_SF_MAX, 0, uptr:&((*recplay_conf)->u_sf_max), defintval:DEF_NB_SF, TYPE_UINT, 0}, \ + {CONFIG_OPT_SF_LOOPS, CONFIG_HLP_SF_LOOPS, 0, uptr:&((*recplay_conf)->u_sf_loops), defintval:DEF_SF_NB_LOOP, TYPE_UINT, 0}, \ + {CONFIG_OPT_SF_RDELAY, CONFIG_HLP_SF_RDELAY, 0, uptr:&((*recplay_conf)->u_sf_read_delay), defintval:DEF_SF_DELAY_READ, TYPE_UINT, 0}, \ + {CONFIG_OPT_SF_WDELAY, CONFIG_HLP_SF_WDELAY, 0, uptr:&((*recplay_conf)->u_sf_write_delay), defintval:DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \ + }/*! \brief Record Player Configuration and state */ typedef struct { - FILE *pFile; - int mmapfd; - int iqfd; - int use_mmap; // default is to use mmap - size_t mapsize; - iqrec_t *ms_sample; // memory for all subframes - unsigned int nb_samples; char u_sf_filename[1024]; // subframes file path unsigned int u_sf_max ; // max number of recorded subframes unsigned int u_sf_loops ; // number of loops in replay mode unsigned int u_sf_read_delay; // read delay in replay mode unsigned int u_sf_write_delay ; // write delay in replay mode +} recplay_conf_t; + +typedef struct { + int use_mmap; // default is to use mmap + size_t mapsize; + FILE *pFile; + int mmapfd; + int iqfd; + iqrec_t *ms_sample; // memory for all subframes + unsigned int nb_samples; } recplay_state_t; -extern int read_usrpconfig(uint32_t *recplay_mode, recplay_state_t **recplay_state); + #ifdef __cplusplus } #endif -#endif // __USRP_LIB_H +#endif // __RECORD_PLAYER_H diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c index 259b1fc277..c5822a3650 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c @@ -417,7 +417,6 @@ int transport_init(openair0_device *device, device->trx_stop_func = trx_eth_stop; device->trx_set_freq_func = trx_eth_set_freq; device->trx_set_gains_func = trx_eth_set_gains; - device->uhd_set_thread_priority = NULL; if (eth->flags == ETH_RAW_MODE) { device->trx_write_func = trx_eth_write_raw; diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp index c563569506..9fcfbdf571 100644 --- a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp +++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp @@ -178,7 +178,7 @@ int trx_lms_start(openair0_device *device){ } LMS_Init(lms_device); - LMS_EnableCalibCache(lms_device,false); + LMS_EnableCache(lms_device,false); if (LMS_LoadConfig(lms_device,device->openair0_cfg[0].configFilename) != 0) { @@ -277,6 +277,7 @@ int trx_lms_stop(openair0_device *device) { LMS_DestroyStream(lms_device,&rx_stream); LMS_DestroyStream(lms_device,&tx_stream); LMS_Close(lms_device); + return 0; } /*! \brief Set frequencies (TX/RX) @@ -405,7 +406,6 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg){ device->trx_stop_func = trx_lms_stop; device->trx_set_freq_func = trx_lms_set_freq; device->trx_set_gains_func = trx_lms_set_gains; - device->uhd_set_thread_priority = NULL; device->openair0_cfg = openair0_cfg; diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp index 9b11415631..6f1afe47c0 100644 --- a/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp +++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp @@ -706,7 +706,6 @@ int openair0_dev_init_sodera(openair0_device* device, openair0_config_t *openair device->trx_stop_func = trx_sodera_stop; device->trx_set_freq_func = trx_sodera_set_freq; device->trx_set_gains_func = trx_sodera_set_gains; - device->uhd_set_thread_priority = NULL; s->sample_rate = openair0_cfg[0].sample_rate; s->channelscount = openair0_cfg[0].rx_num_channels; diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index e2418bcb76..f37c8cf5cf 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -23,7 +23,8 @@ * * \author: HongliangXU : hong-liang-xu@agilent.com */ - +#define _LARGEFILE_SOURCE +#define _FILE_OFFSET_BITS 64 #include #include #include @@ -51,8 +52,6 @@ #include -#include "usrp_lib.h" - #ifdef __SSE4_1__ #include #endif @@ -108,8 +107,6 @@ typedef struct { int first_tx; //! timestamp of RX packet openair0_timestamp rx_timestamp; - uint32_t recplay_mode; - recplay_state_t *recplay_state; } usrp_state_t; //void print_notes(void) @@ -271,19 +268,19 @@ static int sync_to_gps(openair0_device *device) { static int trx_usrp_start(openair0_device *device) { usrp_state_t *s = (usrp_state_t *)device->priv; - if ( s->recplay_mode == RECPLAY_REPLAYMODE) - return 0; - // setup GPIO for TDD, GPIO(4) = ATR_RX //set data direction register (DDR) to output - s->usrp->set_gpio_attr("FP0", "DDR", 0x7f, 0x7f); - //set control register to ATR - s->usrp->set_gpio_attr("FP0", "CTRL", 0x7f,0x7f); + s->usrp->set_gpio_attr("FP0", "DDR", 0xfff, 0xfff); + //set lower 7 bits to be controlled automatically by ATR (the rest 5 bits are controlled manually) + s->usrp->set_gpio_attr("FP0", "CTRL", 0x7f,0xfff); //set pins 4 (RX_TX_Switch) and 6 (Shutdown PA) to 1 when the radio is only receiving (ATR_RX) s->usrp->set_gpio_attr("FP0", "ATR_RX", (1<<4)|(1<<6), 0x7f); // set pin 5 (Shutdown LNA) to 1 when the radio is transmitting and receiveing (ATR_XX) // (we use full duplex here, because our RX is on all the time - this might need to change later) s->usrp->set_gpio_attr("FP0", "ATR_XX", (1<<5), 0x7f); + // set the output pins to 0 + s->usrp->set_gpio_attr("FP0", "OUT", 7<<7, 0xf80); + // init recv and send streaming uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); LOG_I(HW,"Time in secs now: %llu \n", s->usrp->get_time_now().to_ticks(s->sample_rate)); @@ -316,86 +313,14 @@ static void trx_usrp_end(openair0_device *device) { return; usrp_state_t *s = (usrp_state_t *)device->priv; - + if (s == NULL) return; + iqrecorder_end(device); - if (s->recplay_mode != RECPLAY_REPLAYMODE) { // not subframes replay - s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); - //send a mini EOB packet - s->tx_md.end_of_burst = true; - s->tx_stream->send("", 0, s->tx_md); - s->tx_md.end_of_burst = false; - sleep(1); - } - if (s->recplay_mode == RECPLAY_RECORDMODE) { // subframes store - s->recplay_state->pFile = fopen (s->recplay_state->u_sf_filename,"wb+"); - - if (s->recplay_state->pFile == NULL) { - std::cerr << "Cannot open " << s->recplay_state->u_sf_filename << std::endl; - } else { - unsigned int i = 0; - unsigned int modu = 0; - - if ((modu = s->recplay_state->nb_samples % 10) != 0) { - s->recplay_state->nb_samples -= modu; // store entire number of frames - } - - std::cerr << "Writing " << s->recplay_state->nb_samples << " subframes to " << s->recplay_state->u_sf_filename << " ..." << std::endl; - - for (i = 0; i < s->recplay_state->nb_samples; i++) { - fwrite(s->recplay_state->ms_sample+i, sizeof(unsigned char), sizeof(iqrec_t), s->recplay_state->pFile); - } - - fclose (s->recplay_state->pFile); - std::cerr << "File " << s->recplay_state->u_sf_filename << " closed." << std::endl; - } - - if (s->recplay_state->ms_sample != NULL) { - free((void *)s->recplay_state->ms_sample); - s->recplay_state->ms_sample = NULL; - } - } else if (s->recplay_mode == RECPLAY_REPLAYMODE) { // replay - if (s->recplay_state->use_mmap) { - if (s->recplay_state->ms_sample != MAP_FAILED) { - munmap(s->recplay_state->ms_sample, s->recplay_state->mapsize); - s->recplay_state->ms_sample = NULL; - } - - if (s->recplay_state->mmapfd != 0) { - close(s->recplay_state->mmapfd); - s->recplay_state->mmapfd = 0; - } - } else { - if (s->recplay_state->ms_sample != NULL) { - free(s->recplay_state->ms_sample); - s->recplay_state->ms_sample = NULL; - } - - if (s->recplay_state->iqfd != 0) { - close(s->recplay_state->iqfd); - s->recplay_state->iqfd = 0; - } - } - } -} -/*! \brief Write iqs function when in replay mode, just introduce a delay, as configured at init time, - @param device pointer to the device structure specific to the RF hardware target - @param timestamp The timestamp at which the first sample MUST be sent - @param buff Buffer which holds the samples - @param nsamps number of samples to be sent - @param antenna_id index of the antenna if the device has multiple antennas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied -*/ -static int trx_usrp_write_recplay(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { - struct timespec req; - usrp_state_t *s = (usrp_state_t *)device->priv; - req.tv_sec = 0; - req.tv_nsec = s->recplay_state->u_sf_write_delay * 1000; - nanosleep(&req, NULL); - return nsamps; } + /*! \brief Called to send samples to the USRP RF target @param device pointer to the device structure specific to the RF hardware target @param timestamp The timestamp at which the first sample MUST be sent @@ -404,10 +329,19 @@ static int trx_usrp_write_recplay(openair0_device *device, openair0_timestamp ti @param antenna_id index of the antenna if the device has multiple antennas @param flags flags must be set to TRUE if timestamp parameter needs to be applied */ -static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { +static int trx_usrp_write(openair0_device *device, + openair0_timestamp timestamp, + void **buff, + int nsamps, + int cc, + int flags) { int ret=0; usrp_state_t *s = (usrp_state_t *)device->priv; int nsamps2; // aligned to upper 32 or 16 byte boundary + + int flags_lsb = flags&0xff; + int flags_msb = (flags>>8)&0xff; + #if defined(__x86_64) || defined(__i386__) #ifdef __AVX2__ nsamps2 = (nsamps+7)>>3; @@ -441,40 +375,51 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, boolean_t first_packet_state=false,last_packet_state=false; - if (flags == 2) { // start of burst + if (flags_lsb == 2) { // start of burst // s->tx_md.start_of_burst = true; // s->tx_md.end_of_burst = false; first_packet_state = true; last_packet_state = false; - } else if (flags == 3) { // end of burst + } else if (flags_lsb == 3) { // end of burst //s->tx_md.start_of_burst = false; //s->tx_md.end_of_burst = true; first_packet_state = false; last_packet_state = true; - } else if (flags == 4) { // start and end - // s->tx_md.start_of_burst = true; - // s->tx_md.end_of_burst = true; + } else if (flags_lsb == 4) { // start and end + // s->tx_md.start_of_burst = true; + // s->tx_md.end_of_burst = true; first_packet_state = true; last_packet_state = true; - } else if (flags==1) { // middle of burst - // s->tx_md.start_of_burst = false; - // s->tx_md.end_of_burst = false; + } else if (flags_lsb==1) { // middle of burst + // s->tx_md.start_of_burst = false; + // s->tx_md.end_of_burst = false; first_packet_state = false; last_packet_state = false; - } else if (flags==10) { // fail safe mode - // s->tx_md.has_time_spec = false; - // s->tx_md.start_of_burst = false; - // s->tx_md.end_of_burst = true; - first_packet_state = false; - last_packet_state = true; + } + else if (flags_lsb==10) { // fail safe mode + // s->tx_md.has_time_spec = false; + // s->tx_md.start_of_burst = false; + // s->tx_md.end_of_burst = true; + first_packet_state = false; + last_packet_state = true; } + s->tx_md.has_time_spec = true; s->tx_md.start_of_burst = (s->tx_count==0) ? true : first_packet_state; s->tx_md.end_of_burst = last_packet_state; s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate); s->tx_count++; + // bit 3 enables gpio (for backward compatibility) + if (flags_msb&8) { + // push GPIO bits 7-9 from flags_msb + int gpio789=(flags_msb&7)<<7; + s->usrp->set_command_time(s->tx_md.time_spec); + s->usrp->set_gpio_attr("FP0", "OUT", gpio789, 0x380); + s->usrp->clear_command_time(); + } + if (cc>1) { std::vector buff_ptrs; @@ -482,112 +427,16 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, buff_ptrs.push_back(&(((int16_t *)buff_tx[i])[0])); ret = (int)s->tx_stream->send(buff_ptrs, nsamps, s->tx_md); - } else ret = (int)s->tx_stream->send(&(((int16_t *)buff_tx[0])[0]), nsamps, s->tx_md); + } + else { + ret = (int)s->tx_stream->send(&(((int16_t *)buff_tx[0])[0]), nsamps, s->tx_md); + } + if (ret != nsamps) LOG_E(HW,"[xmit] tx samples %d != %d\n",ret,nsamps); return ret; } -/*! \brief Receive samples from iq file. - * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for - * the first channel. *ptimestamp is the time at which the first sample - * was received. - * \param device the hardware to use - * \param[out] ptimestamp the time at which the first sample was received. - * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps. - * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte. - * \param antenna_id Index of antenna for which to receive samples - * \returns the number of sample read -*/ -static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) { - int samples_received=0; - static unsigned int cur_samples; - static int64_t wrap_count; - static int64_t wrap_ts; - usrp_state_t *s = (usrp_state_t *)device->priv; - - - if (cur_samples == s->recplay_state->nb_samples) { - cur_samples = 0; - wrap_count++; - if (wrap_count == s->recplay_state->u_sf_loops) { - std::cerr << "USRP device terminating subframes replay mode after " << s->recplay_state->u_sf_loops << " loops." << std::endl; - exit_function(__FILE__, __FUNCTION__, __LINE__,"replay ended, triggering process termination\n"); - } - - wrap_ts = wrap_count * (s->recplay_state->nb_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)); - - if (!s->recplay_state->use_mmap) { - if (lseek(s->recplay_state->iqfd, 0, SEEK_SET) == 0) { - std::cerr << "Seeking at the beginning of IQ file" << std::endl; - } else { - std::cerr << "Problem seeking at the beginning of IQ file" << std::endl; - } - } - } - - if (s->recplay_state->use_mmap) { - if (cur_samples < s->recplay_state->nb_samples) { - *ptimestamp = (s->recplay_state->ms_sample[0].ts + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000))) + wrap_ts; - - if (cur_samples == 0) { - std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts - << " ts=" << *ptimestamp << std::endl; - } - - memcpy(buff[0], &s->recplay_state->ms_sample[cur_samples].samples[0], nsamps*4); - cur_samples++; - } - } else { - // read sample from file - if (read(s->recplay_state->iqfd, s->recplay_state->ms_sample, sizeof(iqrec_t)) != sizeof(iqrec_t)) { - std::cerr << "pb reading iqfile at index " << sizeof(iqrec_t)*cur_samples << std::endl; - close(s->recplay_state->iqfd); - free(s->recplay_state->ms_sample); - s->recplay_state->ms_sample = NULL; - s->recplay_state->iqfd = 0; - exit(-1); - } - - if (cur_samples < s->recplay_state->nb_samples) { - static int64_t ts0 = 0; - - if ((cur_samples == 0) && (wrap_count == 0)) { - ts0 = s->recplay_state->ms_sample->ts; - } - - *ptimestamp = ts0 + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)) + wrap_ts; - - if (cur_samples == 0) { - std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts - << " ts=" << *ptimestamp << std::endl; - } - - memcpy(buff[0], &s->recplay_state->ms_sample->samples[0], nsamps*4); - cur_samples++; - // Prepare for next read - off_t where = lseek(s->recplay_state->iqfd, cur_samples * sizeof(iqrec_t), SEEK_SET); - - if (where < 0) { - LOG_E(HW,"Cannot lseek in iqfile: %s\n",strerror(errno)); - } - } - } - - struct timespec req; - - req.tv_sec = 0; - - req.tv_nsec = s->recplay_state->u_sf_read_delay * 1000; - - nanosleep(&req, NULL); - - return nsamps; - - return samples_received; -} - - /*! \brief Receive samples from hardware. * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for * the first channel. *ptimestamp is the time at which the first sample @@ -689,13 +538,13 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); *ptimestamp = s->rx_timestamp; - if (s->recplay_mode == RECPLAY_RECORDMODE) { // record mode + if (device->recplay_state != NULL) { // record mode // Copy subframes to memory (later dump on a file) - if (s->recplay_state->nb_samples < s->recplay_state->u_sf_max) { - (s->recplay_state->ms_sample+s->recplay_state->nb_samples)->header = BELL_LABS_IQ_HEADER; - (s->recplay_state->ms_sample+s->recplay_state->nb_samples)->ts = *ptimestamp; - memcpy((s->recplay_state->ms_sample+s->recplay_state->nb_samples)->samples, buff[0], nsamps*4); - s->recplay_state->nb_samples++; + if (device->recplay_state->nb_samples < device->openair0_cfg->recplay_conf->u_sf_max) { + (device->recplay_state->ms_sample+device->recplay_state->nb_samples)->header = BELL_LABS_IQ_HEADER; + (device->recplay_state->ms_sample+device->recplay_state->nb_samples)->ts = *ptimestamp; + memcpy((device->recplay_state->ms_sample+device->recplay_state->nb_samples)->samples, buff[0], nsamps*4); + device->recplay_state->nb_samples++; } else exit_function(__FILE__, __FUNCTION__, __LINE__,"Recording reaches max iq limit\n"); } @@ -893,15 +742,6 @@ int trx_usrp_reset_stats(openair0_device *device) { return(0); } -/*! \brief Set uhd priority - */ -static void uhd_set_thread_priority(void) { - uhd::set_thread_priority_safe(1.0); -} - -void noop_func(void) { - return; -} extern "C" { int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { LOG_D(HW, "openair0_cfg[0].sdr_addrs == '%s'\n", openair0_cfg[0].sdr_addrs); @@ -918,7 +758,6 @@ extern "C" { } device->openair0_cfg = openair0_cfg; - read_usrpconfig(&(s->recplay_mode), &(s->recplay_state)); device->trx_start_func = trx_usrp_start; device->trx_get_stats_func = trx_usrp_get_stats; device->trx_reset_stats_func = trx_usrp_reset_stats; @@ -927,91 +766,74 @@ extern "C" { device->trx_set_freq_func = trx_usrp_set_freq; device->trx_set_gains_func = trx_usrp_set_gains; - if ( s->recplay_mode == RECPLAY_REPLAYMODE) { - // Replay subframes from from file - int bw_gain_adjust=0; - device->type = USRP_B200_DEV; - openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; - bw_gain_adjust=1; - openair0_cfg[0].tx_sample_advance = 80; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - openair0_cfg[0].iq_txshift = 4;//shift - openair0_cfg[0].iq_rxrescale = 15;//rescale iqs - set_rx_gain_offset(&openair0_cfg[0],0,bw_gain_adjust); - device->trx_write_func = trx_usrp_write_recplay; - device->trx_read_func = trx_usrp_read_recplay; - device->uhd_set_thread_priority = noop_func; - std::cerr << "USRP device initialized in subframes replay mode for " << s->recplay_state->u_sf_loops << " loops. Use mmap=" - << s->recplay_state->use_mmap << std::endl; + + // hotfix! to be checked later + uhd::set_thread_priority_safe(1.0); + // Initialize USRP device + int vers=0,subvers=0,subsubvers=0; + int bw_gain_adjust=0; + + if (device->openair0_cfg->recplay_mode == RECPLAY_RECORDMODE) { + std::cerr << "USRP device initialized in subframes record mode" << std::endl; + } + + sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers); + LOG_I(HW,"UHD version %s (%d.%d.%d)\n", + uhd::get_version_string().c_str(),vers,subvers,subsubvers); + std::string args; + + if (openair0_cfg[0].sdr_addrs == NULL) { + args = "type=b200"; } else { - // hotfix! to be checked later - uhd::set_thread_priority_safe(1.0); - // Initialize USRP device - int vers=0,subvers=0,subsubvers=0; - int bw_gain_adjust=0; - - if (s->recplay_mode == RECPLAY_RECORDMODE) { - std::cerr << "USRP device initialized in subframes record mode" << std::endl; - } - - sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers); - LOG_I(HW,"UHD version %s (%d.%d.%d)\n", - uhd::get_version_string().c_str(),vers,subvers,subsubvers); - std::string args; - - if (openair0_cfg[0].sdr_addrs == NULL) { - args = "type=b200"; - } else { - args = openair0_cfg[0].sdr_addrs; - LOG_I(HW,"Checking for USRP with args %s\n",openair0_cfg[0].sdr_addrs); - } - - uhd::device_addrs_t device_adds = uhd::device::find(args); - - if (device_adds.size() == 0) { - LOG_E(HW,"No USRP Device Found.\n "); - free(s); - return -1; - } else if (device_adds.size() > 1) { - LOG_E(HW,"More than one USRP Device Found. Please specify device more precisely in config file.\n"); - free(s); - return -1; - } - - LOG_I(HW,"Found USRP %s\n", device_adds[0].get("type").c_str()); - double usrp_master_clock; - - if (device_adds[0].get("type") == "b200") { - printf("Found USRP b200\n"); - device->type = USRP_B200_DEV; - usrp_master_clock = 30.72e6; - args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); - args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=7680, recv_frame_size=7680" ; - } - - if (device_adds[0].get("type") == "n3xx") { - printf("Found USRP n300\n"); - device->type=USRP_X300_DEV; //treat it as X300 for now - usrp_master_clock = 122.88e6; - args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); - //args += ", send_buff_size=33554432"; - } - - if (device_adds[0].get("type") == "x300") { - printf("Found USRP x300\n"); - device->type=USRP_X300_DEV; - usrp_master_clock = 184.32e6; - args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); - - // USRP recommended: https://files.ettus.com/manual/page_usrp_x3x0_config.html - if ( 0 != system("sysctl -w net.core.rmem_max=33554432 net.core.wmem_max=33554432") ) - LOG_W(HW,"Can't set kernel parameters for X3xx\n"); - } - - s->usrp = uhd::usrp::multi_usrp::make(args); - - if (args.find("clock_source")==std::string::npos) { + args = openair0_cfg[0].sdr_addrs; + LOG_I(HW,"Checking for USRP with args %s\n",openair0_cfg[0].sdr_addrs); + } + + uhd::device_addrs_t device_adds = uhd::device::find(args); + + if (device_adds.size() == 0) { + LOG_E(HW,"No USRP Device Found.\n "); + free(s); + return -1; + } else if (device_adds.size() > 1) { + LOG_E(HW,"More than one USRP Device Found. Please specify device more precisely in config file.\n"); + free(s); + return -1; + } + + LOG_I(HW,"Found USRP %s\n", device_adds[0].get("type").c_str()); + double usrp_master_clock; + + if (device_adds[0].get("type") == "b200") { + printf("Found USRP b200\n"); + device->type = USRP_B200_DEV; + usrp_master_clock = 30.72e6; + args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); + args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=7680, recv_frame_size=7680" ; + } + + if (device_adds[0].get("type") == "n3xx") { + printf("Found USRP n300\n"); + device->type=USRP_X300_DEV; //treat it as X300 for now + usrp_master_clock = 122.88e6; + args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); + //args += ", send_buff_size=33554432"; + } + + if (device_adds[0].get("type") == "x300") { + printf("Found USRP x300\n"); + device->type=USRP_X300_DEV; + usrp_master_clock = 184.32e6; + args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); + + // USRP recommended: https://files.ettus.com/manual/page_usrp_x3x0_config.html + if ( 0 != system("sysctl -w net.core.rmem_max=33554432 net.core.wmem_max=33554432") ) + LOG_W(HW,"Can't set kernel parameters for X3xx\n"); + } + + s->usrp = uhd::usrp::multi_usrp::make(args); + + if (args.find("clock_source")==std::string::npos) { if (openair0_cfg[0].clock_source == internal) { //in UHD 3.14 we could use //s->usrp->set_sync_source("clock_source=internal","time_source=internal"); @@ -1033,359 +855,292 @@ extern "C" { else { LOG_W(HW,"Clock source set neither in usrp_args nor on command line, using default!\n"); } - } - else { + } + else { if (openair0_cfg[0].clock_source != unset) { LOG_W(HW,"Clock source set in both usrp_args and in clock_source, ingnoring the latter!\n"); } - } - - if (s->usrp->get_clock_source(0) == "gpsdo") { - s->use_gps = 1; - - if (sync_to_gps(device)==EXIT_SUCCESS) { - LOG_I(HW,"USRP synced with GPS!\n"); - } else { - LOG_I(HW,"USRP fails to sync with GPS. Exiting.\n"); - exit(EXIT_FAILURE); - } - } else if (s->usrp->get_clock_source(0) == "external") { - if (check_ref_locked(s,0)) { - LOG_I(HW,"USRP locked to external reference!\n"); - } else { - LOG_I(HW,"Failed to lock to external reference. Exiting.\n"); - exit(EXIT_FAILURE); - } - } - - if (device->type==USRP_X300_DEV) { - openair0_cfg[0].rx_gain_calib_table = calib_table_x310; - std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info - LOG_I(HW,"%s() sample_rate:%u\n", __FUNCTION__, (int)openair0_cfg[0].sample_rate); - - switch ((int)openair0_cfg[0].sample_rate) { - case 122880000: - // from usrp_time_offset - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 15; //to be checked - openair0_cfg[0].tx_bw = 80e6; - openair0_cfg[0].rx_bw = 80e6; - break; - - case 92160000: - // from usrp_time_offset - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 15; //to be checked - openair0_cfg[0].tx_bw = 80e6; - openair0_cfg[0].rx_bw = 80e6; - break; - - case 61440000: - // from usrp_time_offset - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 15; - openair0_cfg[0].tx_bw = 40e6; - openair0_cfg[0].rx_bw = 40e6; - break; - - case 46080000: - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 15; - openair0_cfg[0].tx_bw = 40e6; - openair0_cfg[0].rx_bw = 40e6; - break; - - case 30720000: - // from usrp_time_offset - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 15; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - break; - - case 15360000: - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 45; - openair0_cfg[0].tx_bw = 10e6; - openair0_cfg[0].rx_bw = 10e6; - break; - - case 7680000: - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 50; - openair0_cfg[0].tx_bw = 5e6; - openair0_cfg[0].rx_bw = 5e6; - break; - - case 1920000: - //openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 50; - openair0_cfg[0].tx_bw = 1.25e6; - openair0_cfg[0].rx_bw = 1.25e6; - break; - - default: - LOG_E(HW,"Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); - exit(-1); - break; - } - } - - if (device->type == USRP_B200_DEV) { - if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) { - openair0_cfg[0].rx_gain_calib_table = calib_table_b210; - bw_gain_adjust=0; - std::cerr << "-- Using calibration table: calib_table_b210" << std::endl; // Bell Labs info - } else { - openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; - bw_gain_adjust=1; - std::cerr << "-- Using calibration table: calib_table_b210_38" << std::endl; // Bell Labs info - } - - switch ((int)openair0_cfg[0].sample_rate) { - case 46080000: - s->usrp->set_master_clock_rate(46.08e6); - //openair0_cfg[0].samples_per_packet = 1024; - openair0_cfg[0].tx_sample_advance = 115; - openair0_cfg[0].tx_bw = 40e6; - openair0_cfg[0].rx_bw = 40e6; - break; - - case 30720000: - s->usrp->set_master_clock_rate(30.72e6); - //openair0_cfg[0].samples_per_packet = 1024; - openair0_cfg[0].tx_sample_advance = 115; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - break; - - case 23040000: - s->usrp->set_master_clock_rate(23.04e6); //to be checked - //openair0_cfg[0].samples_per_packet = 1024; - openair0_cfg[0].tx_sample_advance = 113; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - break; - - case 15360000: - s->usrp->set_master_clock_rate(30.72e06); - //openair0_cfg[0].samples_per_packet = 1024; - openair0_cfg[0].tx_sample_advance = 103; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - break; - - case 7680000: - s->usrp->set_master_clock_rate(30.72e6); - //openair0_cfg[0].samples_per_packet = 1024; - openair0_cfg[0].tx_sample_advance = 80; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - break; - - case 1920000: - s->usrp->set_master_clock_rate(30.72e6); - //openair0_cfg[0].samples_per_packet = 1024; - openair0_cfg[0].tx_sample_advance = 40; - openair0_cfg[0].tx_bw = 20e6; - openair0_cfg[0].rx_bw = 20e6; - break; - - default: - LOG_E(HW,"Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); - exit(-1); - break; - } - } - - /* device specific */ - //openair0_cfg[0].txlaunch_wait = 1;//manage when TX processing is triggered - //openair0_cfg[0].txlaunch_wait_slotcount = 1; //manage when TX processing is triggered - openair0_cfg[0].iq_txshift = 4;//shift - openair0_cfg[0].iq_rxrescale = 15;//rescale iqs - - for(int i=0; i<((int) s->usrp->get_rx_num_channels()); i++) { - if (iusrp->set_rx_rate(openair0_cfg[0].sample_rate,i); - s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i); - set_rx_gain_offset(&openair0_cfg[0],i,bw_gain_adjust); - ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i); - // limit to maximum gain - AssertFatal( openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] <= gain_range.stop(), - "RX Gain too high, lower by %f dB\n", - openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop()); - s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i); - LOG_I(HW,"RX Gain %d %f (%f) => %f (max %f)\n",i, - openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i], - openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop()); - } - } - - LOG_D(HW, "usrp->get_tx_num_channels() == %zd\n", s->usrp->get_tx_num_channels()); - LOG_D(HW, "openair0_cfg[0].tx_num_channels == %d\n", openair0_cfg[0].tx_num_channels); - - for(int i=0; i<((int) s->usrp->get_tx_num_channels()); i++) { - ::uhd::gain_range_t gain_range_tx = s->usrp->get_tx_gain_range(i); - - if (iusrp->set_tx_rate(openair0_cfg[0].sample_rate,i); - s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i); - s->usrp->set_tx_gain(gain_range_tx.stop()-openair0_cfg[0].tx_gain[i],i); - LOG_I(HW,"USRP TX_GAIN:%3.2lf gain_range:%3.2lf tx_gain:%3.2lf\n", gain_range_tx.stop()-openair0_cfg[0].tx_gain[i], gain_range_tx.stop(), openair0_cfg[0].tx_gain[i]); - } - } - - //s->usrp->set_clock_source("external"); - //s->usrp->set_time_source("external"); - // display USRP settings - LOG_I(HW,"Actual master clock: %fMHz...\n",s->usrp->get_master_clock_rate()/1e6); - sleep(1); - // create tx & rx streamer - uhd::stream_args_t stream_args_rx("sc16", "sc16"); - int samples=openair0_cfg[0].sample_rate; - int max=s->usrp->get_rx_stream(stream_args_rx)->get_max_num_samps(); - samples/=10000; - LOG_I(HW,"RF board max packet size %u, size for 100µs jitter %d \n", max, samples); - - if ( samples < max ) { - stream_args_rx.args["spp"] = str(boost::format("%d") % samples ); - } - - LOG_I(HW,"rx_max_num_samps %zu\n", - s->usrp->get_rx_stream(stream_args_rx)->get_max_num_samps()); - - for (int i = 0; irx_stream = s->usrp->get_rx_stream(stream_args_rx); - uhd::stream_args_t stream_args_tx("sc16", "sc16"); - - for (int i = 0; itx_stream = s->usrp->get_tx_stream(stream_args_tx); - - /* Setting TX/RX BW after streamers are created due to USRP calibration issue */ - for(int i=0; i<((int) s->usrp->get_tx_num_channels()) && iusrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i); - - for(int i=0; i<((int) s->usrp->get_rx_num_channels()) && iusrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i); - - for (int i=0; iusrp->get_rx_rate(i)/1e6); - LOG_I(HW," Actual RX frequency: %fGHz...\n", s->usrp->get_rx_freq(i)/1e9); - LOG_I(HW," Actual RX gain: %f...\n", s->usrp->get_rx_gain(i)); - LOG_I(HW," Actual RX bandwidth: %fM...\n", s->usrp->get_rx_bandwidth(i)/1e6); - LOG_I(HW," Actual RX antenna: %s...\n", s->usrp->get_rx_antenna(i).c_str()); - } - - for (int i=0; iusrp->get_tx_rate(i)/1e6); - LOG_I(HW," Actual TX frequency: %fGHz...\n", s->usrp->get_tx_freq(i)/1e9); - LOG_I(HW," Actual TX gain: %f...\n", s->usrp->get_tx_gain(i)); - LOG_I(HW," Actual TX bandwidth: %fM...\n", s->usrp->get_tx_bandwidth(i)/1e6); - LOG_I(HW," Actual TX antenna: %s...\n", s->usrp->get_tx_antenna(i).c_str()); - LOG_I(HW," Actual TX packet size: %lu\n",s->tx_stream->get_max_num_samps()); - } - - LOG_I(HW,"Device timestamp: %f...\n", s->usrp->get_time_now().get_real_secs()); - device->trx_write_func = trx_usrp_write; - device->trx_read_func = trx_usrp_read; - device->uhd_set_thread_priority = uhd_set_thread_priority; - s->sample_rate = openair0_cfg[0].sample_rate; - - // TODO: - // init tx_forward_nsamps based usrp_time_offset ex - if(is_equal(s->sample_rate, (double)30.72e6)) - s->tx_forward_nsamps = 176; - - if(is_equal(s->sample_rate, (double)15.36e6)) - s->tx_forward_nsamps = 90; - - if(is_equal(s->sample_rate, (double)7.68e6)) - s->tx_forward_nsamps = 50; - } - - if (s->recplay_mode == RECPLAY_RECORDMODE) { // record mode - s->recplay_state->ms_sample = (iqrec_t *) malloc(s->recplay_state->u_sf_max * sizeof(iqrec_t)); - - if (s->recplay_state->ms_sample == NULL) { - std::cerr<< "Memory allocation failed for subframe record or replay mode." << std::endl; - exit(-1); - } - - memset(s->recplay_state->ms_sample, 0, s->recplay_state->u_sf_max * BELL_LABS_IQ_BYTES_PER_SF); - } else if (s->recplay_mode == RECPLAY_REPLAYMODE) { - if (s->recplay_state->use_mmap) { - // use mmap - s->recplay_state->mmapfd = open(s->recplay_state->u_sf_filename, O_RDONLY | O_LARGEFILE); - - if (s->recplay_state->mmapfd != 0) { - struct stat sb; - fstat(s->recplay_state->mmapfd, &sb); - s->recplay_state->mapsize=sb.st_size; - std::cerr << "Loading subframes using mmap() from " << s->recplay_state->u_sf_filename << " size=" << (uint64_t)sb.st_size << " bytes ..." << std::endl; - s->recplay_state->ms_sample = (iqrec_t *) mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, s->recplay_state->mmapfd, 0); - - if (s->recplay_state->ms_sample != MAP_FAILED) { - s->recplay_state->nb_samples = (sb.st_size / sizeof(iqrec_t)); - int aligned = (((unsigned long)s->recplay_state->ms_sample & 31) == 0)? 1:0; - std::cerr<< "Loaded "<< s->recplay_state->nb_samples << " subframes." << std::endl; - - if (aligned == 0) { - std::cerr<< "mmap address is not 32 bytes aligned, exiting." << std::endl; - close(s->recplay_state->mmapfd); - exit(-1); - } - } else { - std::cerr << "Cannot mmap file, exiting." << std::endl; - close(s->recplay_state->mmapfd); - exit(-1); - } - } else { - std::cerr << "Cannot open " << s->recplay_state->u_sf_filename << " , exiting." << std::endl; - exit(-1); - } - } else { - s->recplay_state->iqfd = open(s->recplay_state->u_sf_filename, O_RDONLY | O_LARGEFILE); - - if (s->recplay_state->iqfd != 0) { - struct stat sb; - fstat(s->recplay_state->iqfd, &sb); - s->recplay_state->mapsize=sb.st_size; - s->recplay_state->nb_samples = (sb.st_size / sizeof(iqrec_t)); - std::cerr << "Loading " << s->recplay_state->nb_samples << " subframes from " << s->recplay_state->u_sf_filename - << " size=" << (uint64_t)sb.st_size << " bytes ..." << std::endl; - // allocate buffer for 1 sample at a time - s->recplay_state->ms_sample = (iqrec_t *) malloc(sizeof(iqrec_t)); - - if (s->recplay_state->ms_sample == NULL) { - std::cerr<< "Memory allocation failed for individual subframe replay mode." << std::endl; - close(s->recplay_state->iqfd); - exit(-1); - } - - memset(s->recplay_state->ms_sample, 0, sizeof(iqrec_t)); - - // point at beginning of file - if (lseek(s->recplay_state->iqfd, 0, SEEK_SET) == 0) { - std::cerr << "Initial seek at beginning of the file" << std::endl; - } else { - std::cerr << "Problem initial seek at beginning of the file" << std::endl; - } - } else { - std::cerr << "Cannot open " << s->recplay_state->u_sf_filename << " , exiting." << std::endl; - exit(-1); - } - } - } - - return 0; } - - + + if (s->usrp->get_clock_source(0) == "gpsdo") { + s->use_gps = 1; + + if (sync_to_gps(device)==EXIT_SUCCESS) { + LOG_I(HW,"USRP synced with GPS!\n"); + } else { + LOG_I(HW,"USRP fails to sync with GPS. Exiting.\n"); + exit(EXIT_FAILURE); + } + } else if (s->usrp->get_clock_source(0) == "external") { + if (check_ref_locked(s,0)) { + LOG_I(HW,"USRP locked to external reference!\n"); + } else { + LOG_I(HW,"Failed to lock to external reference. Exiting.\n"); + exit(EXIT_FAILURE); + } + } + + if (device->type==USRP_X300_DEV) { + openair0_cfg[0].rx_gain_calib_table = calib_table_x310; + std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info + LOG_I(HW,"%s() sample_rate:%u\n", __FUNCTION__, (int)openair0_cfg[0].sample_rate); + + switch ((int)openair0_cfg[0].sample_rate) { + case 122880000: + // from usrp_time_offset + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 15; //to be checked + openair0_cfg[0].tx_bw = 80e6; + openair0_cfg[0].rx_bw = 80e6; + break; + + case 92160000: + // from usrp_time_offset + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 15; //to be checked + openair0_cfg[0].tx_bw = 80e6; + openair0_cfg[0].rx_bw = 80e6; + break; + + case 61440000: + // from usrp_time_offset + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 15; + openair0_cfg[0].tx_bw = 40e6; + openair0_cfg[0].rx_bw = 40e6; + break; + + case 46080000: + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 15; + openair0_cfg[0].tx_bw = 40e6; + openair0_cfg[0].rx_bw = 40e6; + break; + + case 30720000: + // from usrp_time_offset + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 15; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + break; + + case 15360000: + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 45; + openair0_cfg[0].tx_bw = 10e6; + openair0_cfg[0].rx_bw = 10e6; + break; + + case 7680000: + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 50; + openair0_cfg[0].tx_bw = 5e6; + openair0_cfg[0].rx_bw = 5e6; + break; + + case 1920000: + //openair0_cfg[0].samples_per_packet = 2048; + openair0_cfg[0].tx_sample_advance = 50; + openair0_cfg[0].tx_bw = 1.25e6; + openair0_cfg[0].rx_bw = 1.25e6; + break; + + default: + LOG_E(HW,"Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); + exit(-1); + break; + } + } + + if (device->type == USRP_B200_DEV) { + if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) { + openair0_cfg[0].rx_gain_calib_table = calib_table_b210; + bw_gain_adjust=0; + std::cerr << "-- Using calibration table: calib_table_b210" << std::endl; // Bell Labs info + } else { + openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; + bw_gain_adjust=1; + std::cerr << "-- Using calibration table: calib_table_b210_38" << std::endl; // Bell Labs info + } + + switch ((int)openair0_cfg[0].sample_rate) { + case 46080000: + s->usrp->set_master_clock_rate(46.08e6); + //openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 115; + openair0_cfg[0].tx_bw = 40e6; + openair0_cfg[0].rx_bw = 40e6; + break; + + case 30720000: + s->usrp->set_master_clock_rate(30.72e6); + //openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 115; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + break; + + case 23040000: + s->usrp->set_master_clock_rate(23.04e6); //to be checked + //openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 113; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + break; + + case 15360000: + s->usrp->set_master_clock_rate(30.72e06); + //openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 103; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + break; + + case 7680000: + s->usrp->set_master_clock_rate(30.72e6); + //openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 80; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + break; + + case 1920000: + s->usrp->set_master_clock_rate(30.72e6); + //openair0_cfg[0].samples_per_packet = 1024; + openair0_cfg[0].tx_sample_advance = 40; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + break; + + default: + LOG_E(HW,"Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); + exit(-1); + break; + } + } + + /* device specific */ + //openair0_cfg[0].txlaunch_wait = 1;//manage when TX processing is triggered + //openair0_cfg[0].txlaunch_wait_slotcount = 1; //manage when TX processing is triggered + openair0_cfg[0].iq_txshift = 4;//shift + openair0_cfg[0].iq_rxrescale = 15;//rescale iqs + + for(int i=0; i<((int) s->usrp->get_rx_num_channels()); i++) { + if (iusrp->set_rx_rate(openair0_cfg[0].sample_rate,i); + s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i); + set_rx_gain_offset(&openair0_cfg[0],i,bw_gain_adjust); + ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i); + // limit to maximum gain + AssertFatal( openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] <= gain_range.stop(), + "RX Gain too high, lower by %f dB\n", + openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop()); + s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i); + LOG_I(HW,"RX Gain %d %f (%f) => %f (max %f)\n",i, + openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i], + openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop()); + } + } + + LOG_D(HW, "usrp->get_tx_num_channels() == %zd\n", s->usrp->get_tx_num_channels()); + LOG_D(HW, "openair0_cfg[0].tx_num_channels == %d\n", openair0_cfg[0].tx_num_channels); + + for(int i=0; i<((int) s->usrp->get_tx_num_channels()); i++) { + ::uhd::gain_range_t gain_range_tx = s->usrp->get_tx_gain_range(i); + + if (iusrp->set_tx_rate(openair0_cfg[0].sample_rate,i); + s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i); + s->usrp->set_tx_gain(gain_range_tx.stop()-openair0_cfg[0].tx_gain[i],i); + LOG_I(HW,"USRP TX_GAIN:%3.2lf gain_range:%3.2lf tx_gain:%3.2lf\n", gain_range_tx.stop()-openair0_cfg[0].tx_gain[i], gain_range_tx.stop(), openair0_cfg[0].tx_gain[i]); + } + } + + //s->usrp->set_clock_source("external"); + //s->usrp->set_time_source("external"); + // display USRP settings + LOG_I(HW,"Actual master clock: %fMHz...\n",s->usrp->get_master_clock_rate()/1e6); + sleep(1); + // create tx & rx streamer + uhd::stream_args_t stream_args_rx("sc16", "sc16"); + int samples=openair0_cfg[0].sample_rate; + int max=s->usrp->get_rx_stream(stream_args_rx)->get_max_num_samps(); + samples/=10000; + LOG_I(HW,"RF board max packet size %u, size for 100µs jitter %d \n", max, samples); + + if ( samples < max ) { + stream_args_rx.args["spp"] = str(boost::format("%d") % samples ); + } + + LOG_I(HW,"rx_max_num_samps %zu\n", + s->usrp->get_rx_stream(stream_args_rx)->get_max_num_samps()); + + for (int i = 0; irx_stream = s->usrp->get_rx_stream(stream_args_rx); + uhd::stream_args_t stream_args_tx("sc16", "sc16"); + + for (int i = 0; itx_stream = s->usrp->get_tx_stream(stream_args_tx); + + /* Setting TX/RX BW after streamers are created due to USRP calibration issue */ + for(int i=0; i<((int) s->usrp->get_tx_num_channels()) && iusrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i); + + for(int i=0; i<((int) s->usrp->get_rx_num_channels()) && iusrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i); + + for (int i=0; iusrp->get_rx_rate(i)/1e6); + LOG_I(HW," Actual RX frequency: %fGHz...\n", s->usrp->get_rx_freq(i)/1e9); + LOG_I(HW," Actual RX gain: %f...\n", s->usrp->get_rx_gain(i)); + LOG_I(HW," Actual RX bandwidth: %fM...\n", s->usrp->get_rx_bandwidth(i)/1e6); + LOG_I(HW," Actual RX antenna: %s...\n", s->usrp->get_rx_antenna(i).c_str()); + } + + for (int i=0; iusrp->get_tx_rate(i)/1e6); + LOG_I(HW," Actual TX frequency: %fGHz...\n", s->usrp->get_tx_freq(i)/1e9); + LOG_I(HW," Actual TX gain: %f...\n", s->usrp->get_tx_gain(i)); + LOG_I(HW," Actual TX bandwidth: %fM...\n", s->usrp->get_tx_bandwidth(i)/1e6); + LOG_I(HW," Actual TX antenna: %s...\n", s->usrp->get_tx_antenna(i).c_str()); + LOG_I(HW," Actual TX packet size: %lu\n",s->tx_stream->get_max_num_samps()); + } + + LOG_I(HW,"Device timestamp: %f...\n", s->usrp->get_time_now().get_real_secs()); + device->trx_write_func = trx_usrp_write; + device->trx_read_func = trx_usrp_read; + s->sample_rate = openair0_cfg[0].sample_rate; + + // TODO: + // init tx_forward_nsamps based usrp_time_offset ex + if(is_equal(s->sample_rate, (double)30.72e6)) + s->tx_forward_nsamps = 176; + + if(is_equal(s->sample_rate, (double)15.36e6)) + s->tx_forward_nsamps = 90; + + if(is_equal(s->sample_rate, (double)7.68e6)) + s->tx_forward_nsamps = 50; + + + if (device->recplay_state != NULL) { // record mode + device->recplay_state->ms_sample = (iqrec_t *) malloc(openair0_cfg[0].recplay_conf->u_sf_max * sizeof(iqrec_t)); + + if (device->recplay_state->ms_sample == NULL) { + std::cerr<< "Memory allocation failed for subframe record or replay mode." << std::endl; + exit(-1); + } + + memset(device->recplay_state->ms_sample, 0, openair0_cfg[0].recplay_conf->u_sf_max * BELL_LABS_IQ_BYTES_PER_SF); + } + return 0; } /*@}*/ +}/* extern c */ diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib_config.c b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib_config.c deleted file mode 100644 index ebf1d61eed..0000000000 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib_config.c +++ /dev/null @@ -1,73 +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 - */ - -/** usrp_lib_config.c - * - * \author: HongliangXU : hong-liang-xu@agilent.com - */ - -#include -#include -#include -#include -#include -#include "common/utils/LOG/log.h" -#include "assertions.h" -#include "common_lib.h" -#include "usrp_lib.h" - - -int read_usrpconfig(uint32_t *recplay_mode, recplay_state_t **recplay_state) { -unsigned int u_sf_record = 0; // record mode -unsigned int u_sf_replay = 0; // replay mode -uint32_t enable_recplay; - - paramdef_t usrp_params[] = USRP_DEVICE_PARAMS_DESC; - config_get(usrp_params,sizeof(usrp_params)/sizeof(paramdef_t),USRP_SECTION); - if (enable_recplay) { - *recplay_state = calloc(sizeof(recplay_state_t),1); - paramdef_t usrp_recplay_params[]=USRP_RECPLAY_PARAMS_DESC ; - struct sysinfo systeminfo; - - // Use mmap for IQ files for systems with less than 6GB total RAM - sysinfo(&systeminfo); - - if (systeminfo.totalram < 6144000000) { - (*recplay_state)->use_mmap = 0; - } else { - (*recplay_state)->use_mmap = 1; - } - - memset((*recplay_state)->u_sf_filename, 0, 1024); - config_get(usrp_recplay_params,sizeof(usrp_recplay_params)/sizeof(paramdef_t),USRP_RECPLAY_SECTION); - - if (strlen((*recplay_state)->u_sf_filename) == 0) { - (void) strcpy(( - *recplay_state)->u_sf_filename, DEF_SF_FILE); - } - } /* record player enabled */ - if (u_sf_replay == 1) *recplay_mode = RECPLAY_REPLAYMODE; - - if (u_sf_record == 1) *recplay_mode = RECPLAY_RECORDMODE; - - - return 0; - } \ No newline at end of file diff --git a/targets/ARCH/iqplayer/DOC/iqrecordplayer_usage.md b/targets/ARCH/iqplayer/DOC/iqrecordplayer_usage.md new file mode 100644 index 0000000000..a6e4138e8e --- /dev/null +++ b/targets/ARCH/iqplayer/DOC/iqrecordplayer_usage.md @@ -0,0 +1,163 @@ +# I/Q record-playback +## using the iq recorder or iq player + +This feature provides I/Q record-playback as presented in the 4th OAI workshop. Tests have only been performed with a eNB, but the implementation should allow any softmodem executable to use the iq's record/player. +The I/Q record/playback feature is briefly described hereafter, it allows you to: +* record subframes received by the USRP board in a file while the system is operating (for example you can record a full UE connection/traffic/ disconnection sequence). Today the oai USRP device is the only one supporting the recording feature. +* replay subframes from a file to operate the system (possibly in multiple loops if the recorded sequence is convenient from the logical point of view). + +The record/replay are activated and configured using oai configuration parameters + +### Record mode +options for record mode are: +* `subframes-record` Activate record mode +* `subframes-file` Path of the file used for subframes recording (default is `/tmp/iqfile`) +* `subframes-max` Maximum count of subframes to be recorded in subframe file (default is 120000) + +Note that the value of `--subframes-max` parameter needs to be tuned according to your RAM capabilities. The default value is 120000, which allows for 120 seconds of record/replay but will require ~3.6GB of RAM and disk space. +If RAM does not allow for the parameter value, an error message will be displayed and the run will be aborted. In record mode, to minimize pzerformance impact, +subframes are saved into memory and written to disk when the process is terminating . When you estimate the recorded sequence is achieved, you should terminate the eNB/RRU by typing `CTRL-C`. At that time, up to the value of `--subframes-max` subframes will be written on disk. The eNB/RRU will indicate the exact count of subframes written to disk, which may be less (but not higher) that the value of `--subframes-max` parameter (120000 by default). The number of subframes written to disk is rounded to an integral number of frames. +Although it is possible to perform recording with a fronthaul setup, it is suggested to perform recording in full eNB mode and then replay in either monolithic or split eNB. +The option can be used while operating full eNB or RCC/RRU linked by NGFI IF5/IF4p5 fronthaul techniques. One of the advantage of the record/replay technique is that you can replay on a fronthauling setup a file that has been recorded in full eNB mode. This can easily asserts that the fronthauling underlying set up or technique is correct. + +>recording session example: +```bash + ./lte-softmodem -O libconfig:/usr/local/oai/conf/enb.band7.tm1.20PRB.usrpb210.conf:dbgl5 --log_config.global_log_options level,thread --device.recplay.subframes-record 1 +............................................ +............................................ +[CONFIG] device.recplay.subframes-file set to default value "/tmp/iqfile" +[CONFIG] subframes-record: 0 +[CONFIG] device.recplay.subframes-record set to default value +[CONFIG] subframes-replay: 0 +[CONFIG] device.recplay.subframes-replay set to default value +[CONFIG] subframes-max: 120000 +[CONFIG] device.recplay.subframes-max set to default value +[CONFIG] subframes-loops: 5 +[CONFIG] device.recplay.subframes-loops set to default value +[CONFIG] subframes-read-delay: 700 +[CONFIG] device.recplay.subframes-read-delay set to default value +[CONFIG] subframes-write-delay: 15 +[CONFIG] device.recplay.subframes-write-delay set to default value +[LIBCONFIG] device.recplay: 7/7 parameters successfully set, (7 to default value) +[CONFIG] subframes-record: 1 +[CONFIG] device.recplay 1 options set from command line +[CONFIG] loader.oai_device.shlibversion set to default value "" +[LIBCONFIG] loader.oai_device: 2/2 parameters successfully set, (1 to default value) +[CONFIG] loader.oai_device 0 options set from command line +[LOADER] library liboai_device.so successfully loaded +USRP device initialized in subframes record mode +[HW]I lte-softmodem UHD version 3.14.1.1-release (3.14.1) +................................................... +................................................... +[PHY]I lte-softmodem prach_I0 = 0.0 dB +[PHY]I ru thread max_I0 18, min_I0 12 +^C +Run time: 0h 26s + Time executing user inst.: 1s 865251us + Time executing system inst.: 2s 805162us + Max. Phy. memory usage: 4068328kB + Page fault number (no io): 1008741 + Page fault number (requiring io): 15 + Number of file system read: 97672 + Number of filesystem write: 0 + Number of context switch (process origin, io...): 562871 + Number of context switch (os origin, priority...): 112 +Linux signal Interrupt... +/usr/local/oai/develop/openairinterface5g/executables/softmodem-common.c:188 signal_handler() Exiting OAI softmodem: softmodem starting exit procedure +Exiting ru_thread +U[HW]I ru thread Writing file header to /tmp/iqfile +[HW]I lte-softmodem Writing file header to /tmp/iqfile +[HW]I ru thread Writing 19730 subframes to /tmp/iqfile +[HW]I lte-softmodem Writing 19730 subframes to /tmp/iqfile +[HW]I lte-softmodem File /tmp/iqfile closed +[HW]I ru thread File /tmp/iqfile closed +[PHY]I ru thread RU 0 rf device stopped +``` + +### Playback/replay mode +The option works only for 5MHz bandwidth because the information stored in the iq's file header regarding bandwidth is not yet properly processed. + In this version, mismatch between file content and run time parameters might lead to unpredictable results. In addition a file recorded on a AVX2-capable processor cannot be replayed on a non-AVX2-capable processor (this is to be further investigated). +options for replay mode are: +* `subframes-replay` Activate replay mode +* `subframes-file` Path of the file used for subframes replay (default is `/tmp/iqfile`) +* `subframes-loops` Number of iterations to replay the entire subframes file (default is 5) +* `subframes-read-delay` Delay in microseconds to read a subframe in replay mode (default 200) +* `subframes-write-delay` Delay in milliseconds to write a subframe in replay mode (default 15) + +>iq player session example: +```bash +./lte-softmodem -O libconfig:/usr/local/oai/conf/enb.nbiot.band7.tm1.50PRB.usrpb210.conf:dbgl5 --T_stdout 1 --log_config.global_log_options level,thread --eNBs.[0].component_carriers.[0].N_RB_DL 25 --device.recplay.subframes-replay 1 +[CONFIG] get parameters from libconfig /usr/local/oai/conf/enb.nbiot.band7.tm1.50PRB.usrpb210.conf , debug flags: 0x00000005 +................................ +.................................. +[PHY]I lte-softmodem rxdataF[0] 0x55f52df52f40 for RU 0 +[CONFIG] device.recplay.subframes-file set to default value "/tmp/iqfile" +[CONFIG] subframes-record: 0 +[CONFIG] device.recplay.subframes-record set to default value +[CONFIG] subframes-replay: 0 +[CONFIG] device.recplay.subframes-replay set to default value +[CONFIG] subframes-max: 120000 +[CONFIG] device.recplay.subframes-max set to default value +[CONFIG] subframes-loops: 5 +[CONFIG] device.recplay.subframes-loops set to default value +[CONFIG] subframes-read-delay: 700 +[CONFIG] device.recplay.subframes-read-delay set to default value +[CONFIG] subframes-write-delay: 15 +[CONFIG] device.recplay.subframes-write-delay set to default value +[LIBCONFIG] device.recplay: 7/7 parameters successfully set, (7 to default value) +[CONFIG] subframes-replay: 1 +[CONFIG] device.recplay 1 options set from command line +[CONFIG] loader.oai_iqplayer.shlibversion set to default value "" +[LIBCONFIG] loader.oai_iqplayer: 2/2 parameters successfully set, (1 to default value) +[CONFIG] loader.oai_iqplayer 0 options set from command line +[LOADER] library liboai_iqplayer.so successfully loaded +[HW]I lte-softmodem Loading subframes using mmap() from /tmp/iqfile size=324433632 bytes ... +[HW]I lte-softmodem Replay iqs from USRP B200 device, bandwidth 5.000000e+06 +[HW]I lte-softmodem Loaded 10550 subframes. +[HW]I lte-softmodem iqplayer device initialized, replay /tmp/iqfile for 5 iterations[HW]I lte-softmodem [RAU] has loaded USRP B200 device. +............................................. +............................................. +[PHY]I ru thread max_I0 18, min_I0 12 +[PHY]I lte-softmodem prach_I0 = 0.0 dB +[PHY]I ru thread max_I0 18, min_I0 0 +[HW]I ru thread starting subframes file with wrap_count=1 wrap_ts=81024000 ts=107616555 +[PHY]I lte-softmodem prach_I0 = 0.0 dB +[PHY]I ru thread max_I0 18, min_I0 12 +[HW]I ru thread starting subframes file with wrap_count=2 wrap_ts=162048000 ts=188640555 +[PHY]I lte-softmodem prach_I0 = 0.0 dB +[PHY]I ru thread max_I0 18, min_I0 0 +[HW]I ru thread starting subframes file with wrap_count=3 wrap_ts=243072000 ts=269664555 +[PHY]I lte-softmodem prach_I0 = 0.0 dB +[PHY]I ru thread max_I0 19, min_I0 12 +[HW]I ru thread starting subframes file with wrap_count=4 wrap_ts=324096000 ts=350688555 +[PHY]I lte-softmodem prach_I0 = 0.0 dB +[PHY]I ru thread max_I0 18, min_I0 12 +[HW]W ru thread iqplayer device terminating subframes replay after 5 iteration +/usr/local/oai/develop/openairinterface5g/targets/ARCH/iqplayer/iqplayer_lib.c:222 trx_iqplayer_read() Exiting OAI softmodem: replay ended, triggering process termination +``` + +## iq recorder and iq player implementation overview + +### configuration +The iq's record/player is using the [configuration module](../../../../common/config/DOC/config.md). Configuration parameters supported by the record player are defined in the [record_player.h](../../COMMON/record_player.h) include file. + There are no specific sections for the recorder or the replayer, parameters are defined under the `device.recplay`section and the `read_recplayconfig` function is common to both the recorder and the player. `device.recplay` configuration section is read from oai code common to all devices: +Implemented in [record_player.c](../../COMMON/record_player.c), the `read_recplayconfig` function is called from `load_lib` and reads the configuration parameters, saving them in a `recplay_conf_t` sub-structure of the oai device. It also allocates a `recplay_state_t` structure which will save the recorder or player data. +3GPP authentication algorithm doesn't allow session establishment via replaying iq's. When using the replayer, a softmodem parameter is set (`SOFTMODEM_RECPLAY_BIT` in the `optmask` bitmask of the `softmodem_params_t` structure. It allows bypassing or activating specific code in the softmodem to allow session establishment replay. This mechanism only works if in parallel specific code is also activated in the EPC, which is supported by the NOKIA LTE box. +An easiest scenario is to use the record player in parallel with the noS1 mode, as described [here](../../../../doc/RUNMODEM.md) + +### iq recorder +most of the implementation is now located in the oai device common code: +* The`load_lib` function in [common-lib.c](../../COMMON/common_lib.c) reads the record player parameters. +* Recorder specific functions are implemented in `iqrecorder_end` saves the cached iq's to disk, it has to be called by the oai device in it's end function. +* When recording is enabled, the device must implement iq's caching in it's read function. It also has to call the `iqrecorder_end ` function when terminating to write iqs to a file on disk. Look at the USRP device ( [../usrp_lib.cpp](../../USRP/USERSPACE/LIB/usrp_lib.cpp) ) for details. + +### iq player +The replay feature is implemented as a oai device. +* The`load_lib` function in [common-lib.c](../../COMMON/common_lib.c) reads the record player parameters, this code is common with the recorder. +* The player device is implemented in [iqplayer_lib.c](../iqplayer_lib.c) which at build time creates the `liboai_iqplayer.so` shared library. Thi +* s device is automatically, dynamicaly loaded when the player feature is activated at runtime when the boolean `device.recplay.subframes-replay` option is set. + +### iq's file format +The recorder adds a header containing the device type, the bandwith and a format identifier. Using these information when replaying a file has not yet been implemented, so the player only supports USRP B2xx device and 5MHz bandwith. + +[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/targets/ARCH/iqplayer/iqplayer_lib.c b/targets/ARCH/iqplayer/iqplayer_lib.c new file mode 100644 index 0000000000..c4133d1b11 --- /dev/null +++ b/targets/ARCH/iqplayer/iqplayer_lib.c @@ -0,0 +1,317 @@ +/* + * 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 + */ + +/** iqplayer_lib.cpp + * + * \author:FrancoisTaburet: francois.taburet@nokia-bell-labs.com + */ +#define _LARGEFILE_SOURCE +#define _FILE_OFFSET_BITS 64 +#define NB_ANTENNAS_RX 2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common_lib.h" +#include "assertions.h" +#include "common/utils/LOG/log.h" + + + + + + +static void parse_iqfile_header(openair0_device *device, iqfile_header_t *iq_fh) { + AssertFatal((memcmp(iq_fh->oaiid,OAIIQFILE_ID,sizeof(OAIIQFILE_ID)) == 0), + "iqfile doesn't seem to be compatible with oai (invalid id %.4s in header)\n", + iq_fh->oaiid); + device->type = iq_fh->devtype; + device->openair0_cfg[0].tx_sample_advance=iq_fh->tx_sample_advance; + device->openair0_cfg[0].tx_bw = device->openair0_cfg[0].rx_bw = iq_fh->bw; + LOG_UI(HW,"Replay iqs from %s device, bandwidth %e\n",get_devname(iq_fh->devtype),iq_fh->bw); +} + + +/*! \brief Called to start the iqplayer device. Return 0 if OK, < 0 if error + @param device pointer to the device structure specific to the RF hardware target +*/ +static int iqplayer_loadfile(openair0_device *device, openair0_config_t *openair0_cfg) { + recplay_state_t *s = device->recplay_state; + recplay_conf_t *c = openair0_cfg->recplay_conf; + + if (s->use_mmap) { + // use mmap + s->mmapfd = open(c->u_sf_filename, O_RDONLY ); + + if (s->mmapfd != 0) { + struct stat sb; + fstat(s->mmapfd, &sb); + s->mapsize=sb.st_size; + LOG_I(HW,"Loading subframes using mmap() from %s size=%lu bytes ...\n",c->u_sf_filename, (uint64_t)sb.st_size ); + void *mptr = mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, s->mmapfd, 0) ; + s->ms_sample = (iqrec_t *) ( mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, s->mmapfd, 0) + sizeof(iqfile_header_t)); + + if (mptr != MAP_FAILED) { + parse_iqfile_header(device, (iqfile_header_t *)mptr); + s->ms_sample = (iqrec_t *)((char *)mptr + sizeof(iqfile_header_t)); + s->nb_samples = ((sb.st_size-sizeof(iqfile_header_t)) / sizeof(iqrec_t)); + int aligned = (((unsigned long)s->ms_sample & 31) == 0)? 1:0; + LOG_I(HW,"Loaded %u subframes.\n",s->nb_samples ); + + if (aligned == 0) { + LOG_E(HW, "mmap address is not 32 bytes aligned, exiting.\n" ); + close(s->mmapfd); + exit(-1); + } + } else { + LOG_E(HW,"Cannot mmap file, exiting.\n"); + close(s->mmapfd); + exit(-1); + } + } else { + LOG_E( HW,"Cannot open %s exiting.\n", c->u_sf_filename ); + exit(-1); + } + } else { + s->iqfd = open(c->u_sf_filename, O_RDONLY); + + if (s->iqfd != 0) { + struct stat sb; + iqfile_header_t fh; + size_t hs = read(s->iqfd,&fh,sizeof(fh)); + + if (hs == sizeof(fh)) { + parse_iqfile_header(device, &fh); + fstat(s->iqfd, &sb); + s->mapsize=sb.st_size; + s->nb_samples = ((sb.st_size-sizeof(iqfile_header_t))/ sizeof(iqrec_t)); + LOG_I(HW, "Loading %u subframes from %s,size=%lu bytes ...\n",s->nb_samples, c->u_sf_filename,(uint64_t)sb.st_size); + // allocate buffer for 1 sample at a time + s->ms_sample = (iqrec_t *) malloc(sizeof(iqrec_t)); + + if (s->ms_sample == NULL) { + LOG_E(HW,"Memory allocation failed for individual subframe replay mode.\n" ); + close(s->iqfd); + exit(-1); + } + + memset(s->ms_sample, 0, sizeof(iqrec_t)); + + // point at beginning of iqs in file + if (lseek(s->iqfd,sizeof(iqfile_header_t), SEEK_SET) == 0) { + LOG_I(HW,"Initial seek at beginning of the file\n" ); + } else { + LOG_I(HW,"Problem initial seek at beginning of the file\n"); + } + } else { + LOG_E(HW,"Cannot read header in %s exiting.\n",c->u_sf_filename ); + close(s->iqfd); + exit(-1); + } + } else { + LOG_E(HW,"Cannot open %s exiting.\n",c->u_sf_filename ); + exit(-1); + } + } + + return 0; +} + +/*! \brief start the oai iq player + * \param device, the hardware used + */ +static int trx_iqplayer_start(openair0_device *device){ + return 0; +} + +/*! \brief Terminate operation of the oai iq player + * \param device, the hardware used + */ +static void trx_iqplayer_end(openair0_device *device) { + if (device == NULL) + return; + + if (device->recplay_state == NULL) + return; + + if (device->recplay_state->use_mmap) { + if (device->recplay_state->ms_sample != MAP_FAILED) { + munmap(device->recplay_state->ms_sample, device->recplay_state->mapsize); + device->recplay_state->ms_sample = NULL; + } + + if (device->recplay_state->mmapfd != 0) { + close(device->recplay_state->mmapfd); + device->recplay_state->mmapfd = 0; + } + } else { + if (device->recplay_state->ms_sample != NULL) { + free(device->recplay_state->ms_sample); + device->recplay_state->ms_sample = NULL; + } + + if (device->recplay_state->iqfd != 0) { + close(device->recplay_state->iqfd); + device->recplay_state->iqfd = 0; + } + } +} +/*! \brief Write iqs function when in replay mode, just introduce a delay, as configured at init time, + @param device pointer to the device structure specific to the RF hardware target + @param timestamp The timestamp at which the first sample MUST be sent + @param buff Buffer which holds the samples + @param nsamps number of samples to be sent + @param antenna_id index of the antenna if the device has multiple antennas + @param flags flags must be set to TRUE if timestamp parameter needs to be applied +*/ +static int trx_iqplayer_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { + struct timespec req; + req.tv_sec = 0; + req.tv_nsec = device->openair0_cfg->recplay_conf->u_sf_write_delay * 1000; + nanosleep(&req, NULL); + return nsamps; +} + +/*! \brief Receive samples from iq file. + * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for + * the first channel. *ptimestamp is the time at which the first sample + * was received. + * \param device the hardware to use + * \param[out] ptimestamp the time at which the first sample was received. + * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps. + * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte. + * \param antenna_id Index of antenna for which to receive samples + * \returns the number of sample read +*/ +static int trx_iqplayer_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) { + int samples_received=0; + static unsigned int cur_samples; + static int64_t wrap_count; + static int64_t wrap_ts; + recplay_state_t *s = device->recplay_state; + + if (cur_samples == s->nb_samples) { + cur_samples = 0; + wrap_count++; + + if (wrap_count == device->openair0_cfg->recplay_conf->u_sf_loops) { + LOG_W(HW, "iqplayer device terminating subframes replay after %u iteration\n",device->openair0_cfg->recplay_conf->u_sf_loops); + exit_function(__FILE__, __FUNCTION__, __LINE__,"replay ended, triggering process termination\n"); + } + + wrap_ts = wrap_count * (s->nb_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)); + + if (!device->recplay_state->use_mmap) { + if (lseek(device->recplay_state->iqfd, 0, SEEK_SET) == 0) { + LOG_I(HW,"Seeking at the beginning of IQ file"); + } else { + LOG_I(HW, "Problem seeking at the beginning of IQ file"); + } + } + } + + if (s->use_mmap) { + if (cur_samples < s->nb_samples) { + *ptimestamp = (s->ms_sample[0].ts + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000))) + wrap_ts; + + if (cur_samples == 0) { + LOG_I(HW,"starting subframes file with wrap_count=%lu wrap_ts=%lu ts=%lu\n", wrap_count,wrap_ts,*ptimestamp); + } + + memcpy(buff[0], &s->ms_sample[cur_samples].samples[0], nsamps*4); + cur_samples++; + } + } else { + // read sample from file + if (read(s->iqfd, s->ms_sample, sizeof(iqrec_t)) != sizeof(iqrec_t)) { + LOG_E(HW,"pb reading iqfile at index %lu\n",sizeof(iqrec_t)*cur_samples ); + close(s->iqfd); + free(s->ms_sample); + s->ms_sample = NULL; + s->iqfd = 0; + exit(-1); + } + + if (cur_samples < s->nb_samples) { + static int64_t ts0 = 0; + + if ((cur_samples == 0) && (wrap_count == 0)) { + ts0 = s->ms_sample->ts; + } + + *ptimestamp = ts0 + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)) + wrap_ts; + + if (cur_samples == 0) { + LOG_I(HW, "starting subframes file with wrap_count=%lu wrap_ts=%lu ts=%lu ",wrap_count,wrap_ts, *ptimestamp); + } + + memcpy(buff[0], &s->ms_sample->samples[0], nsamps*4); + cur_samples++; + // Prepare for next read + off_t where = lseek(s->iqfd, cur_samples * sizeof(iqrec_t), SEEK_SET); + + if (where < 0) { + LOG_E(HW,"Cannot lseek in iqfile: %s\n",strerror(errno)); + exit(-1); + } + } + } + + struct timespec req; + + req.tv_sec = 0; + + req.tv_nsec = (device->openair0_cfg[0].recplay_conf->u_sf_read_delay) * 1000; + + nanosleep(&req, NULL); + + return nsamps; + + return samples_received; +} + + +int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { + device->openair0_cfg = openair0_cfg; + device->trx_start_func = trx_iqplayer_start; + device->trx_get_stats_func = NULL; + device->trx_reset_stats_func = NULL; + device->trx_end_func = trx_iqplayer_end; + device->trx_stop_func = NULL; + device->trx_set_freq_func = NULL; + device->trx_set_gains_func = NULL; + // Replay subframes from from file + // openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; + // bw_gain_adjust=1; + device->trx_write_func = trx_iqplayer_write; + device->trx_read_func = trx_iqplayer_read; + iqplayer_loadfile(device, openair0_cfg); + LOG_UI(HW,"iqplayer device initialized, replay %s for %i iterations",openair0_cfg->recplay_conf->u_sf_filename,openair0_cfg->recplay_conf->u_sf_loops); + return 0; +} + +/*@}*/ diff --git a/targets/ARCH/rfsimulator/README.md b/targets/ARCH/rfsimulator/README.md index e3ce219d73..a4b030af85 100644 --- a/targets/ARCH/rfsimulator/README.md +++ b/targets/ARCH/rfsimulator/README.md @@ -3,6 +3,12 @@ This is an RF simulator that allows to test OAI without an RF board. It replaces As much as possible, it works like an RF board, but not in real-time: It can run faster than real-time if there is enough CPU, or slower (it is CPU-bound instead of real-time RF sampling-bound). +It can be run either in: + +- "noS1" mode: the generated IP traffic is sent and received between gNB and UE IP tunnel interfaces ("oaitun") by applications like ping and iperf +- "phy-test" mode: random UL and DL traffic is generated at every scheduling opportunity + + # build ## From [build_oai](../../../doc/BUILD.md) script @@ -84,19 +90,40 @@ make rfsimulator ### Launch gNB in one window ```bash -sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD +sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test ``` ### Launch UE in another window ```bash -sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C 3510000000 +sudo RFSIMULATOR= ./nr-uesoftmodem --rfsim --phy-test --rrc_config_path ../../../ci-scripts/rrc-files ``` +Note: +1. can be 127.0.0.1 if both gNB and nrUE executables run on the same host, OR the IP interface address of the remote host running the gNB executable, if the gNB and nrUE run on separate hosts +2. the --rrc_config_path parameter can be omitted (but not necessarily) if the gNB and nrUE run on the same host, in which case the gNB provides the nrUE with the necessary rrc configuration +3. to enable the noS1 mode --noS1 and --nokrnmod 1 options should be added to the command line -Of course, set the gNB machine IP address if the UE and the gNB are not on the same machine. In the UE, you can add `-d` option to get the softscope. +### Testing IP traffic (ping and iperf) + +``` +ping -I oaitun_enb1 10.0.1.2 (from gNB mchine) +ping -I oaitun_ue1 10.0.1.1 (from nrUE mchine) +``` + +```iperf (Downlink): +Server nrUE machine: iperf -s -i 1 -u -B 10.0.1.2 +Client gNB machine: iperf -c 10.0.1.2 -u -b 0.1M --bind 10.0.1.1 +``` + +```iperf (Uplink): +Server gNB machine: iperf -s -i 1 -u -B 10.0.1.1 +Client nrUE machine: iperf -c 10.0.1.1 -u -b 0.1M --bind 10.0.1.2 +Note: iperf tests cannot be performed only when running gNB and nrUE on separate hosts. +``` + ### Store and replay You can store emitted I/Q samples. If you set the option `saviq`, the simulator will write all the I/Q samples into this file. Then, you can replay with the executable `replay_node`. diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 906314a67c..54dfd3b888 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -478,9 +478,9 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi } if ( b->headerMode==false ) { - LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS); if ( ! b->trashingPacket ) { b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); + LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS); } if ( b->remainToTransfer==0) { diff --git a/targets/ARCH/tcp_bridge/tcp_bridge.c b/targets/ARCH/tcp_bridge/tcp_bridge.c index 3e2979f849..8b287acfa1 100644 --- a/targets/ARCH/tcp_bridge/tcp_bridge.c +++ b/targets/ARCH/tcp_bridge/tcp_bridge.c @@ -267,7 +267,6 @@ int device_init(openair0_device* device, openair0_config_t *openair0_cfg) device->trx_set_gains_func = tcp_bridge_set_gains; device->trx_write_func = tcp_bridge_write; device->trx_read_func = tcp_bridge_read; - device->uhd_set_thread_priority = NULL; device->priv = tcp_bridge; diff --git a/targets/ARCH/tcp_bridge/tcp_bridge_oai.c b/targets/ARCH/tcp_bridge/tcp_bridge_oai.c index 7c06d14360..c3d5355876 100644 --- a/targets/ARCH/tcp_bridge/tcp_bridge_oai.c +++ b/targets/ARCH/tcp_bridge/tcp_bridge_oai.c @@ -413,7 +413,6 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { device->trx_set_freq_func = tcp_bridge_set_freq; device->trx_set_gains_func = tcp_bridge_set_gains; device->trx_write_func = tcp_bridge_write; - device->uhd_set_thread_priority = NULL; if (tcp_bridge->is_enb) { device->trx_read_func = tcp_bridge_read; diff --git a/targets/COMMON/create_nr_tasks.c b/targets/COMMON/create_nr_tasks.c index 12532e0fd4..24c4115980 100644 --- a/targets/COMMON/create_nr_tasks.c +++ b/targets/COMMON/create_nr_tasks.c @@ -19,24 +19,22 @@ * contact@openairinterface.org */ -#if defined(ENABLE_ITTI) + # include "intertask_interface.h" # include "create_nr_tasks.h" # include "common/utils/LOG/log.h" # ifdef OPENAIR2 -# if defined(ENABLE_USE_MME) -# include "sctp_eNB_task.h" -# include "s1ap_eNB.h" -# include "nas_ue_task.h" -# include "udp_eNB_task.h" -# include "gtpv1u_eNB_task.h" -# endif +#include "sctp_eNB_task.h" +#include "s1ap_eNB.h" +#include "nas_ue_task.h" +#include "udp_eNB_task.h" +#include "gtpv1u_eNB_task.h" # if ENABLE_RAL # include "lteRALue.h" # include "lteRALenb.h" # endif -# include "RRC/NR/nr_rrc_defs.h" +#include "RRC/NR/nr_rrc_defs.h" # endif # include "gnb_app.h" @@ -61,7 +59,7 @@ int create_gNB_tasks(uint32_t gnb_nb) } /* -# if defined(ENABLE_USE_MME) + if (EPC_MODE_ENABLED) { if (gnb_nb > 0) { if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) { LOG_E(SCTP, "Create task for SCTP failed\n"); @@ -85,7 +83,7 @@ int create_gNB_tasks(uint32_t gnb_nb) } } -# endif + } */ if (gnb_nb > 0) { diff --git a/targets/COMMON/create_nr_tasks.h b/targets/COMMON/create_nr_tasks.h index 7f5961f5ae..ca259a2b34 100644 --- a/targets/COMMON/create_nr_tasks.h +++ b/targets/COMMON/create_nr_tasks.h @@ -22,12 +22,10 @@ #ifndef CREATE_NR_TASKS_H_ #define CREATE_NR_TASKS_H_ -#if defined(ENABLE_ITTI) /* External declaration of L2L1 task that depend on the target */ extern void *l2l1_task(void *arg); int create_gNB_tasks(uint32_t gnb_nb); -#endif #endif /* CREATE_TASKS_H_ */ diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index cfc2bc2215..cbbd30b62c 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -26,11 +26,11 @@ # include "common/ran_context.h" #ifdef OPENAIR2 - #include "sctp_eNB_task.h" - #include "x2ap_eNB.h" - #include "s1ap_eNB.h" - #include "udp_eNB_task.h" - #include "gtpv1u_eNB_task.h" + #include "sctp_eNB_task.h" + #include "x2ap_eNB.h" + #include "s1ap_eNB.h" + #include "udp_eNB_task.h" + #include "gtpv1u_eNB_task.h" #if ENABLE_RAL #include "lteRALue.h" #include "lteRALenb.h" @@ -40,6 +40,7 @@ # include "f1ap_cu_task.h" # include "f1ap_du_task.h" # include "enb_app.h" +# include "openair2/LAYER2/MAC/mac_proto.h" extern RAN_CONTEXT_t RC; @@ -63,7 +64,6 @@ int create_tasks(uint32_t enb_nb) { AssertFatal(rc >= 0, "Create task for SCTP failed\n"); } - if (EPC_MODE_ENABLED && !NODE_IS_DU(type)) { rc = itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL); AssertFatal(rc >= 0, "Create task for S1AP failed\n"); @@ -91,5 +91,11 @@ int create_tasks(uint32_t enb_nb) { AssertFatal(rc >= 0, "Create task for DU F1AP failed\n"); } + if (!NODE_IS_CU(type)) { + LOG_I(MAC,"Creating MAC eNB Task\n"); + rc = itti_create_task(TASK_MAC_ENB, mac_enb_task, NULL); + AssertFatal(rc >= 0, "Create task for MAC eNB failed\n"); + } + return 0; } diff --git a/targets/COMMON/create_tasks.h b/targets/COMMON/create_tasks.h index ff1d9ace51..843897cefb 100644 --- a/targets/COMMON/create_tasks.h +++ b/targets/COMMON/create_tasks.h @@ -22,12 +22,11 @@ #ifndef CREATE_TASKS_H_ #define CREATE_TASKS_H_ -#if defined(ENABLE_ITTI) /* External declaration of L2L1 task that depend on the target */ extern void *l2l1_task(void *arg); int create_tasks(uint32_t enb_nb); int create_tasks_ue(uint32_t ue_nb); -#endif +int create_tasks_mbms(uint32_t enb_nb); #endif /* CREATE_TASKS_H_ */ diff --git a/targets/COMMON/create_tasks_mbms.c b/targets/COMMON/create_tasks_mbms.c new file mode 100644 index 0000000000..5f81592b96 --- /dev/null +++ b/targets/COMMON/create_tasks_mbms.c @@ -0,0 +1,148 @@ +/* + * 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 "intertask_interface.h" +# include "create_tasks.h" +# include "common/utils/LOG/log.h" +# include "targets/RT/USER/lte-softmodem.h" +# include "common/ran_context.h" + +#ifdef OPENAIR2 + #include "sctp_eNB_task.h" + #include "x2ap_eNB.h" + #include "s1ap_eNB.h" + #include "udp_eNB_task.h" + #include "gtpv1u_eNB_task.h" + #include "m2ap_eNB.h" + #include "m2ap_MCE.h" + #include "m3ap_MME.h" + #include "m3ap_MCE.h" + #if ENABLE_RAL + #include "lteRALue.h" + #include "lteRALenb.h" + #endif + #include "RRC/LTE/rrc_defs.h" +#endif +# include "f1ap_cu_task.h" +# include "f1ap_du_task.h" +# include "enb_app.h" +# include "mce_app.h" +# include "mme_app.h" + +//extern RAN_CONTEXT_t RC; + +int create_tasks_mbms(uint32_t enb_nb) { + // LOG_D(ENB_APP, "%s(enb_nb:%d\n", __FUNCTION__, enb_nb); + // ngran_node_t type = RC.rrc[0]->node_type; + int rc; + + if (enb_nb == 0) return 0; + + if(!EPC_MODE_ENABLED){ + rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); + AssertFatal(rc >= 0, "Create task for SCTP failed\n"); + } + + + LOG_I(MME_APP, "Creating MME_APP eNB Task\n"); + rc = itti_create_task (TASK_MME_APP, MME_app_task, NULL); + AssertFatal(rc >= 0, "Create task for MME APP failed\n"); + + if (is_m3ap_MME_enabled()) { + rc = itti_create_task(TASK_M3AP_MME, m3ap_MME_task, NULL); + AssertFatal(rc >= 0, "Create task for M3AP MME failed\n"); + } + + LOG_I(MCE_APP, "Creating MCE_APP eNB Task\n"); + rc = itti_create_task (TASK_MCE_APP, MCE_app_task, NULL); + AssertFatal(rc >= 0, "Create task for MCE APP failed\n"); + + +// LOG_I(ENB_APP, "Creating ENB_APP eNB Task\n"); +// rc = itti_create_task (TASK_ENB_APP, eNB_app_task, NULL); +// AssertFatal(rc >= 0, "Create task for eNB APP failed\n"); +// +// LOG_I(RRC,"Creating RRC eNB Task\n"); +// rc = itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL); +// AssertFatal(rc >= 0, "Create task for RRC eNB failed\n"); +// +// if (EPC_MODE_ENABLED) { +// rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); +// AssertFatal(rc >= 0, "Create task for SCTP failed\n"); +// } +// rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); +// AssertFatal(rc >= 0, "Create task for SCTP failed\n"); +// +// +// if (EPC_MODE_ENABLED && !NODE_IS_DU(type)) { +// rc = itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL); +// AssertFatal(rc >= 0, "Create task for S1AP failed\n"); +// if (!(get_softmodem_params()->emulate_rf)){ +// rc = itti_create_task(TASK_UDP, udp_eNB_task, NULL); +// AssertFatal(rc >= 0, "Create task for UDP failed\n"); +// } +// rc = itti_create_task(TASK_GTPV1_U, gtpv1u_eNB_task, NULL); +// AssertFatal(rc >= 0, "Create task for GTPV1U failed\n"); +// if (is_x2ap_enabled()) { +// rc = itti_create_task(TASK_X2AP, x2ap_task, NULL); +// AssertFatal(rc >= 0, "Create task for X2AP failed\n"); +// } else { +// LOG_I(X2AP, "X2AP is disabled.\n"); +// } +// } +//// + if(!EPC_MODE_ENABLED){ + // rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); + // AssertFatal(rc >= 0, "Create task for SCTP failed\n"); + rc = itti_create_task(TASK_UDP, udp_eNB_task, NULL); + AssertFatal(rc >= 0, "Create task for UDP failed\n"); + rc = itti_create_task(TASK_GTPV1_U, gtpv1u_eNB_task, NULL); + AssertFatal(rc >= 0, "Create task for GTPV1U failed\n"); + } +/// +// if (NODE_IS_CU(type)) { +// rc = itti_create_task(TASK_CU_F1, F1AP_CU_task, NULL); +// AssertFatal(rc >= 0, "Create task for CU F1AP failed\n"); +// } +// +// if (NODE_IS_DU(type)) { +// rc = itti_create_task(TASK_DU_F1, F1AP_DU_task, NULL); +// AssertFatal(rc >= 0, "Create task for DU F1AP failed\n"); +// } +// + + if (is_m3ap_MCE_enabled()) { + rc = itti_create_task(TASK_M3AP_MCE, m3ap_MCE_task, NULL); + AssertFatal(rc >= 0, "Create task for M3AP MCE failed\n"); + + } + if (is_m2ap_MCE_enabled()) { + rc = itti_create_task(TASK_M2AP_MCE, m2ap_MCE_task, NULL); + AssertFatal(rc >= 0, "Create task for M2AP failed\n"); + } + + if (is_m2ap_eNB_enabled()) { + rc = itti_create_task(TASK_M2AP_ENB, m2ap_eNB_task, NULL); + AssertFatal(rc >= 0, "Create task for M2AP failed\n"); + } + + return 0; +} diff --git a/targets/COMMON/create_tasks_mbms.h b/targets/COMMON/create_tasks_mbms.h new file mode 100644 index 0000000000..843897cefb --- /dev/null +++ b/targets/COMMON/create_tasks_mbms.h @@ -0,0 +1,32 @@ +/* + * 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 + */ + +#ifndef CREATE_TASKS_H_ +#define CREATE_TASKS_H_ + +/* External declaration of L2L1 task that depend on the target */ +extern void *l2l1_task(void *arg); + +int create_tasks(uint32_t enb_nb); +int create_tasks_ue(uint32_t ue_nb); +int create_tasks_mbms(uint32_t enb_nb); + +#endif /* CREATE_TASKS_H_ */ diff --git a/targets/DOCS/openair_header.tex b/targets/DOCS/openair_header.tex new file mode 100644 index 0000000000..14e1baee5a --- /dev/null +++ b/targets/DOCS/openair_header.tex @@ -0,0 +1,47 @@ +\documentclass[a4paper]{book} +\usepackage{a4wide} +\usepackage{makeidx} +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{multicol} +\usepackage{float} +\usepackage{textcomp} +\usepackage{alltt} +\usepackage{amsmath} +\usepackage{amssymb} +\ifx\pdfoutput\undefined +\usepackage[ps2pdf, + pagebackref=true, + colorlinks=true, + linkcolor=blue + ]{hyperref} +\usepackage{pspicture} +\else +\usepackage[pdftex, + pagebackref=true, + colorlinks=true, + linkcolor=blue + ]{hyperref} +\fi +\usepackage{doxygen} +\usepackage{times} +\makeindex +\setcounter{tocdepth}{1} +\renewcommand{\footrulewidth}{0.4pt} +\begin{document} +\begin{titlepage} +\vspace*{7cm} +\begin{center} +{\Large openair Specifications }\\ +Phyiscal, Medium-Access, Radio-link Control, Packet Data Convergence Protocol and Radio Resource Control Layers\\ +\vspace*{1cm} +{\large Generated by Doxygen 1.3.8}\\ +\vspace*{0.5cm} +{\small Sun Oct 31 19:27:37 2004}\\ +\end{center} +\end{titlepage} +\clearemptydoublepage +\pagenumbering{roman} +\tableofcontents +\clearemptydoublepage +\pagenumbering{arabic} diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.master.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.master.conf new file mode 100644 index 0000000000..c0decd362f --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.master.conf @@ -0,0 +1,298 @@ +Active_eNBs = ( "eNB-Eurecom-LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe01; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_eNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2685000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 1; + N_RB_DL = 50; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -27; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -104; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + + //Parameters for SIB18 + rxPool_sc_CP_Len = "normal"; + rxPool_sc_Period = "sf40"; + rxPool_data_CP_Len = "normal"; + rxPool_ResourceConfig_prb_Num = 20; + rxPool_ResourceConfig_prb_Start = 5; + rxPool_ResourceConfig_prb_End = 44; + rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + rxPool_ResourceConfig_offsetIndicator_choice = 0; + rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; +/* rxPool_dataHoppingConfig_hoppingParameter = 0; + rxPool_dataHoppingConfig_numSubbands = "ns1"; + rxPool_dataHoppingConfig_rbOffset = 0; + rxPool_commTxResourceUC-ReqAllowed = "TRUE"; +*/ + // Parameters for SIB19 + discRxPool_cp_Len = "normal" + discRxPool_discPeriod = "rf32" + discRxPool_numRetx = 1; + discRxPool_numRepetition = 2; + discRxPool_ResourceConfig_prb_Num = 5; + discRxPool_ResourceConfig_prb_Start = 3; + discRxPool_ResourceConfig_prb_End = 21; + discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + discRxPool_ResourceConfig_offsetIndicator_choice = 0; + discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; + + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.26"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + ///X2 + enable_x2 = "yes"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "enp0s31f6"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.188/23"; + ENB_INTERFACE_NAME_FOR_S1U = "enp0s31f6"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.188/23"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + + ENB_IPV4_ADDRESS_FOR_X2C = "192.168.12.188/23"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + + } +); + +DU = ( + { + DU_INTERFACE_NAME_FOR_F1U = "lo"; + DU_IPV4_ADDRESS_FOR_F1U = "127.0.0.1/16"; + DU_PORT_FOR_F1U = 22100; + F1_U_DU_TRANSPORT_TYPE = "TCP"; + } + ); + +CU = ( + { + CU_INTERFACE_NAME_FOR_F1U = "lo"; + CU_IPV4_ADDRESS_FOR_F1U = "127.0.0.1"; //Address to search the DU + CU_PORT_FOR_F1U = 22100; + F1_U_CU_TRANSPORT_TYPE = "TCP"; // One of TCP/UDP/SCTP + DU_TYPE = "LTE"; + }//, +// { +// CU_INTERFACE_NAME_FOR_F1U = "eth0"; +// CU_IPV4_ADDRESS_FOR_F1U = "10.64.93.142"; //Address to search the DU +// CU_PORT_FOR_F1U = 2211; +// F1_U_CU_TRANSPORT_TYPE = "TCP"; // One of TCP/UDP/SCTP +// DU_TYPE = "WiFi"; +// } + ); + + CU_BALANCING = "ALL"; + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + phy_test_mode = 0; + puSch10xSnr = 200; + puCch10xSnr = 200; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 125; + eNB_instances = [0]; + + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "lo"; + FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf index 3eadc9af68..1363be3bce 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf @@ -33,7 +33,7 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL # this is pointA + 23 PRBs@120kHz SCS (same as initial BWP) - absoluteFrequencySSB = 2077643; + absoluteFrequencySSB = 2077907; dl_frequencyBand = 257; # this is 27.900 GHz dl_absoluteFrequencyPointA = 2077499; @@ -148,11 +148,11 @@ gNBs = # ssb_PositionsInBurs_BitmapPR # 1=short, 2=medium, 3=long ssb_PositionsInBurst_PR = 3; - ssb_PositionsInBurst_Bitmap = 1; + ssb_PositionsInBurst_Bitmap = 0x100000001L; # ssb_periodicityServingCell # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 - ssb_periodicityServingCell = 1; + ssb_periodicityServingCell = 2; # dmrs_TypeA_position # 0 = pos2, 1 = pos3 @@ -170,8 +170,8 @@ gNBs = # pattern1 # dl_UL_TransmissionPeriodicity # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 - dl_UL_TransmissionPeriodicity = 6; - nrofDownlinkSlots = 30; + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 10; nrofDownlinkSymbols = 0; nrofUplinkSlots = 10; nrofUplinkSymbols = 0; @@ -237,8 +237,8 @@ RUs = ( max_pdschReferenceSignalPower = -27; max_rxgain = 114; eNB_instances = [0]; - sdr_addrs = "type=x300"; - if_freq = 3000000000; + sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2"; + if_freq = 5300000000; } ); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf index 1de784a73a..1fbc8e30ef 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf @@ -33,7 +33,7 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL # this is pointA + 23 PRBs@120kHz SCS (same as initial BWP) - absoluteFrequencySSB = 2078051; + absoluteFrequencySSB = 2078315; dl_frequencyBand = 257; # this is 27.900 GHz dl_absoluteFrequencyPointA = 2077499; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf new file mode 100644 index 0000000000..72a27cc1e7 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf @@ -0,0 +1,271 @@ +Active_gNBs = ( "gNB-Eurecom-5GNRBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + + cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-Eurecom-5GNRBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 600; + + plmn_list = ({mcc = 311; mnc = 480; mnc_length = 3;}); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is pointA + 23 PRBs@120kHz SCS (same as initial BWP) + absoluteFrequencySSB = 2071241; + dl_frequencyBand = 261; + # this is 27.900 GHz + dl_absoluteFrequencyPointA = 2070833; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 3; + dl_carrierBandwidth = 32; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=50 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 8525; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 3; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=2,L=3 + initialDLBWPstartSymbolAndLength_0 = 40; + + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=2,L=12 + initialDLBWPstartSymbolAndLength_1 = 53; + + initialDLBWPk0_2 = 0; + initialDLBWPmappingType_2 = 0; + #this is SS=1,L=12 + initialDLBWPstartSymbolAndLength_2 = 54; + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 261; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 3; + ul_carrierBandwidth = 32; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 8525; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 3; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -118; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#0 = 839, 1 = 139 + prach_RootSequenceIndex_PR = 1; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, + +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 2; + initialULBWPmappingType_0 = 1 + # this is SS=0 L=11 + initialULBWPstartSymbolAndLength_0 = 55; + + initialULBWPk2_1 = 2; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=12 + initialULBWPstartSymbolAndLength_1 = 69; + + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 3; + ssb_PositionsInBurst_Bitmap = 0x100000001L; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 3; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 3; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 10; + nrofDownlinkSymbols = 0; + nrofUplinkSlots = 10; + nrofUplinkSymbols = 0; + + ssPBCH_BlockPower = 10; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.26"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.111/24"; + GNB_INTERFACE_NAME_FOR_S1U = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.111/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1; + nb_rx = 1; + att_tx = 0; + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2"; + if_freq = 5124520000L; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf index 033ceef40c..ff8e261783 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf @@ -21,19 +21,19 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; + ssb_SubcarrierOffset = 31; pdsch_AntennaPorts = 1; servingCellConfigCommon = ( { #spCellConfigCommon - physCellId = 0; + physCellId = 10; # downlinkConfigCommon #frequencyInfoDL # this is 3600 MHz + 84 PRBs@30kHz SCS (same as initial BWP) - absoluteFrequencySSB = 642016; + absoluteFrequencySSB = 641272; dl_frequencyBand = 78; # this is 3600 MHz dl_absoluteFrequencyPointA = 640000; @@ -46,12 +46,12 @@ gNBs = #initialDownlinkBWP #genericParameters # this is RBstart=84,L=13 (275*(L-1))+RBstart - initialDLBWPlocationAndBandwidth = 3384; + initialDLBWPlocationAndBandwidth = 6366; # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialDLBWPsubcarrierSpacing = 1; #pdcch-ConfigCommon - initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPcontrolResourceSetZero = 0; initialDLBWPsearchSpaceZero = 0; #pdsch-ConfigCommon #pdschTimeDomainAllocationList (up to 16 entries) @@ -83,7 +83,7 @@ gNBs = pMax = 20; #initialUplinkBWP #genericParameters - initialULBWPlocationAndBandwidth = 3384; + initialULBWPlocationAndBandwidth = 6366; # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialULBWPsubcarrierSpacing = 1; @@ -103,10 +103,10 @@ gNBs = powerRampingStep = 1; #ra_ReponseWindow #1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; + ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR -#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; #oneHalf (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer @@ -114,9 +114,9 @@ gNBs = ra_ContentionResolutionTimer = 7; rsrp_ThresholdSSB = 19; #prach-RootSequenceIndex_PR -#0 = 839, 1 = 139 - prach_RootSequenceIndex_PR = 1; - prach_RootSequenceIndex = 1; +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 0; # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex # msg1_SubcarrierSpacing = 1, @@ -199,6 +199,17 @@ gNBs = } ); + ///X2 + enable_x2 = "yes"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + target_enb_x2_ip_address = ( + { ipv4 = "192.168.12.196"; + ipv6 = "192:168:30::17"; + preference = "ipv4"; + } + ); + NETWORK_INTERFACES : { @@ -207,6 +218,8 @@ gNBs = GNB_INTERFACE_NAME_FOR_S1U = "eth0"; GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.111/24"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 + GNB_IPV4_ADDRESS_FOR_X2C = "192.168.12.111/24"; + GNB_PORT_FOR_X2C = 36422; # Spec 36422 }; } ); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf new file mode 100644 index 0000000000..771f5d1839 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf @@ -0,0 +1,284 @@ +Active_gNBs = ( "gNB-Eurecom-5GNRBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + + cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-Eurecom-5GNRBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({mcc = 208; mnc = 93; mnc_length = 2;}); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 84 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 642016; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640000; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 217; + #initialDownlinkBWP + #genericParameters + # this is RBstart=84,L=50 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 13559; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=2,L=3 + initialDLBWPstartSymbolAndLength_0 = 40; + + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=2,L=12 + initialDLBWPstartSymbolAndLength_1 = 53; + + initialDLBWPk0_2 = 0; + initialDLBWPmappingType_2 = 0; + #this is SS=1,L=12 + initialDLBWPstartSymbolAndLength_2 = 54; + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 217; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 13559; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -118; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#0 = 839, 1 = 139 + prach_RootSequenceIndex_PR = 1; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, + +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 2; + initialULBWPmappingType_0 = 1 + # this is SS=0 L=11 + initialULBWPstartSymbolAndLength_0 = 55; + + initialULBWPk2_1 = 2; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=12 + initialULBWPstartSymbolAndLength_1 = 69; + + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 15; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 2; + nrofDownlinkSymbols = 1; + nrofUplinkSlots = 7; + nrofUplinkSymbols = 7; + + ssPBCH_BlockPower = 10; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.26"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + ///X2 + enable_x2 = "yes"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + target_enb_x2_ip_address = ( + { ipv4 = "192.168.12.188"; + ipv6 = "192:168:30::17"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_S1_MME = "enp0s31f6"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.75/24"; + GNB_INTERFACE_NAME_FOR_S1U = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.75/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + + GNB_IPV4_ADDRESS_FOR_X2C = "192.168.12.75/23"; + GNB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + sdr_addrs = "addr=192.168.20.2,mgmt_addr=192.168.20.2"; + clock_src = "internal"; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf index 4564907fa8..904a455600 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf @@ -148,7 +148,7 @@ gNBs = # ssb_PositionsInBurs_BitmapPR # 1=short, 2=medium, 3=long ssb_PositionsInBurst_PR = 2; - ssb_PositionsInBurst_Bitmap = 255; + ssb_PositionsInBurst_Bitmap = 1; # ssb_periodicityServingCell # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 @@ -238,7 +238,7 @@ RUs = ( max_rxgain = 114; eNB_instances = [0]; sdr_addrs = "addr=192.168.10.2,mgmt_addr=192.168.10.2"; - clock_src = "external"; + #clock_src = "external"; } ); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf index 7664db8f69..b82c455ef4 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf @@ -171,10 +171,10 @@ gNBs = # dl_UL_TransmissionPeriodicity # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 dl_UL_TransmissionPeriodicity = 6; - nrofDownlinkSlots = 2; - nrofDownlinkSymbols = 1; - nrofUplinkSlots = 7; - nrofUplinkSymbols = 7; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; ssPBCH_BlockPower = 10; } @@ -198,15 +198,29 @@ gNBs = preference = "ipv4"; } ); + + ///X2 + enable_x2 = "no"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + target_enb_x2_ip_address = ( + { ipv4 = "192.168.12.108"; + ipv6 = "192:168:30::17"; + preference = "ipv4"; + } + ); NETWORK_INTERFACES : { GNB_INTERFACE_NAME_FOR_S1_MME = "eth0"; - GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.111/24"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.188/24"; GNB_INTERFACE_NAME_FOR_S1U = "eth0"; - GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.111/24"; + GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.188/24"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 + + GNB_IPV4_ADDRESS_FOR_X2C = "192.168.12.188/23"; + GNB_PORT_FOR_X2C = 36422; # Spec 36422 }; } ); diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 87001d2fc6..8c5c50836f 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -512,17 +512,16 @@ int wakeup_txfh(PHY_VARS_eNB *eNB, continue;//hacking only works when all RU_tx works on the same subframe #TODO: adding mask stuff } - AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_eNBs))==0,"ERROR pthread_mutex_lock failed on mutex_eNBs L1_thread_tx with ret=%d\n",ret); - if (ru_proc->instance_cnt_eNBs == 0) { LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->tti_tx, proc->frame_rx, proc->subframe_rx); AssertFatal((ret=pthread_mutex_lock(&eNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); eNB->proc.RU_mask_tx = 0; AssertFatal((ret=pthread_mutex_unlock(&eNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); - AssertFatal((ret=pthread_mutex_unlock( &ru_proc->mutex_eNBs ))==0,"mutex_unlock return %d\n",ret); return(-1); } + AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_eNBs))==0,"ERROR pthread_mutex_lock failed on mutex_eNBs L1_thread_tx with ret=%d\n",ret); + ru_proc->instance_cnt_eNBs = 0; ru_proc->timestamp_tx = timestamp_tx; ru_proc->tti_tx = subframe_tx; @@ -1255,6 +1254,8 @@ void init_eNB(int single_thread_flag, AssertFatal((eNB->if_inst = IF_Module_init(inst))!=NULL,"Cannot register interface"); eNB->if_inst->schedule_response = schedule_response; eNB->if_inst->PHY_config_req = phy_config_request; + eNB->if_inst->PHY_config_update_sib2_req = phy_config_update_sib2_request; + eNB->if_inst->PHY_config_update_sib13_req = phy_config_update_sib13_request; memset((void *)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO)); memset((void *)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO)); LOG_I(PHY,"Setting indication lists\n"); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index e81b1ddc06..e6364cad23 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -97,6 +97,8 @@ static int DEFBFW[] = {0x00007fff}; #include "pdcp.h" +#define MBMS_EXPERIMENTAL + extern volatile int oai_exit; extern int emulate_rf; extern int numerology; @@ -1881,10 +1883,19 @@ static void *ru_thread( void *param ) { AssertFatal((ret=pthread_mutex_unlock(&ru->proc.mutex_pre_scd))==0,"[eNB] error unlocking mutex_pre_scd mutex for eNB pre scd\n"); #endif + // wakeup all eNB processes waiting for this RU + if (ru->num_eNB>0) wakeup_L1s(ru); - // wakeup all eNB processes waiting for this RU - if (ru->num_eNB>0) wakeup_L1s(ru); - +#ifdef MBMS_EXPERIMENTAL + //Workaround ... this must be properly handled + if(ru->if_south==LOCAL_RF && ru->function==eNodeB_3GPP && RC.eNB[0][0]!=NULL){ + if(ru->frame_parms->num_MBSFN_config!=RC.eNB[0][0]->frame_parms.num_MBSFN_config){ + ru->frame_parms = &RC.eNB[0][0]->frame_parms;//->frame_parms; + LOG_W(PHY,"RU MBSFN SF PARAMS Updated\n"); + } + } +#endif + #ifndef PHY_TX_THREAD if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0) { @@ -2183,7 +2194,9 @@ int start_rf(RU_t *ru) { } int stop_rf(RU_t *ru) { - ru->rfdevice.trx_end_func(&ru->rfdevice); + if(ru->rfdevice.trx_end_func != NULL) { + ru->rfdevice.trx_end_func(&ru->rfdevice); + } return 0; } @@ -2331,11 +2344,15 @@ void init_RU_proc(RU_t *ru) { init_frame_parms(ru->frame_parms,1); ru->frame_parms->nb_antennas_rx = ru->nb_rx; phy_init_RU(ru); - openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + if (ret < 0) { + LOG_I(PHY,"Exiting, cannot load device. Make sure that your SDR board is connected!\n"); + exit(1); + } if (setup_RU_buffers(ru)!=0) { - printf("Exiting, cannot initialize RU Buffers\n"); - exit(-1); + LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n"); + exit(1); } } @@ -2672,13 +2689,9 @@ void init_RU(char *rf_config_file, clock_source_t clock_source, clock_source_t t PHY_VARS_eNB *eNB0 = (PHY_VARS_eNB *)NULL; LTE_DL_FRAME_PARMS *fp = (LTE_DL_FRAME_PARMS *)NULL; // create status mask - RC.ru_mask = 0; + RC.ru_mask= (1 << RC.nb_RU) - 1; pthread_mutex_init(&RC.ru_mutex,NULL); pthread_cond_init(&RC.ru_cond,NULL); - // read in configuration file) - printf("configuring RU from file\n"); - RCconfig_RU(); - LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs()); if (RC.nb_CC != 0) for (i=0; i 0) { RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); - RC.ru_mask=(1<node_type)) { @@ -535,9 +518,6 @@ int main ( int argc, char **argv ) printf("Reading in command-line options\n"); get_options (); - if (is_nos1exec(argv[0]) ) - set_softmodem_optmask(SOFTMODEM_NOS1_BIT); - EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1; if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { @@ -568,10 +548,7 @@ int main ( int argc, char **argv ) MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); init_opt(); // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGABRT, signal_handler); + set_softmodem_sighandler(); check_clock(); #ifndef PACKAGE_VERSION # define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" @@ -583,9 +560,22 @@ int main ( int argc, char **argv ) /* Read configuration */ if (RC.nb_inst > 0) { read_config_and_init(); - /* Start the agent. If it is turned off in the configuration, it won't start */ - RCconfig_flexran(); + } else { + printf("RC.nb_inst = 0, Initializing L1\n"); + RCconfig_L1(); + } + /* We need to read RU configuration before FlexRAN starts so it knows what + * splits to report. Actual RU start comes later. */ + if (RC.nb_RU > 0 && NFAPI_MODE != NFAPI_MODE_VNF) { + RCconfig_RU(); + LOG_I(PHY, + "number of L1 instances %d, number of RU %d, number of CPU cores %d\n", + RC.nb_L1_inst, RC.nb_RU, get_nprocs()); + } + + if (RC.nb_inst > 0) { + /* Start the agent. If it is turned off in the configuration, it won't start */ for (i = 0; i < RC.nb_inst; i++) { flexran_agent_start(i); } @@ -605,9 +595,6 @@ int main ( int argc, char **argv ) itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); } node_type = RC.rrc[0]->node_type; - } else { - printf("RC.nb_inst = 0, Initializing L1\n"); - RCconfig_L1(); } if (RC.nb_inst > 0 && NODE_IS_CU(node_type)) { @@ -707,6 +694,8 @@ int main ( int argc, char **argv ) pthread_mutex_unlock(&sync_mutex); config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS); } + create_tasks_mbms(1); + // wait for end of program LOG_UI(ENB_APP,"TYPE TO TERMINATE\n"); // CI -- Flushing the std outputs for the previous marker to show on the eNB / DU / CU log file diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index d97d86611c..5e1bf36160 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -35,63 +35,7 @@ #include "proto_agent.h" #include "executables/softmodem-common.h" -/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ -#define CONFIG_HLP_RFCFGF "Configuration file for front-end (e.g. LMS7002M)\n" -#define CONFIG_HLP_ULMAXE "set the eNodeB max ULSCH erros\n" -#define CONFIG_HLP_CALUER "set UE RX calibration\n" -#define CONFIG_HLP_CALUERM "" -#define CONFIG_HLP_CALUERB "" -#define CONFIG_HLP_DBGUEPR "UE run normal prach power ramping, but don't continue random-access\n" -#define CONFIG_HLP_CALPRACH "UE run normal prach with maximum power, but don't continue random-access\n" -#define CONFIG_HLP_NOL2CN "bypass L2 and upper layers\n" -#define CONFIG_HLP_SIML1 "activate RF simulator instead of HW\n" -#define CONFIG_HLP_NUMUE "number of UE instances\n" -#define CONFIG_HLP_UERXG "set UE RX gain\n" -#define CONFIG_HLP_UERXGOFF "external UE amplifier offset\n" -#define CONFIG_HLP_UETXG "set UE TX gain\n" -#define CONFIG_HLP_UENANTR "set UE number of rx antennas\n" -#define CONFIG_HLP_UENANTT "set UE number of tx antennas\n" -#define CONFIG_HLP_UESCAN "set UE to scan around carrier\n" -#define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n" -#define CONFIG_HLP_DLSHIFT "dynamic shift for LLR compuation for TM3/4 (default 0)\n" -#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n" -#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n" -#define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n" -#define CONFIG_HLP_EXTS "tells hardware to use an external timing reference\n" -#define CONFIG_HLP_DMRSSYNC "tells RU to insert DMRS in subframe 1 slot 0" -#define CONFIG_HLP_CLK "tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)\n" -#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n" -#define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n" -#define CONFIG_HLP_TADV "Set timing_advance\n" -#define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n" -#define CONFIG_HLP_CHOFF "Channel id offset\n" -#define CONFIG_HLP_SOFTS "Enable soft scope and L1 and L2 stats (Xforms)\n" -#define CONFIG_HLP_EXMCAL "Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n" -#define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" -#define CONFIG_HLP_DLMCS "Set the maximum downlink MCS\n" -#define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" -#define CONFIG_HLP_PRB "Set the PRB, valid values: 6, 25, 50, 100 \n" -#define CONFIG_HLP_EMULIFACE "Set the interface name for the multicast transport for emulation mode (e.g. eth0, lo, etc.) \n" -//#define CONFIG_HLP_NUMUES "Set the number of UEs for the emulation" -#define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" -#define CONFIG_HLP_ULMCS "Set the maximum uplink MCS\n" -#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n" -#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n" -#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n" -#define CONFIG_HLP_TPORT "tracer port\n" -#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n" -#define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n" -#define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n" -#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n" -#define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n" -#define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n" -#define CONFIG_HLP_NOS1 "Disable s1 interface\n" -#define CONFIG_HLP_RFSIM "Run in rf simulator mode (also known as basic simulator)\n" -#define CONFIG_HLP_NOKRNMOD "(noS1 only): Use tun instead of namesh module \n" -#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" - -#define CONFIG_HLP_USRP_ARGS "set the arguments to identify USRP (same syntax as in UHD)\n" /***************************************************************************************************************************************/ /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument @@ -121,6 +65,31 @@ #define CMDLINE_MEMLOOP_IDX 6 #define CMDLINE_DUMPMEMORY_IDX 7 /*------------------------------------------------------------------------------------------------------------------------------------------*/ +/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ + + +#define CONFIG_HLP_SIML1 "activate RF simulator instead of HW\n" +#define CONFIG_HLP_NUMUE "number of UE instances\n" +#define CONFIG_HLP_UERXG "set UE RX gain\n" +#define CONFIG_HLP_UERXGOFF "external UE amplifier offset\n" +#define CONFIG_HLP_UETXG "set UE TX gain\n" +#define CONFIG_HLP_UENANTR "set UE number of rx antennas\n" +#define CONFIG_HLP_UENANTT "set UE number of tx antennas\n" +#define CONFIG_HLP_UESCAN "set UE to scan around carrier\n" +#define CONFIG_HLP_EMULIFACE "Set the interface name for the multicast transport for emulation mode (e.g. eth0, lo, etc.) \n" +#define CONFIG_HLP_PRB "Set the PRB, valid values: 6, 25, 50, 100 \n" +#define CONFIG_HLP_DLSHIFT "dynamic shift for LLR compuation for TM3/4 (default 0)\n" +#define CONFIG_HLP_USRP_ARGS "set the arguments to identify USRP (same syntax as in UHD)\n" +#define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n" +#define CONFIG_HLP_CLK "tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)\n" +#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n" +#define CONFIG_HLP_TADV "Set timing_advance\n" + + + + + + /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ @@ -166,99 +135,7 @@ #define DEFAULT_DLF 2680000000 -/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* command line parameters common to eNodeB and UE */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define RF_CONFIG_FILE softmodem_params.rf_config_file -#define PHY_TEST softmodem_params.phy_test -#define WAIT_FOR_SYNC softmodem_params.wait_for_sync -#define SINGLE_THREAD_FLAG softmodem_params.single_thread_flag -#define CHAIN_OFFSET softmodem_params.chain_offset -#define NUMEROLOGY softmodem_params.numerology -#define EMULATE_RF softmodem_params.emulate_rf -#define CLOCK_SOURCE softmodem_params.clock_source -#define TIMING_SOURCE softmodem_params.timing_source -#define SEND_DMRSSYNC softmodem_params.send_dmrs_sync -#define USIM_TEST softmodem_params.usim_test -#define CMDLINE_PARAMS_DESC { \ - {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)},\ - {"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \ - {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \ - {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \ - {"clock", CONFIG_HLP_CLK, 0, uptr:&CLOCK_SOURCE, defintval:0, TYPE_UINT, 0}, \ - {"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&WAIT_FOR_SYNC, defintval:0, TYPE_INT, 0}, \ - {"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&SINGLE_THREAD_FLAG, defintval:0, TYPE_INT, 0}, \ - {"C" , CONFIG_HLP_DLF, 0, u64ptr:&(downlink_frequency[0][0]), defuintval:2680000000, TYPE_UINT64, 0}, \ - {"a" , CONFIG_HLP_CHOFF, 0, iptr:&CHAIN_OFFSET, defintval:0, TYPE_INT, 0}, \ - {"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \ - {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ - {"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \ - {"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&NUMEROLOGY, defintval:0, TYPE_INT, 0}, \ - {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&EMULATE_RF, defintval:0, TYPE_INT, 0}, \ - {"parallel-config", CONFIG_HLP_PARALLEL_CMD, 0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \ - {"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \ - {"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, uptr:&noS1, defintval:0, TYPE_INT, 0}, \ - {"rfsim", CONFIG_HLP_RFSIM, PARAMFLAG_BOOL, uptr:&rfsim, defintval:0, TYPE_INT, 0}, \ - {"basicsim", CONFIG_HLP_RFSIM, PARAMFLAG_BOOL, uptr:&basicsim, defintval:0, TYPE_INT, 0}, \ - {"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0}, \ - {"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, uptr:&nonbiot, defuintval:0, TYPE_INT, 0}, \ - } -#define CONFIG_HLP_FLOG "Enable online log \n" -#define CONFIG_HLP_LOGL "Set the global log level, valid options: (4:trace, 3:debug, 2:info, 1:warn, (0:error))\n" -#define CONFIG_HLP_LOGV "Set the global log verbosity \n" -#define CONFIG_HLP_TELN "Start embedded telnet server \n" -#define CONFIG_HLP_MSC "Enable the MSC tracing utility \n" -/*----------------------------------------------------------------------------------------------------------------------------*/ -/* command line parameters for LOG utility */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*----------------------------------------------------------------------------------------------------------------------------*/ -#define START_MSC softmodem_params.start_msc -#define CMDLINE_LOGPARAMS_DESC { \ - {"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \ - {"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \ - {"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \ - {"msc", CONFIG_HLP_MSC, PARAMFLAG_BOOL, uptr:&START_MSC, defintval:0, TYPE_UINT, 0}, \ - {"log-mem", NULL, 0, strptr:(char **)&logmem_filename, defstrval:NULL, TYPE_STRING, 0}, \ - } - -#define CMDLINE_ONLINELOG_IDX 0 -#define CMDLINE_GLOGLEVEL_IDX 1 -#define CMDLINE_GLOGVERBO_IDX 2 -#define CMDLINE_STARTTELN_IDX 3 - -/* check function for global log level */ -#define CMDLINE_LOGPARAMS_CHECK_DESC { \ - { .s5= {NULL} } , \ - { .s2= {config_check_intrange, {0,4}}}, \ - { .s5= {NULL} } , \ - { .s5= {NULL} } , \ - { .s5= {NULL} } , \ - } - -/***************************************************************************************************************************************/ - -#define SOFTMODEM_NOS1_BIT (1<<0) -#define SOFTMODEM_NOKRNMOD_BIT (1<<1) -#define SOFTMODEM_NONBIOT_BIT (1<<2) -#define SOFTMODEM_RFSIM_BIT (1<<10) -#define SOFTMODEM_BASICSIM_BIT (1<<11) -#define SOFTMODEM_SIML1_BIT (1<<12) -#define SOFTMODEM_DOFORMS_BIT (1<<15) - -#define IS_SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT) -#define IS_SOFTMODEM_NOKRNMOD ( get_softmodem_optmask() & SOFTMODEM_NOKRNMOD_BIT) -#define IS_SOFTMODEM_NONBIOT ( get_softmodem_optmask() & SOFTMODEM_NONBIOT_BIT) -#define IS_SOFTMODEM_RFSIM ( get_softmodem_optmask() & SOFTMODEM_RFSIM_BIT) -#define IS_SOFTMODEM_BASICSIM ( get_softmodem_optmask() & SOFTMODEM_BASICSIM_BIT) -#define IS_SOFTMODEM_SIML1 ( get_softmodem_optmask() & SOFTMODEM_SIML1_BIT) -#define IS_SOFTMODEM_DOFORMS ( get_softmodem_optmask() & SOFTMODEM_DOFORMS_BIT) -extern uint64_t get_softmodem_optmask(void); -extern uint64_t set_softmodem_optmask(uint64_t bitmask); -extern void get_common_options(void); -extern softmodem_params_t *get_softmodem_params(void); -extern unsigned int is_nos1exec(char *exepath) ; uint64_t get_pdcp_optmask(void); extern pthread_cond_t sync_cond; extern pthread_mutex_t sync_mutex; @@ -268,7 +145,6 @@ extern uint64_t downlink_frequency[MAX_NUM_CCs][4]; extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; extern int rx_input_level_dBm; -extern uint8_t exit_missed_slots; extern uint64_t num_missed_slots; // counter for the number of missed slots extern int oaisim_flag; diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 8a4172965e..75ed018434 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -59,6 +59,7 @@ #include "UTIL/MATH/oml.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" +#include "lte-softmodem.h" #include "common/config/config_userapi.h" #include "T.h" @@ -87,7 +88,7 @@ extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); extern void multicast_link_start(void (*rx_handlerP) (unsigned int, char *), unsigned char _multicast_group, char *multicast_ifname); extern int oai_nfapi_crc_indication(nfapi_crc_indication_t *crc_ind); -extern int oai_nfapi_crc_indication(nfapi_crc_indication_t *crc_ind); +extern int oai_nfapi_cqi_indication(nfapi_cqi_indication_t *cqi_ind); extern int oai_nfapi_harq_indication(nfapi_harq_indication_t *harq_ind); extern int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind); extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind); @@ -208,10 +209,10 @@ char uecap_xer[1024]; void init_thread(int sched_runtime, - int sched_deadline, - int sched_fifo, - cpu_set_t *cpuset, - char *name) + int sched_deadline, + int sched_fifo, + cpu_set_t *cpuset, + char *name) { #ifdef DEADLINE_SCHEDULER @@ -255,16 +256,16 @@ void init_thread(int sched_runtime, } void init_UE(int nb_inst, - int eMBMS_active, - int uecap_xer_in, - int timing_correction, - int phy_test, - int UE_scan, - int UE_scan_carrier, - runmode_t mode, - int rxgain, - int txpowermax, - LTE_DL_FRAME_PARMS *fp0) + int eMBMS_active, + int uecap_xer_in, + int timing_correction, + int phy_test, + int UE_scan, + int UE_scan_carrier, + runmode_t mode, + int rxgain, + int txpowermax, + LTE_DL_FRAME_PARMS *fp0) { PHY_VARS_UE *UE; int inst; @@ -397,9 +398,9 @@ void init_UE(int nb_inst, // Initiating all UEs within a single set of threads for PHY_STUB. Future extensions -> multiple // set of threads for multiple UEs. void init_UE_stub_single_thread(int nb_inst, - int eMBMS_active, - int uecap_xer_in, - char *emul_iface) + int eMBMS_active, + int uecap_xer_in, + char *emul_iface) { int inst; LOG_I(PHY,"UE : Calling Layer 2 for initialization, nb_inst: %d \n", nb_inst); @@ -423,9 +424,9 @@ void init_UE_stub_single_thread(int nb_inst, void init_UE_stub(int nb_inst, - int eMBMS_active, - int uecap_xer_in, - char *emul_iface) + int eMBMS_active, + int uecap_xer_in, + char *emul_iface) { int inst; LOG_I(PHY,"UE : Calling Layer 2 for initialization\n"); @@ -899,7 +900,7 @@ static void *UE_thread_rxn_txnp4(void *arg) unsigned int emulator_absSF; void ue_stub_rx_handler(unsigned int num_bytes, - char *rx_buffer) + char *rx_buffer) { PHY_VARS_UE *UE; UE = PHY_vars_UE_g[0][0]; @@ -991,6 +992,19 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) phy_stub_ticking->num_single_thread[ue_thread_id] = -1; UE = rtd->UE; + UL_INFO = (UL_IND_t *)malloc(sizeof(UL_IND_t)); + UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_rx_indication_pdu_t)); + UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; + UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_crc_indication_pdu_t)); + UL_INFO->crc_ind.crc_indication_body.number_of_crcs = 0; + UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_harq_indication_pdu_t)); + UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0; + UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_sr_indication_pdu_t)); + UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; + UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_cqi_indication_pdu_t)); + UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = calloc(NB_UE_INST, sizeof(nfapi_cqi_indication_raw_pdu_t)); + UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; + if(ue_thread_id == 0) { phy_stub_ticking->ticking_var = -1; proc->subframe_rx=proc->sub_frame_start; @@ -1063,20 +1077,6 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) initRefTimes(t3); pickTime(current); updateTimes(proc->gotIQs, &t2, 10000, "Delay to wake up UE_Thread_Rx (case 2)");*/ - // Not sure whether we should put the memory allocation here and not sure how much memory - //we should allocate for each subframe cycle. - UL_INFO = (UL_IND_t *)malloc(sizeof(UL_IND_t)); - UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = (nfapi_rx_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_rx_indication_pdu_t)); - UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; - UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = (nfapi_crc_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_crc_indication_pdu_t)); - UL_INFO->crc_ind.crc_indication_body.number_of_crcs = 0; - UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = (nfapi_harq_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_harq_indication_pdu_t)); - UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0; - UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = (nfapi_sr_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_sr_indication_pdu_t)); - UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; - UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = (nfapi_cqi_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_cqi_indication_pdu_t)); - UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = (nfapi_cqi_indication_raw_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_cqi_indication_raw_pdu_t)); - UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; if (pthread_mutex_lock(&phy_stub_ticking->mutex_single_thread) != 0) { LOG_E( MAC, "[SCHED][UE] error locking mutex for ue_thread_id %d (mutex_single_thread)\n",ue_thread_id); @@ -1252,6 +1252,11 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0; } + if (UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis > 0) { + oai_nfapi_cqi_indication(&UL_INFO->cqi_ind); + UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0; + } + if(UL_INFO->harq_ind.harq_indication_body.number_of_harqs>0) { //LOG_D(MAC, "ul_config_req_UE_MAC 2.4, SFN/SF of PNF counter:%d.%d, number_of_harqs: %d \n", timer_frame, timer_subframe, UL_INFO->harq_ind.harq_indication_body.number_of_harqs); oai_nfapi_harq_indication(&UL_INFO->harq_ind); @@ -1266,30 +1271,6 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0; } - // Free UL_INFO messages - //if(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list != NULL){ - free(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list); - UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = NULL; - //} - //if(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list != NULL){ - free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list); - UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = NULL; - //} - //if(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list !=NULL){ - free(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list); - UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = NULL; - //} - //if(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list!=NULL){ - free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list); - UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL; - //} - free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list); - UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL; - free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list); - UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL; - free(UL_INFO); - UL_INFO = NULL; - // De-allocate memory of nfapi requests copies before next subframe round if(dl_config_req!=NULL) { if(dl_config_req->vendor_extension!=NULL) { @@ -1307,6 +1288,13 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) } if(tx_request_pdu_list!=NULL) { + for (int i = 0; i < tx_req_num_elems; i++) { + for (int j = 0; j < tx_request_pdu_list[i].num_segments; j++) { + free(tx_request_pdu_list[i].segments[j].segment_data); + tx_request_pdu_list[i].segments[j].segment_data = NULL; + } + } + tx_req_num_elems = 0; free(tx_request_pdu_list); tx_request_pdu_list = NULL; } @@ -1333,6 +1321,22 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) } } + // Free UL_INFO messages + free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list); + UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL; + free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list); + UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL; + free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list); + UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL; + free(UL_INFO->harq_ind.harq_indication_body.harq_pdu_list); + UL_INFO->harq_ind.harq_indication_body.harq_pdu_list = NULL; + free(UL_INFO->crc_ind.crc_indication_body.crc_pdu_list); + UL_INFO->crc_ind.crc_indication_body.crc_pdu_list = NULL; + free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list); + UL_INFO->rx_ind.rx_indication_body.rx_pdu_list = NULL; + free(UL_INFO); + UL_INFO = NULL; + // thread finished free(arg); return &UE_thread_rxtx_retval; @@ -1511,6 +1515,23 @@ static void *UE_phy_stub_thread_rxn_txnp4(void *arg) * \param arg unused * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ +void write_dummy(PHY_VARS_UE *UE, openair0_timestamp timestamp) { + // we have to write to tell explicitly to the eNB, else it will wait for us forever + // we write the next subframe (always write in future of what we received) + // + struct complex16 v= {0}; + void *samplesVoid[UE->frame_parms.nb_antennas_tx]; + + for ( int i=0; i < UE->frame_parms.nb_antennas_tx; i++) + samplesVoid[i]=(void *)&v; + + AssertFatal(1 == UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp+2*UE->frame_parms.samples_per_tti, + samplesVoid, + 1, + UE->frame_parms.nb_antennas_tx, + 1),""); +} void *UE_thread(void *arg) { @@ -1564,16 +1585,32 @@ void *UE_thread(void *arg) if (is_synchronized == 0) { if (instance_cnt_synch < 0) { // we can invoke the synch // grab 10 ms of signal and wakeup synch thread - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&UE->common_vars.rxdata[i][0]; - if (UE->mode != loop_through_memory) - AssertFatal( UE->frame_parms.samples_per_tti*10 == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - UE->frame_parms.samples_per_tti*10, - UE->frame_parms.nb_antennas_rx), ""); + if (UE->mode != loop_through_memory) { + if (IS_SOFTMODEM_RFSIM) { + for(int sf=0; sf<10; sf++) { + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.samples_per_tti*sf]; + + AssertFatal(UE->frame_parms.samples_per_tti == UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti, + UE->frame_parms.nb_antennas_rx), ""); + write_dummy(UE, timestamp); + } + } else { + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&UE->common_vars.rxdata[i][0]; + + AssertFatal( UE->frame_parms.samples_per_tti*10 == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti*10, + UE->frame_parms.nb_antennas_rx), ""); + } + } AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); instance_cnt_synch = ++UE->proc.instance_cnt_synch; @@ -1591,21 +1628,22 @@ void *UE_thread(void *arg) (void)dummy_rx; /* avoid gcc warnings */ usleep(500); #else - // grab 10 ms of signal into dummy buffer if (UE->mode != loop_through_memory) { for (int i=0; iframe_parms.nb_antennas_rx; i++) rxp[i] = (void *)&dummy_rx[i][0]; - for (int sf=0; sf<10; sf++) + for (int sf=0; sf<10; sf++) { // printf("Reading dummy sf %d\n",sf); UE->rfdevice.trx_read_func(&UE->rfdevice, ×tamp, rxp, UE->frame_parms.samples_per_tti, UE->frame_parms.nb_antennas_rx); + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + } } - #endif } } // UE->is_synchronized==0 @@ -1616,12 +1654,17 @@ void *UE_thread(void *arg) if (UE->mode != loop_through_memory) { if (UE->no_timing_correction==0) { LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); - AssertFatal(UE->rx_offset == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - (void **)UE->common_vars.rxdata, - UE->rx_offset, - UE->frame_parms.nb_antennas_rx),""); + while ( UE->rx_offset ) { + size_t s=min(UE->rx_offset,UE->frame_parms.samples_per_tti); + AssertFatal(s == UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + (void **)UE->common_vars.rxdata, + s, + UE->frame_parms.nb_antennas_rx),""); + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + UE->rx_offset-=s; + } } UE->rx_offset=0; @@ -1662,6 +1705,7 @@ void *UE_thread(void *arg) pthread_mutex_unlock(&proc->mutex_rxtx); } + usleep(300); } LOG_D(PHY,"Process Subframe %d thread Idx %d \n", sub_frame, UE->current_thread_id[sub_frame]); @@ -2014,7 +2058,7 @@ void fill_ue_band_info(void) #endif int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, - openair0_config_t *openair0_cfg) + openair0_config_t *openair0_cfg) { int i, CC_id; LTE_DL_FRAME_PARMS *frame_parms; @@ -2206,8 +2250,8 @@ int init_timer_thread(void) * fix it somehow */ int8_t find_dlsch(uint16_t rnti, - PHY_VARS_eNB *eNB, - find_type_t type) + PHY_VARS_eNB *eNB, + find_type_t type) { printf("you cannot read this\n"); abort(); diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index cd96b8adf4..25371260bf 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -79,10 +79,7 @@ #include "UTIL/OTG/otg_vars.h" #endif -#if defined(ENABLE_ITTI) - #include "create_tasks.h" -#endif - +#include "create_tasks.h" #include "system.h" @@ -123,7 +120,7 @@ clock_source_t clock_source = internal,time_source=internal; unsigned int mmapped_dma=0; -uint32_t downlink_frequency[MAX_NUM_CCs][4]; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; @@ -169,7 +166,6 @@ int rx_input_level_dBm; static LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; -uint8_t exit_missed_slots=1; uint64_t num_missed_slots=0; // counter for the number of missed slots // prototypes from function implemented in lte-ue.c, probably should be elsewhere in a include file. @@ -264,26 +260,6 @@ unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { } - -void signal_handler(int sig) { - void *array[10]; - size_t size; - - if (sig==SIGSEGV) { - // get void*'s for all entries on the stack - size = backtrace(array, 10); - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, 2); - exit(-1); - } else { - char msg[64]; - sprintf(msg,"Received linux signal %s...\n",strsignal(sig)); - exit_function(__FILE__, __FUNCTION__, __LINE__,msg); - } -} - - void exit_function(const char *file, const char *function, const int line, const char *s) { int CC_id; logClean(); @@ -321,7 +297,7 @@ static void get_options(void) { CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); /* unknown parameters on command line will be checked in main after all init have been performed */ - get_common_options(); + get_common_options(SOFTMODEM_4GUE_BIT ); get_uethreads_params(); paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC; paramdef_t cmdline_ueparams[] =CMDLINE_UEPARAMS_DESC; @@ -596,9 +572,6 @@ int main( int argc, char **argv ) { get_options (); - if (is_nos1exec(argv[0]) ) - set_softmodem_optmask(SOFTMODEM_NOS1_BIT); - EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1; printf("Running with %d UE instances\n",NB_UE_INST); @@ -645,10 +618,7 @@ int main( int argc, char **argv ) { printf ("PDCP PC5S socket\n"); pdcp_pc5_socket_init(); // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGABRT, signal_handler); + set_softmodem_sighandler(); check_clock(); #ifndef PACKAGE_VERSION # define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" @@ -807,19 +777,11 @@ int main( int argc, char **argv ) { // wait for end of program printf("TYPE TO TERMINATE\n"); //getchar(); -#if defined(ENABLE_ITTI) printf("Entering ITTI signals handler\n"); itti_wait_tasks_end(); printf("Returned from ITTI signal handler\n"); oai_exit=1; printf("oai_exit=%d\n",oai_exit); -#else - - while (oai_exit==0) - rt_sleep_ns(100000000ULL); - - printf("Terminating application - oai_exit=%d\n",oai_exit); -#endif // stop threads if(IS_SOFTMODEM_DOFORMS) diff --git a/targets/RT/USER/ru_control.c b/targets/RT/USER/ru_control.c index d13abfc753..6daf0f4dfa 100644 --- a/targets/RT/USER/ru_control.c +++ b/targets/RT/USER/ru_control.c @@ -483,6 +483,27 @@ void configure_rru(int idx, phy_init_RU(ru); } +static int send_update_rru(RU_t * ru, LTE_DL_FRAME_PARMS * fp){ + //ssize_t msg_len/*,len*/; + int i; + //LTE_DL_FRAME_PARMS *fp = &RC.eNB[0][0]->frame_parms; + RRU_CONFIG_msg_t rru_config_msg; + memset((void *)&rru_config_msg,0,sizeof(rru_config_msg)); + rru_config_msg.type = RRU_config_update; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + LOG_I(PHY,"Sending RAU tick to RRU %d %lu bytes\n",ru->idx,rru_config_msg.len); + + RRU_config_t *config = (RRU_config_t *)&rru_config_msg.msg[0]; + config->num_MBSFN_config=fp->num_MBSFN_config; + for(i=0; i < fp->num_MBSFN_config; i++){ + config->MBSFN_config[i] = fp->MBSFN_config[i]; + LOG_W(PHY,"Configuration send to RAU (num MBSFN %d, MBSFN_SubframeConfig[%d] pattern is %x )\n",config->num_MBSFN_config,i,config->MBSFN_config[i].mbsfn_SubframeConfig); + + } + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d cannot access remote radio\n",ru->idx); + return 0; +} void* ru_thread_control( void* param ) { @@ -491,6 +512,7 @@ void* ru_thread_control( void* param ) RRU_CONFIG_msg_t rru_config_msg; ssize_t msg_len; int len; + int ru_sf_update=0; // SF config update flag (MBSFN) // Start IF device if any if (ru->start_if) { @@ -512,6 +534,16 @@ void* ru_thread_control( void* param ) if (ru->state == RU_IDLE && ru->if_south != LOCAL_RF) send_tick(ru); + if (ru->state == RU_RUN && ru->if_south != LOCAL_RF){ + LTE_DL_FRAME_PARMS *fp = &RC.eNB[0][0]->frame_parms; + LOG_D(PHY,"Check MBSFN SF changes\n"); + if(fp->num_MBSFN_config != ru_sf_update){ + ru_sf_update = fp->num_MBSFN_config; + LOG_W(PHY,"RU SF should be updated ... calling send_update_rru(ru)\n"); + send_update_rru(ru,fp); + } + } + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, @@ -646,6 +678,30 @@ void* ru_thread_control( void* param ) } } break; + case RRU_config_update: //RRU + if (ru->if_south == LOCAL_RF){ + LOG_W(PHY,"Configuration update received from RAU \n"); + + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + + LOG_W(PHY,"New MBSFN config received from RAU --- num_MBSFN_config %d\n",((RRU_config_t *)&rru_config_msg.msg[0])->num_MBSFN_config); + ru->frame_parms->num_MBSFN_config = ((RRU_config_t *)&rru_config_msg.msg[0])->num_MBSFN_config; + for(int i=0; i < ((RRU_config_t *)&rru_config_msg.msg[0])->num_MBSFN_config; i++){ + ru->frame_parms->MBSFN_config[i].mbsfn_SubframeConfig=((RRU_config_t *)&rru_config_msg.msg[0])->MBSFN_config[i].mbsfn_SubframeConfig; + LOG_W(PHY,"Configuration received from RAU (num MBSFN %d, MBSFN_SubframeConfig[%d] pattern is %x )\n", + ((RRU_config_t *)&rru_config_msg.msg[0])->num_MBSFN_config, + i, + ((RRU_config_t *)&rru_config_msg.msg[0])->MBSFN_config[i].mbsfn_SubframeConfig + ); + } + } else LOG_E(PHY,"Received RRU_config msg...Ignoring\n"); + break; + case RRU_config_update_ok: //RAU + if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_config_update_ok msg...Ignoring\n"); + else{ + LOG_W(PHY,"Received RRU_config_update_ok msg...\n"); + } + break; case RRU_start: // RRU if (ru->if_south == LOCAL_RF){
Log File Name$NAME_ENB --- $NAME_UEN/AOK