First release 83/9083/1
authorAndrea Lacava <thecave003@gmail.com>
Sun, 25 Sep 2022 12:08:28 +0000 (14:08 +0200)
committerAndrea Lacava <thecave003@gmail.com>
Sun, 25 Sep 2022 12:08:28 +0000 (14:08 +0200)
Signed-off-by: Andrea Lacava <thecave003@gmail.com>
Change-Id: I1992a91fb1d0cdf8a0ccb33527a24f6a8aba1faa

33 files changed:
README.md [new file with mode: 0644]
doc/oran-interface.rst [new file with mode: 0644]
examples/e2sim-integration-example.cc [new file with mode: 0644]
examples/l3-rrc-example.cc [new file with mode: 0644]
examples/oran-interface-example.cc [new file with mode: 0644]
examples/ric-control-function-desc.cc [new file with mode: 0644]
examples/ric-indication-messages.cc [new file with mode: 0644]
examples/test-wrappers.cc [new file with mode: 0644]
examples/wscript [new file with mode: 0644]
helper/indication-message-helper.cc [new file with mode: 0644]
helper/indication-message-helper.h [new file with mode: 0644]
helper/lte-indication-message-helper.cc [new file with mode: 0644]
helper/lte-indication-message-helper.h [new file with mode: 0644]
helper/mmwave-indication-message-helper.cc [new file with mode: 0644]
helper/mmwave-indication-message-helper.h [new file with mode: 0644]
helper/oran-interface-helper.cc [new file with mode: 0644]
helper/oran-interface-helper.h [new file with mode: 0644]
model/asn1c-types.cc [new file with mode: 0644]
model/asn1c-types.h [new file with mode: 0644]
model/function-description.cc [new file with mode: 0644]
model/function-description.h [new file with mode: 0644]
model/kpm-function-description.cc [new file with mode: 0644]
model/kpm-function-description.h [new file with mode: 0644]
model/kpm-indication.cc [new file with mode: 0644]
model/kpm-indication.h [new file with mode: 0644]
model/oran-interface.cc [new file with mode: 0644]
model/oran-interface.h [new file with mode: 0644]
model/ric-control-function-description.cc [new file with mode: 0644]
model/ric-control-function-description.h [new file with mode: 0644]
model/ric-control-message.cc [new file with mode: 0644]
model/ric-control-message.h [new file with mode: 0644]
test/oran-interface-test-suite.cc [new file with mode: 0644]
wscript [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
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
+<!-- More information can be found in the paper TODO -->
+
+# 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 (file)
index 0000000..82df1a1
--- /dev/null
@@ -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 (file)
index 0000000..f2714d9
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#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 (file)
index 0000000..5264cf5
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/oran-interface.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("L3RrcExample");
+
+Ptr<L3RrcMeasurements>
+CreateL3RrcUeSpecificSinrServing (long servingCellId, long physCellId, long sinr)
+{
+  Ptr<L3RrcMeasurements> l3RrcMeasurement = Create<L3RrcMeasurements> (RRCEvent_b1);
+  Ptr<ServingCellMeasurementsWrap> servingCellMeasurements =
+      Create<ServingCellMeasurementsWrap> (ServingCellMeasurements_PR_nr_measResultServingMOList);
+
+  Ptr<MeasResultNr> measResultNr = Create<MeasResultNr> (physCellId);
+  Ptr<MeasQuantityResultsWrap> measQuantityResultWrap = Create<MeasQuantityResultsWrap> ();
+  measQuantityResultWrap->AddSinr (sinr);
+  measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ());
+  Ptr<MeasResultServMo> measResultServMo =
+      Create<MeasResultServMo> (servingCellId, measResultNr->GetValue ());
+  servingCellMeasurements->AddMeasResultServMo (measResultServMo->GetPointer ());
+  l3RrcMeasurement->AddServingCellMeasurement (servingCellMeasurements->GetPointer ());
+  return l3RrcMeasurement;
+}
+
+Ptr<L3RrcMeasurements>
+CreateL3RrcUeSpecificSinrNeigh (long neighCellId, long sinr)
+{
+  Ptr<L3RrcMeasurements> l3RrcMeasurement = Create<L3RrcMeasurements> (RRCEvent_b1);
+  Ptr<MeasResultNr> measResultNr = Create<MeasResultNr> (neighCellId);
+  Ptr<MeasQuantityResultsWrap> measQuantityResultWrap = Create<MeasQuantityResultsWrap> ();
+  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<L3RrcMeasurements> 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<L3RrcMeasurements> 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<MeasResultNr> measResultNr3 = Create<MeasResultNr> (neighCellId3);
+  Ptr<MeasQuantityResultsWrap> measQuantityResultWrap3 = Create<MeasQuantityResultsWrap> ();
+  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<L3RrcMeasurements> 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<L3RrcMeasurements> l3RrcMeasurement3 = Create<L3RrcMeasurements> (RRCEvent_a5);
+  Ptr<MeasResultEutra> measResultEutra5 = Create<MeasResultEutra> (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 (file)
index 0000000..d6d763e
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/oran-interface.h"
+#include "encode_e2apv1.hpp"
+#include <errno.h>
+
+
+using namespace ns3;
+
+Ptr<E2Termination> 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<KpmIndicationHeader> header = Create<KpmIndicationHeader> (KpmIndicationHeader::GlobalE2nodeType::gNB, headerValues);
+  
+  KpmIndicationMessage::KpmIndicationMessageValues msgValues;
+  
+  Ptr<OCuUpContainerValues> cuUpValues = Create<OCuUpContainerValues> ();
+  cuUpValues->m_plmId = plmId;
+  cuUpValues->m_pDCPBytesUL = 100;
+  cuUpValues->m_pDCPBytesDL = 100;
+  msgValues.m_pmContainerValues = cuUpValues;
+  
+  Ptr<MeasurementItemList> ue0DummyValues = Create<MeasurementItemList> ("UE-0");
+  ue0DummyValues->AddItem<long> ("DRB.PdcpSduVolumeDl_Filter.UEID", 6);
+  ue0DummyValues->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7);
+  ue0DummyValues->AddItem<long> ("Tot.PdcpSduNbrDl.UEID", 8);
+  ue0DummyValues->AddItem<long> ("DRB.PdcpPduNbrDl.Qos.UEID", 9);
+  ue0DummyValues->AddItem<double> ("DRB.IPThpDl.UEID", 10.0);
+  ue0DummyValues->AddItem<double> ("DRB.IPLateDl.UEID", 11.0);
+  msgValues.m_ueIndications.insert (ue0DummyValues);
+  Ptr<MeasurementItemList> ue1DummyValues = Create<MeasurementItemList> ("UE-1");;
+  ue1DummyValues->AddItem<long> ("DRB.PdcpSduVolumeDl_Filter.UEID", 6);
+  ue1DummyValues->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7);
+  ue1DummyValues->AddItem<long> ("Tot.PdcpSduNbrDl.UEID", 8);
+  ue1DummyValues->AddItem<long> ("DRB.PdcpPduNbrDl.Qos.UEID", 9);
+  ue1DummyValues->AddItem<double> ("DRB.IPThpDl.UEID", 10.0);
+  ue1DummyValues->AddItem<double> ("DRB.IPLateDl.UEID", 11.0);
+  msgValues.m_ueIndications.insert (ue1DummyValues);
+  
+  Ptr<KpmIndicationMessage> msg = Create<KpmIndicationMessage> (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<E2Termination> ("10.244.0.191", 36422, 38472, gnb, plmId);
+  Ptr<KpmFunctionDescription> kpmFd = Create<KpmFunctionDescription> ();
+  e2Term->RegisterKpmCallbackToE2Sm (200, kpmFd, &KpmSubscriptionCallback);    
+  Ptr<RicControlFunctionDescription> rcFd = Create<RicControlFunctionDescription> ();
+  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 (file)
index 0000000..4e1f894
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#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<RicControlFunctionDescription> rcFd = Create<RicControlFunctionDescription> ();
+
+  return 0;
+}
diff --git a/examples/ric-indication-messages.cc b/examples/ric-indication-messages.cc
new file mode 100644 (file)
index 0000000..6605a57
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/oran-interface.h"
+#include <errno.h>
+
+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<KpmIndicationHeader> header = Create<KpmIndicationHeader> (KpmIndicationHeader::GlobalE2nodeType::eNB, headerValues);
+  Ptr<KpmIndicationHeader> header2 = Create<KpmIndicationHeader> (KpmIndicationHeader::GlobalE2nodeType::gNB, headerValues2);
+  Ptr<KpmIndicationHeader> header3 = Create<KpmIndicationHeader> (KpmIndicationHeader::GlobalE2nodeType::ng_eNB, headerValues3);
+  Ptr<KpmIndicationHeader> header4 = Create<KpmIndicationHeader> (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<OCuUpContainerValues> cuUpValues = Create<OCuUpContainerValues> ();
+  cuUpValues->m_plmId = plmId;
+  cuUpValues->m_pDCPBytesUL = 100;
+  cuUpValues->m_pDCPBytesDL = 100;
+
+  Ptr<MeasurementItemList> ue0DummyValues = Create<MeasurementItemList> ("UE-0");
+  ue0DummyValues->AddItem<long> ("DRB.PdcpSduVolumeDl_Filter.UEID", 6);
+  ue0DummyValues->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7);
+  ue0DummyValues->AddItem<long> ("Tot.PdcpSduNbrDl.UEID", 8);
+  ue0DummyValues->AddItem<long> ("DRB.PdcpPduNbrDl.Qos.UEID", 9);
+  ue0DummyValues->AddItem<double> ("DRB.IPThpDl.UEID", 10.0);
+  ue0DummyValues->AddItem<double> ("DRB.IPLateDl.UEID", 11.0);
+  msgValues1.m_ueIndications.insert (ue0DummyValues);
+  Ptr<MeasurementItemList> ue1DummyValues = Create<MeasurementItemList> ("UE-1");
+  ue1DummyValues->AddItem<long> ("DRB.PdcpSduVolumeDl_Filter.UEID", 6);
+  ue1DummyValues->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter.UEID", 7);
+  ue1DummyValues->AddItem<long> ("Tot.PdcpSduNbrDl.UEID", 8);
+  ue1DummyValues->AddItem<long> ("DRB.PdcpPduNbrDl.Qos.UEID", 9);
+  ue1DummyValues->AddItem<double> ("DRB.IPThpDl.UEID", 10.0);
+  ue1DummyValues->AddItem<double> ("DRB.IPLateDl.UEID", 11.0);
+  msgValues1.m_ueIndications.insert(ue1DummyValues);
+  msgValues1.m_pmContainerValues = cuUpValues; 
+
+  Ptr<KpmIndicationMessage> msg = Create<KpmIndicationMessage> (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<OCuCpContainerValues> cuCpValues = Create<OCuCpContainerValues> ();
+  cuCpValues->m_numActiveUes = 100;
+
+  Ptr<MeasurementItemList> ue2DummyValues =
+      Create<MeasurementItemList> ("UE-2");
+  ue2DummyValues->AddItem<long> ("DRB.EstabSucc.5QI.UEID", 6);
+  ue2DummyValues->AddItem<long> ("DRB.RelActNbr.5QI.UEID", 7);
+  msgValues2.m_ueIndications.insert (ue2DummyValues);
+
+   Ptr<MeasurementItemList> ue3DummyValues =
+      Create<MeasurementItemList> ("UE-3");
+  ue3DummyValues->AddItem<long> ("DRB.EstabSucc.5QI.UEID", 6);
+  ue3DummyValues->AddItem<long> ("DRB.RelActNbr.5QI.UEID", 7);
+  msgValues2.m_ueIndications.insert (ue3DummyValues);
+
+  Ptr<MeasurementItemList> ue4DummyValues =
+      Create<MeasurementItemList> ("UE-4");
+
+  Ptr<L3RrcMeasurements> l3RrcMeasurement = Create<L3RrcMeasurements> (RRCEvent_b1);
+  Ptr<ServingCellMeasurementsWrap> servingCellMeasurements =
+      Create<ServingCellMeasurementsWrap> (ServingCellMeasurements_PR_nr_measResultServingMOList);
+
+  Ptr<MeasResultNr> measResultNr = Create<MeasResultNr> (39);
+  Ptr<MeasQuantityResultsWrap> measQuantityResultWrap = Create<MeasQuantityResultsWrap> ();
+  measQuantityResultWrap->AddSinr (20);
+  measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ());
+  Ptr<MeasResultServMo> measResultServMo =
+      Create<MeasResultServMo> (10, measResultNr->GetValue ());
+  servingCellMeasurements->AddMeasResultServMo (measResultServMo->GetPointer ());
+  l3RrcMeasurement->AddServingCellMeasurement (servingCellMeasurements->GetPointer ());
+
+  ue4DummyValues->AddItem<Ptr<L3RrcMeasurements>> ("calla",l3RrcMeasurement);
+  ue4DummyValues->AddItem<long> ("DRB.RelActNbr.5QI.UEID", 7);
+  msgValues2.m_ueIndications.insert (ue4DummyValues);
+  msgValues2.m_pmContainerValues = cuCpValues;
+
+  Ptr<KpmIndicationMessage> msg2 = Create<KpmIndicationMessage> (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<ODuContainerValues> oDuContainerVal = Create<ODuContainerValues> ();
+  Ptr<CellResourceReport> cellResRep = Create<CellResourceReport> ();
+  cellResRep->m_plmId = "111";
+  // std::stringstream ss;
+  // ss << std::hex << 1340012;
+  cellResRep->m_nrCellId = 2;
+  cellResRep->dlAvailablePrbs = 6;
+  cellResRep->ulAvailablePrbs = 6;
+
+    Ptr<CellResourceReport> cellResRep2 = Create<CellResourceReport> ();
+  cellResRep2->m_plmId = "444";
+  cellResRep2->m_nrCellId = 3;
+  cellResRep2->dlAvailablePrbs = 5;
+  cellResRep2->ulAvailablePrbs = 5;
+
+  Ptr<ServedPlmnPerCell> servedPlmnPerCell = Create<ServedPlmnPerCell> ();
+  servedPlmnPerCell->m_plmId = "121";
+  servedPlmnPerCell->m_nrCellId = 3;
+
+  Ptr<ServedPlmnPerCell> servedPlmnPerCell2 = Create<ServedPlmnPerCell> ();
+  servedPlmnPerCell2->m_plmId = "121";
+  servedPlmnPerCell2->m_nrCellId = 2;
+
+  Ptr<EpcDuPmContainer> epcDuVal = Create<EpcDuPmContainer> ();
+  epcDuVal->m_qci = 1;
+  epcDuVal->m_dlPrbUsage = 1;
+  epcDuVal->m_ulPrbUsage = 2;
+
+  Ptr<EpcDuPmContainer> epcDuVal2 = Create<EpcDuPmContainer> ();
+  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<MeasurementItemList> ue5DummyValues = Create<MeasurementItemList> ("UE-5");
+  ue5DummyValues->AddItem<long> ("DRB.EstabSucc.5QI.UEID", 6);
+  ue5DummyValues->AddItem<long> ("DRB.RelActNbr.5QI.UEID", 7);
+  msgValues3.m_ueIndications.insert (ue5DummyValues);
+
+  msgValues3.m_pmContainerValues = oDuContainerVal;
+  Ptr<KpmIndicationMessage> msg3 = Create<KpmIndicationMessage> (msgValues3);
+  
+  NS_LOG_UNCOND ("----------- End test of the DU message -----------");
+
+  NS_LOG_UNCOND ("----------- Begin test of the KpmFunctionDescription -----------");
+  Ptr<KpmFunctionDescription> fd = Create<KpmFunctionDescription> ();
+  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 (file)
index 0000000..16477ad
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/oran-interface.h"
+#include <errno.h>
+
+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<OctetString> one = Create<OctetString> (test, test.size ());
+  // Ptr<OctetString> due = Create<OctetString> (test, test.size ());
+  // Ptr<Snssai> snssai = Create<Snssai> ("test");
+
+  // std::cout << due->DecodeContent() << std::endl;
+
+  std::vector<Ptr<NrCellId>> nrCellIds;
+  for (uint16_t i = 0; i < 20; i++)
+    {
+      nrCellIds.push_back(Create<NrCellId> (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 (file)
index 0000000..ac88cd1
--- /dev/null
@@ -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 (file)
index 0000000..3783400
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/indication-message-helper.h>
+
+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<OCuUpContainerValues> ();
+          break;
+
+        case IndicationMessageType::CuCp:
+          m_cuCpValues = Create<OCuCpContainerValues> ();
+          m_msgValues.m_cellObjectId = "NRCellCU";
+          break;
+
+        case IndicationMessageType::Du:
+          m_duValues = Create<ODuContainerValues> ();
+          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<KpmIndicationMessage>
+IndicationMessageHelper::CreateIndicationMessage ()
+{
+  return Create<KpmIndicationMessage> (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 (file)
index 0000000..605f633
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#ifndef INDICATION_MESSAGE_HELPER_H
+#define INDICATION_MESSAGE_HELPER_H
+
+#include <ns3/kpm-indication.h>
+
+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<KpmIndicationMessage> 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<OCuUpContainerValues> m_cuUpValues;
+  Ptr<OCuCpContainerValues> m_cuCpValues;
+  Ptr<ODuContainerValues> 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 (file)
index 0000000..1f77021
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+
+#include <ns3/lte-indication-message-helper.h>
+
+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<MeasurementItemList> ueVal = Create<MeasurementItemList> (ueImsiComplete);
+
+  if (!m_reducedPmValues)
+    {
+      // UE-specific PDCP SDU volume from LTE eNB. Unit is Mbits
+      ueVal->AddItem<long> ("DRB.PdcpSduVolumeDl_Filter.UEID", txBytes);
+
+      // UE-specific number of PDCP SDUs from LTE eNB
+      ueVal->AddItem<long> ("Tot.PdcpSduNbrDl.UEID", txDlPackets);
+
+      // UE-specific Downlink IP combined EN-DC throughput from LTE eNB. Unit is kbps
+      ueVal->AddItem<double> ("DRB.PdcpSduBitRateDl.UEID", pdcpThroughput);
+
+      //UE-specific Downlink IP combined EN-DC throughput from LTE eNB
+      ueVal->AddItem<double> ("DRB.PdcpSduDelayDl.UEID", pdcpLatency);
+    }
+
+  m_msgValues.m_ueIndications.insert (ueVal);
+}
+
+void
+LteIndicationMessageHelper::AddCuUpCellPmItem (double cellAverageLatency)
+{
+  if (!m_reducedPmValues)
+    {
+      Ptr<MeasurementItemList> cellVal = Create<MeasurementItemList> ();
+      cellVal->AddItem<double> ("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<MeasurementItemList> ueVal = Create<MeasurementItemList> (ueImsiComplete);
+  if (!m_reducedPmValues)
+    {
+      ueVal->AddItem<long> ("DRB.EstabSucc.5QI.UEID", numDrb);
+      ueVal->AddItem<long> ("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 (file)
index 0000000..b4c3c2d
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#ifndef LTE_INDICATION_MESSAGE_HELPER_H
+#define LTE_INDICATION_MESSAGE_HELPER_H
+
+#include <ns3/indication-message-helper.h>
+
+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 (file)
index 0000000..9a3a531
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/mmwave-indication-message-helper.h>
+
+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<MeasurementItemList> ueVal = Create<MeasurementItemList> (ueImsiComplete);
+  if (!m_reducedPmValues)
+    {
+      // UE-specific PDCP PDU volume transmitted to NR gNB (Unit is Kbits)
+      ueVal->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter.UEID", txPdcpPduBytesNrRlc);
+
+      // UE-specific number of PDCP PDUs split with NR gNB
+      ueVal->AddItem<long> ("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<MeasurementItemList> ueVal = Create<MeasurementItemList> (ueImsiComplete);
+  if (!m_reducedPmValues)
+    {
+      ueVal->AddItem<long> ("TB.TotNbrDl.1.UEID", macPduUe);
+      ueVal->AddItem<long> ("TB.TotNbrDlInitial.UEID", macPduInitialUe);
+      ueVal->AddItem<long> ("TB.TotNbrDlInitial.Qpsk.UEID", macQpsk);
+      ueVal->AddItem<long> ("TB.TotNbrDlInitial.16Qam.UEID", mac16Qam);
+      ueVal->AddItem<long> ("TB.TotNbrDlInitial.64Qam.UEID", mac64Qam);
+      ueVal->AddItem<long> ("TB.ErrTotalNbrDl.1.UEID", macRetx);
+      ueVal->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter.UEID", macVolume);
+      ueVal->AddItem<long> ("RRU.PrbUsedDl.UEID", (long) std::ceil (macPrb));
+      ueVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin1.UEID", macMac04);
+      ueVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin2.UEID", macMac59);
+      ueVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin3.UEID", macMac1014);
+      ueVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin4.UEID", macMac1519);
+      ueVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin5.UEID", macMac2024);
+      ueVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin6.UEID", macMac2529);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin34.UEID", macSinrBin1);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin46.UEID", macSinrBin2);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin58.UEID", macSinrBin3);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin70.UEID", macSinrBin4);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin82.UEID", macSinrBin5);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin94.UEID", macSinrBin6);
+      ueVal->AddItem<long> ("L1M.RS-SINR.Bin127.UEID", macSinrBin7);
+      ueVal->AddItem<long> ("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<double> ("DRB.UEThpDlPdcpBased.UEID", drbThrDlPdcpBasedUeid);
+  
+  ueVal->AddItem<double> ("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<MeasurementItemList> cellVal = Create<MeasurementItemList> ();
+
+  if (!m_reducedPmValues)
+    {
+      cellVal->AddItem<long> ("TB.TotNbrDl.1", macPduCellSpecific);
+      cellVal->AddItem<long> ("TB.TotNbrDlInitial", macPduInitialCellSpecific);
+    }
+
+  cellVal->AddItem<long> ("TB.TotNbrDlInitial.Qpsk", macQpskCellSpecific);
+  cellVal->AddItem<long> ("TB.TotNbrDlInitial.16Qam", mac16QamCellSpecific);
+  cellVal->AddItem<long> ("TB.TotNbrDlInitial.64Qam", mac64QamCellSpecific);
+  cellVal->AddItem<long> ("RRU.PrbUsedDl", (long) std::ceil (prbUtilizationDl));
+
+  if (!m_reducedPmValues)
+    {
+      cellVal->AddItem<long> ("TB.ErrTotalNbrDl.1", macRetxCellSpecific);
+      cellVal->AddItem<long> ("QosFlow.PdcpPduVolumeDL_Filter", macVolumeCellSpecific);
+      cellVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin1", macMac04CellSpecific);
+      cellVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin2", macMac59CellSpecific);
+      cellVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin3", macMac1014CellSpecific);
+      cellVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin4", macMac1519CellSpecific);
+      cellVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin5", macMac2024CellSpecific);
+      cellVal->AddItem<long> ("CARR.PDSCHMCSDist.Bin6", macMac2529CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin34", macSinrBin1CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin46", macSinrBin2CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin58", macSinrBin3CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin70", macSinrBin4CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin82", macSinrBin5CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin94", macSinrBin6CellSpecific);
+      cellVal->AddItem<long> ("L1M.RS-SINR.Bin127", macSinrBin7CellSpecific);
+      cellVal->AddItem<long> ("DRB.BufferSize.Qos", rlcBufferOccupCellSpecific);
+    }
+
+  cellVal->AddItem<long> ("DRB.MeanActiveUeDl",activeUeDl);
+
+  m_msgValues.m_cellMeasurementItems = cellVal;
+}
+
+void
+MmWaveIndicationMessageHelper::AddDuCellResRepPmItem (Ptr<CellResourceReport> cellResRep)
+{
+  m_duValues->m_cellResourceReportItems.insert (cellResRep);
+}
+
+void
+MmWaveIndicationMessageHelper::AddCuCpUePmItem (std::string ueImsiComplete, long numDrb,
+                                                long drbRelAct,
+                                                Ptr<L3RrcMeasurements> l3RrcMeasurementServing,
+                                                Ptr<L3RrcMeasurements> l3RrcMeasurementNeigh)
+{
+
+  Ptr<MeasurementItemList> ueVal = Create<MeasurementItemList> (ueImsiComplete);
+  if (!m_reducedPmValues)
+    {
+      ueVal->AddItem<long> ("DRB.EstabSucc.5QI.UEID", numDrb);
+      ueVal->AddItem<long> ("DRB.RelActNbr.5QI.UEID", drbRelAct); // not modeled in the simulator
+    }
+
+  ueVal->AddItem<Ptr<L3RrcMeasurements>> ("HO.SrcCellQual.RS-SINR.UEID", l3RrcMeasurementServing);
+  ueVal->AddItem<Ptr<L3RrcMeasurements>> ("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 (file)
index 0000000..20cf003
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#ifndef MMWAVE_INDICATION_MESSAGE_HELPER_H
+#define MMWAVE_INDICATION_MESSAGE_HELPER_H
+
+#include <ns3/indication-message-helper.h>
+
+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<CellResourceReport> cellResRep);
+  void AddCuCpUePmItem (std::string ueImsiComplete, long numDrb, long drbRelAct,
+                        Ptr<L3RrcMeasurements> l3RrcMeasurementServing,
+                        Ptr<L3RrcMeasurements> 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 (file)
index 0000000..c2b56fc
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#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 (file)
index 0000000..dc339a5
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#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 (file)
index 0000000..7dbcfb2
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+
+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<BitString> (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>
+L3RrcMeasurements::CreateL3RrcUeSpecificSinrServing (long servingCellId, long physCellId, long sinr)
+{
+  Ptr<L3RrcMeasurements> l3RrcMeasurement = Create<L3RrcMeasurements> (RRCEvent_b1);
+  Ptr<ServingCellMeasurementsWrap> servingCellMeasurements =
+      Create<ServingCellMeasurementsWrap> (ServingCellMeasurements_PR_nr_measResultServingMOList);
+
+  Ptr<MeasResultNr> measResultNr = Create<MeasResultNr> (physCellId);
+  Ptr<MeasQuantityResultsWrap> measQuantityResultWrap = Create<MeasQuantityResultsWrap> ();
+  measQuantityResultWrap->AddSinr (sinr);
+  measResultNr->AddCellResults (MeasResultNr::SSB, measQuantityResultWrap->GetPointer ());
+  Ptr<MeasResultServMo> measResultServMo =
+      Create<MeasResultServMo> (servingCellId, measResultNr->GetValue ());
+  servingCellMeasurements->AddMeasResultServMo (measResultServMo->GetPointer ());
+  l3RrcMeasurement->AddServingCellMeasurement (servingCellMeasurements->GetPointer ());
+  return l3RrcMeasurement;
+}
+
+Ptr<L3RrcMeasurements>
+L3RrcMeasurements::CreateL3RrcUeSpecificSinrNeigh ()
+{
+  return Create<L3RrcMeasurements> (RRCEvent_b1);
+}
+
+void
+L3RrcMeasurements::AddNeighbourCellMeasurement (long neighCellId, long sinr)
+{
+  Ptr<MeasResultNr> measResultNr = Create<MeasResultNr> (neighCellId);
+  Ptr<MeasQuantityResultsWrap> measQuantityResultWrap = Create<MeasQuantityResultsWrap> ();
+  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, Ptr<L3RrcMeasurements>value)
+    : 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>
+RANParameterItem::ExtractRANParametersFromRANParameter (RANParameter_Item_t *ranParameterItem)
+{
+  std::vector<RANParameterItem> 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<OctetString> (
+                  (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 (file)
index 0000000..83464db
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#ifndef ASN1C_TYPES_H
+#define ASN1C_TYPES_H
+
+#include "ns3/object.h"
+#include <ns3/math.h>
+
+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<OctetString>
+{
+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<BitString>
+{
+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<NrCellId>
+{
+public: 
+  NrCellId (uint16_t value);
+  virtual ~NrCellId ();
+  BIT_STRING_t *GetPointer ();
+  BIT_STRING_t GetValue ();
+  
+private: 
+  Ptr<BitString> m_bitString;
+};
+
+/**
+* Wrapper for class for S-NSSAI  
+*/
+class Snssai : public SimpleRefCount<Snssai>
+{
+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<MeasQuantityResultsWrap>
+{
+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<ResultsPerCsiRsIndex>
+{
+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<ResultsPerSSBIndex>
+{
+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<MeasResultNr>
+{
+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<MeasResultEutra>
+{
+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<MeasResultPCellWrap>
+{
+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<MeasResultServMo>
+{
+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<ServingCellMeasurementsWrap>
+{
+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<L3RrcMeasurements>
+{
+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<L3RrcMeasurements> CreateL3RrcUeSpecificSinrServing (long servingCellId,
+                                                                  long physCellId, long sinr);
+
+  static Ptr<L3RrcMeasurements> 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<MeasurementItem>
+{
+public:
+  MeasurementItem (std::string name, long value);
+  MeasurementItem (std::string name, double value);
+  MeasurementItem (std::string name, Ptr<L3RrcMeasurements> 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<RANParameterItem>
+{
+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<OctetString> m_valueStr;
+
+  static std::vector<RANParameterItem>
+  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 (file)
index 0000000..b5a8b98
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/function-description.h>
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+
+
+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 (file)
index 0000000..28b388b
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#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<FunctionDescription>
+  {
+  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 (file)
index 0000000..b318503
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/kpm-function-description.h>
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+
+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<OctetString> shortName = Create<OctetString> (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 (file)
index 0000000..2cbb101
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#ifndef KPM_FUNCTION_DESCRIPTION_H
+#define KPM_FUNCTION_DESCRIPTION_H
+
+#include "ns3/object.h"
+#include <ns3/function-description.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 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 (file)
index 0000000..ae237e0
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/kpm-indication.h>
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+
+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<OctetString> plmnid = Create<OctetString> (values.m_plmId, 3);
+  Ptr<BitString> 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<BitString> (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<BitString> (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<BitString> (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<BitString> (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<OctetString> ts = Create<OctetString> ((void *) &bigEndianTimestamp, TIMESTAMP_LIMIT_SIZE);
+    //NS_LOG_INFO (xer_fprint (stderr, &asn_DEF_OCTET_STRING, ts->GetPointer() ));
+    
+    // Ptr<OctetString> ts2 = Create<OctetString> ((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<PmContainerValues> values)
+{
+  Ptr<OCuUpContainerValues> cuUpVal = DynamicCast<OCuUpContainerValues> (values);
+  Ptr<OCuCpContainerValues> cuCpVal = DynamicCast<OCuCpContainerValues> (values);
+  Ptr<ODuContainerValues> duVal = DynamicCast<ODuContainerValues> (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<OCuUpContainerValues> 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<OctetString> plmnidstr = Create<OctetString> (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<OCuCpContainerValues> 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<ODuContainerValues> 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<OctetString> plmnid = Create<OctetString> (cellReport->m_plmId, 3);
+      Ptr<NrCellId> nrcellid = Create<NrCellId> (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<OctetString> servedPlmnId = Create<OctetString> (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<OctetString> (id, id.length ());
+}
+
+MeasurementItemList::~MeasurementItemList (){};
+
+std::vector<Ptr<MeasurementItem>>
+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 (file)
index 0000000..7121ef0
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#ifndef KPM_INDICATION_H
+#define KPM_INDICATION_H
+
+#include "ns3/object.h"
+#include <set>
+
+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<KpmIndicationHeader>
+  {
+  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<MeasurementItemList>
+  {
+  private:
+    Ptr<OctetString> m_id; // ID, contains the UE IMSI if used to carry UE-specific measurement items
+    std::vector<Ptr<MeasurementItem>> m_items; //!< list of Measurement Information Items
+  public:
+    MeasurementItemList ();
+    MeasurementItemList (std::string ueId);
+     ~MeasurementItemList ();
+
+    // NOTE defined here to avoid undefined references
+    template<class T> 
+    void AddItem (std::string name, T value)
+    {
+      Ptr<MeasurementItem> item = Create<MeasurementItem> (name, value);
+      m_items.push_back (item);
+    }
+    
+    std::vector<Ptr<MeasurementItem>> GetItems();
+    OCTET_STRING_t GetId ();
+  };
+
+  /**
+  * Base class to carry PM Container values  
+  */    
+  class PmContainerValues : public SimpleRefCount<PmContainerValues> 
+  {
+  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<EpcDuPmContainer>
+  {
+  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<FiveGcDuPmContainer>
+  {
+  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<ServedPlmnPerCell>
+  {
+  public:
+    std::string m_plmId; //!< PLMN identity, octet string, 3 bytes
+    uint16_t m_nrCellId;
+    std::set<Ptr<EpcDuPmContainer>> m_perQciReportItems;
+  };
+
+  class CellResourceReport : public SimpleRefCount<CellResourceReport>
+  {
+  public:
+    std::string m_plmId; //!< PLMN identity, octet string, 3 bytes
+    uint16_t m_nrCellId;
+    long dlAvailablePrbs;
+    long ulAvailablePrbs;
+    std::set<Ptr<ServedPlmnPerCell>> m_servedPlmnPerCellItems;
+  };
+
+  /**
+  * Contains the values to be inserted in the O-DU Measurement Container  
+  */
+  class ODuContainerValues : public PmContainerValues
+  {
+  public:
+    std::set<Ptr<CellResourceReport>> m_cellResourceReportItems;
+  };
+
+  class KpmIndicationMessage : public SimpleRefCount<KpmIndicationMessage>
+  {
+  public:
+    
+    /**
+    * Holds the values to be used to fill the RIC Indication Message 
+    */
+    struct KpmIndicationMessageValues
+    {
+      std::string m_cellObjectId; //!< Cell Object ID
+      Ptr<PmContainerValues> m_pmContainerValues; //!< struct containing values to be inserted in the PM Container
+      Ptr<MeasurementItemList> m_cellMeasurementItems; //!< list of cell-specific Measurement Information Items
+      std::set<Ptr<MeasurementItemList>> 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<PmContainerValues> values);
+    void FillOCuUpContainer (PF_Container_t *ranContainer, 
+                            Ptr<OCuUpContainerValues> values);
+    void FillOCuCpContainer (PF_Container_t *ranContainer, 
+                             Ptr<OCuCpContainerValues> values);
+    void FillODuContainer (PF_Container_t *ranContainer, 
+                           Ptr<ODuContainerValues> 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 (file)
index 0000000..4baf123
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/oran-interface.h>
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+#include <thread>
+#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<Object>()
+    .AddConstructor<E2Termination>();
+  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<FunctionDescription> 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<FunctionDescription> ranFunctionDescription,
+                             SubscriptionCallback sbCb)
+{
+  RegisterFunctionDescToE2Sm (ranFunctionId,ranFunctionDescription);
+  m_e2sim->register_subscription_callback (ranFunctionId, sbCb);
+}
+
+void
+E2Termination::RegisterSmCallbackToE2Sm (long ranFunctionId, Ptr<FunctionDescription> 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<long> actionIdsAccept;
+  std::vector<long> 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 (file)
index 0000000..87a82d7
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+#ifndef ORAN_INTERFACE_H
+#define ORAN_INTERFACE_H
+
+#include "ns3/object.h"
+#include <ns3/kpm-indication.h>
+#include <ns3/kpm-function-description.h>
+#include <ns3/ric-control-function-description.h>
+#include <ns3/ric-control-message.h>
+#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<FunctionDescription> 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<FunctionDescription> 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<FunctionDescription> 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 (file)
index 0000000..6bfea1c
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+#include <ns3/ric-control-function-description.h>
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+
+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<OctetString> shortName = Create<OctetString> (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 (file)
index 0000000..08c9516
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+#ifndef RIC_CONTROL_FUNCTION_DESCRIPTION_H
+#define RIC_CONTROL_FUNCTION_DESCRIPTION_H
+
+#include <ns3/function-description.h>
+#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 (file)
index 0000000..78252f1
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+#include <ns3/ric-control-message.h>
+#include <ns3/asn1c-types.h>
+#include <ns3/log.h>
+#include <bitset>
+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<RANParameterItem>
+RicControlMessage::ExtractRANParametersFromControlMessage (
+    E2SM_RC_ControlMessage_Format1_t *e2SmRcControlMessageFormat1)
+{
+  std::vector<RANParameterItem> 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 (file)
index 0000000..a4836aa
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+#ifndef RIC_CONTROL_MESSAGE_H
+#define RIC_CONTROL_MESSAGE_H
+
+#include "ns3/object.h"
+#include <ns3/asn1c-types.h>
+
+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<RicControlMessage>
+  {
+  public:
+    enum ControlMessageRequestIdType { TS = 1001, QoS = 1002 };
+    RicControlMessage (E2AP_PDU_t *pdu);
+    ~RicControlMessage ();
+
+    ControlMessageRequestIdType m_requestType;
+    
+    static std::vector<RANParameterItem> ExtractRANParametersFromControlMessage (
+      E2SM_RC_ControlMessage_Format1_t *e2SmRcControlMessageFormat1);
+    
+    std::vector<RANParameterItem> 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 (file)
index 0000000..fa33f64
--- /dev/null
@@ -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 <thecave003@gmail.com>
+ *                Tommaso Zugno <tommasozugno@gmail.com>
+ *                Michele Polese <michele.polese@gmail.com>
+ */
+
+// 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 (file)
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()