From 8585bec317470bd91aa09d3274748af569ec5b75 Mon Sep 17 00:00:00 2001 From: Andrea Lacava Date: Sun, 25 Sep 2022 14:08:28 +0200 Subject: [PATCH] First release Signed-off-by: Andrea Lacava Change-Id: I1992a91fb1d0cdf8a0ccb33527a24f6a8aba1faa --- README.md | 24 + doc/oran-interface.rst | 98 +++ examples/e2sim-integration-example.cc | 60 ++ examples/l3-rrc-example.cc | 120 ++++ examples/oran-interface-example.cc | 145 +++++ examples/ric-control-function-desc.cc | 40 ++ examples/ric-indication-messages.cc | 230 +++++++ examples/test-wrappers.cc | 54 ++ examples/wscript | 20 + helper/indication-message-helper.cc | 84 +++ helper/indication-message-helper.h | 64 ++ helper/lte-indication-message-helper.cc | 106 ++++ helper/lte-indication-message-helper.h | 55 ++ helper/mmwave-indication-message-helper.cc | 194 ++++++ helper/mmwave-indication-message-helper.h | 73 +++ helper/oran-interface-helper.cc | 33 + helper/oran-interface-helper.h | 37 ++ model/asn1c-types.cc | 963 +++++++++++++++++++++++++++++ model/asn1c-types.h | 357 +++++++++++ model/function-description.cc | 69 +++ model/function-description.h | 59 ++ model/kpm-function-description.cc | 147 +++++ model/kpm-function-description.h | 62 ++ model/kpm-indication.cc | 506 +++++++++++++++ model/kpm-indication.h | 256 ++++++++ model/oran-interface.cc | 288 +++++++++ model/oran-interface.h | 161 +++++ model/ric-control-function-description.cc | 232 +++++++ model/ric-control-function-description.h | 51 ++ model/ric-control-message.cc | 218 +++++++ model/ric-control-message.h | 76 +++ test/oran-interface-test-suite.cc | 90 +++ wscript | 57 ++ 33 files changed, 5029 insertions(+) create mode 100644 README.md create mode 100644 doc/oran-interface.rst create mode 100644 examples/e2sim-integration-example.cc create mode 100644 examples/l3-rrc-example.cc create mode 100644 examples/oran-interface-example.cc create mode 100644 examples/ric-control-function-desc.cc create mode 100644 examples/ric-indication-messages.cc create mode 100644 examples/test-wrappers.cc create mode 100644 examples/wscript create mode 100644 helper/indication-message-helper.cc create mode 100644 helper/indication-message-helper.h create mode 100644 helper/lte-indication-message-helper.cc create mode 100644 helper/lte-indication-message-helper.h create mode 100644 helper/mmwave-indication-message-helper.cc create mode 100644 helper/mmwave-indication-message-helper.h create mode 100644 helper/oran-interface-helper.cc create mode 100644 helper/oran-interface-helper.h create mode 100644 model/asn1c-types.cc create mode 100644 model/asn1c-types.h create mode 100644 model/function-description.cc create mode 100644 model/function-description.h create mode 100644 model/kpm-function-description.cc create mode 100644 model/kpm-function-description.h create mode 100644 model/kpm-indication.cc create mode 100644 model/kpm-indication.h create mode 100644 model/oran-interface.cc create mode 100644 model/oran-interface.h create mode 100644 model/ric-control-function-description.cc create mode 100644 model/ric-control-function-description.h create mode 100644 model/ric-control-message.cc create mode 100644 model/ric-control-message.h create mode 100644 test/oran-interface-test-suite.cc create mode 100644 wscript diff --git a/README.md b/README.md new file mode 100644 index 0000000..36c0783 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# ns3-o-ran-e2 + +================================ + +This ns-3 module enables the support for running multiple terminations of an O-RAN-compliant E2 interface inside the simulation process. It has been developed by a team at the [Institute for the Wireless Internet of Things (WIoT)](https://wiot.northeastern.edu) at Northeastern University, in collaboration with the University of Padova and with support from Mavenir. + +# References + +TBD + + +# How to use + +This module can be used with an extension of the [ns3-mmWave module](https://github.com/nyuwireless-unipd/ns3-mmwave) that will soon be released. The module needs to be cloned in the contrib folder. The [e2sim library](https://github.com/o-ran-sc/sim-e2-interface) needs to be installed. + +We will provide further instructions as part of this README file. + +# Authors + +The ns3-o-ran-e2 module is the result of the development effort carried out by different people. The main contributors are: + +- Andrea Lacava, Northeastern University and Sapienza University of Rome +- Michele Polese, Northeastern University +- Tommaso Zugno, University of Padova diff --git a/doc/oran-interface.rst b/doc/oran-interface.rst new file mode 100644 index 0000000..82df1a1 --- /dev/null +++ b/doc/oran-interface.rst @@ -0,0 +1,98 @@ +Example Module Documentation +---------------------------- + +.. include:: replace.txt +.. highlight:: cpp + +.. heading hierarchy: + ------------- Chapter + ************* Section (#.#) + ============= Subsection (#.#.#) + ############# Paragraph (no number) + +This is a suggested outline for adding new module documentation to |ns3|. +See ``src/click/doc/click.rst`` for an example. + +The introductory paragraph is for describing what this code is trying to +model. + +For consistency (italicized formatting), please use |ns3| to refer to +ns-3 in the documentation (and likewise, |ns2| for ns-2). These macros +are defined in the file ``replace.txt``. + +Model Description +***************** + +The source code for the new module lives in the directory ``contrib/oran-interface``. + +Add here a basic description of what is being modeled. + +Design +====== + +Briefly describe the software design of the model and how it fits into +the existing ns-3 architecture. + +Scope and Limitations +===================== + +What can the model do? What can it not do? Please use this section to +describe the scope and limitations of the model. + +References +========== + +Add academic citations here, such as if you published a paper on this +model, or if readers should read a particular specification or other work. + +Usage +***** + +This section is principally concerned with the usage of your model, using +the public API. Focus first on most common usage patterns, then go +into more advanced topics. + +Building New Module +=================== + +Include this subsection only if there are special build instructions or +platform limitations. + +Helpers +======= + +What helper API will users typically use? Describe it here. + +Attributes +========== + +What classes hold attributes, and what are the key ones worth mentioning? + +Output +====== + +What kind of data does the model generate? What are the key trace +sources? What kind of logging output can be enabled? + +Advanced Usage +============== + +Go into further details (such as using the API outside of the helpers) +in additional sections, as needed. + +Examples +======== + +What examples using this new code are available? Describe them here. + +Troubleshooting +=============== + +Add any tips for avoiding pitfalls, etc. + +Validation +********** + +Describe how the model has been tested/validated. What tests run in the +test suite? How much API and code is covered by the tests? Again, +references to outside published work may help here. diff --git a/examples/e2sim-integration-example.cc b/examples/e2sim-integration-example.cc new file mode 100644 index 0000000..f2714d9 --- /dev/null +++ b/examples/e2sim-integration-example.cc @@ -0,0 +1,60 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "ns3/core-module.h" +#include "ns3/oran-interface.h" + +extern "C" { + // #include "OCUCP-PF-Container.h" + #include "OCTET_STRING.h" + #include "asn_application.h" + // #include "E2SM-KPM-IndicationMessage.h" + // #include "FQIPERSlicesPerPlmnListItem.h" + // #include "E2SM-KPM-RANfunction-Description.h" + // #include "E2SM-KPM-IndicationHeader-Format1.h" + // #include "E2SM-KPM-IndicationHeader.h" + // #include "Timestamp.h" + #include "E2AP-PDU.h" + #include "RICsubscriptionRequest.h" + #include "RICsubscriptionResponse.h" + #include "RICactionType.h" + #include "ProtocolIE-Field.h" + #include "ProtocolIE-SingleContainer.h" + #include "InitiatingMessage.h" +} + +#include "e2sim.hpp" + +using namespace ns3; + +int +main (int argc, char *argv[]) +{ + E2Sim e2sim; + e2sim.run_loop (argc, argv); + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/examples/l3-rrc-example.cc b/examples/l3-rrc-example.cc new file mode 100644 index 0000000..5264cf5 --- /dev/null +++ b/examples/l3-rrc-example.cc @@ -0,0 +1,120 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "ns3/core-module.h" +#include "ns3/oran-interface.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("L3RrcExample"); + +Ptr +CreateL3RrcUeSpecificSinrServing (long servingCellId, long physCellId, long sinr) +{ + Ptr l3RrcMeasurement = Create (RRCEvent_b1); + Ptr servingCellMeasurements = + Create (ServingCellMeasurements_PR_nr_measResultServingMOList); + + Ptr measResultNr = Create (physCellId); + Ptr measQuantityResultWrap = Create (); + measQuantityResultWrap->AddSinr (sinr); + measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ()); + Ptr measResultServMo = + Create (servingCellId, measResultNr->GetValue ()); + servingCellMeasurements->AddMeasResultServMo (measResultServMo->GetPointer ()); + l3RrcMeasurement->AddServingCellMeasurement (servingCellMeasurements->GetPointer ()); + return l3RrcMeasurement; +} + +Ptr +CreateL3RrcUeSpecificSinrNeigh (long neighCellId, long sinr) +{ + Ptr l3RrcMeasurement = Create (RRCEvent_b1); + Ptr measResultNr = Create (neighCellId); + Ptr measQuantityResultWrap = Create (); + measQuantityResultWrap->AddSinr (sinr); + measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ()); + + l3RrcMeasurement->AddMeasResultNRNeighCells ( + measResultNr->GetPointer ()); // MAX 8 UE per message (standard) + + return l3RrcMeasurement; +} + + +// The memory leaks occurring in this file are wanted because L3-RRC is usually freed after use in the Ric Indication Message + +int +main (int argc, char *argv[]) +{ + LogComponentEnableAll (LOG_PREFIX_ALL); + LogComponentEnable ("L3RrcExample", LOG_LEVEL_ALL); + LogComponentEnable ("Asn1Types", LOG_LEVEL_ALL); + + // 1 UE-specific (L3) SINR from NR serving cells + NS_LOG_INFO ("1 UE-specific (L3) SINR from NR serving cells"); + Ptr l3RrcMeasurement1 = CreateL3RrcUeSpecificSinrServing (1, 1, 10); + xer_fprint (stderr, &asn_DEF_L3_RRC_Measurements, l3RrcMeasurement1->GetPointer ()); + + // 2 UE-specific (L3) SINR from NR neighboring cells + NS_LOG_INFO ("2 UE-specific (L3) SINR from NR neighboring cells"); + Ptr l3RrcMeasurement2 = CreateL3RrcUeSpecificSinrNeigh (2, 20); + + // 3 UE-specific (L3) SINR report from NR neighboring cells + NS_LOG_INFO ("3 UE-specific (L3) SINR report from NR neighboring cells"); + long neighCellId3 = 3; + long sinr3 = 30; + + Ptr measResultNr3 = Create (neighCellId3); + Ptr measQuantityResultWrap3 = Create (); + measQuantityResultWrap3->AddSinr (sinr3); + measResultNr3->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap3->GetPointer ()); + + l3RrcMeasurement2->AddMeasResultNRNeighCells (measResultNr3->GetPointer ()); + + xer_fprint (stderr, &asn_DEF_L3_RRC_Measurements, l3RrcMeasurement2->GetPointer ()); + + // 4 UE-specific (L3) SINR from LTE serving cells + NS_LOG_INFO ("4 UE-specific (L3) SINR from LTE serving cells"); + long eutraPhysCellId4 = 4; + long servCellId4 = 4; + long sinr4 = 40; + Ptr l3RrcMeasurement4 = + CreateL3RrcUeSpecificSinrServing (servCellId4, eutraPhysCellId4, sinr4); + xer_fprint (stderr, &asn_DEF_L3_RRC_Measurements, l3RrcMeasurement4->GetPointer ()); + + + // 5 UE-specific (L3) SINR from LTE neighboring cells + NS_LOG_INFO ("5 UE-specific (L3) SINR from LTE neighboring cells"); + long neighCellId5 = 5; + long sinr5 = 50; + Ptr l3RrcMeasurement3 = Create (RRCEvent_a5); + Ptr measResultEutra5 = Create (neighCellId5); + measResultEutra5->AddSinr (sinr5); + l3RrcMeasurement3->AddMeasResultEUTRANeighCells (measResultEutra5->GetPointer ()); + xer_fprint (stderr, &asn_DEF_L3_RRC_Measurements, l3RrcMeasurement3->GetPointer ()); + + + return 0; +} diff --git a/examples/oran-interface-example.cc b/examples/oran-interface-example.cc new file mode 100644 index 0000000..d6d763e --- /dev/null +++ b/examples/oran-interface-example.cc @@ -0,0 +1,145 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "ns3/core-module.h" +#include "ns3/oran-interface.h" +#include "encode_e2apv1.hpp" +#include + + +using namespace ns3; + +Ptr e2Term; +// TODO create getters for these parameters in e2Term +std::string plmId = "111"; +uint16_t cellId = 1; +const std::string gnb = std::to_string (cellId); + +/** +* Creates an empty RIC Report message and send it to the RIC +* +* \param params the RIC Subscription Request parameters +*/ +static void BuildAndSendReportMessage (E2Termination::RicSubscriptionRequest_rval_s params) +{ + KpmIndicationHeader::KpmRicIndicationHeaderValues headerValues; + headerValues.m_plmId = plmId; + headerValues.m_gnbId = cellId; + headerValues.m_nrCellId = cellId; + + Ptr header = Create (KpmIndicationHeader::GlobalE2nodeType::gNB, headerValues); + + KpmIndicationMessage::KpmIndicationMessageValues msgValues; + + Ptr cuUpValues = Create (); + cuUpValues->m_plmId = plmId; + cuUpValues->m_pDCPBytesUL = 100; + cuUpValues->m_pDCPBytesDL = 100; + msgValues.m_pmContainerValues = cuUpValues; + + Ptr ue0DummyValues = Create ("UE-0"); + ue0DummyValues->AddItem ("DRB.PdcpSduVolumeDl_Filter.UEID", 6); + ue0DummyValues->AddItem ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7); + ue0DummyValues->AddItem ("Tot.PdcpSduNbrDl.UEID", 8); + ue0DummyValues->AddItem ("DRB.PdcpPduNbrDl.Qos.UEID", 9); + ue0DummyValues->AddItem ("DRB.IPThpDl.UEID", 10.0); + ue0DummyValues->AddItem ("DRB.IPLateDl.UEID", 11.0); + msgValues.m_ueIndications.insert (ue0DummyValues); + + Ptr ue1DummyValues = Create ("UE-1");; + ue1DummyValues->AddItem ("DRB.PdcpSduVolumeDl_Filter.UEID", 6); + ue1DummyValues->AddItem ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7); + ue1DummyValues->AddItem ("Tot.PdcpSduNbrDl.UEID", 8); + ue1DummyValues->AddItem ("DRB.PdcpPduNbrDl.Qos.UEID", 9); + ue1DummyValues->AddItem ("DRB.IPThpDl.UEID", 10.0); + ue1DummyValues->AddItem ("DRB.IPLateDl.UEID", 11.0); + msgValues.m_ueIndications.insert (ue1DummyValues); + + Ptr msg = Create (msgValues); + + E2AP_PDU *pdu_cuup_ue = new E2AP_PDU; + encoding::generate_e2apv1_indication_request_parameterized(pdu_cuup_ue, + params.requestorId, + params.instanceId, + params.ranFuncionId, + params.actionId, + 1, // TODO sequence number + (uint8_t*) header->m_buffer, // buffer containing the encoded header + header->m_size, // size of the encoded header + (uint8_t*) msg->m_buffer, // buffer containing the encoded message + msg->m_size); // size of the encoded message + e2Term->SendE2Message (pdu_cuup_ue); + delete pdu_cuup_ue; + +} + +/** +* KPM Subscription Request callback. +* This function is triggered whenever a RIC Subscription Request for +* the KPM RAN Function is received. +* +* \param pdu request message +*/ +static void KpmSubscriptionCallback (E2AP_PDU_t* sub_req_pdu) +{ + NS_LOG_UNCOND ("\n\nReceived RIC Subscription Request"); + + E2Termination::RicSubscriptionRequest_rval_s params = e2Term->ProcessRicSubscriptionRequest (sub_req_pdu); + NS_LOG_UNCOND ("requestorId " << +params.requestorId << + ", instanceId " << +params.instanceId << + ", ranFuncionId " << +params.ranFuncionId << + ", actionId " << +params.actionId); + + BuildAndSendReportMessage (params); +} + +/** +* RIC Control Message callback. +* This function is triggered whenever a RIC Control Message is received. +* +* \param pdu request message +*/ +static void +RicControlMessageCallback (E2AP_PDU_t *ric_ctrl_pdu) +{ + NS_LOG_UNCOND ("\n\nReceived RIC Control Message"); + + RicControlMessage msg = RicControlMessage (ric_ctrl_pdu); + // TODO log something +} + + +int +main (int argc, char *argv[]) +{ + LogComponentEnable ("Asn1Types", LOG_LEVEL_ALL); + LogComponentEnable ("RicControlMessage", LOG_LEVEL_ALL); + e2Term = CreateObject ("10.244.0.191", 36422, 38472, gnb, plmId); + Ptr kpmFd = Create (); + e2Term->RegisterKpmCallbackToE2Sm (200, kpmFd, &KpmSubscriptionCallback); + Ptr rcFd = Create (); + e2Term->RegisterSmCallbackToE2Sm (300, rcFd, &RicControlMessageCallback); + + return 0; +} diff --git a/examples/ric-control-function-desc.cc b/examples/ric-control-function-desc.cc new file mode 100644 index 0000000..4e1f894 --- /dev/null +++ b/examples/ric-control-function-desc.cc @@ -0,0 +1,40 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "ns3/core-module.h" +#include "ns3/oran-interface.h" + +using namespace ns3; + + + +int +main (int argc, char *argv[]) +{ + LogComponentEnable ("Asn1Types", LOG_LEVEL_ALL); + LogComponentEnable ("RicControlMessage", LOG_LEVEL_ALL); + Ptr rcFd = Create (); + + return 0; +} diff --git a/examples/ric-indication-messages.cc b/examples/ric-indication-messages.cc new file mode 100644 index 0000000..6605a57 --- /dev/null +++ b/examples/ric-indication-messages.cc @@ -0,0 +1,230 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "ns3/core-module.h" +#include "ns3/oran-interface.h" +#include + +using namespace ns3; + +/** +* Create and encode RIC Indication messages. +* Prints the encoded messages in XML format. +*/ +int +main (int argc, char *argv[]) +{ + // LogComponentEnable ("Asn1Types", LOG_LEVEL_ALL); + LogComponentEnable ("KpmIndication", LOG_LEVEL_INFO); + LogComponentEnable ("KpmFunctionDescription", LOG_LEVEL_INFO); + + std::string plmId = "111"; + std::string gnbId = "1"; + uint16_t nrCellId = 5; + + uint64_t timestamp = 1630068655325; + // "12:58:04.123456"; + uint64_t timestamp2 = 1630068679511; + // "12:58:05.123457"; + uint64_t timestamp3 = 1630068680196; + // "12:58:06.123458"; + uint64_t timestamp4 = 1630068681372; + // "12:58:07.123459"; + + NS_LOG_UNCOND ("----------- Begin of Kpm Indication header -----------"); + + KpmIndicationHeader::KpmRicIndicationHeaderValues headerValues; + headerValues.m_plmId = plmId; + headerValues.m_gnbId = gnbId; + headerValues.m_nrCellId = nrCellId; + headerValues.m_timestamp = timestamp; + +KpmIndicationHeader::KpmRicIndicationHeaderValues headerValues2; + headerValues2.m_plmId = plmId; + headerValues2.m_gnbId = gnbId; + headerValues2.m_nrCellId = nrCellId; + headerValues2.m_timestamp = timestamp2; + + KpmIndicationHeader::KpmRicIndicationHeaderValues headerValues3; + headerValues3.m_plmId = plmId; + headerValues3.m_gnbId = gnbId; + headerValues3.m_nrCellId = nrCellId; + headerValues3.m_timestamp = timestamp3; + + KpmIndicationHeader::KpmRicIndicationHeaderValues headerValues4; + headerValues4.m_plmId = plmId; + headerValues4.m_gnbId = gnbId; + headerValues4.m_nrCellId = nrCellId; + headerValues4.m_timestamp = timestamp4; + + Ptr header = Create (KpmIndicationHeader::GlobalE2nodeType::eNB, headerValues); + Ptr header2 = Create (KpmIndicationHeader::GlobalE2nodeType::gNB, headerValues2); + Ptr header3 = Create (KpmIndicationHeader::GlobalE2nodeType::ng_eNB, headerValues3); + Ptr header4 = Create (KpmIndicationHeader::GlobalE2nodeType::en_gNB, headerValues4); + + NS_LOG_UNCOND ("----------- End of the Kpm Indication header -----------"); + return 0; + + KpmIndicationMessage::KpmIndicationMessageValues msgValues1; + + NS_LOG_UNCOND ("----------- Begin of the CU-UP message -----------"); + + // Begin example CU-UP + // uncomment this to test CU-UP + + Ptr cuUpValues = Create (); + cuUpValues->m_plmId = plmId; + cuUpValues->m_pDCPBytesUL = 100; + cuUpValues->m_pDCPBytesDL = 100; + + Ptr ue0DummyValues = Create ("UE-0"); + ue0DummyValues->AddItem ("DRB.PdcpSduVolumeDl_Filter.UEID", 6); + ue0DummyValues->AddItem ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7); + ue0DummyValues->AddItem ("Tot.PdcpSduNbrDl.UEID", 8); + ue0DummyValues->AddItem ("DRB.PdcpPduNbrDl.Qos.UEID", 9); + ue0DummyValues->AddItem ("DRB.IPThpDl.UEID", 10.0); + ue0DummyValues->AddItem ("DRB.IPLateDl.UEID", 11.0); + msgValues1.m_ueIndications.insert (ue0DummyValues); + + Ptr ue1DummyValues = Create ("UE-1"); + ue1DummyValues->AddItem ("DRB.PdcpSduVolumeDl_Filter.UEID", 6); + ue1DummyValues->AddItem ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7); + ue1DummyValues->AddItem ("Tot.PdcpSduNbrDl.UEID", 8); + ue1DummyValues->AddItem ("DRB.PdcpPduNbrDl.Qos.UEID", 9); + ue1DummyValues->AddItem ("DRB.IPThpDl.UEID", 10.0); + ue1DummyValues->AddItem ("DRB.IPLateDl.UEID", 11.0); + msgValues1.m_ueIndications.insert(ue1DummyValues); + msgValues1.m_pmContainerValues = cuUpValues; + + Ptr msg = Create (msgValues1); + + NS_LOG_UNCOND ("----------- End of the CU-UP message -----------"); + + NS_LOG_UNCOND ("----------- Begin of the CU-CP message -----------"); + KpmIndicationMessage::KpmIndicationMessageValues msgValues2; + msgValues2.m_cellObjectId = "NRCellCU"; + Ptr cuCpValues = Create (); + cuCpValues->m_numActiveUes = 100; + + Ptr ue2DummyValues = + Create ("UE-2"); + ue2DummyValues->AddItem ("DRB.EstabSucc.5QI.UEID", 6); + ue2DummyValues->AddItem ("DRB.RelActNbr.5QI.UEID", 7); + msgValues2.m_ueIndications.insert (ue2DummyValues); + + Ptr ue3DummyValues = + Create ("UE-3"); + ue3DummyValues->AddItem ("DRB.EstabSucc.5QI.UEID", 6); + ue3DummyValues->AddItem ("DRB.RelActNbr.5QI.UEID", 7); + msgValues2.m_ueIndications.insert (ue3DummyValues); + + Ptr ue4DummyValues = + Create ("UE-4"); + + Ptr l3RrcMeasurement = Create (RRCEvent_b1); + Ptr servingCellMeasurements = + Create (ServingCellMeasurements_PR_nr_measResultServingMOList); + + Ptr measResultNr = Create (39); + Ptr measQuantityResultWrap = Create (); + measQuantityResultWrap->AddSinr (20); + measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ()); + Ptr measResultServMo = + Create (10, measResultNr->GetValue ()); + servingCellMeasurements->AddMeasResultServMo (measResultServMo->GetPointer ()); + l3RrcMeasurement->AddServingCellMeasurement (servingCellMeasurements->GetPointer ()); + + ue4DummyValues->AddItem> ("calla",l3RrcMeasurement); + ue4DummyValues->AddItem ("DRB.RelActNbr.5QI.UEID", 7); + msgValues2.m_ueIndications.insert (ue4DummyValues); + msgValues2.m_pmContainerValues = cuCpValues; + + Ptr msg2 = Create (msgValues2); + NS_LOG_UNCOND ("----------- End of the CU-CP message -----------"); + + NS_LOG_UNCOND ("----------- Begin test of the DU message -----------"); + KpmIndicationMessage::KpmIndicationMessageValues msgValues3; + msgValues3.m_cellObjectId = "NRCellCU"; + + Ptr oDuContainerVal = Create (); + Ptr cellResRep = Create (); + cellResRep->m_plmId = "111"; + // std::stringstream ss; + // ss << std::hex << 1340012; + cellResRep->m_nrCellId = 2; + cellResRep->dlAvailablePrbs = 6; + cellResRep->ulAvailablePrbs = 6; + + Ptr cellResRep2 = Create (); + cellResRep2->m_plmId = "444"; + cellResRep2->m_nrCellId = 3; + cellResRep2->dlAvailablePrbs = 5; + cellResRep2->ulAvailablePrbs = 5; + + Ptr servedPlmnPerCell = Create (); + servedPlmnPerCell->m_plmId = "121"; + servedPlmnPerCell->m_nrCellId = 3; + + Ptr servedPlmnPerCell2 = Create (); + servedPlmnPerCell2->m_plmId = "121"; + servedPlmnPerCell2->m_nrCellId = 2; + + Ptr epcDuVal = Create (); + epcDuVal->m_qci = 1; + epcDuVal->m_dlPrbUsage = 1; + epcDuVal->m_ulPrbUsage = 2; + + Ptr epcDuVal2 = Create (); + epcDuVal2->m_qci = 1; + epcDuVal2->m_dlPrbUsage = 3; + epcDuVal2->m_ulPrbUsage = 4; + + servedPlmnPerCell->m_perQciReportItems.insert (epcDuVal); + servedPlmnPerCell->m_perQciReportItems.insert (epcDuVal2); + servedPlmnPerCell2->m_perQciReportItems.insert (epcDuVal); + servedPlmnPerCell2->m_perQciReportItems.insert (epcDuVal2); + cellResRep->m_servedPlmnPerCellItems.insert (servedPlmnPerCell2); + cellResRep->m_servedPlmnPerCellItems.insert (servedPlmnPerCell); + cellResRep2->m_servedPlmnPerCellItems.insert (servedPlmnPerCell2); + cellResRep2->m_servedPlmnPerCellItems.insert (servedPlmnPerCell); + + oDuContainerVal->m_cellResourceReportItems.insert (cellResRep); + oDuContainerVal->m_cellResourceReportItems.insert (cellResRep2); + + Ptr ue5DummyValues = Create ("UE-5"); + ue5DummyValues->AddItem ("DRB.EstabSucc.5QI.UEID", 6); + ue5DummyValues->AddItem ("DRB.RelActNbr.5QI.UEID", 7); + msgValues3.m_ueIndications.insert (ue5DummyValues); + + msgValues3.m_pmContainerValues = oDuContainerVal; + Ptr msg3 = Create (msgValues3); + + NS_LOG_UNCOND ("----------- End test of the DU message -----------"); + + NS_LOG_UNCOND ("----------- Begin test of the KpmFunctionDescription -----------"); + Ptr fd = Create (); + NS_LOG_UNCOND ("----------- End test of the KpmFunctionDescription -----------"); + + return 0; +} diff --git a/examples/test-wrappers.cc b/examples/test-wrappers.cc new file mode 100644 index 0000000..16477ad --- /dev/null +++ b/examples/test-wrappers.cc @@ -0,0 +1,54 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "ns3/core-module.h" +#include "ns3/oran-interface.h" +#include + +using namespace ns3; + +/** +* Test field for the wrappers and their functions +*/ +int +main (int argc, char *argv[]) +{ + // LogComponentEnable ("Asn1Types", LOG_LEVEL_ALL); + std::string test = "test"; +// Ptr one = Create (test, test.size ()); + // Ptr due = Create (test, test.size ()); + // Ptr snssai = Create ("test"); + + // std::cout << due->DecodeContent() << std::endl; + + std::vector> nrCellIds; + for (uint16_t i = 0; i < 20; i++) + { + nrCellIds.push_back(Create (i)); + NS_LOG_UNCOND ("Count: " << i << " , value: "); + xer_fprint (stdout, &asn_DEF_BIT_STRING, nrCellIds[i]->GetPointer ()); + } + + return 0; +} diff --git a/examples/wscript b/examples/wscript new file mode 100644 index 0000000..ac88cd1 --- /dev/null +++ b/examples/wscript @@ -0,0 +1,20 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_program('e2sim-integration-example', ['oran-interface']) + obj.source = 'e2sim-integration-example.cc' + + obj = bld.create_ns3_program('oran-interface-example', ['oran-interface']) + obj.source = 'oran-interface-example.cc' + + obj = bld.create_ns3_program('ric-indication-messages', ['oran-interface']) + obj.source = 'ric-indication-messages.cc' + + obj = bld.create_ns3_program('ric-control-function-desc', ['oran-interface']) + obj.source = 'ric-control-function-desc.cc' + + obj = bld.create_ns3_program('l3-rrc-example', ['oran-interface']) + obj.source = 'l3-rrc-example.cc' + + obj = bld.create_ns3_program('test-wrappers', ['oran-interface']) + obj.source = 'test-wrappers.cc' diff --git a/helper/indication-message-helper.cc b/helper/indication-message-helper.cc new file mode 100644 index 0000000..3783400 --- /dev/null +++ b/helper/indication-message-helper.cc @@ -0,0 +1,84 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include + +namespace ns3 { + +IndicationMessageHelper::IndicationMessageHelper (IndicationMessageType type, bool isOffline, + bool reducedPmValues) + : m_type (type), m_offline (isOffline), m_reducedPmValues (reducedPmValues) +{ + + if (!m_offline) + { + switch (type) + { + case IndicationMessageType::CuUp: + m_cuUpValues = Create (); + break; + + case IndicationMessageType::CuCp: + m_cuCpValues = Create (); + m_msgValues.m_cellObjectId = "NRCellCU"; + break; + + case IndicationMessageType::Du: + m_duValues = Create (); + break; + + default: + + break; + } + } +} + +void +IndicationMessageHelper::FillBaseCuUpValues (std::string plmId) +{ + NS_ABORT_MSG_IF (m_type != IndicationMessageType::CuUp, "Wrong function for this object"); + m_cuUpValues->m_plmId = plmId; + m_msgValues.m_pmContainerValues = m_cuUpValues; +} + +void +IndicationMessageHelper::FillBaseCuCpValues (uint16_t numActiveUes) +{ + NS_ABORT_MSG_IF (m_type != IndicationMessageType::CuCp, "Wrong function for this object"); + m_cuCpValues->m_numActiveUes = numActiveUes; + m_msgValues.m_pmContainerValues = m_cuCpValues; +} + +IndicationMessageHelper::~IndicationMessageHelper () +{ +} + +Ptr +IndicationMessageHelper::CreateIndicationMessage () +{ + return Create (m_msgValues); +} + +} // namespace ns3 \ No newline at end of file diff --git a/helper/indication-message-helper.h b/helper/indication-message-helper.h new file mode 100644 index 0000000..605f633 --- /dev/null +++ b/helper/indication-message-helper.h @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef INDICATION_MESSAGE_HELPER_H +#define INDICATION_MESSAGE_HELPER_H + +#include + +namespace ns3 { + +class IndicationMessageHelper : public Object +{ +public: + enum class IndicationMessageType { CuCp = 0, CuUp = 1, Du = 2 }; + IndicationMessageHelper (IndicationMessageType type, bool isOffline, bool reducedPmValues); + + ~IndicationMessageHelper (); + + Ptr CreateIndicationMessage (); + + bool const & + IsOffline () const + { + return m_offline; + } + +protected: + void FillBaseCuUpValues (std::string plmId); + + void FillBaseCuCpValues (uint16_t numActiveUes); + + IndicationMessageType m_type; + bool m_offline; + bool m_reducedPmValues; + KpmIndicationMessage::KpmIndicationMessageValues m_msgValues; + Ptr m_cuUpValues; + Ptr m_cuCpValues; + Ptr m_duValues; +}; + +} // namespace ns3 + +#endif /* INDICATION_MESSAGE_HELPER_H */ \ No newline at end of file diff --git a/helper/lte-indication-message-helper.cc b/helper/lte-indication-message-helper.cc new file mode 100644 index 0000000..1f77021 --- /dev/null +++ b/helper/lte-indication-message-helper.cc @@ -0,0 +1,106 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + + +#include + +namespace ns3 { + +LteIndicationMessageHelper::LteIndicationMessageHelper (IndicationMessageType type, bool isOffline, + bool reducedPmValues) + : IndicationMessageHelper (type, isOffline, reducedPmValues) +{ + NS_ABORT_MSG_IF (type == IndicationMessageType::Du, + "Wrong type for LTE Indication Message, expected CuUp or CuCp"); +} + +void +LteIndicationMessageHelper::AddCuUpUePmItem (std::string ueImsiComplete, long txBytes, + long txDlPackets, double pdcpThroughput, + double pdcpLatency) +{ + Ptr ueVal = Create (ueImsiComplete); + + if (!m_reducedPmValues) + { + // UE-specific PDCP SDU volume from LTE eNB. Unit is Mbits + ueVal->AddItem ("DRB.PdcpSduVolumeDl_Filter.UEID", txBytes); + + // UE-specific number of PDCP SDUs from LTE eNB + ueVal->AddItem ("Tot.PdcpSduNbrDl.UEID", txDlPackets); + + // UE-specific Downlink IP combined EN-DC throughput from LTE eNB. Unit is kbps + ueVal->AddItem ("DRB.PdcpSduBitRateDl.UEID", pdcpThroughput); + + //UE-specific Downlink IP combined EN-DC throughput from LTE eNB + ueVal->AddItem ("DRB.PdcpSduDelayDl.UEID", pdcpLatency); + } + + m_msgValues.m_ueIndications.insert (ueVal); +} + +void +LteIndicationMessageHelper::AddCuUpCellPmItem (double cellAverageLatency) +{ + if (!m_reducedPmValues) + { + Ptr cellVal = Create (); + cellVal->AddItem ("DRB.PdcpSduDelayDl", cellAverageLatency); + m_msgValues.m_cellMeasurementItems = cellVal; + } +} + +void +LteIndicationMessageHelper::FillCuUpValues (std::string plmId, long pdcpBytesUl, long pdcpBytesDl) +{ + m_cuUpValues->m_pDCPBytesUL = pdcpBytesUl; + m_cuUpValues->m_pDCPBytesDL = pdcpBytesDl; + FillBaseCuUpValues (plmId); +} + +void +LteIndicationMessageHelper::FillCuCpValues (uint16_t numActiveUes) +{ + FillBaseCuCpValues (numActiveUes); +} + +void +LteIndicationMessageHelper::AddCuCpUePmItem (std::string ueImsiComplete, long numDrb, + long drbRelAct) +{ + + Ptr ueVal = Create (ueImsiComplete); + if (!m_reducedPmValues) + { + ueVal->AddItem ("DRB.EstabSucc.5QI.UEID", numDrb); + ueVal->AddItem ("DRB.RelActNbr.5QI.UEID", drbRelAct); // not modeled in the simulator + } + m_msgValues.m_ueIndications.insert (ueVal); +} + +LteIndicationMessageHelper::~LteIndicationMessageHelper () +{ +} + +} // namespace ns3 \ No newline at end of file diff --git a/helper/lte-indication-message-helper.h b/helper/lte-indication-message-helper.h new file mode 100644 index 0000000..b4c3c2d --- /dev/null +++ b/helper/lte-indication-message-helper.h @@ -0,0 +1,55 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef LTE_INDICATION_MESSAGE_HELPER_H +#define LTE_INDICATION_MESSAGE_HELPER_H + +#include + +namespace ns3 { + +class LteIndicationMessageHelper : public IndicationMessageHelper +{ +public: + LteIndicationMessageHelper (IndicationMessageType type, bool isOffline, bool reducedPmValues); + + ~LteIndicationMessageHelper (); + + void FillCuUpValues (std::string plmId, long pdcpBytesUl, long pdcpBytesDl); + + void AddCuUpUePmItem (std::string ueImsiComplete, long txBytes, long txDlPackets, + double pdcpThroughput, double pdcpLatency); + + void AddCuUpCellPmItem (double cellAverageLatency); + + void FillCuCpValues (uint16_t numActiveUes); + + void AddCuCpUePmItem (std::string ueImsiComplete, long numDrb, long drbRelAct); + +private: +}; + +} // namespace ns3 + +#endif /* LTE_INDICATION_MESSAGE_HELPER_H */ \ No newline at end of file diff --git a/helper/mmwave-indication-message-helper.cc b/helper/mmwave-indication-message-helper.cc new file mode 100644 index 0000000..9a3a531 --- /dev/null +++ b/helper/mmwave-indication-message-helper.cc @@ -0,0 +1,194 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include + +namespace ns3 { + +MmWaveIndicationMessageHelper::MmWaveIndicationMessageHelper (IndicationMessageType type, + bool isOffline, bool reducedPmValues) + : IndicationMessageHelper (type, isOffline, reducedPmValues) +{ +} + +void +MmWaveIndicationMessageHelper::AddCuUpUePmItem (std::string ueImsiComplete, + long txPdcpPduBytesNrRlc, long txPdcpPduNrRlc) +{ + Ptr ueVal = Create (ueImsiComplete); + if (!m_reducedPmValues) + { + // UE-specific PDCP PDU volume transmitted to NR gNB (Unit is Kbits) + ueVal->AddItem ("QosFlow.PdcpPduVolumeDL_Filter.UEID", txPdcpPduBytesNrRlc); + + // UE-specific number of PDCP PDUs split with NR gNB + ueVal->AddItem ("DRB.PdcpPduNbrDl.Qos.UEID", txPdcpPduNrRlc); + } + + m_msgValues.m_ueIndications.insert (ueVal); +} + +void +MmWaveIndicationMessageHelper::FillCuUpValues (std::string plmId) +{ + FillBaseCuUpValues (plmId); +} + +void +MmWaveIndicationMessageHelper::FillCuCpValues (uint16_t numActiveUes) +{ + FillBaseCuCpValues (numActiveUes); +} + +void +MmWaveIndicationMessageHelper::FillDuValues (std::string cellObjectId) +{ + m_msgValues.m_cellObjectId = cellObjectId; + m_msgValues.m_pmContainerValues = m_duValues; +} + +void +MmWaveIndicationMessageHelper::AddDuUePmItem ( + std::string ueImsiComplete, long macPduUe, long macPduInitialUe, long macQpsk, long mac16Qam, + long mac64Qam, long macRetx, long macVolume, long macPrb, long macMac04, long macMac59, + long macMac1014, long macMac1519, long macMac2024, long macMac2529, long macSinrBin1, + long macSinrBin2, long macSinrBin3, long macSinrBin4, long macSinrBin5, long macSinrBin6, + long macSinrBin7, long rlcBufferOccup, double drbThrDlUeid) +{ + + Ptr ueVal = Create (ueImsiComplete); + if (!m_reducedPmValues) + { + ueVal->AddItem ("TB.TotNbrDl.1.UEID", macPduUe); + ueVal->AddItem ("TB.TotNbrDlInitial.UEID", macPduInitialUe); + ueVal->AddItem ("TB.TotNbrDlInitial.Qpsk.UEID", macQpsk); + ueVal->AddItem ("TB.TotNbrDlInitial.16Qam.UEID", mac16Qam); + ueVal->AddItem ("TB.TotNbrDlInitial.64Qam.UEID", mac64Qam); + ueVal->AddItem ("TB.ErrTotalNbrDl.1.UEID", macRetx); + ueVal->AddItem ("QosFlow.PdcpPduVolumeDL_Filter.UEID", macVolume); + ueVal->AddItem ("RRU.PrbUsedDl.UEID", (long) std::ceil (macPrb)); + ueVal->AddItem ("CARR.PDSCHMCSDist.Bin1.UEID", macMac04); + ueVal->AddItem ("CARR.PDSCHMCSDist.Bin2.UEID", macMac59); + ueVal->AddItem ("CARR.PDSCHMCSDist.Bin3.UEID", macMac1014); + ueVal->AddItem ("CARR.PDSCHMCSDist.Bin4.UEID", macMac1519); + ueVal->AddItem ("CARR.PDSCHMCSDist.Bin5.UEID", macMac2024); + ueVal->AddItem ("CARR.PDSCHMCSDist.Bin6.UEID", macMac2529); + ueVal->AddItem ("L1M.RS-SINR.Bin34.UEID", macSinrBin1); + ueVal->AddItem ("L1M.RS-SINR.Bin46.UEID", macSinrBin2); + ueVal->AddItem ("L1M.RS-SINR.Bin58.UEID", macSinrBin3); + ueVal->AddItem ("L1M.RS-SINR.Bin70.UEID", macSinrBin4); + ueVal->AddItem ("L1M.RS-SINR.Bin82.UEID", macSinrBin5); + ueVal->AddItem ("L1M.RS-SINR.Bin94.UEID", macSinrBin6); + ueVal->AddItem ("L1M.RS-SINR.Bin127.UEID", macSinrBin7); + ueVal->AddItem ("DRB.BufferSize.Qos.UEID", rlcBufferOccup); + } + + // This value is not requested anymore, so it has been removed from the delivery, but it will be still logged; + // ueVal->AddItem ("DRB.UEThpDlPdcpBased.UEID", drbThrDlPdcpBasedUeid); + + ueVal->AddItem ("DRB.UEThpDl.UEID", drbThrDlUeid); + + m_msgValues.m_ueIndications.insert (ueVal); +} + +void +MmWaveIndicationMessageHelper::AddDuCellPmItem ( + long macPduCellSpecific, long macPduInitialCellSpecific, long macQpskCellSpecific, + long mac16QamCellSpecific, long mac64QamCellSpecific, double prbUtilizationDl, + long macRetxCellSpecific, long macVolumeCellSpecific, long macMac04CellSpecific, + long macMac59CellSpecific, long macMac1014CellSpecific, long macMac1519CellSpecific, + long macMac2024CellSpecific, long macMac2529CellSpecific, long macSinrBin1CellSpecific, + long macSinrBin2CellSpecific, long macSinrBin3CellSpecific, long macSinrBin4CellSpecific, + long macSinrBin5CellSpecific, long macSinrBin6CellSpecific, long macSinrBin7CellSpecific, + long rlcBufferOccupCellSpecific, long activeUeDl) +{ + Ptr cellVal = Create (); + + if (!m_reducedPmValues) + { + cellVal->AddItem ("TB.TotNbrDl.1", macPduCellSpecific); + cellVal->AddItem ("TB.TotNbrDlInitial", macPduInitialCellSpecific); + } + + cellVal->AddItem ("TB.TotNbrDlInitial.Qpsk", macQpskCellSpecific); + cellVal->AddItem ("TB.TotNbrDlInitial.16Qam", mac16QamCellSpecific); + cellVal->AddItem ("TB.TotNbrDlInitial.64Qam", mac64QamCellSpecific); + cellVal->AddItem ("RRU.PrbUsedDl", (long) std::ceil (prbUtilizationDl)); + + if (!m_reducedPmValues) + { + cellVal->AddItem ("TB.ErrTotalNbrDl.1", macRetxCellSpecific); + cellVal->AddItem ("QosFlow.PdcpPduVolumeDL_Filter", macVolumeCellSpecific); + cellVal->AddItem ("CARR.PDSCHMCSDist.Bin1", macMac04CellSpecific); + cellVal->AddItem ("CARR.PDSCHMCSDist.Bin2", macMac59CellSpecific); + cellVal->AddItem ("CARR.PDSCHMCSDist.Bin3", macMac1014CellSpecific); + cellVal->AddItem ("CARR.PDSCHMCSDist.Bin4", macMac1519CellSpecific); + cellVal->AddItem ("CARR.PDSCHMCSDist.Bin5", macMac2024CellSpecific); + cellVal->AddItem ("CARR.PDSCHMCSDist.Bin6", macMac2529CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin34", macSinrBin1CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin46", macSinrBin2CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin58", macSinrBin3CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin70", macSinrBin4CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin82", macSinrBin5CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin94", macSinrBin6CellSpecific); + cellVal->AddItem ("L1M.RS-SINR.Bin127", macSinrBin7CellSpecific); + cellVal->AddItem ("DRB.BufferSize.Qos", rlcBufferOccupCellSpecific); + } + + cellVal->AddItem ("DRB.MeanActiveUeDl",activeUeDl); + + m_msgValues.m_cellMeasurementItems = cellVal; +} + +void +MmWaveIndicationMessageHelper::AddDuCellResRepPmItem (Ptr cellResRep) +{ + m_duValues->m_cellResourceReportItems.insert (cellResRep); +} + +void +MmWaveIndicationMessageHelper::AddCuCpUePmItem (std::string ueImsiComplete, long numDrb, + long drbRelAct, + Ptr l3RrcMeasurementServing, + Ptr l3RrcMeasurementNeigh) +{ + + Ptr ueVal = Create (ueImsiComplete); + if (!m_reducedPmValues) + { + ueVal->AddItem ("DRB.EstabSucc.5QI.UEID", numDrb); + ueVal->AddItem ("DRB.RelActNbr.5QI.UEID", drbRelAct); // not modeled in the simulator + } + + ueVal->AddItem> ("HO.SrcCellQual.RS-SINR.UEID", l3RrcMeasurementServing); + ueVal->AddItem> ("HO.TrgtCellQual.RS-SINR.UEID", l3RrcMeasurementNeigh); + + m_msgValues.m_ueIndications.insert (ueVal); +} + +MmWaveIndicationMessageHelper::~MmWaveIndicationMessageHelper () +{ +} + +} // namespace ns3 \ No newline at end of file diff --git a/helper/mmwave-indication-message-helper.h b/helper/mmwave-indication-message-helper.h new file mode 100644 index 0000000..20cf003 --- /dev/null +++ b/helper/mmwave-indication-message-helper.h @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef MMWAVE_INDICATION_MESSAGE_HELPER_H +#define MMWAVE_INDICATION_MESSAGE_HELPER_H + +#include + +namespace ns3 { + +class MmWaveIndicationMessageHelper : public IndicationMessageHelper +{ +public: + MmWaveIndicationMessageHelper (IndicationMessageType type, bool isOffline, bool reducedPmValues); + + ~MmWaveIndicationMessageHelper (); + + void FillCuUpValues (std::string plmId); + + void AddCuUpUePmItem (std::string ueImsiComplete, long txPdcpPduBytesNrRlc, long txPdcpPduNrRlc); + + void FillCuCpValues (uint16_t numActiveUes); + + void FillDuValues (std::string cellObjectId); + + void AddDuUePmItem (std::string ueImsiComplete, long macPduUe, long macPduInitialUe, long macQpsk, + long mac16Qam, long mac64Qam, long macRetx, long macVolume, long macPrb, + long macMac04, long macMac59, long macMac1014, long macMac1519, + long macMac2024, long macMac2529, long macSinrBin1, long macSinrBin2, + long macSinrBin3, long macSinrBin4, long macSinrBin5, long macSinrBin6, + long macSinrBin7, long rlcBufferOccup, double drbThrDlUeid); + + void AddDuCellPmItem ( + long macPduCellSpecific, long macPduInitialCellSpecific, long macQpskCellSpecific, + long mac16QamCellSpecific, long mac64QamCellSpecific, double prbUtilizationDl, + long macRetxCellSpecific, long macVolumeCellSpecific, long macMac04CellSpecific, + long macMac59CellSpecific, long macMac1014CellSpecific, long macMac1519CellSpecific, + long macMac2024CellSpecific, long macMac2529CellSpecific, long macSinrBin1CellSpecific, + long macSinrBin2CellSpecific, long macSinrBin3CellSpecific, long macSinrBin4CellSpecific, + long macSinrBin5CellSpecific, long macSinrBin6CellSpecific, long macSinrBin7CellSpecific, + long rlcBufferOccupCellSpecific, long activeUeDl); + void AddDuCellResRepPmItem (Ptr cellResRep); + void AddCuCpUePmItem (std::string ueImsiComplete, long numDrb, long drbRelAct, + Ptr l3RrcMeasurementServing, + Ptr l3RrcMeasurementNeigh); + +private: +}; + +} // namespace ns3 + +#endif /* MMWAVE_INDICATION_MESSAGE_HELPER_H */ \ No newline at end of file diff --git a/helper/oran-interface-helper.cc b/helper/oran-interface-helper.cc new file mode 100644 index 0000000..c2b56fc --- /dev/null +++ b/helper/oran-interface-helper.cc @@ -0,0 +1,33 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include "oran-interface-helper.h" + +namespace ns3 { + +/* ... */ + + +} + diff --git a/helper/oran-interface-helper.h b/helper/oran-interface-helper.h new file mode 100644 index 0000000..dc339a5 --- /dev/null +++ b/helper/oran-interface-helper.h @@ -0,0 +1,37 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef ORAN_INTERFACE_HELPER_H +#define ORAN_INTERFACE_HELPER_H + +#include "ns3/oran-interface.h" + +namespace ns3 { + +/* ... */ + +} + +#endif /* ORAN_INTERFACE_HELPER_H */ + diff --git a/model/asn1c-types.cc b/model/asn1c-types.cc new file mode 100644 index 0000000..7dbcfb2 --- /dev/null +++ b/model/asn1c-types.cc @@ -0,0 +1,963 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include + +NS_LOG_COMPONENT_DEFINE ("Asn1Types"); + +namespace ns3 { + +OctetString::OctetString (std::string value, size_t size) +{ + NS_LOG_FUNCTION (this); + CreateBaseOctetString (size); + memcpy (m_octetString->buf, value.c_str (), size); +} + +void OctetString::CreateBaseOctetString (size_t size) +{ + NS_LOG_FUNCTION (this); + m_octetString = (OCTET_STRING_t *) calloc (1, sizeof (OCTET_STRING_t)); + m_octetString->buf = (uint8_t *) calloc (1, size); + m_octetString->size = size; +} + +OctetString::OctetString (void *value, size_t size) +{ + NS_LOG_FUNCTION (this); + CreateBaseOctetString (size); + memcpy (m_octetString->buf, value, size); +} + +OctetString::~OctetString () +{ + NS_LOG_FUNCTION (this); + // if (m_octetString->buf != NULL) + // free (m_octetString->buf); + free (m_octetString); +} + +OCTET_STRING_t * +OctetString::GetPointer () +{ + return m_octetString; +} + +OCTET_STRING_t +OctetString::GetValue () +{ + return *m_octetString; +} + +std::string OctetString::DecodeContent(){ + int size = this->GetValue ().size; + char out[size + 1]; + std::memcpy (out, this->GetValue ().buf, size); + out[size] = '\0'; + + return std::string (out); +} + +BitString::BitString (std::string value, size_t size) + +{ + NS_LOG_FUNCTION (this); + m_bitString = (BIT_STRING_t *) calloc (1, sizeof (BIT_STRING_t)); + m_bitString->buf = (uint8_t *) calloc (1, size); + m_bitString->size = size; + memcpy (m_bitString->buf, value.c_str(), size); +} + +BitString::BitString (std::string value, size_t size, size_t bits_unused) + : BitString::BitString (value, size) +{ + NS_LOG_FUNCTION (this); + m_bitString->bits_unused = bits_unused; +} + +BitString::~BitString () +{ + NS_LOG_FUNCTION (this); + free (m_bitString); +} + +BIT_STRING_t * +BitString::GetPointer () +{ + return m_bitString; +} + +BIT_STRING_t +BitString::GetValue () +{ + return *m_bitString; +} + +NrCellId::NrCellId (uint16_t value) +{ + NS_LOG_FUNCTION (this); + + // TODO check why with more than 15 cells is not working + // if (value > 15) + // { + // NS_FATAL_ERROR ("TODO: update the encoding to support more than 15 cells"); + // } + + // convert value to a char array + // char ar [5] {}; + // ar [4] = value * 16; // multiply by 16 to obtain a left shift of 4 bits + uint16_t shifted = value * 16; + std::string str_shift = std::to_string (shifted); + m_bitString = Create (str_shift, 5, 4); +} + +NrCellId::~NrCellId () +{ +} + +BIT_STRING_t +NrCellId::GetValue () +{ + return m_bitString->GetValue (); +} + +BIT_STRING_t* +NrCellId::GetPointer () +{ + return m_bitString->GetPointer (); +} + +Snssai::Snssai (std::string sst) +{ + m_sNssai = (SNSSAI_t *) calloc (1, sizeof (SNSSAI_t)); + m_sst = (OCTET_STRING_t *) calloc (1, sizeof (OCTET_STRING_t)); + m_sst->buf = (uint8_t *) calloc (1, sst.size ()); + m_sst->size = sst.size (); + memcpy (m_sst->buf, sst.c_str (), sst.size ()); + m_sNssai->sST = *m_sst; +} +Snssai::Snssai (std::string sst, std::string sd) : Snssai (sst) +{ + m_sd = (OCTET_STRING_t *) calloc (1, sizeof (OCTET_STRING_t)); + m_sd->buf = (uint8_t *) calloc (1, sst.size ()); + m_sd->size = sd.size (); + memcpy (m_sd->buf, sd.c_str (), sd.size ()); + m_sNssai->sD = m_sd; +} + +Snssai::~Snssai () +{ + if (m_sNssai != NULL) + ASN_STRUCT_FREE (asn_DEF_SNSSAI, m_sNssai); + + // if (m_sst != NULL) + // ASN_STRUCT_FREE (asn_DEF_OCTET_STRING, m_sst); + // if (m_sd != NULL) + // ASN_STRUCT_FREE (asn_DEF_OCTET_STRING, m_sd); +} + +SNSSAI_t * +Snssai::GetPointer () +{ + return m_sNssai; +} + +SNSSAI_t +Snssai::GetValue () +{ + return *m_sNssai; +} + +void +MeasQuantityResultsWrap::AddRsrp (long rsrp) +{ + + m_measQuantityResults->rsrp = (RSRP_Range_t *) calloc (1, sizeof (RSRP_Range_t)); + *m_measQuantityResults->rsrp = rsrp; +} + +void +MeasQuantityResultsWrap::AddRsrq (long rsrq) +{ + m_measQuantityResults->rsrq = (RSRQ_Range_t *) calloc (1, sizeof (RSRQ_Range_t)); + *m_measQuantityResults->rsrq = rsrq; +} + +void +MeasQuantityResultsWrap::AddSinr (long sinr) +{ + m_measQuantityResults->sinr = (SINR_Range_t *) calloc (1, sizeof (SINR_Range_t)); + *m_measQuantityResults->sinr = sinr; +} + +MeasQuantityResultsWrap::MeasQuantityResultsWrap () +{ + m_measQuantityResults = (MeasQuantityResults_t *) calloc (1, sizeof (MeasQuantityResults_t)); +} + +MeasQuantityResultsWrap::~MeasQuantityResultsWrap () +{ + // if (m_measQuantityResults->sinr != NULL) + // ASN_STRUCT_FREE (asn_DEF_SINR_Range, m_measQuantityResults->sinr); + + // if (m_measQuantityResults->rsrp != NULL) + // ASN_STRUCT_FREE (asn_DEF_RSRP_Range, m_measQuantityResults->rsrp); + + // if (m_measQuantityResults->rsrq != NULL) + // ASN_STRUCT_FREE (asn_DEF_RSRQ_Range, m_measQuantityResults->rsrq); + + // if (m_measQuantityResults != NULL){ + // free (m_measQuantityResults); + // } +} + +MeasQuantityResults_t * +MeasQuantityResultsWrap::GetPointer () +{ + return m_measQuantityResults; +} + +MeasQuantityResults_t +MeasQuantityResultsWrap::GetValue () +{ + return *m_measQuantityResults; +} + +ResultsPerCsiRsIndex::ResultsPerCsiRsIndex (long csiRsIndex, MeasQuantityResults_t *csiRsResults) + : ResultsPerCsiRsIndex (csiRsIndex) +{ + m_resultsPerCsiRsIndex->csi_RS_Results = csiRsResults; +} + +ResultsPerCsiRsIndex::ResultsPerCsiRsIndex (long csiRsIndex) +{ + m_resultsPerCsiRsIndex = + (ResultsPerCSI_RS_Index_t *) calloc (1, sizeof (ResultsPerCSI_RS_Index_t)); + m_resultsPerCsiRsIndex->csi_RS_Index = csiRsIndex; +} + +ResultsPerCSI_RS_Index_t * +ResultsPerCsiRsIndex::GetPointer () +{ + return m_resultsPerCsiRsIndex; +} + +ResultsPerCSI_RS_Index_t +ResultsPerCsiRsIndex::GetValue () +{ + return *m_resultsPerCsiRsIndex; +} + +ResultsPerSSBIndex::ResultsPerSSBIndex (long ssbIndex, MeasQuantityResults_t *ssbResults) + : ResultsPerSSBIndex (ssbIndex) +{ + m_resultsPerSSBIndex->ssb_Results = ssbResults; +} + +ResultsPerSSBIndex::ResultsPerSSBIndex (long ssbIndex) +{ + m_resultsPerSSBIndex = (ResultsPerSSB_Index_t *) calloc (1, sizeof (ResultsPerSSB_Index_t)); + m_resultsPerSSBIndex->ssb_Index = ssbIndex; +} + +ResultsPerSSB_Index_t * +ResultsPerSSBIndex::GetPointer () +{ + return m_resultsPerSSBIndex; +} + +ResultsPerSSB_Index_t +ResultsPerSSBIndex::GetValue () +{ + return *m_resultsPerSSBIndex; +} + +void +MeasResultNr::AddCellResults (MeasResultNr::ResultCell cell, MeasQuantityResults_t *results) +{ + switch (cell) + { + case MeasResultNr::ResultCell::SSB: + + m_measResultNr->measResult.cellResults.resultsSSB_Cell = results; + break; + + case MeasResultNr::ResultCell::CSI_RS: + + m_measResultNr->measResult.cellResults.resultsCSI_RS_Cell = results; + break; + + default: + NS_LOG_ERROR ("Unrecognized cell identifier."); + break; + } +} + +void +MeasResultNr::AddPerSsbIndexResults (ResultsPerSSB_Index_t *resultsSSB_Index) +{ + ASN_SEQUENCE_ADD (m_measResultNr->measResult.rsIndexResults->resultsSSB_Indexes, + resultsSSB_Index); +} + +void +MeasResultNr::AddPerCsiRsIndexResults (ResultsPerCSI_RS_Index_t *resultsCSI_RS_Index) +{ + ASN_SEQUENCE_ADD (m_measResultNr->measResult.rsIndexResults->resultsCSI_RS_Indexes, + resultsCSI_RS_Index); +} + +void MeasResultNr::AddPhyCellId (long physCellId) +{ + PhysCellId_t *s_physCellId = (PhysCellId_t *) calloc (1, sizeof (PhysCellId_t)); + *s_physCellId = physCellId; + m_measResultNr->physCellId = s_physCellId; +} + +MeasResultNr::MeasResultNr (long physCellId) : MeasResultNr () +{ + AddPhyCellId (physCellId); +} + +MeasResultNr::MeasResultNr () +{ + m_measResultNr = (MeasResultNR_t *) calloc (1, sizeof (MeasResultNR_t)); + m_shouldFree = false; +} + +MeasResultNr::~MeasResultNr () +{ + if (m_shouldFree) + { + free (m_measResultNr); + } +} + +MeasResultNR_t * +MeasResultNr::GetPointer () +{ + // Fallback procedure, this should not happen if correctly used; + m_shouldFree = false; + return m_measResultNr; +} + +MeasResultNR_t +MeasResultNr::GetValue () +{ + m_shouldFree = true; + return *m_measResultNr; +} + +MeasResultEutra::MeasResultEutra (long eutraPhysCellId, long rsrp, long rsrq, long sinr) + : MeasResultEutra (eutraPhysCellId) +{ + AddRsrp (rsrp); + AddRsrq (rsrq); + AddSinr (sinr); +} + +MeasResultEutra::MeasResultEutra (long eutraPhysCellId) +{ + m_measResultEutra = (MeasResultEUTRA_t *) calloc (1, sizeof (MeasResultEUTRA_t)); + m_measResultEutra->eutra_PhysCellId = eutraPhysCellId; +} + +void +MeasResultEutra::AddRsrp (long rsrp) +{ + m_measResultEutra->measResult.rsrp = + (RSRP_RangeEUTRA_t *) calloc (1, sizeof (RSRP_RangeEUTRA_t)); + *m_measResultEutra->measResult.rsrp = rsrp; +} +void +MeasResultEutra::AddRsrq (long rsrq) +{ + m_measResultEutra->measResult.rsrq = + (RSRQ_RangeEUTRA_t *) calloc (1, sizeof (RSRQ_RangeEUTRA_t)); + *m_measResultEutra->measResult.rsrq = rsrq; +} +void +MeasResultEutra::AddSinr (long sinr) +{ + m_measResultEutra->measResult.sinr = + (SINR_RangeEUTRA_t *) calloc (1, sizeof (SINR_RangeEUTRA_t)); + *m_measResultEutra->measResult.sinr = sinr; +} + +MeasResultEUTRA_t * +MeasResultEutra::GetPointer () +{ + return m_measResultEutra; +} + +MeasResultEUTRA_t +MeasResultEutra::GetValue () +{ + return *m_measResultEutra; +} + +MeasResultPCellWrap::MeasResultPCellWrap (long eutraPhysCellId, long rsrpResult, long rsrqResult) + : MeasResultPCellWrap (eutraPhysCellId) +{ + AddRsrpResult (rsrpResult); + AddRsrqResult (rsrqResult); +} + +MeasResultPCellWrap::MeasResultPCellWrap (long eutraPhysCellId) +{ + m_measResultPCell = (MeasResultPCell_t *) calloc (1, sizeof (MeasResultPCell_t)); + m_measResultPCell->eutra_PhysCellId = eutraPhysCellId; +} + +void +MeasResultPCellWrap::AddRsrpResult (long rsrpResult) +{ + m_measResultPCell->rsrpResult = rsrpResult; +} + +void +MeasResultPCellWrap::AddRsrqResult (long rsrqResult) +{ + m_measResultPCell->rsrqResult = rsrqResult; +} + +MeasResultPCell_t * +MeasResultPCellWrap::GetPointer () +{ + return m_measResultPCell; +} + +MeasResultPCell_t +MeasResultPCellWrap::GetValue () +{ + return *m_measResultPCell; +} + +MeasResultServMo::MeasResultServMo (long servCellId, MeasResultNR_t measResultServingCell, + MeasResultNR_t *measResultBestNeighCell) + : MeasResultServMo (servCellId, measResultServingCell) +{ + m_measResultServMo->measResultBestNeighCell = measResultBestNeighCell; +} + +MeasResultServMo::MeasResultServMo (long servCellId, MeasResultNR_t measResultServingCell) +{ + m_measResultServMo = (MeasResultServMO_t *) calloc (1, sizeof (MeasResultServMO_t)); + m_measResultServMo->servCellId = servCellId; + m_measResultServMo->measResultServingCell = measResultServingCell; +} + +MeasResultServMO_t * +MeasResultServMo::GetPointer () +{ + return m_measResultServMo; +} + +MeasResultServMO_t +MeasResultServMo::GetValue () +{ + return *m_measResultServMo; +} + +void +ServingCellMeasurementsWrap::AddMeasResultPCell (MeasResultPCell_t *measResultPCell) +{ + if (m_servingCellMeasurements->present != ServingCellMeasurements_PR_eutra_measResultPCell) + { + NS_LOG_ERROR ("Wrong measurement item for this present, it will not be added."); + } + m_servingCellMeasurements->choice.eutra_measResultPCell = measResultPCell; +} + +void +ServingCellMeasurementsWrap::AddMeasResultServMo (MeasResultServMO_t *measResultServMO) +{ + if (m_servingCellMeasurements->present != ServingCellMeasurements_PR_nr_measResultServingMOList) + { + NS_LOG_ERROR ("Wrong measurement item for this present, it will not be added."); + } + + ASN_SEQUENCE_ADD (&m_nr_measResultServingMOList->list, measResultServMO); +} + +ServingCellMeasurementsWrap::ServingCellMeasurementsWrap (ServingCellMeasurements_PR present) +{ + m_servingCellMeasurements = + (ServingCellMeasurements_t *) calloc (1, sizeof (ServingCellMeasurements_t)); + m_servingCellMeasurements->present = present; + + if (m_servingCellMeasurements->present == ServingCellMeasurements_PR_nr_measResultServingMOList) + { + m_nr_measResultServingMOList = + (MeasResultServMOList_t *) calloc (1, sizeof (MeasResultServMOList_t)); + m_servingCellMeasurements->choice.nr_measResultServingMOList = m_nr_measResultServingMOList; + } +} + +ServingCellMeasurements_t * +ServingCellMeasurementsWrap::GetPointer () +{ + return m_servingCellMeasurements; +} + +ServingCellMeasurements_t +ServingCellMeasurementsWrap::GetValue () +{ + return *m_servingCellMeasurements; +} + +Ptr +L3RrcMeasurements::CreateL3RrcUeSpecificSinrServing (long servingCellId, long physCellId, long sinr) +{ + Ptr l3RrcMeasurement = Create (RRCEvent_b1); + Ptr servingCellMeasurements = + Create (ServingCellMeasurements_PR_nr_measResultServingMOList); + + Ptr measResultNr = Create (physCellId); + Ptr measQuantityResultWrap = Create (); + measQuantityResultWrap->AddSinr (sinr); + measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ()); + Ptr measResultServMo = + Create (servingCellId, measResultNr->GetValue ()); + servingCellMeasurements->AddMeasResultServMo (measResultServMo->GetPointer ()); + l3RrcMeasurement->AddServingCellMeasurement (servingCellMeasurements->GetPointer ()); + return l3RrcMeasurement; +} + +Ptr +L3RrcMeasurements::CreateL3RrcUeSpecificSinrNeigh () +{ + return Create (RRCEvent_b1); +} + +void +L3RrcMeasurements::AddNeighbourCellMeasurement (long neighCellId, long sinr) +{ + Ptr measResultNr = Create (neighCellId); + Ptr measQuantityResultWrap = Create (); + measQuantityResultWrap->AddSinr (sinr); + measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ()); + + this->AddMeasResultNRNeighCells (measResultNr->GetPointer ()); // MAX 8 UE per message (standard) +} + +void +L3RrcMeasurements::AddServingCellMeasurement (ServingCellMeasurements_t *servingCellMeasurements) +{ + m_l3RrcMeasurements->servingCellMeasurements = servingCellMeasurements; +} + +void +L3RrcMeasurements::AddMeasResultEUTRANeighCells (MeasResultEUTRA_t *measResultItemEUTRA) +{ + if (m_measItemsCounter == L3RrcMeasurements::MAX_MEAS_RESULTS_ITEMS) + { + NS_LOG_ERROR ("Maximum number of items (" + << L3RrcMeasurements::MAX_MEAS_RESULTS_ITEMS + << ")for the standard reached. This item will not be " + "inserted in the list"); + return; + } + + if (m_l3RrcMeasurements->measResultNeighCells == NULL) + { + addMeasResultNeighCells (MeasResultNeighCells_PR_measResultListEUTRA); + } + + if (m_l3RrcMeasurements->measResultNeighCells->present != + MeasResultNeighCells_PR_measResultListEUTRA) + { + NS_LOG_ERROR ("Wrong measurement item for this list, it will not be added."); + return; + } + + m_measItemsCounter++; + ASN_SEQUENCE_ADD (&m_measResultListEUTRA->list, measResultItemEUTRA); +} + +void +L3RrcMeasurements::AddMeasResultNRNeighCells (MeasResultNR_t *measResultItemNR) +{ + if (m_measItemsCounter == L3RrcMeasurements::MAX_MEAS_RESULTS_ITEMS) + { + NS_LOG_ERROR ("Maximum number of items (" + << L3RrcMeasurements::MAX_MEAS_RESULTS_ITEMS + << ")for the standard reached. This item will not be " + "inserted in the list"); + return; + } + + if (m_l3RrcMeasurements->measResultNeighCells == NULL) + { + addMeasResultNeighCells (MeasResultNeighCells_PR_measResultListNR); + } + + if (m_l3RrcMeasurements->measResultNeighCells->present != + MeasResultNeighCells_PR_measResultListNR) + { + NS_LOG_ERROR ("Wrong measurement item for this list, it will not be added."); + return; + } + + m_measItemsCounter++; + ASN_SEQUENCE_ADD (&m_measResultListNR->list, measResultItemNR); +} + +void +L3RrcMeasurements::addMeasResultNeighCells (MeasResultNeighCells_PR present) +{ + m_l3RrcMeasurements->measResultNeighCells = + (MeasResultNeighCells_t *) calloc (1, sizeof (MeasResultNeighCells_t)); + m_l3RrcMeasurements->measResultNeighCells->present = present; + + switch (present) + { + case MeasResultNeighCells_PR_measResultListEUTRA: { + m_measResultListEUTRA = + (MeasResultListEUTRA_t *) calloc (1, sizeof (MeasResultListEUTRA_t)); + m_l3RrcMeasurements->measResultNeighCells->choice.measResultListEUTRA = + m_measResultListEUTRA; + break; + } + + case MeasResultNeighCells_PR_measResultListNR: { + m_measResultListNR = (MeasResultListNR_t *) calloc (1, sizeof (MeasResultListNR_t)); + m_l3RrcMeasurements->measResultNeighCells->choice.measResultListNR = m_measResultListNR; + break; + } + + default: { + NS_LOG_ERROR ("Unrecognized present for Measurment result."); + break; + } + } +} + +L3RrcMeasurements::L3RrcMeasurements (RRCEvent_t rrcEvent) +{ + m_l3RrcMeasurements = (L3_RRC_Measurements_t *) calloc (1, sizeof (L3_RRC_Measurements_t)); + m_l3RrcMeasurements->rrcEvent = rrcEvent; + m_measItemsCounter = 0; +} + +L3RrcMeasurements::L3RrcMeasurements (L3_RRC_Measurements_t *l3RrcMeasurements) +{ + m_l3RrcMeasurements = l3RrcMeasurements; +} + +L3RrcMeasurements::~L3RrcMeasurements () +{ + // Memory deallocation is handled by RIC Indication Message + // if (m_l3RrcMeasurements != NULL) + // { + // ASN_STRUCT_FREE (asn_DEF_L3_RRC_Measurements, m_l3RrcMeasurements); + // } +} + +L3_RRC_Measurements * +L3RrcMeasurements::GetPointer () +{ + return m_l3RrcMeasurements; +} + +L3_RRC_Measurements +L3RrcMeasurements::GetValue () +{ + return *m_l3RrcMeasurements; +} + +// TODO change definition and return the values +// this function shall be finished for decoding +void +L3RrcMeasurements::ExtractMeasurementsFromL3RrcMeas (L3_RRC_Measurements_t *l3RrcMeasurements) +{ + RRCEvent_t rrcEvent = l3RrcMeasurements->rrcEvent; // Mandatory + switch (rrcEvent) + { + case RRCEvent_b1: { + NS_LOG_DEBUG ("RRCEvent_b1"); + } + break; + + case RRCEvent_a3: { + NS_LOG_DEBUG ("RRCEvent_a3"); + } + break; + case RRCEvent_a5: { + NS_LOG_DEBUG ("RRCEvent_a5"); + } + break; + case RRCEvent_periodic: { + NS_LOG_DEBUG ("RRCEvent_periodic"); + } + break; + + default: { + NS_LOG_ERROR ("Rrc event unrecognised"); + } + break; + } + + if (l3RrcMeasurements->measResultNeighCells) + { + MeasResultNeighCells_t *measResultNeighCells = l3RrcMeasurements->measResultNeighCells; + switch (measResultNeighCells->present) + { + case MeasResultNeighCells_PR_NOTHING: { /* No components present */ + NS_LOG_DEBUG ("No components present"); + } + break; + case MeasResultNeighCells_PR_measResultListNR: { + NS_LOG_DEBUG ("MeasResultNeighCells_PR_measResultListNR"); + // measResultNeighCells->choice.measResultListNR + } + break; + case MeasResultNeighCells_PR_measResultListEUTRA: { + NS_LOG_DEBUG ("MeasResultNeighCells_PR_measResultListEUTRA"); + } + break; + default: + NS_LOG_ERROR ("measResultNeighCells present unrecognised"); + break; + } + } + if (l3RrcMeasurements->servingCellMeasurements) + { + ServingCellMeasurements_t *servingCellMeasurements = + l3RrcMeasurements->servingCellMeasurements; + switch (servingCellMeasurements->present) + { + case ServingCellMeasurements_PR_NOTHING: { /* No components present */ + NS_LOG_DEBUG ("No components present"); + } + break; + case ServingCellMeasurements_PR_nr_measResultServingMOList: { + NS_LOG_DEBUG ("ServingCellMeasurements_PR_nr_measResultServingMOList"); + } + break; + case ServingCellMeasurements_PR_eutra_measResultPCell: { + NS_LOG_DEBUG ("ServingCellMeasurements_PR_eutra_measResultPCell"); + } + break; + default: + NS_LOG_ERROR ("servingCellMeasurements present unrecognised"); + break; + } + } +} + +double +L3RrcMeasurements::ThreeGppMapSinr (double sinr) +{ + double inputEnd = 40; + double inputStart = -23; + double outputStart = 0; + double outputEnd = 127; + double outputSinr; + double slope = (outputEnd - outputStart) / (inputEnd - inputStart); + + if (sinr < inputStart) + { + outputSinr = outputStart; + } + else if (sinr > inputEnd) + { + outputSinr = outputEnd; + } + else + { + outputSinr = outputStart + std::round (slope * (sinr - inputStart)); + } + + NS_LOG_DEBUG ("input sinr" << sinr << " output sinr" << outputSinr); + + return outputSinr; +} + +MeasurementItem::MeasurementItem (std::string name) +{ + + m_measurementItem = (PM_Info_Item_t *) calloc (1, sizeof (PM_Info_Item_t)); + m_pmType = (MeasurementType_t *) calloc (1, sizeof (MeasurementType_t)); + m_measurementItem->pmType = *m_pmType; + + m_measName = + (MeasurementTypeName_t *) calloc (1, sizeof (MeasurementTypeName_t)); + m_measName->buf = (uint8_t *) calloc (1, sizeof (OCTET_STRING)); + m_measName->size = name.length (); + memcpy (m_measName->buf, name.c_str (), m_measName->size); + + m_measurementItem->pmType.choice.measName = *m_measName; + m_measurementItem->pmType.present = MeasurementType_PR_measName; +} + +MeasurementItem::MeasurementItem (std::string name, long value) : MeasurementItem (name) +{ + NS_LOG_FUNCTION (this << name << "long" << value); + this->CreateMeasurementValue (MeasurementValue_PR_valueInt); + m_measurementItem->pmVal.choice.valueInt = value; +} + +MeasurementItem::MeasurementItem (std::string name, double value) : MeasurementItem (name) +{ + NS_LOG_FUNCTION (this << name << "double" << value); + this->CreateMeasurementValue (MeasurementValue_PR_valueReal); + m_measurementItem->pmVal.choice.valueReal = value; +} + +MeasurementItem::MeasurementItem (std::string name, Ptrvalue) + : MeasurementItem (name) +{ + NS_LOG_FUNCTION (this << name << "L3 RRC" << value); + this->CreateMeasurementValue (MeasurementValue_PR_valueRRC); + m_measurementItem->pmVal.choice.valueRRC = value->GetPointer (); +} + +void +MeasurementItem::CreateMeasurementValue (MeasurementValue_PR measurementValue_PR) +{ + m_pmVal = ((MeasurementValue_t *) calloc (1, sizeof (MeasurementValue_t))); + m_measurementItem->pmVal = *m_pmVal; + m_measurementItem->pmVal.present = measurementValue_PR; +} + +MeasurementItem::~MeasurementItem () +{ + NS_LOG_FUNCTION (this); + if (m_pmVal != NULL) + ASN_STRUCT_FREE (asn_DEF_MeasurementValue, m_pmVal); + + if (m_measName != NULL) + { + free (m_measName); + } + + if (m_pmType != NULL) + ASN_STRUCT_FREE (asn_DEF_MeasurementType, m_pmType); +} + +PM_Info_Item_t * +MeasurementItem::GetPointer () +{ + return m_measurementItem; +} + +PM_Info_Item_t +MeasurementItem::GetValue () +{ + return *m_measurementItem; +} + +RANParameterItem::RANParameterItem (RANParameter_Item_t *ranParameterItem) +{ + m_ranParameterItem = ranParameterItem; +} + +RANParameterItem::~RANParameterItem () +{ + if (m_ranParameterItem != NULL) + ASN_STRUCT_FREE (asn_DEF_RANParameter_Item, m_ranParameterItem); +} + +std::vector +RANParameterItem::ExtractRANParametersFromRANParameter (RANParameter_Item_t *ranParameterItem) +{ + std::vector ranParameterList; + + // NS_LOG_DEBUG ("RAN Parameter examined:"); + // xer_fprint (stderr, &asn_DEF_RANParameter_Item, ranParameterItem); + // NS_LOG_DEBUG ("----"); + // NS_LOG_DEBUG (" ID " << ranParameterItem->ranParameterItem_ID); + + switch (ranParameterItem->ranParameterItem_valueType->present) + { + case RANParameter_ValueType_PR_NOTHING: { + NS_LOG_DEBUG ("[E2SM] RANParameter_ValueType_PR_NOTHING"); + break; + } + case RANParameter_ValueType_PR_ranParameter_Element: { + RANParameterItem newItem = + RANParameterItem (ranParameterItem); + NS_LOG_DEBUG ("[E2SM] RANParameter_ValueType_PR_ranParameter_Element"); + RANParameter_ELEMENT_t *ranParameterElement = + ranParameterItem->ranParameterItem_valueType->choice.ranParameter_Element; + newItem.m_keyFlag = &ranParameterElement->keyFlag; + switch (ranParameterElement->ranParameter_Value.present) + { + case RANParameter_Value_PR_NOTHING: { + NS_LOG_DEBUG ("[E2SM] RANParameter_Value_PR_NOTHING"); + newItem.m_valueType = ValueType::Nothing; + break; + } + case RANParameter_Value_PR_valueInt: { + NS_LOG_DEBUG ("[E2SM] RANParameter_Value_PR_valueInt"); + newItem.m_valueInt = ranParameterElement->ranParameter_Value.choice.valueInt; + newItem.m_valueType = ValueType::Int; + NS_LOG_DEBUG ("[E2SM] Value: " << newItem.m_valueInt); + break; + } + case RANParameter_Value_PR_valueOctS: { + NS_LOG_DEBUG ("[E2SM] RANParameter_Value_PR_valueOctS"); + newItem.m_valueStr = Create ( + (void *) ranParameterElement->ranParameter_Value.choice.valueOctS.buf, + ranParameterElement->ranParameter_Value.choice.valueOctS.size); + newItem.m_valueType = ValueType::OctectString; + NS_LOG_DEBUG ("[E2SM] Value: OctectString"); + break; + } + } + ranParameterList.push_back (newItem); + break; + } + case RANParameter_ValueType_PR_ranParameter_Structure: { + NS_LOG_DEBUG ("[E2SM] RANParameter_ValueType_PR_ranParameter_Structure"); + RANParameter_STRUCTURE_t *ranParameterStructure = + ranParameterItem->ranParameterItem_valueType->choice.ranParameter_Structure; + int count = ranParameterStructure->sequence_of_ranParameters.list.count; + for (int i = 0; i < count; i++) + { + RANParameter_Item_t *childRanItem = + ranParameterStructure->sequence_of_ranParameters.list.array[i]; + + for (RANParameterItem extractedParameter : ExtractRANParametersFromRANParameter (childRanItem)) + { + ranParameterList.push_back (extractedParameter); + } + } + break; + } + case RANParameter_ValueType_PR_ranParameter_List: { + NS_LOG_DEBUG ("[E2SM] RANParameter_ValueType_PR_ranParameter_List"); + // No list passed for the moment from RIC, thus no parsed as case + // ranParameterItem->ranParameterItem_valueType->choice.ranParameter_List; + break; + } + } + + return ranParameterList; +} + + +}; // namespace ns3 diff --git a/model/asn1c-types.h b/model/asn1c-types.h new file mode 100644 index 0000000..83464db --- /dev/null +++ b/model/asn1c-types.h @@ -0,0 +1,357 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef ASN1C_TYPES_H +#define ASN1C_TYPES_H + +#include "ns3/object.h" +#include + +extern "C" { + #include "OCTET_STRING.h" + #include "BIT_STRING.h" + #include "PM-Info-Item.h" + #include "SNSSAI.h" + #include "RRCEvent.h" + #include "L3-RRC-Measurements.h" + #include "ServingCellMeasurements.h" + #include "MeasResultNeighCells.h" + #include "MeasResultNR.h" + #include "MeasResultEUTRA.h" + #include "MeasResultPCell.h" + #include "MeasResultListEUTRA.h" + #include "MeasResultListNR.h" + #include "MeasResultServMO.h" + #include "MeasResultServMOList.h" + #include "MeasQuantityResults.h" + #include "ResultsPerSSB-Index.h" + #include "ResultsPerCSI-RS-Index.h" + #include "E2SM-RC-ControlMessage-Format1.h" + #include "RANParameter-Item.h" + #include "RANParameter-ValueType.h" + #include "RANParameter-ELEMENT.h" + #include "RANParameter-STRUCTURE.h" +} + +namespace ns3 { + +/** +* Wrapper for class for OCTET STRING +*/ +class OctetString : public SimpleRefCount +{ +public: + OctetString (std::string value, size_t size); + OctetString (void *value, size_t size); + ~OctetString (); + OCTET_STRING_t *GetPointer (); + OCTET_STRING_t GetValue (); + std::string DecodeContent (); + +private: + void CreateBaseOctetString (size_t size); + OCTET_STRING_t *m_octetString; +}; + +/** +* Wrapper for class for BIT STRING +*/ +class BitString : public SimpleRefCount +{ +public: + BitString (std::string value, size_t size); + BitString (std::string value, size_t size, size_t bits_unused); + ~BitString (); + BIT_STRING_t *GetPointer (); + BIT_STRING_t GetValue (); + // TODO maybe a to string or a decode method should be created + +private: + BIT_STRING_t *m_bitString; +}; + +class NrCellId : public SimpleRefCount +{ +public: + NrCellId (uint16_t value); + virtual ~NrCellId (); + BIT_STRING_t *GetPointer (); + BIT_STRING_t GetValue (); + +private: + Ptr m_bitString; +}; + +/** +* Wrapper for class for S-NSSAI +*/ +class Snssai : public SimpleRefCount +{ +public: + Snssai (std::string sst); + Snssai (std::string sst, std::string sd); + ~Snssai (); + SNSSAI_t *GetPointer (); + SNSSAI_t GetValue (); + +private: + OCTET_STRING_t *m_sst; + OCTET_STRING_t *m_sd; + SNSSAI_t *m_sNssai; +}; + +/** +* Wrapper for class for MeasQuantityResults_t +*/ +class MeasQuantityResultsWrap : public SimpleRefCount +{ +public: + MeasQuantityResultsWrap (); + ~MeasQuantityResultsWrap (); + MeasQuantityResults_t *GetPointer (); + MeasQuantityResults_t GetValue (); + void AddRsrp (long rsrp); + void AddRsrq (long rsrq); + void AddSinr (long sinr); + +private: + MeasQuantityResults_t *m_measQuantityResults; +}; + +/** +* Wrapper for class for ResultsPerCSI_RS_Index_t +*/ +class ResultsPerCsiRsIndex : public SimpleRefCount +{ +public: + ResultsPerCsiRsIndex (long csiRsIndex, MeasQuantityResults_t *csiRsResults); + ResultsPerCsiRsIndex (long csiRsIndex); + ResultsPerCSI_RS_Index_t *GetPointer (); + ResultsPerCSI_RS_Index_t GetValue (); + +private: + ResultsPerCSI_RS_Index_t *m_resultsPerCsiRsIndex; +}; + +/** +* Wrapper for class for ResultsPerSSB_Index_t +*/ +class ResultsPerSSBIndex : public SimpleRefCount +{ +public: + ResultsPerSSBIndex (long ssbIndex, MeasQuantityResults_t *ssbResults); + ResultsPerSSBIndex (long ssbIndex); + ResultsPerSSB_Index_t *GetPointer (); + ResultsPerSSB_Index_t GetValue (); + +private: + ResultsPerSSB_Index_t *m_resultsPerSSBIndex; +}; + +/** +* Wrapper for class for MeasResultNR_t +*/ +class MeasResultNr : public SimpleRefCount +{ +public: + enum ResultCell { SSB = 0, CSI_RS = 1 }; + MeasResultNr (long physCellId); + MeasResultNr (); + ~MeasResultNr (); + MeasResultNR_t *GetPointer (); + MeasResultNR_t GetValue (); + void AddCellResults (ResultCell cell, MeasQuantityResults_t *results); + void AddPerSsbIndexResults (ResultsPerSSB_Index_t *resultsSsbIndex); + void AddPerCsiRsIndexResults (ResultsPerCSI_RS_Index_t *resultsCsiRsIndex); + void AddPhyCellId (long physCellId); + +private: + MeasResultNR_t *m_measResultNr; + bool m_shouldFree; +}; + +/** +* Wrapper for class for MeasResultEUTRA_t +*/ +class MeasResultEutra : public SimpleRefCount +{ +public: + MeasResultEutra (long eutraPhysCellId, long rsrp, long rsrq, long sinr); + MeasResultEutra (long eutraPhysCellId); + MeasResultEUTRA_t *GetPointer (); + MeasResultEUTRA_t GetValue (); + void AddRsrp (long rsrp); + void AddRsrq (long rsrq); + void AddSinr (long sinr); + +private: + MeasResultEUTRA_t *m_measResultEutra; +}; + +/** +* Wrapper for class for MeasResultPCell_t +*/ +class MeasResultPCellWrap : public SimpleRefCount +{ +public: + MeasResultPCellWrap (long eutraPhysCellId, long rsrpResult, long rsrqResult); + MeasResultPCellWrap (long eutraPhysCellId); + MeasResultPCell_t *GetPointer (); + MeasResultPCell_t GetValue (); + void AddRsrpResult (long rsrpResult); + void AddRsrqResult (long rsrqResult); + +private: + MeasResultPCell_t *m_measResultPCell; +}; + +/** +* Wrapper for class for MeasResultServMO_t +*/ +class MeasResultServMo : public SimpleRefCount +{ +public: + MeasResultServMo (long servCellId, MeasResultNR_t measResultServingCell, + MeasResultNR_t *measResultBestNeighCell); + MeasResultServMo (long servCellId, MeasResultNR_t measResultServingCell); + MeasResultServMO_t *GetPointer (); + MeasResultServMO_t GetValue (); + +private: + MeasResultServMO_t *m_measResultServMo; +}; + +/** +* Wrapper for class for ServingCellMeasurements_t +*/ +class ServingCellMeasurementsWrap : public SimpleRefCount +{ +public: + ServingCellMeasurementsWrap (ServingCellMeasurements_PR present); + ServingCellMeasurements_t *GetPointer (); + ServingCellMeasurements_t GetValue (); + void AddMeasResultPCell (MeasResultPCell_t *measResultPCell); + void AddMeasResultServMo (MeasResultServMO_t *measResultServMO); + +private: + ServingCellMeasurements_t *m_servingCellMeasurements; + MeasResultServMOList_t *m_nr_measResultServingMOList; +}; + +/** +* Wrapper for class for L3 RRC Measurements +*/ +class L3RrcMeasurements : public SimpleRefCount +{ +public: + int MAX_MEAS_RESULTS_ITEMS = 8; // Maximum 8 per UE (standard) + L3RrcMeasurements (RRCEvent_t rrcEvent); + L3RrcMeasurements (L3_RRC_Measurements_t *l3RrcMeasurements); + ~L3RrcMeasurements (); + L3_RRC_Measurements_t *GetPointer (); + L3_RRC_Measurements_t GetValue (); + + void AddMeasResultEUTRANeighCells (MeasResultEUTRA_t *measResultItemEUTRA); + void AddMeasResultNRNeighCells (MeasResultNR_t *measResultItemNR); + void AddServingCellMeasurement (ServingCellMeasurements_t *servingCellMeasurements); + void AddNeighbourCellMeasurement (long neighCellId, long sinr); + + static Ptr CreateL3RrcUeSpecificSinrServing (long servingCellId, + long physCellId, long sinr); + + static Ptr CreateL3RrcUeSpecificSinrNeigh (); + + // TODO change definition and return the values (to be used for decoding) + static void ExtractMeasurementsFromL3RrcMeas (L3_RRC_Measurements_t *l3RrcMeasurements); + + /** + * Returns the input SINR on a 0-127 scale + * + * Refer to 3GPP TS 38.133 V17.2.0(2021-06), Table 10.1.16.1-1: SS-SINR and CSI-SINR measurement report mapping + * + * @param sinr + * @return double + */ + static double ThreeGppMapSinr (double sinr); + +private: + void addMeasResultNeighCells (MeasResultNeighCells_PR present); + L3_RRC_Measurements_t *m_l3RrcMeasurements; + MeasResultListEUTRA_t *m_measResultListEUTRA; + MeasResultListNR_t *m_measResultListNR; + int m_measItemsCounter; +}; + +/** +* Wrapper for class for PM_Info_Item_t +*/ +class MeasurementItem : public SimpleRefCount +{ +public: + MeasurementItem (std::string name, long value); + MeasurementItem (std::string name, double value); + MeasurementItem (std::string name, Ptr value); + ~MeasurementItem (); + PM_Info_Item_t *GetPointer (); + PM_Info_Item_t GetValue (); + +private: + MeasurementItem (std::string name); + void CreateMeasurementValue (MeasurementValue_PR measurementValue_PR); + // Main struct to be compiled + PM_Info_Item_t *m_measurementItem; + + // Accessory structs that we must track to release memory after use + MeasurementTypeName_t *m_measName; + MeasurementValue_t *m_pmVal; + MeasurementType_t *m_pmType; +}; + +/** +* Wrapper for class for RANParameter_Item_t +*/ +class RANParameterItem : public SimpleRefCount +{ +public: + enum ValueType{ Nothing = 0, Int = 1, OctectString = 2 }; + RANParameterItem (RANParameter_Item_t *ranParameterItem); + ~RANParameterItem (); + RANParameter_Item_t *GetPointer (); + RANParameter_Item_t GetValue (); + + ValueType m_valueType; + long m_valueInt; + Ptr m_valueStr; + + static std::vector + ExtractRANParametersFromRANParameter (RANParameter_Item_t *ranParameterItem); + +private: + // Main struct + RANParameter_Item_t *m_ranParameterItem; + BOOLEAN_t *m_keyFlag; +}; + +} // namespace ns3 +#endif /* ASN1C_TYPES_H */ diff --git a/model/function-description.cc b/model/function-description.cc new file mode 100644 index 0000000..b5a8b98 --- /dev/null +++ b/model/function-description.cc @@ -0,0 +1,69 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include +#include + + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("FunctionDescription"); + +FunctionDescription::FunctionDescription () +{ +// E2SM_KPM_RANfunction_Description_t *descriptor = new E2SM_KPM_RANfunction_Description_t (); +// FillAndEncodeKpmFunctionDescription (descriptor); +// ASN_STRUCT_FREE_CONTENTS_ONLY (asn_DEF_E2SM_KPM_RANfunction_Description, descriptor); +// delete descriptor; + m_size = 0; +} + +FunctionDescription::~FunctionDescription () +{ + free (m_buffer); + m_size = 0; +} + +// TODO improve +// void +// FunctionDescription::Encode (E2SM_KPM_RANfunction_Description_t *descriptor) +// { +// asn_codec_ctx_t *opt_cod = 0; // disable stack bounds checking +// // encode the structure into the e2smbuffer +// asn_encode_to_new_buffer_result_s encodedMsg = asn_encode_to_new_buffer ( +// opt_cod, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_KPM_RANfunction_Description, descriptor); + +// if (encodedMsg.result.encoded < 0) +// { +// NS_FATAL_ERROR ("Error during the encoding of the RIC Indication Header, errno: " +// << strerror (errno) << ", failed_type " << encodedMsg.result.failed_type->name +// << ", structure_ptr " << encodedMsg.result.structure_ptr); +// } + +// m_buffer = encodedMsg.buffer; +// m_size = encodedMsg.result.encoded; +// } + +} // namespace ns3 diff --git a/model/function-description.h b/model/function-description.h new file mode 100644 index 0000000..28b388b --- /dev/null +++ b/model/function-description.h @@ -0,0 +1,59 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef FUNCTION_DESCRIPTION_H +#define FUNCTION_DESCRIPTION_H + +#include "ns3/object.h" + +// extern "C" { +// #include "E2SM-KPM-RANfunction-Description.h" +// #include "E2SM-KPM-IndicationHeader.h" +// #include "E2SM-KPM-IndicationMessage.h" +// #include "RAN-Container.h" +// #include "PF-Container.h" +// #include "OCUUP-PF-Container.h" +// #include "PF-ContainerListItem.h" +// #include "asn1c-types.h" +// } + +namespace ns3 { + + class FunctionDescription : public SimpleRefCount + { + public: + FunctionDescription (); + ~FunctionDescription (); + + void* m_buffer; + size_t m_size; + + // TODO improve the abstraction +// private: +// virtual void Encode (E2SM_KPM_RANfunction_Description_t* descriptor); + }; + +} + +#endif /* FUNCTION_DESCRIPTION_H */ diff --git a/model/kpm-function-description.cc b/model/kpm-function-description.cc new file mode 100644 index 0000000..b318503 --- /dev/null +++ b/model/kpm-function-description.cc @@ -0,0 +1,147 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include +#include + +extern "C" { +#include "RIC-EventTriggerStyle-Item.h" +#include "RIC-ReportStyle-Item.h" +} + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("KpmFunctionDescription"); + +KpmFunctionDescription::KpmFunctionDescription () +{ + E2SM_KPM_RANfunction_Description_t *descriptor = new E2SM_KPM_RANfunction_Description_t (); + FillAndEncodeKpmFunctionDescription (descriptor); + ASN_STRUCT_FREE_CONTENTS_ONLY (asn_DEF_E2SM_KPM_RANfunction_Description, descriptor); + delete descriptor; +} + +KpmFunctionDescription::~KpmFunctionDescription () +{ + free (m_buffer); + m_size = 0; +} + +void +KpmFunctionDescription::Encode (E2SM_KPM_RANfunction_Description_t *descriptor) +{ + asn_codec_ctx_t *opt_cod = 0; // disable stack bounds checking + // encode the structure into the e2smbuffer + asn_encode_to_new_buffer_result_s encodedMsg = asn_encode_to_new_buffer ( + opt_cod, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_KPM_RANfunction_Description, descriptor); + + if (encodedMsg.result.encoded < 0) + { + NS_FATAL_ERROR ("Error during the encoding of the RIC Indication Header, errno: " + << strerror (errno) << ", failed_type " << encodedMsg.result.failed_type->name + << ", structure_ptr " << encodedMsg.result.structure_ptr); + } + + m_buffer = encodedMsg.buffer; + m_size = encodedMsg.result.encoded; +} + +void +KpmFunctionDescription::FillAndEncodeKpmFunctionDescription ( + E2SM_KPM_RANfunction_Description_t *ranfunc_desc) +{ + std::string shortNameBuffer = "ORAN-WG3-KPM"; + uint8_t *descriptionBuffer = (uint8_t *) "KPM monitor"; + uint8_t *oidBuffer = (uint8_t *) "OID123"; // this is optional, dummy value + + Ptr shortName = Create (shortNameBuffer, shortNameBuffer.size ()); + + ranfunc_desc->ranFunction_Name.ranFunction_ShortName = shortName->GetValue (); + + long *inst = (long *) calloc (1, sizeof (long)); + + // ranfunc_desc->ranFunction_Name.ranFunction_Description = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t)); + ranfunc_desc->ranFunction_Name.ranFunction_Description.buf = + (uint8_t *) calloc (1, strlen ((char *) descriptionBuffer)); + memcpy (ranfunc_desc->ranFunction_Name.ranFunction_Description.buf, descriptionBuffer, + strlen ((char *) descriptionBuffer)); + ranfunc_desc->ranFunction_Name.ranFunction_Description.size = strlen ((char *) descriptionBuffer); + ranfunc_desc->ranFunction_Name.ranFunction_Instance = inst; + + // ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t)); + ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.buf = + (uint8_t *) calloc (1, strlen ((char *) oidBuffer)); + memcpy (ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.buf, oidBuffer, + strlen ((char *) oidBuffer)); + ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.size = strlen ((char *) oidBuffer); + + RIC_EventTriggerStyle_Item_t *trigger_style = + (RIC_EventTriggerStyle_Item_t *) calloc (1, sizeof (RIC_EventTriggerStyle_Item_t)); + trigger_style->ric_EventTriggerStyle_Type = 1; + uint8_t *eventTriggerStyleNameBuffer = (uint8_t *) "Periodic report"; + // trigger_style->ric_EventTriggerStyle_Name = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t)); + trigger_style->ric_EventTriggerStyle_Name.buf = + (uint8_t *) calloc (1, strlen ((char *) eventTriggerStyleNameBuffer)); + memcpy (trigger_style->ric_EventTriggerStyle_Name.buf, eventTriggerStyleNameBuffer, + strlen ((char *) eventTriggerStyleNameBuffer)); + trigger_style->ric_EventTriggerStyle_Name.size = strlen ((char *) eventTriggerStyleNameBuffer); + trigger_style->ric_EventTriggerFormat_Type = 1; + + ranfunc_desc->ric_EventTriggerStyle_List = + (E2SM_KPM_RANfunction_Description:: + E2SM_KPM_RANfunction_Description__ric_EventTriggerStyle_List *) + calloc (1, sizeof (E2SM_KPM_RANfunction_Description:: + E2SM_KPM_RANfunction_Description__ric_EventTriggerStyle_List)); + + ASN_SEQUENCE_ADD (&ranfunc_desc->ric_EventTriggerStyle_List->list, trigger_style); + + RIC_ReportStyle_Item_t *report_style1 = + (RIC_ReportStyle_Item_t *) calloc (1, sizeof (RIC_ReportStyle_Item_t)); + report_style1->ric_ReportStyle_Type = 1; + + uint8_t *reportStyleNameBuffer = + (uint8_t *) "O-CU-CP Measurement Container for the EPC connected deployment"; + + // report_style1->ric_ReportStyle_Name = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t)); + report_style1->ric_ReportStyle_Name.buf = + (uint8_t *) calloc (1, strlen ((char *) reportStyleNameBuffer)); + memcpy (report_style1->ric_ReportStyle_Name.buf, reportStyleNameBuffer, + strlen ((char *) reportStyleNameBuffer)); + report_style1->ric_ReportStyle_Name.size = strlen ((char *) reportStyleNameBuffer); + report_style1->ric_ReportIndicationHeaderFormat_Type = 1; + report_style1->ric_ReportIndicationMessageFormat_Type = 1; + ranfunc_desc->ric_ReportStyle_List = + (E2SM_KPM_RANfunction_Description::E2SM_KPM_RANfunction_Description__ric_ReportStyle_List *) + calloc (1, sizeof (E2SM_KPM_RANfunction_Description:: + E2SM_KPM_RANfunction_Description__ric_ReportStyle_List)); + + ASN_SEQUENCE_ADD (&ranfunc_desc->ric_ReportStyle_List->list, report_style1); + + Encode (ranfunc_desc); + + NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_E2SM_KPM_RANfunction_Description, ranfunc_desc)); +} + +} // namespace ns3 diff --git a/model/kpm-function-description.h b/model/kpm-function-description.h new file mode 100644 index 0000000..2cbb101 --- /dev/null +++ b/model/kpm-function-description.h @@ -0,0 +1,62 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef KPM_FUNCTION_DESCRIPTION_H +#define KPM_FUNCTION_DESCRIPTION_H + +#include "ns3/object.h" +#include + +extern "C" { + #include "E2SM-KPM-RANfunction-Description.h" + #include "E2SM-KPM-IndicationHeader.h" + #include "E2SM-KPM-IndicationMessage.h" + #include "RAN-Container.h" + #include "PF-Container.h" + #include "OCUUP-PF-Container.h" + #include "PF-ContainerListItem.h" + #include "asn1c-types.h" +} + +namespace ns3 { + + class KpmFunctionDescription : public FunctionDescription + { + public: + KpmFunctionDescription (); + ~KpmFunctionDescription (); + + private: + /** + * Encodes the RAN Function Description item for the KPM Service Model. + * + * \param kpmFunctionDescription the RAN Function Description item + */ + void FillAndEncodeKpmFunctionDescription (E2SM_KPM_RANfunction_Description_t* descriptor); + void Encode (E2SM_KPM_RANfunction_Description_t* descriptor); + }; + +} + +#endif /* KPM_FUNCTION_DESCRIPTION_H */ diff --git a/model/kpm-indication.cc b/model/kpm-indication.cc new file mode 100644 index 0000000..ae237e0 --- /dev/null +++ b/model/kpm-indication.cc @@ -0,0 +1,506 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include +#include + +extern "C" { +#include "E2SM-KPM-IndicationHeader-Format1.h" +#include "E2SM-KPM-IndicationMessage-Format1.h" +#include "GlobalE2node-ID.h" +#include "GlobalE2node-gNB-ID.h" +#include "GlobalE2node-eNB-ID.h" +#include "GlobalE2node-ng-eNB-ID.h" +#include "GlobalE2node-en-gNB-ID.h" +#include "NRCGI.h" +#include "PM-Containers-Item.h" +#include "RIC-EventTriggerStyle-Item.h" +#include "RIC-ReportStyle-Item.h" +#include "TimeStamp.h" +#include "CUUPMeasurement-Container.h" +#include "PlmnID-Item.h" +#include "EPC-CUUP-PM-Format.h" +#include "PerQCIReportListItemFormat.h" +#include "PerUE-PM-Item.h" +#include "PM-Info-Item.h" +#include "MeasurementInfoList.h" +#include "CellObjectID.h" +#include "CellResourceReportListItem.h" +#include "ServedPlmnPerCellListItem.h" +#include "EPC-DU-PM-Container.h" +#include "PerQCIReportListItem.h" +} + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("KpmIndication"); + +KpmIndicationHeader::KpmIndicationHeader (GlobalE2nodeType nodeType,KpmRicIndicationHeaderValues values) +{ + m_nodeType = nodeType; + E2SM_KPM_IndicationHeader_t *descriptor = new E2SM_KPM_IndicationHeader_t; + FillAndEncodeKpmRicIndicationHeader (descriptor, values); + delete descriptor; +} + +KpmIndicationHeader::~KpmIndicationHeader () +{ + NS_LOG_FUNCTION (this); + free (m_buffer); + m_size = 0; +} + +void +KpmIndicationHeader::Encode (E2SM_KPM_IndicationHeader_t *descriptor) +{ + asn_codec_ctx_t *opt_cod = 0; // disable stack bounds checking + asn_encode_to_new_buffer_result_s encodedHeader = asn_encode_to_new_buffer ( + opt_cod, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_KPM_IndicationHeader, descriptor); + + if (encodedHeader.result.encoded < 0) + { + NS_FATAL_ERROR ("Error during the encoding of the RIC Indication Header, errno: " + << strerror (errno) << ", failed_type " + << encodedHeader.result.failed_type->name << ", structure_ptr " + << encodedHeader.result.structure_ptr); + } + + m_buffer = encodedHeader.buffer; + m_size = encodedHeader.result.encoded; +} + +void +KpmIndicationHeader::FillAndEncodeKpmRicIndicationHeader (E2SM_KPM_IndicationHeader_t *descriptor, + KpmRicIndicationHeaderValues values) +{ + + E2SM_KPM_IndicationHeader_Format1_t *ind_header = (E2SM_KPM_IndicationHeader_Format1_t *) calloc ( + 1, sizeof (E2SM_KPM_IndicationHeader_Format1_t)); + + Ptr plmnid = Create (values.m_plmId, 3); + Ptr cellId_bstring; + + GlobalE2node_ID *globalE2nodeIdBuf = (GlobalE2node_ID *) calloc (1, sizeof (GlobalE2node_ID)); + ind_header->id_GlobalE2node_ID = *globalE2nodeIdBuf; + + switch (m_nodeType) + { + case gNB: { + static int sizeGnb = 4; // 3GPP Specs + + cellId_bstring = Create (values.m_gnbId, sizeGnb); + + ind_header->id_GlobalE2node_ID.present = GlobalE2node_ID_PR_gNB; + GlobalE2node_gNB_ID_t *globalE2node_gNB_ID = + (GlobalE2node_gNB_ID_t *) calloc (1, sizeof (GlobalE2node_gNB_ID_t)); + globalE2node_gNB_ID->global_gNB_ID.plmn_id = plmnid->GetValue (); + globalE2node_gNB_ID->global_gNB_ID.gnb_id.present = GNB_ID_Choice_PR_gnb_ID; + globalE2node_gNB_ID->global_gNB_ID.gnb_id.choice.gnb_ID = cellId_bstring->GetValue (); + ind_header->id_GlobalE2node_ID.choice.gNB = globalE2node_gNB_ID; + } + break; + + case eNB: { + static int sizeEnb = + 3; // 3GPP TS 36.413 version 14.8.0 Release 14, Section 9.2.1.37 Global eNB ID + static int unsedSizeEnb = 4; + + cellId_bstring = Create (values.m_gnbId, sizeEnb, unsedSizeEnb); + + ind_header->id_GlobalE2node_ID.present = GlobalE2node_ID_PR_eNB; + GlobalE2node_eNB_ID_t *globalE2node_eNB_ID = + (GlobalE2node_eNB_ID_t *) calloc (1, sizeof (GlobalE2node_eNB_ID_t)); + globalE2node_eNB_ID->global_eNB_ID.pLMN_Identity = plmnid->GetValue (); + globalE2node_eNB_ID->global_eNB_ID.eNB_ID.present = ENB_ID_PR_macro_eNB_ID; + globalE2node_eNB_ID->global_eNB_ID.eNB_ID.choice.macro_eNB_ID = cellId_bstring->GetValue (); + ind_header->id_GlobalE2node_ID.choice.eNB = globalE2node_eNB_ID; + } + break; + + case ng_eNB: { + static int sizeEnb = + 3; // 3GPP TS 36.413 version 14.8.0 Release 14, Section 9.2.1.37 Global eNB ID + static int unsedSizeEnb = 4; + + cellId_bstring = Create (values.m_gnbId, sizeEnb, unsedSizeEnb); + + ind_header->id_GlobalE2node_ID.present = GlobalE2node_ID_PR_ng_eNB; + GlobalE2node_ng_eNB_ID_t *globalE2node_ng_eNB_ID = + (GlobalE2node_ng_eNB_ID_t *) calloc (1, sizeof (GlobalE2node_ng_eNB_ID_t)); + + globalE2node_ng_eNB_ID->global_ng_eNB_ID.plmn_id = plmnid->GetValue (); + globalE2node_ng_eNB_ID->global_ng_eNB_ID.enb_id.present = ENB_ID_Choice_PR_enb_ID_macro; + globalE2node_ng_eNB_ID->global_ng_eNB_ID.enb_id.choice.enb_ID_macro = + cellId_bstring->GetValue (); + ind_header->id_GlobalE2node_ID.choice.ng_eNB = globalE2node_ng_eNB_ID; + } + break; + + case en_gNB: { + static int sizeGnb = 4; // 3GPP Specs + cellId_bstring = Create (values.m_gnbId, sizeGnb); + + ind_header->id_GlobalE2node_ID.present = GlobalE2node_ID_PR_en_gNB; + GlobalE2node_en_gNB_ID_t *globalE2node_en_gNB_ID = + (GlobalE2node_en_gNB_ID_t *) calloc (1, sizeof (GlobalE2node_en_gNB_ID_t)); + globalE2node_en_gNB_ID->global_gNB_ID.pLMN_Identity = plmnid->GetValue (); + globalE2node_en_gNB_ID->global_gNB_ID.gNB_ID.present = ENGNB_ID_PR_gNB_ID; + globalE2node_en_gNB_ID->global_gNB_ID.gNB_ID.choice.gNB_ID = cellId_bstring->GetValue (); + ind_header->id_GlobalE2node_ID.choice.en_gNB = globalE2node_en_gNB_ID; + } + break; + + default: + NS_FATAL_ERROR ( + "Unrecognized node type for KpmRicIndicationHeader, value passed: " << m_nodeType); + break; + } + + NS_LOG_DEBUG ("Timestamp received: " << values.m_timestamp); + long bigEndianTimestamp = htobe64 (values.m_timestamp); + NS_LOG_DEBUG ("Timestamp inverted: " << bigEndianTimestamp); + + Ptr ts = Create ((void *) &bigEndianTimestamp, TIMESTAMP_LIMIT_SIZE); + //NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_OCTET_STRING, ts->GetPointer() )); + + // Ptr ts2 = Create ((void *) &values.m_timestamp, TIMESTAMP_LIMIT_SIZE); + // NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_OCTET_STRING, ts2->GetPointer())); + + ind_header->collectionStartTime = ts->GetValue (); + + + NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_E2SM_KPM_IndicationHeader_Format1, ind_header)); + + descriptor->present = E2SM_KPM_IndicationHeader_PR_indicationHeader_Format1; + descriptor->choice.indicationHeader_Format1 = ind_header; + + Encode (descriptor); + ASN_STRUCT_FREE (asn_DEF_E2SM_KPM_IndicationHeader_Format1, ind_header); + free (globalE2nodeIdBuf); + // TraceMessage (&asn_DEF_E2SM_KPM_IndicationHeader, header, "RIC Indication Header"); +} + +KpmIndicationMessage::KpmIndicationMessage (KpmIndicationMessageValues values) +{ + E2SM_KPM_IndicationMessage_t *descriptor = new E2SM_KPM_IndicationMessage_t (); + CheckConstraints (values); + FillAndEncodeKpmIndicationMessage (descriptor, values); + delete descriptor; +} + +KpmIndicationMessage::~KpmIndicationMessage () +{ + free (m_buffer); + m_size = 0; +} + +void +KpmIndicationMessage::CheckConstraints (KpmIndicationMessageValues values) +{ + // TODO remove? + // if (values.m_crnti.length () != 2) + // { + // NS_FATAL_ERROR ("C-RNTI should have length 2"); + // } + // if (values.m_plmId.length () != 3) + // { + // NS_FATAL_ERROR ("PLMID should have length 3"); + // } + // if (values.m_nrCellId.length () != 5) + // { + // NS_FATAL_ERROR ("NR Cell ID should have length 5"); + // } + // TODO add other constraints +} + +void +KpmIndicationMessage::Encode (E2SM_KPM_IndicationMessage_t *descriptor) +{ + asn_codec_ctx_t *opt_cod = 0; // disable stack bounds checking + asn_encode_to_new_buffer_result_s encodedMsg = asn_encode_to_new_buffer ( + opt_cod, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_KPM_IndicationMessage, descriptor); + + if (encodedMsg.result.encoded < 0) + { + NS_FATAL_ERROR ("Error during the encoding of the RIC Indication Message, errno: " + << strerror (errno) << ", failed_type " << encodedMsg.result.failed_type->name + << ", structure_ptr " << encodedMsg.result.structure_ptr); + } + + m_buffer = encodedMsg.buffer; + m_size = encodedMsg.result.encoded; +} + +void +KpmIndicationMessage::FillPmContainer (PF_Container_t *ranContainer, Ptr values) +{ + Ptr cuUpVal = DynamicCast (values); + Ptr cuCpVal = DynamicCast (values); + Ptr duVal = DynamicCast (values); + + if (cuUpVal) + { + FillOCuUpContainer (ranContainer, cuUpVal); + } + else if (cuCpVal) + { + FillOCuCpContainer (ranContainer, cuCpVal); + } + else if (duVal) + { + FillODuContainer (ranContainer, duVal); + } + else + { + NS_FATAL_ERROR ("Unknown PM Container type"); + } +} + +void +KpmIndicationMessage::FillOCuUpContainer (PF_Container_t *ranContainer, + Ptr values) +{ + OCUUP_PF_Container_t* ocuup = (OCUUP_PF_Container_t*) calloc (1, sizeof (OCUUP_PF_Container_t)); + PF_ContainerListItem_t* pcli = (PF_ContainerListItem_t*) calloc (1, sizeof (PF_ContainerListItem_t)); + pcli->interface_type = NI_Type_x2_u; + + CUUPMeasurement_Container_t* cuuppmc = (CUUPMeasurement_Container_t*) calloc (1, sizeof (CUUPMeasurement_Container_t)); + PlmnID_Item_t* plmnItem = (PlmnID_Item_t*) calloc (1, sizeof (PlmnID_Item_t)); + Ptr plmnidstr = Create (values->m_plmId, 3); + plmnItem->pLMN_Identity = plmnidstr->GetValue (); + + EPC_CUUP_PM_Format_t* cuuppmf = (EPC_CUUP_PM_Format_t*) calloc (1, sizeof (EPC_CUUP_PM_Format_t)); + plmnItem->cu_UP_PM_EPC = cuuppmf; + PerQCIReportListItemFormat_t* pqrli = (PerQCIReportListItemFormat_t*) calloc (1, sizeof (PerQCIReportListItemFormat_t)); + pqrli->drbqci = 0; + + INTEGER_t *pDCPBytesDL = (INTEGER_t *) calloc (1, sizeof (INTEGER_t)); + INTEGER_t *pDCPBytesUL = (INTEGER_t *) calloc (1, sizeof (INTEGER_t)); + + asn_long2INTEGER (pDCPBytesDL, values->m_pDCPBytesDL); + asn_long2INTEGER (pDCPBytesUL, values->m_pDCPBytesUL); + + pqrli->pDCPBytesDL = pDCPBytesDL; + pqrli->pDCPBytesUL = pDCPBytesUL; + + ASN_SEQUENCE_ADD (&cuuppmf->perQCIReportList_cuup.list, pqrli); + + ASN_SEQUENCE_ADD (&cuuppmc->plmnList.list, plmnItem); + + pcli->o_CU_UP_PM_Container = *cuuppmc; + ASN_SEQUENCE_ADD (&ocuup->pf_ContainerList, pcli); + ranContainer->choice.oCU_UP = ocuup; + ranContainer->present = PF_Container_PR_oCU_UP; + + free (cuuppmc); +} + +void +KpmIndicationMessage::FillOCuCpContainer (PF_Container_t *ranContainer, + Ptr values) +{ + OCUCP_PF_Container_t *ocucp = (OCUCP_PF_Container_t *) calloc (1, sizeof(OCUCP_PF_Container_t)); + long *numActiveUes = (long *) calloc (1, sizeof (long)); + *numActiveUes = long(values->m_numActiveUes); + ocucp->cu_CP_Resource_Status.numberOfActive_UEs = numActiveUes; + ranContainer->choice.oCU_CP = ocucp; + ranContainer->present = PF_Container_PR_oCU_CP; +} + +void +KpmIndicationMessage::FillODuContainer (PF_Container_t *ranContainer, + Ptr values) +{ + ODU_PF_Container_t *odu = (ODU_PF_Container_t *) calloc (1, sizeof (ODU_PF_Container_t)); + + for (auto cellReport : values->m_cellResourceReportItems) + { + NS_LOG_LOGIC ("O-DU: Add Cell Resource Report Item"); + CellResourceReportListItem_t *crrli = + (CellResourceReportListItem_t *) calloc (1, sizeof (CellResourceReportListItem_t)); + + Ptr plmnid = Create (cellReport->m_plmId, 3); + Ptr nrcellid = Create (cellReport->m_nrCellId); + crrli->nRCGI.pLMN_Identity = plmnid->GetValue (); + crrli->nRCGI.nRCellIdentity = nrcellid->GetValue (); + + long *dlAvailablePrbs = (long *) calloc (1, sizeof (long)); + *dlAvailablePrbs = cellReport->dlAvailablePrbs; + crrli->dl_TotalofAvailablePRBs = dlAvailablePrbs; + + long *ulAvailablePrbs = (long *) calloc (1, sizeof (long)); + *ulAvailablePrbs = cellReport->ulAvailablePrbs; + crrli->ul_TotalofAvailablePRBs = ulAvailablePrbs; + ASN_SEQUENCE_ADD (&odu->cellResourceReportList.list, crrli); + + for (auto servedPlmnCell : cellReport->m_servedPlmnPerCellItems) + { + NS_LOG_LOGIC ("O-DU: Add Served Plmn Per Cell Item"); + ServedPlmnPerCellListItem_t *sppcl = + (ServedPlmnPerCellListItem_t *) calloc (1, sizeof (ServedPlmnPerCellListItem_t)); + Ptr servedPlmnId = Create (servedPlmnCell->m_plmId, 3); + sppcl->pLMN_Identity = servedPlmnId->GetValue (); + + EPC_DU_PM_Container_t *edpc = + (EPC_DU_PM_Container_t *) calloc (1, sizeof (EPC_DU_PM_Container_t)); + + for (auto perQciReportItem : servedPlmnCell->m_perQciReportItems) + { + NS_LOG_LOGIC ("O-DU: Add Per QCI Report Item"); + PerQCIReportListItem_t *pqrl = + (PerQCIReportListItem_t *) calloc (1, sizeof (PerQCIReportListItem_t)); + pqrl->qci = perQciReportItem->m_qci; + + NS_ABORT_MSG_IF ((perQciReportItem->m_dlPrbUsage < 0) | (perQciReportItem->m_dlPrbUsage > 100), + "As per ASN definition, dl_PRBUsage should be between 0 and 100"); + long *dlUsedPrbs = (long *) calloc (1, sizeof (long)); + *dlUsedPrbs = perQciReportItem->m_dlPrbUsage; + pqrl->dl_PRBUsage = dlUsedPrbs; + NS_LOG_LOGIC ("DL PRBs " << dlUsedPrbs); + + NS_ABORT_MSG_IF ((perQciReportItem->m_ulPrbUsage < 0) | (perQciReportItem->m_ulPrbUsage > 100), + "As per ASN definition, ul_PRBUsage should be between 0 and 100"); + long *ulUsedPrbs = (long *) calloc (1, sizeof (long)); + *ulUsedPrbs = perQciReportItem->m_ulPrbUsage; + pqrl->ul_PRBUsage = ulUsedPrbs; + ASN_SEQUENCE_ADD (&edpc->perQCIReportList_du.list, pqrl); + } + + sppcl->du_PM_EPC = edpc; + ASN_SEQUENCE_ADD (&crrli->servedPlmnPerCellList.list, sppcl); + } + } + ranContainer->choice.oDU = odu; + ranContainer->present = PF_Container_PR_oDU; +} + +void +KpmIndicationMessage::FillAndEncodeKpmIndicationMessage (E2SM_KPM_IndicationMessage_t *descriptor, + KpmIndicationMessageValues values) +{ + // Create and fill the RAN Container + PF_Container_t *ranContainer = (PF_Container_t *) calloc (1, sizeof (PF_Container_t)); + FillPmContainer (ranContainer, values.m_pmContainerValues); + + //------- now fill the message + PM_Containers_Item_t *containers_list = + (PM_Containers_Item_t *) calloc (1, sizeof (PM_Containers_Item_t)); + containers_list->performanceContainer = ranContainer; + + E2SM_KPM_IndicationMessage_Format1_t *format = (E2SM_KPM_IndicationMessage_Format1_t *) calloc ( + 1, sizeof (E2SM_KPM_IndicationMessage_Format1_t)); + + ASN_SEQUENCE_ADD (&format->pm_Containers.list, containers_list); + + // Cell Object ID + CellObjectID_t *cellObjectID = (CellObjectID_t *) calloc (1, sizeof (CellObjectID_t)); + cellObjectID->size = values.m_cellObjectId.length (); + cellObjectID->buf = (uint8_t *) calloc (1, cellObjectID->size); + memcpy (cellObjectID->buf, values.m_cellObjectId.c_str (), values.m_cellObjectId.length ()); + format->cellObjectID = *cellObjectID; + + // Measurement Information List + if (values.m_cellMeasurementItems) + { + format->list_of_PM_Information = (E2SM_KPM_IndicationMessage_Format1:: + E2SM_KPM_IndicationMessage_Format1__list_of_PM_Information *) + calloc (1, sizeof (E2SM_KPM_IndicationMessage_Format1:: + E2SM_KPM_IndicationMessage_Format1__list_of_PM_Information)); + for (auto item : values.m_cellMeasurementItems->GetItems ()) + { + ASN_SEQUENCE_ADD (&format->list_of_PM_Information->list, item->GetPointer ()); + } + } + + // List of matched UEs + if (values.m_ueIndications.size () > 0) + { + format->list_of_matched_UEs = (E2SM_KPM_IndicationMessage_Format1_t::E2SM_KPM_IndicationMessage_Format1__list_of_matched_UEs*) + calloc (1, sizeof (E2SM_KPM_IndicationMessage_Format1_t::E2SM_KPM_IndicationMessage_Format1__list_of_matched_UEs)); + + + for (auto ueIndication : values.m_ueIndications) + { + PerUE_PM_Item_t *perUEItem = (PerUE_PM_Item_t *) calloc (1, sizeof (PerUE_PM_Item_t)); + + // UE Identity + perUEItem->ueId = ueIndication->GetId (); + // xer_fprint (stderr, &asn_DEF_UE_Identity, &perUEItem->ueId); + // NS_LOG_UNCOND ("Values " << ueIndication->m_drbIPLateDlUEID); + + // List of Measurements PM information + perUEItem->list_of_PM_Information = + (PerUE_PM_Item::PerUE_PM_Item__list_of_PM_Information *) calloc ( + 1, sizeof (PerUE_PM_Item::PerUE_PM_Item__list_of_PM_Information)); + + for (auto measurementItem : ueIndication->GetItems ()) + { + ASN_SEQUENCE_ADD (&perUEItem->list_of_PM_Information->list, + measurementItem->GetPointer ()); + } + ASN_SEQUENCE_ADD (&format->list_of_matched_UEs->list, perUEItem); + } + } + + descriptor->present = E2SM_KPM_IndicationMessage_PR_indicationMessage_Format1; + descriptor->choice.indicationMessage_Format1 = format; + + + NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_E2SM_KPM_IndicationMessage_Format1, format)); + + // xer_fprint (stderr, &asn_DEF_PF_Container, ranContainer); + Encode (descriptor); + + free (cellObjectID); + // free (ranContainer); + ASN_STRUCT_FREE (asn_DEF_E2SM_KPM_IndicationMessage_Format1, format); +} + +MeasurementItemList::MeasurementItemList () +{ + m_id = NULL; +} + +MeasurementItemList::MeasurementItemList (std::string id) +{ + m_id = Create (id, id.length ()); +} + +MeasurementItemList::~MeasurementItemList (){}; + +std::vector> +MeasurementItemList::GetItems () +{ + return m_items; +} + +OCTET_STRING_t +MeasurementItemList::GetId () +{ + NS_ABORT_IF (m_id == NULL); + return m_id->GetValue (); +} + +} // namespace ns3 diff --git a/model/kpm-indication.h b/model/kpm-indication.h new file mode 100644 index 0000000..7121ef0 --- /dev/null +++ b/model/kpm-indication.h @@ -0,0 +1,256 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef KPM_INDICATION_H +#define KPM_INDICATION_H + +#include "ns3/object.h" +#include + +extern "C" { + #include "E2SM-KPM-RANfunction-Description.h" + #include "E2SM-KPM-IndicationHeader.h" + #include "E2SM-KPM-IndicationMessage.h" + #include "RAN-Container.h" + #include "PF-Container.h" + #include "OCUUP-PF-Container.h" + #include "OCUCP-PF-Container.h" + #include "ODU-PF-Container.h" + #include "PF-ContainerListItem.h" + #include "asn1c-types.h" +} + +namespace ns3 { + + class KpmIndicationHeader : public SimpleRefCount + { + public: + enum GlobalE2nodeType { gNB = 0, eNB = 1, ng_eNB = 2, en_gNB = 3 }; + + const static int TIMESTAMP_LIMIT_SIZE = 8; + /** + * Holds the values to be used to fill the RIC Indication header + */ + struct KpmRicIndicationHeaderValues + { + // E2SM-KPM Indication Header Format 1 + // KPM Node ID IE + std::string m_gnbId; //!< gNB ID bit string + // TODO not supported + // uint64_t m_cuUpId; //!< gNB-CU-UP ID, integer [0, 2^36-1], optional + + // Cell Global ID (NR CGI) IE + uint16_t m_nrCellId; //!< NR, bit string + + // PLMN ID IE + std::string m_plmId; //!< PLMN identity, octet string, 3 bytes + + // Slice ID (S-NSSAI) IE // TODO not supported + // std::string m_sst; //!< SNSSAI sST, 1 byte + // std::string m_sd; //!< SNSSAI sD, 3 bytes, optional + + // FiveQI IE // TODO not supported + // uint8_t m_fiveqi; //!< fiveQI, integer [0, 255], optional + + // QCI IE // TODO not supported + // long m_qci; //!< QCI, integer [0, 255], optional + + // TODO this value is placed in a fiels which seems not to be defined + // in the specs. See line 301 in encode_kpm.cpp + // the field is called gNB_DU_ID + // it should be part of KPM Node ID IE + // m_duId + + // TODO this value is placed in a fiels which seems not to be defined + // in the specs. See line 290 in encode_kpm.cpp, the field is called + // gNB_Name + // m_cuUpName + + // CollectionTimeStamp + uint64_t m_timestamp; + }; + + KpmIndicationHeader (GlobalE2nodeType nodeType,KpmRicIndicationHeaderValues values); + ~KpmIndicationHeader (); + void* m_buffer; + size_t m_size; + + private: + /** + * Fills the KPM INDICATION Header descriptor + * This function fills the RIC Indication Header with the provided + * values + * + * \param descriptor object representing the KPM INDICATION Header + * \param values struct holding the values to be used to fill the header + */ + void FillAndEncodeKpmRicIndicationHeader (E2SM_KPM_IndicationHeader_t* descriptor, + KpmRicIndicationHeaderValues values); + + void Encode (E2SM_KPM_IndicationHeader_t* descriptor); + + GlobalE2nodeType m_nodeType; + }; + + class MeasurementItemList : public SimpleRefCount + { + private: + Ptr m_id; // ID, contains the UE IMSI if used to carry UE-specific measurement items + std::vector> m_items; //!< list of Measurement Information Items + public: + MeasurementItemList (); + MeasurementItemList (std::string ueId); + ~MeasurementItemList (); + + // NOTE defined here to avoid undefined references + template + void AddItem (std::string name, T value) + { + Ptr item = Create (name, value); + m_items.push_back (item); + } + + std::vector> GetItems(); + OCTET_STRING_t GetId (); + }; + + /** + * Base class to carry PM Container values + */ + class PmContainerValues : public SimpleRefCount + { + public: + virtual ~PmContainerValues () = default; + }; + + /** + * Contains the values to be inserted in the O-CU-CP Measurement Container + */ + class OCuCpContainerValues : public PmContainerValues + { + public: + uint16_t m_numActiveUes; //!< mean number of RRC connections + }; + + /** + * Contains the values to be inserted in the O-CU-UP Measurement Container + */ + class OCuUpContainerValues : public PmContainerValues + { + public: + std::string m_plmId; //!< PLMN identity, octet string, 3 bytes + long m_pDCPBytesUL; //!< total PDCP bytes transmitted UL + long m_pDCPBytesDL; //!< total PDCP bytes transmitted DL + }; + + /** + * Contains the values to be inserted in the O-DU EPC Measurement Container + */ + class EpcDuPmContainer : public SimpleRefCount + { + public: + long m_qci; //!< QCI value + long m_dlPrbUsage; //!< Used number of PRBs in an average of DL for the monitored slice during E2 reporting period + long m_ulPrbUsage; //!< Used number of PRBs in an average of UL for the monitored slice during E2 reporting period + virtual ~EpcDuPmContainer () = default; + }; + + /** + * Contains the values to be inserted in the O-DU 5GC Measurement Container + */ + class FiveGcDuPmContainer : public SimpleRefCount + { + public: + // Snssai m_sliceId; //!< S-NSSAI + long m_fiveQi; //!< 5QI value + long m_dlPrbUsage; //!< Used number of PRBs in an average of DL for the monitored slice during E2 reporting period + long m_ulPrbUsage; //!< Used number of PRBs in an average of UL for the monitored slice during E2 reporting period + virtual ~FiveGcDuPmContainer () = default; + }; + + class ServedPlmnPerCell : public SimpleRefCount + { + public: + std::string m_plmId; //!< PLMN identity, octet string, 3 bytes + uint16_t m_nrCellId; + std::set> m_perQciReportItems; + }; + + class CellResourceReport : public SimpleRefCount + { + public: + std::string m_plmId; //!< PLMN identity, octet string, 3 bytes + uint16_t m_nrCellId; + long dlAvailablePrbs; + long ulAvailablePrbs; + std::set> m_servedPlmnPerCellItems; + }; + + /** + * Contains the values to be inserted in the O-DU Measurement Container + */ + class ODuContainerValues : public PmContainerValues + { + public: + std::set> m_cellResourceReportItems; + }; + + class KpmIndicationMessage : public SimpleRefCount + { + public: + + /** + * Holds the values to be used to fill the RIC Indication Message + */ + struct KpmIndicationMessageValues + { + std::string m_cellObjectId; //!< Cell Object ID + Ptr m_pmContainerValues; //!< struct containing values to be inserted in the PM Container + Ptr m_cellMeasurementItems; //!< list of cell-specific Measurement Information Items + std::set> m_ueIndications; //!< list of Measurement Information Items + }; + + KpmIndicationMessage (KpmIndicationMessageValues values); + ~KpmIndicationMessage (); + + void* m_buffer; + size_t m_size; + + private: + static void CheckConstraints (KpmIndicationMessageValues values); + void FillPmContainer (PF_Container_t *ranContainer, + Ptr values); + void FillOCuUpContainer (PF_Container_t *ranContainer, + Ptr values); + void FillOCuCpContainer (PF_Container_t *ranContainer, + Ptr values); + void FillODuContainer (PF_Container_t *ranContainer, + Ptr values); + void FillAndEncodeKpmIndicationMessage (E2SM_KPM_IndicationMessage_t *descriptor, + KpmIndicationMessageValues values); + void Encode (E2SM_KPM_IndicationMessage_t *descriptor); + }; +} + +#endif /* KPM_INDICATION_H */ diff --git a/model/oran-interface.cc b/model/oran-interface.cc new file mode 100644 index 0000000..4baf123 --- /dev/null +++ b/model/oran-interface.cc @@ -0,0 +1,288 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include + +#include +#include +#include "encode_e2apv1.hpp" + +extern "C" { + #include "RICsubscriptionRequest.h" + #include "RICactionType.h" + #include "ProtocolIE-Field.h" + #include "InitiatingMessage.h" +} + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("E2Termination"); + +NS_OBJECT_ENSURE_REGISTERED (E2Termination); + +TypeId E2Termination::GetTypeId () +{ + static TypeId tid = TypeId ("ns3::E2Termination") + .SetParent() + .AddConstructor(); + return tid; +} + +E2Termination::E2Termination () +{ + NS_FATAL_ERROR("Do not use the default constructor"); +} + +E2Termination::E2Termination(const std::string ricAddress, + const uint16_t ricPort, + const uint16_t clientPort, + const std::string gnbId, + const std::string plmnId) + : m_ricAddress (ricAddress), + m_ricPort (ricPort), + m_clientPort (clientPort), + m_gnbId (gnbId), + m_plmnId(plmnId) +{ + NS_LOG_FUNCTION (this); + m_e2sim = new E2Sim; + + // create a new file which will be used to trace the encoded messages + // TODO create an appropriate log class to handle these messages + // FILE* f = fopen ("messages.txt", "w"); + // fclose (f); +} + +void +E2Termination::RegisterFunctionDescToE2Sm (long ranFunctionId, Ptr ranFunctionDescription) +{ + // create an octet string and copy the e2smbuffer + OCTET_STRING_t *rfdBuf = (OCTET_STRING_t *) calloc (1, sizeof (OCTET_STRING_t)); + rfdBuf->buf = (uint8_t *) calloc (1, ranFunctionDescription->m_size); + rfdBuf->size = ranFunctionDescription->m_size; + memcpy (rfdBuf->buf, ranFunctionDescription->m_buffer, ranFunctionDescription->m_size); + + m_e2sim->register_e2sm (ranFunctionId, rfdBuf); +} + +void +E2Termination::RegisterKpmCallbackToE2Sm (long ranFunctionId, Ptr ranFunctionDescription, + SubscriptionCallback sbCb) +{ + RegisterFunctionDescToE2Sm (ranFunctionId,ranFunctionDescription); + m_e2sim->register_subscription_callback (ranFunctionId, sbCb); +} + +void +E2Termination::RegisterSmCallbackToE2Sm (long ranFunctionId, Ptr ranFunctionDescription, SmCallback smCb) +{ + RegisterFunctionDescToE2Sm (ranFunctionId,ranFunctionDescription); + m_e2sim->register_sm_callback (ranFunctionId, smCb); +} + +void E2Termination::Start () +{ + NS_LOG_FUNCTION (this); + + NS_ABORT_MSG_IF(m_ricAddress.empty(), "Set the RIC information first"); + + // create a thread to host e2sim execution + std::thread e2simThread (&E2Termination::DoStart, this); + e2simThread.detach (); +} + +void E2Termination::DoStart () +{ + NS_LOG_FUNCTION (this); + + // start e2sim main loop + // char second[14]; // RIC ADDRESS + // std::strcpy (second, m_ricAddress.c_str ()); + // char third[6]; // RIC PORT + // std::strcpy (third, std::to_string (m_ricPort).c_str ()); + // char fourth[5]; // GNB ID value + // std::strncpy (fourth, m_gnbId.c_str (), 4); + // char fifth[6]; // CLIENT PORT + // std::strcpy (fifth, std::to_string (m_clientPort).c_str ()); + // char sixth[4]; //PLMN ID + // std::strcpy (sixth, m_plmnId.c_str ()); + + NS_LOG_INFO ("In ns3::E2Term: GNB" << m_gnbId << ", clientPort " << m_clientPort << ", ricPort " + << m_ricPort << ", PlmnID " + << m_plmnId); + + // char* argv [] = {nullptr, &second [0], &third [0], &fourth[0], &fifth[0],&sixth[0]}; + m_e2sim->run_loop (m_ricAddress, m_ricPort, m_clientPort, m_gnbId, m_plmnId); +} + +E2Termination::~E2Termination () +{ + NS_LOG_FUNCTION (this); + delete m_e2sim; +} + +E2Termination::RicSubscriptionRequest_rval_s +E2Termination::ProcessRicSubscriptionRequest (E2AP_PDU_t* sub_req_pdu) +{ + //Record RIC Request ID + //Go through RIC action to be Setup List + //Find first entry with REPORT action Type + //Record ricActionID + //Encode subscription response + + RICsubscriptionRequest_t orig_req = sub_req_pdu->choice.initiatingMessage->value.choice.RICsubscriptionRequest; + + // RICsubscriptionResponse_IEs_t *ricreqid = (RICsubscriptionResponse_IEs_t*)calloc(1, sizeof(RICsubscriptionResponse_IEs_t)); + + int count = orig_req.protocolIEs.list.count; + int size = orig_req.protocolIEs.list.size; + + RICsubscriptionRequest_IEs_t **ies = (RICsubscriptionRequest_IEs_t**)orig_req.protocolIEs.list.array; + + NS_LOG_DEBUG ("Number of IEs " << count); + NS_LOG_DEBUG ("Size of IEs " << size); + + RICsubscriptionRequest_IEs__value_PR pres; + + uint16_t reqRequestorId {}; + uint16_t reqInstanceId {}; + uint16_t ranFuncionId {}; + uint8_t reqActionId {}; + + std::vector actionIdsAccept; + std::vector actionIdsReject; + + // iterate over the IEs + for (int i = 0; i < count; i++) + { + RICsubscriptionRequest_IEs_t *next_ie = ies[i]; + pres = next_ie->value.present; // value of the current IE + + switch(pres) + { + // IE containing the RIC Request ID + case RICsubscriptionRequest_IEs__value_PR_RICrequestID: + { + NS_LOG_DEBUG ("Processing RIC Request ID field"); + RICrequestID_t reqId = next_ie->value.choice.RICrequestID; + reqRequestorId = reqId.ricRequestorID; + reqInstanceId = reqId.ricInstanceID; + NS_LOG_DEBUG ( "RIC Requestor ID " << reqRequestorId); + NS_LOG_DEBUG ( "RIC Instance ID " << reqInstanceId); + break; + } + // IE containing the RAN Function ID + case RICsubscriptionRequest_IEs__value_PR_RANfunctionID: + { + NS_LOG_DEBUG ("Processing RAN Function ID field"); + ranFuncionId = next_ie->value.choice.RANfunctionID; + NS_LOG_DEBUG ("RAN Function ID " << ranFuncionId); + break; + } + case RICsubscriptionRequest_IEs__value_PR_RICsubscriptionDetails: + { + NS_LOG_DEBUG ("Processing RIC Subscription Details field"); + RICsubscriptionDetails_t subDetails = next_ie->value.choice.RICsubscriptionDetails; + + // RIC Event Trigger Definition + RICeventTriggerDefinition_t triggerDef = subDetails.ricEventTriggerDefinition; + + // TODO How to decode this field? + uint8_t size = 20; + uint8_t *buf = (uint8_t *)calloc(1,size); + memcpy(buf, &triggerDef, size); + NS_LOG_DEBUG ("RIC Event Trigger Definition " << std::to_string (*buf)); + + // Sequence of actions + RICactions_ToBeSetup_List_t actionList = subDetails.ricAction_ToBeSetup_List; + // TODO We are ignoring the trigger definition + + int actionCount = actionList.list.count; + NS_LOG_DEBUG ("Number of actions " << actionCount); + + auto **item_array = actionList.list.array; + bool foundAction = false; + + for (int i = 0; i < actionCount; i++) + { + auto *next_item = item_array[i]; + RICactionID_t actionId = ((RICaction_ToBeSetup_ItemIEs*)next_item)->value.choice.RICaction_ToBeSetup_Item.ricActionID; + RICactionType_t actionType = ((RICaction_ToBeSetup_ItemIEs*)next_item)->value.choice.RICaction_ToBeSetup_Item.ricActionType; + + //We identify the first action whose type is REPORT + //That is the only one accepted; all others are rejected + if (!foundAction && (actionType == RICactionType_report || actionType == RICactionType_insert)) + { + reqActionId = actionId; + actionIdsAccept.push_back(reqActionId); + NS_LOG_DEBUG ("Action ID " << actionId << " accepted"); + foundAction = true; + } + else + { + reqActionId = actionId; + NS_LOG_DEBUG ("Action ID " << actionId << " rejected"); + // actionIdsReject.push_back(reqActionId); + } + } + break; + } + default: + { + NS_LOG_DEBUG ("in case default"); + break; + } + } + } + + NS_LOG_DEBUG ("Create RIC Subscription Response"); + + E2AP_PDU *e2ap_pdu = (E2AP_PDU*)calloc(1,sizeof(E2AP_PDU)); + + long *accept_array = &actionIdsAccept[0]; + long *reject_array = &actionIdsReject[0]; + int accept_size = actionIdsAccept.size(); + int reject_size = actionIdsReject.size(); + + encoding::generate_e2apv1_subscription_response_success(e2ap_pdu, accept_array, reject_array, accept_size, reject_size, reqRequestorId, reqInstanceId); + + NS_LOG_DEBUG ("Send RIC Subscription Response"); + m_e2sim->encode_and_send_sctp_data(e2ap_pdu); + + RicSubscriptionRequest_rval_s reqParams; + reqParams.requestorId = reqRequestorId; + reqParams.instanceId = reqInstanceId; + reqParams.ranFuncionId = ranFuncionId; + reqParams.actionId = reqActionId; + return reqParams; +} + +void +E2Termination::SendE2Message (E2AP_PDU* pdu) +{ + m_e2sim->encode_and_send_sctp_data (pdu); +} + +} diff --git a/model/oran-interface.h b/model/oran-interface.h new file mode 100644 index 0000000..87a82d7 --- /dev/null +++ b/model/oran-interface.h @@ -0,0 +1,161 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef ORAN_INTERFACE_H +#define ORAN_INTERFACE_H + +#include "ns3/object.h" +#include +#include +#include +#include +#include "e2sim.hpp" + +namespace ns3 { + + class E2Termination : public Object + { + public: + + E2Termination(); + + /** + * + * \param ricAddress RIC IP address + * \param ricPort RIC port + * \param clientPort the local port to which the client will bind + * \param gnbId the GNB ID + * \param plmnId the PLMN ID + */ + E2Termination(const std::string ricAddress, + const uint16_t ricPort, + const uint16_t clientPort, + const std::string gnbId, + const std::string plmnId); + + virtual ~E2Termination (); + + /** + * inherited from Object + * @return + */ + static TypeId GetTypeId(); + + /** + * Start the E2 termination. + * Create a separate thread to host the execution of e2sim. The thread will + * execute the method DoStart. + */ + void Start (); + + /** + * Register an E2 Service Model. + * Create a RAN Function Description item containing the configurations + * for the SM, add it to the list of supported RAN functions, and + * register a callback. + * Whenever a RIC Subscription Request to this RAN Function is received, + * the callback is triggered. + * + * \param ranFunctionId ID used to identify the KPM RAN Function + * \param ranFunctionDescription + * \param cb callback that will be triggered if the RIC subscribes to + * this function + */ + void RegisterKpmCallbackToE2Sm (long ranFunctionId, + Ptr ranFunctionDescription, + SubscriptionCallback sbCb); + + /** + * Register an E2 Service Model. + * Create a RAN Function Description item containing the configurations + * for the SM, add it to the list of supported RAN functions, and + * register a callback. + * Whenever a Sm message to this RAN Function is received, + * the callback is triggered. + * + * \param ranFunctionId ID used to identify the KPM RAN Function + * \param ranFunctionDescription + * \param cb callback that will be triggered if the RIC subscribes to + * this function + */ + void RegisterSmCallbackToE2Sm (long ranFunctionId, + Ptr ranFunctionDescription, + SmCallback smCb); + + /** + * Struct holding the values returned by ProcessRicSubscriptionRequest + */ + struct RicSubscriptionRequest_rval_s + { + uint16_t requestorId; //!< RIC Requestor ID + uint16_t instanceId; //!< RIC Instance ID + uint16_t ranFuncionId; //!< RAN Function ID + uint8_t actionId; //!< RIC Action ID + }; + + /** + * Process RIC Subscription Request. + * This function processes the RIC Subscription Request and sends the + * RIC Subscription Response. + * + * \param sub_req_pdu request message + * \return RIC subscription request parameters + */ + RicSubscriptionRequest_rval_s ProcessRicSubscriptionRequest (E2AP_PDU_t* sub_req_pdu); + + /** + * Sends an E2 message to the RIC + * This function encodes and sends an E2 message to the RIC + * + * \param pdu the PDU of the message + */ + void SendE2Message (E2AP_PDU* pdu); + + private: + /** + * Run the e2sim main loop. + * Starts the e2sim main loop, it will open a socket towards the RIC and + * start the reception routine. + */ + void DoStart (); + + /** + * \brief Accessory function to populate to the registration of the ran function description to e2sim + * + * \param ranFunctionId + * \param ranFunctionDescription + */ + void RegisterFunctionDescToE2Sm (long ranFunctionId, + Ptr ranFunctionDescription); + + E2Sim* m_e2sim; //!< pointer to an instance of the O-RAN E2 simulator + std::string m_ricAddress; //!< IP address of the RIC + uint16_t m_ricPort; //!< port of the RIC + uint16_t m_clientPort; //!< local bind port + std::string m_gnbId; //!< GNB id + std::string m_plmnId; //!< PLMN Id + }; +} + +#endif /* ORAN_INTERFACE_H */ diff --git a/model/ric-control-function-description.cc b/model/ric-control-function-description.cc new file mode 100644 index 0000000..6bfea1c --- /dev/null +++ b/model/ric-control-function-description.cc @@ -0,0 +1,232 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include +#include + +extern "C" { + #include "RIC-ControlStyle-Item.h" + #include "RIC-ControlAction-Item.h" + #include "RAN-ControlParameter-Item.h" +} + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("RicControlFunctionDescription"); + +RicControlFunctionDescription::RicControlFunctionDescription () +{ + E2SM_RC_RANFunctionDefinition_t *descriptor = new E2SM_RC_RANFunctionDefinition_t (); + FillAndEncodeRCFunctionDescription (descriptor); + ASN_STRUCT_FREE_CONTENTS_ONLY (asn_DEF_E2SM_RC_RANFunctionDefinition, descriptor); + delete descriptor; +} + +RicControlFunctionDescription::~RicControlFunctionDescription () +{ + +} + +void +RicControlFunctionDescription::Encode (E2SM_RC_RANFunctionDefinition_t *descriptor) +{ + asn_codec_ctx_t *opt_cod = 0; // disable stack bounds checking + // encode the structure into the e2smbuffer + asn_encode_to_new_buffer_result_s encodedMsg = asn_encode_to_new_buffer ( + opt_cod, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_RC_RANFunctionDefinition, descriptor); + + if (encodedMsg.result.encoded < 0) + { + NS_FATAL_ERROR ("Error during the encoding of the RIC Indication Header, errno: " + << strerror (errno) << ", failed_type " << encodedMsg.result.failed_type->name + << ", structure_ptr " << encodedMsg.result.structure_ptr); + } + + m_buffer = encodedMsg.buffer; + m_size = encodedMsg.result.encoded; +} + +void +RicControlFunctionDescription::FillAndEncodeRCFunctionDescription ( + E2SM_RC_RANFunctionDefinition_t *ranfunc_desc) +{ + + std::string shortNameBuffer = "ORAN-WG3-RC"; + + Ptr shortName = Create (shortNameBuffer, shortNameBuffer.size ()); + + ranfunc_desc->ranFunction_Name.ranFunction_ShortName = shortName->GetValue (); + + // This part is not in the specs, maybe it can be removed? + + uint8_t *descriptionBuffer = (uint8_t *) "RIC Control Definitions"; + uint8_t *oidBuffer = (uint8_t *) "OID123"; // this is optional, dummy value + + long *inst = (long *) calloc (1, sizeof (long)); + + ranfunc_desc->ranFunction_Name.ranFunction_Description.buf = + (uint8_t *) calloc (1, strlen ((char *) descriptionBuffer)); + memcpy (ranfunc_desc->ranFunction_Name.ranFunction_Description.buf, descriptionBuffer, + strlen ((char *) descriptionBuffer)); + ranfunc_desc->ranFunction_Name.ranFunction_Description.size = strlen ((char *) descriptionBuffer); + ranfunc_desc->ranFunction_Name.ranFunction_Instance = inst; + ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.buf = + (uint8_t *) calloc (1, strlen ((char *) oidBuffer)); + memcpy (ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.buf, oidBuffer, + strlen ((char *) oidBuffer)); + ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.size = strlen ((char *) oidBuffer); + + // End part of of specs + + RIC_ControlStyle_Item_t *control_style0 = + (RIC_ControlStyle_Item_t *) calloc (1, sizeof (RIC_ControlStyle_Item_t)); + control_style0->ric_ControlStyle_Type = 1; + + uint8_t *controlStyleName0Buffer = (uint8_t *) "Radio Bearer Control"; + size_t controlStyleName0BufferSize = strlen ((char *) controlStyleName0Buffer); + control_style0->ric_ControlStyle_Name.buf = (uint8_t *) calloc (1, controlStyleName0BufferSize); + memcpy (control_style0->ric_ControlStyle_Name.buf, controlStyleName0Buffer, + controlStyleName0BufferSize); + control_style0->ric_ControlStyle_Name.size = controlStyleName0BufferSize; + + // these two were not present in the spec in this control style but just in the second, remove if they lead to crash + control_style0->ric_ControlMessageFormat_Type = 1; + control_style0->ric_ControlHeaderFormat_Type = 1; + + control_style0->ric_ControlAction_List = + (RIC_ControlStyle_Item::RIC_ControlStyle_Item__ric_ControlAction_List *) calloc ( + 1, sizeof (RIC_ControlStyle_Item::RIC_ControlStyle_Item__ric_ControlAction_List)); + + RIC_ControlAction_Item_t *control_action0 = + (RIC_ControlAction_Item_t *) calloc (1, sizeof (RIC_ControlAction_Item_t)); + + control_action0->ric_ControlAction_ID = 6; + uint8_t *controlActionName0Buffer = (uint8_t *) "DRB split ratio control"; + size_t controlActionName0BufferSize = strlen ((char *) controlActionName0Buffer); + control_action0->ric_ControlAction_Name.buf = + (uint8_t *) calloc (1, controlActionName0BufferSize); + memcpy (control_action0->ric_ControlAction_Name.buf, controlActionName0Buffer, + controlActionName0BufferSize); + control_action0->ric_ControlAction_Name.size = controlActionName0BufferSize; + control_action0->ran_ControlParameters_List = + (RIC_ControlAction_Item::RIC_ControlAction_Item__ran_ControlParameters_List *) calloc ( + 1, sizeof (RIC_ControlAction_Item::RIC_ControlAction_Item__ran_ControlParameters_List)); + + RAN_ControlParameter_Item_t *ranParameter0 = + (RAN_ControlParameter_Item_t *) calloc (1, sizeof (RAN_ControlParameter_Item_t)); + uint8_t *ranParameter0NameBuffer = (uint8_t *) "Downlink PDCP Data Split"; + size_t ranParameter0NameBufferSize = strlen ((char *) ranParameter0NameBuffer); + ranParameter0->ranParameter_Name.buf = (uint8_t *) calloc (1, ranParameter0NameBufferSize); + memcpy (ranParameter0->ranParameter_Name.buf, ranParameter0NameBuffer, + ranParameter0NameBufferSize); + ranParameter0->ranParameter_Name.size = ranParameter0NameBufferSize; + ranParameter0->ranParameter_ID = 3; + + RAN_ControlParameter_Item_t *ranParameter1 = + (RAN_ControlParameter_Item_t *) calloc (1, sizeof (RAN_ControlParameter_Item_t)); + uint8_t *ranParameter1NameBuffer = (uint8_t *) "Uplink PDCP Data Split Threshold"; + size_t ranParameter1NameBufferSize = strlen ((char *) ranParameter1NameBuffer); + ranParameter1->ranParameter_Name.buf = (uint8_t *) calloc (1, ranParameter1NameBufferSize); + memcpy (ranParameter1->ranParameter_Name.buf, ranParameter1NameBuffer, + ranParameter1NameBufferSize); + ranParameter1->ranParameter_ID = 2; + + ASN_SEQUENCE_ADD (&control_action0->ran_ControlParameters_List->list, ranParameter0); + ASN_SEQUENCE_ADD (&control_action0->ran_ControlParameters_List->list, ranParameter1); + + ASN_SEQUENCE_ADD (&control_style0->ric_ControlAction_List->list, control_action0); + + RIC_ControlStyle_Item_t *control_style1 = + (RIC_ControlStyle_Item_t *) calloc (1, sizeof (RIC_ControlStyle_Item_t)); + control_style1->ric_ControlStyle_Type = 3; + + uint8_t *controlStyleName1Buffer = (uint8_t *) "Radio Bearer Control"; + size_t controlStyleName1BufferSize = strlen ((char *) controlStyleName1Buffer); + control_style1->ric_ControlStyle_Name.buf = (uint8_t *) calloc (1, controlStyleName1BufferSize); + memcpy (control_style1->ric_ControlStyle_Name.buf, controlStyleName1Buffer, + controlStyleName1BufferSize); + control_style1->ric_ControlStyle_Name.size = controlStyleName1BufferSize; + + control_style1->ric_ControlMessageFormat_Type = 1; + control_style1->ric_ControlHeaderFormat_Type = 1; + + control_style1->ric_ControlAction_List = + (RIC_ControlStyle_Item::RIC_ControlStyle_Item__ric_ControlAction_List *) calloc ( + 1, sizeof (RIC_ControlStyle_Item::RIC_ControlStyle_Item__ric_ControlAction_List)); + + RIC_ControlAction_Item_t *control_action1 = + (RIC_ControlAction_Item_t *) calloc (1, sizeof (RIC_ControlAction_Item_t)); + + control_action1->ric_ControlAction_ID = 1; + uint8_t *controlActionName1Buffer = (uint8_t *) "Handover control"; + size_t controlActionName1BufferSize = strlen ((char *) controlActionName1Buffer); + control_action1->ric_ControlAction_Name.buf = + (uint8_t *) calloc (1, controlActionName1BufferSize); + memcpy (control_action1->ric_ControlAction_Name.buf, controlActionName1Buffer, + controlActionName1BufferSize); + control_action1->ric_ControlAction_Name.size = controlActionName1BufferSize; + control_action1->ran_ControlParameters_List = + (RIC_ControlAction_Item::RIC_ControlAction_Item__ran_ControlParameters_List *) calloc ( + 1, sizeof (RIC_ControlAction_Item::RIC_ControlAction_Item__ran_ControlParameters_List)); + + RAN_ControlParameter_Item_t *ranParameter2 = + (RAN_ControlParameter_Item_t *) calloc (1, sizeof (RAN_ControlParameter_Item_t)); + uint8_t *ranParameter2NameBuffer = (uint8_t *) "NR CGI"; + size_t ranParameter2NameBufferSize = strlen ((char *) ranParameter2NameBuffer); + ranParameter2->ranParameter_Name.buf = (uint8_t *) calloc (1, ranParameter2NameBufferSize); + memcpy (ranParameter2->ranParameter_Name.buf, ranParameter2NameBuffer, + ranParameter2NameBufferSize); + ranParameter2->ranParameter_Name.size = ranParameter2NameBufferSize; + ranParameter2->ranParameter_ID = 4; + + RAN_ControlParameter_Item_t *ranParameter3 = + (RAN_ControlParameter_Item_t *) calloc (1, sizeof (RAN_ControlParameter_Item_t)); + uint8_t *ranParameter3NameBuffer = (uint8_t *) "E-UTRA CGI"; + size_t ranParameter3NameBufferSize = strlen ((char *) ranParameter3NameBuffer); + ranParameter3->ranParameter_Name.buf = (uint8_t *) calloc (1, ranParameter3NameBufferSize); + memcpy (ranParameter3->ranParameter_Name.buf, ranParameter3NameBuffer, + ranParameter3NameBufferSize); + ranParameter3->ranParameter_Name.size = ranParameter3NameBufferSize; + ranParameter3->ranParameter_ID = 6; + + ASN_SEQUENCE_ADD (&control_action1->ran_ControlParameters_List->list, ranParameter2); + ASN_SEQUENCE_ADD (&control_action1->ran_ControlParameters_List->list, ranParameter3); + + ASN_SEQUENCE_ADD (&control_style1->ric_ControlAction_List->list, control_action1); + + ranfunc_desc->ric_ControlStyle_List = + (E2SM_RC_RANFunctionDefinition::E2SM_RC_RANFunctionDefinition__ric_ControlStyle_List *) + calloc (1, sizeof (E2SM_RC_RANFunctionDefinition:: + E2SM_RC_RANFunctionDefinition__ric_ControlStyle_List)); + + ASN_SEQUENCE_ADD (&ranfunc_desc->ric_ControlStyle_List->list, control_style0); + ASN_SEQUENCE_ADD (&ranfunc_desc->ric_ControlStyle_List->list, control_style1); + + Encode (ranfunc_desc); + + NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_E2SM_RC_RANFunctionDefinition, ranfunc_desc)); +} + +} // namespace ns3 diff --git a/model/ric-control-function-description.h b/model/ric-control-function-description.h new file mode 100644 index 0000000..08c9516 --- /dev/null +++ b/model/ric-control-function-description.h @@ -0,0 +1,51 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef RIC_CONTROL_FUNCTION_DESCRIPTION_H +#define RIC_CONTROL_FUNCTION_DESCRIPTION_H + +#include +#include "ns3/object.h" + +extern "C" { + #include "E2SM-RC-RANFunctionDefinition.h" +} + +namespace ns3 { + + class RicControlFunctionDescription : public FunctionDescription + { + public: + RicControlFunctionDescription (); + ~RicControlFunctionDescription (); + + + private: + + void FillAndEncodeRCFunctionDescription (E2SM_RC_RANFunctionDefinition_t* descriptor); + void Encode (E2SM_RC_RANFunctionDefinition_t* descriptor); + }; +} + +#endif /* RIC_CONTROL_FUNCTION_DESCRIPTION_H */ diff --git a/model/ric-control-message.cc b/model/ric-control-message.cc new file mode 100644 index 0000000..78252f1 --- /dev/null +++ b/model/ric-control-message.cc @@ -0,0 +1,218 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#include +#include +#include +#include +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("RicControlMessage"); + + +RicControlMessage::RicControlMessage (E2AP_PDU_t* pdu) +{ + DecodeRicControlMessage (pdu); + NS_LOG_INFO ("End of RicControlMessage::RicControlMessage()"); +} + +RicControlMessage::~RicControlMessage () +{ + +} + +void +RicControlMessage::DecodeRicControlMessage(E2AP_PDU_t* pdu) +{ + InitiatingMessage_t* mess = pdu->choice.initiatingMessage; + auto *request = (RICcontrolRequest_t *) &mess->value.choice.RICcontrolRequest; + NS_LOG_INFO (xer_fprint(stderr, &asn_DEF_RICcontrolRequest, request)); + + size_t count = request->protocolIEs.list.count; + if (count <= 0) { + NS_LOG_ERROR("[E2SM] received empty list"); + return; + } + + for (size_t i = 0; i < count; i++) + { + RICcontrolRequest_IEs_t *ie = request->protocolIEs.list.array [i]; + switch (ie->value.present) { + case RICcontrolRequest_IEs__value_PR_RICrequestID: { + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_RICrequestID"); + m_ricRequestId = ie->value.choice.RICrequestID; + switch (m_ricRequestId.ricRequestorID) { + case 1001: { + NS_LOG_DEBUG("TS xApp message"); + m_requestType = ControlMessageRequestIdType::TS; + break; + } + case 1002: { + NS_LOG_DEBUG("QoS xApp message"); + m_requestType = ControlMessageRequestIdType::QoS; + break; + } + } + break; + } + case RICcontrolRequest_IEs__value_PR_RANfunctionID: { + m_ranFunctionId = ie->value.choice.RANfunctionID; + + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_RANfunctionID"); + break; + } + case RICcontrolRequest_IEs__value_PR_RICcallProcessID: { + m_ricCallProcessId = ie->value.choice.RICcallProcessID; + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_RICcallProcessID"); + break; + } + case RICcontrolRequest_IEs__value_PR_RICcontrolHeader: { + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_RICcontrolHeader"); + // xer_fprint(stderr, &asn_DEF_RICcontrolHeader, &ie->value.choice.RICcontrolHeader); + + auto *e2smControlHeader = (E2SM_RC_ControlHeader_t *) calloc(1, + sizeof(E2SM_RC_ControlHeader_t)); + ASN_STRUCT_RESET(asn_DEF_E2SM_RC_ControlHeader, e2smControlHeader); + asn_decode (nullptr, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_RC_ControlHeader, + (void **) &e2smControlHeader, ie->value.choice.RICcontrolHeader.buf, + ie->value.choice.RICcontrolHeader.size); + + NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_E2SM_RC_ControlHeader, e2smControlHeader)); + if (e2smControlHeader->present == E2SM_RC_ControlHeader_PR_controlHeader_Format1) { + m_e2SmRcControlHeaderFormat1 = e2smControlHeader->choice.controlHeader_Format1; + //m_e2SmRcControlHeaderFormat1->ric_ControlAction_ID; + //m_e2SmRcControlHeaderFormat1->ric_ControlStyle_Type; + //m_e2SmRcControlHeaderFormat1->ueId; + } else { + NS_LOG_DEBUG("[E2SM] Error in checking format of E2SM Control Header"); + } + break; + } + case RICcontrolRequest_IEs__value_PR_RICcontrolMessage: { + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_RICcontrolMessage"); + // xer_fprint(stderr, &asn_DEF_RICcontrolMessage, &ie->value.choice.RICcontrolMessage); + + auto *e2SmControlMessage = (E2SM_RC_ControlMessage_t *) calloc(1, + sizeof(E2SM_RC_ControlMessage_t)); + ASN_STRUCT_RESET(asn_DEF_E2SM_RC_ControlMessage, e2SmControlMessage); + + asn_decode (nullptr, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2SM_RC_ControlMessage, + (void **) &e2SmControlMessage, ie->value.choice.RICcontrolMessage.buf, + ie->value.choice.RICcontrolMessage.size); + + NS_LOG_INFO (xer_fprint(stderr, &asn_DEF_E2SM_RC_ControlMessage, e2SmControlMessage)); + + if (e2SmControlMessage->present == E2SM_RC_ControlMessage_PR_controlMessage_Format1) + { + NS_LOG_DEBUG ("[E2SM] E2SM_RC_ControlMessage_PR_controlMessage_Format1"); + E2SM_RC_ControlMessage_Format1_t *e2SmRcControlMessageFormat1 = + e2SmControlMessage->choice.controlMessage_Format1; + m_valuesExtracted = + ExtractRANParametersFromControlMessage (e2SmRcControlMessageFormat1); + if (m_requestType == ControlMessageRequestIdType::TS) + { + // Get and parse the secondaty cell id according to 3GPP TS 38.473, Section 9.2.2.1 + for (RANParameterItem item : m_valuesExtracted) + { + if (item.m_valueType == RANParameterItem::ValueType::OctectString) + { + // First 3 digits are the PLMNID (always 111), last digit is CellId + std::string cgi = item.m_valueStr->DecodeContent (); + NS_LOG_INFO ("Decoded CGI value is: " << cgi); + m_secondaryCellId = cgi.back(); + } + } + } + } + else + { + NS_LOG_DEBUG("[E2SM] Error in checking format of E2SM Control Message"); + } + break; + } + case RICcontrolRequest_IEs__value_PR_RICcontrolAckRequest: { + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_RICcontrolAckRequest"); + + switch (ie->value.choice.RICcontrolAckRequest) { + case RICcontrolAckRequest_noAck: { + NS_LOG_DEBUG("[E2SM] RIC Control ack value: NO ACK"); + break; + } + case RICcontrolAckRequest_ack: { + NS_LOG_DEBUG("[E2SM] RIC Control ack value: ACK"); + break; + } + case RICcontrolAckRequest_nAck: { + NS_LOG_DEBUG("[E2SM] RIC Control ack value: NACK"); + break; + } + default: { + NS_LOG_DEBUG("[E2SM] RIC Control ack value unknown"); + break; + } + } + break; + } + case RICcontrolRequest_IEs__value_PR_NOTHING: { + NS_LOG_DEBUG("[E2SM] RICcontrolRequest_IEs__value_PR_NOTHING"); + NS_LOG_DEBUG("[E2SM] Nothing"); + break; + } + default: { + NS_LOG_DEBUG("[E2SM] RIC Control value unknown"); + break; + } + } + } + + NS_LOG_INFO ("End of DecodeRicControlMessage"); +} + +std::string +RicControlMessage::GetSecondaryCellIdHO () +{ + return m_secondaryCellId; +} + +std::vector +RicControlMessage::ExtractRANParametersFromControlMessage ( + E2SM_RC_ControlMessage_Format1_t *e2SmRcControlMessageFormat1) +{ + std::vector ranParameterList; + int count = e2SmRcControlMessageFormat1->ranParameters_List->list.count; + for (int i = 0; i < count; i++) + { + RANParameter_Item_t *ranParameterItem = + e2SmRcControlMessageFormat1->ranParameters_List->list.array[i]; + for (RANParameterItem extractedParameter : + RANParameterItem::ExtractRANParametersFromRANParameter (ranParameterItem)) + { + ranParameterList.push_back (extractedParameter); + } + } + + return ranParameterList; +} + +} // namespace ns3 diff --git a/model/ric-control-message.h b/model/ric-control-message.h new file mode 100644 index 0000000..a4836aa --- /dev/null +++ b/model/ric-control-message.h @@ -0,0 +1,76 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +#ifndef RIC_CONTROL_MESSAGE_H +#define RIC_CONTROL_MESSAGE_H + +#include "ns3/object.h" +#include + +extern "C" { + #include "E2AP-PDU.h" + #include "E2SM-RC-ControlHeader.h" + #include "E2SM-RC-ControlMessage.h" + #include "E2SM-RC-ControlHeader-Format1.h" + #include "E2SM-RC-ControlMessage-Format1.h" + #include "RICcontrolRequest.h" + #include "ProtocolIE-Field.h" + #include "InitiatingMessage.h" + #include "CellGlobalID.h" + #include "NRCGI.h" + } + +namespace ns3 { + + class RicControlMessage : public SimpleRefCount + { + public: + enum ControlMessageRequestIdType { TS = 1001, QoS = 1002 }; + RicControlMessage (E2AP_PDU_t *pdu); + ~RicControlMessage (); + + ControlMessageRequestIdType m_requestType; + + static std::vector ExtractRANParametersFromControlMessage ( + E2SM_RC_ControlMessage_Format1_t *e2SmRcControlMessageFormat1); + + std::vector m_valuesExtracted; + RANfunctionID_t m_ranFunctionId; + RICrequestID_t m_ricRequestId; + RICcallProcessID_t m_ricCallProcessId; + E2SM_RC_ControlHeader_Format1_t *m_e2SmRcControlHeaderFormat1; + std::string GetSecondaryCellIdHO (); + + private: + /** + * Decodes the RIC Control message . + * + * \param pdu PDU passed by the RIC + */ + void DecodeRicControlMessage (E2AP_PDU_t *pdu); + std::string m_secondaryCellId; + }; +} + +#endif /* RIC_CONTROL_MESSAGE_H */ diff --git a/test/oran-interface-test-suite.cc b/test/oran-interface-test-suite.cc new file mode 100644 index 0000000..fa33f64 --- /dev/null +++ b/test/oran-interface-test-suite.cc @@ -0,0 +1,90 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Northeastern University + * Copyright (c) 2022 Sapienza, University of Rome + * Copyright (c) 2022 University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Andrea Lacava + * Tommaso Zugno + * Michele Polese + */ + +// Include a header file from your module to test. +#include "ns3/oran-interface.h" + +// An essential include is test.h +#include "ns3/test.h" + +// Do not put your test classes in namespace ns3. You may find it useful +// to use the using directive to access the ns3 namespace directly +using namespace ns3; + +// This is an example TestCase. +class OranInterfaceTestCase1 : public TestCase +{ +public: + OranInterfaceTestCase1 (); + virtual ~OranInterfaceTestCase1 (); + +private: + virtual void DoRun (void); +}; + +// Add some help text to this case to describe what it is intended to test +OranInterfaceTestCase1::OranInterfaceTestCase1 () + : TestCase ("OranInterface test case (does nothing)") +{ +} + +// This destructor does nothing but we include it as a reminder that +// the test case should clean up after itself +OranInterfaceTestCase1::~OranInterfaceTestCase1 () +{ +} + +// +// This method is the pure virtual method from class TestCase that every +// TestCase must implement +// +void +OranInterfaceTestCase1::DoRun (void) +{ + // A wide variety of test macros are available in src/core/test.h + NS_TEST_ASSERT_MSG_EQ (true, true, "true doesn't equal true for some reason"); + // Use this one for floating point comparisons + NS_TEST_ASSERT_MSG_EQ_TOL (0.01, 0.01, 0.001, "Numbers are not equal within tolerance"); +} + +// The TestSuite class names the TestSuite, identifies what type of TestSuite, +// and enables the TestCases to be run. Typically, only the constructor for +// this class must be defined +// +class OranInterfaceTestSuite : public TestSuite +{ +public: + OranInterfaceTestSuite (); +}; + +OranInterfaceTestSuite::OranInterfaceTestSuite () + : TestSuite ("oran-interface", UNIT) +{ + // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER + AddTestCase (new OranInterfaceTestCase1, TestCase::QUICK); +} + +// Do not forget to allocate an instance of this TestSuite +static OranInterfaceTestSuite soranInterfaceTestSuite; + diff --git a/wscript b/wscript new file mode 100644 index 0000000..2f7c033 --- /dev/null +++ b/wscript @@ -0,0 +1,57 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +# def options(opt): +# pass + +def configure(conf): + conf.env.append_value('CXXFLAGS', '-I/usr/local/include/e2sim') + conf.env.append_value("LINKFLAGS", ["-L/usr/local/lib"]) + conf.env.append_value("LIB", ["e2sim"]) + +def build(bld): + module = bld.create_ns3_module('oran-interface', ['core']) + module.source = [ + 'model/oran-interface.cc', + 'model/asn1c-types.cc', + 'model/function-description.cc', + 'model/kpm-indication.cc', + 'model/kpm-function-description.cc', + 'model/ric-control-message.cc', + 'model/ric-control-function-description.cc', + 'helper/oran-interface-helper.cc', + 'helper/indication-message-helper.cc', + 'helper/lte-indication-message-helper.cc', + 'helper/mmwave-indication-message-helper.cc' + ] + + module_test = bld.create_ns3_module_test_library('oran-interface') + module_test.source = [ + 'test/oran-interface-test-suite.cc', + ] + # Tests encapsulating example programs should be listed here + if (bld.env['ENABLE_EXAMPLES']): + module_test.source.extend([ + # 'test/oran-interface-examples-test-suite.cc', + ]) + + headers = bld(features='ns3header') + headers.module = 'oran-interface' + headers.source = [ + 'model/oran-interface.h', + 'model/asn1c-types.h', + 'model/function-description.h', + 'model/kpm-indication.h', + 'model/kpm-function-description.h', + 'model/ric-control-message.h', + 'model/ric-control-function-description.h', + 'helper/oran-interface-helper.h', + 'helper/indication-message-helper.h', + 'helper/lte-indication-message-helper.h', + 'helper/mmwave-indication-message-helper.h', + ] + + if bld.env.ENABLE_EXAMPLES: + bld.recurse('examples') + + + # bld.ns3_python_bindings() -- 2.16.6