diff --git a/src/lte/examples/lena-x2-handover-measures.cc b/src/lte/examples/lena-x2-handover-measures.cc index 523021b4e..a29f39d94 100644 --- a/src/lte/examples/lena-x2-handover-measures.cc +++ b/src/lte/examples/lena-x2-handover-measures.cc @@ -124,7 +124,7 @@ NotifyHandoverEndOkEnb (std::string context, int main (int argc, char *argv[]) { - // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL); + // LogLevel logLevel = (LogLevel)(LOG_PREFIX_ALL | LOG_LEVEL_ALL); // LogComponentEnable ("LteHelper", logLevel); // LogComponentEnable ("EpcHelper", logLevel); @@ -136,15 +136,16 @@ main (int argc, char *argv[]) // LogComponentEnable ("LteEnbNetDevice", logLevel); // LogComponentEnable ("LteUeRrc", logLevel); // LogComponentEnable ("LteUeNetDevice", logLevel); + // LogComponentEnable ("A2RsrqHandoverAlgorithm", logLevel); uint16_t numberOfUes = 1; uint16_t numberOfEnbs = 2; uint16_t numBearersPerUe = 0; - double distance = 1000.0; // m - double yForUe = 1000.0; // m - double speed = 20; // m/s - double simTime = 3.0 * distance / speed; // 3000 m / 20 m/s = 150 secs - double enbTxPowerDbm = 20.0; + double distance = 500.0; // m + double yForUe = 500.0; // m + double speed = 20; // m/s + double simTime = (double)(numberOfEnbs + 1) * distance / speed; // 1500 m / 20 m/s = 75 secs + double enbTxPowerDbm = 46.0; // change some default attributes so that they are reasonable for // this scenario, but do this before processing command line @@ -157,7 +158,7 @@ main (int argc, char *argv[]) CommandLine cmd; cmd.AddValue ("simTime", "Total duration of the simulation (in seconds)", simTime); cmd.AddValue ("speed", "Speed of the UE (default = 20 m/s)", speed); - cmd.AddValue ("enbTxPowerDbm", "TX power [dBm] used by HeNBs (defalut = 20.0)", enbTxPowerDbm); + cmd.AddValue ("enbTxPowerDbm", "TX power [dBm] used by HeNBs (defalut = 46.0)", enbTxPowerDbm); cmd.Parse (argc, argv); @@ -166,6 +167,11 @@ main (int argc, char *argv[]) Ptr epcHelper = CreateObject (); lteHelper->SetEpcHelper (epcHelper); lteHelper->SetSchedulerType ("ns3::RrFfMacScheduler"); + lteHelper->SetHandoverAlgorithmType ("ns3::A2RsrqHandoverAlgorithm"); + lteHelper->SetHandoverAlgorithmAttribute ("ServingCellThreshold", + UintegerValue (15)); + lteHelper->SetHandoverAlgorithmAttribute ("NeighbourCellOffset", + UintegerValue (1)); Ptr pgw = epcHelper->GetPgwNode (); @@ -194,6 +200,21 @@ main (int argc, char *argv[]) // interface 0 is localhost, 1 is the p2p device remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.0.0.0"), 1); + /* + * Network topology: + * + * | + ---------------------------------------------------------> + * | UE + * | + * | d d d + * y | |-------------------x-------------------x------------------- + * | | eNodeB eNodeB + * | d | + * | | + * | | d = distance + * o (0, 0, 0) y = yForUe + */ + NodeContainer ueNodes; NodeContainer enbNodes; enbNodes.Create (numberOfEnbs); @@ -223,49 +244,6 @@ main (int argc, char *argv[]) NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice (enbNodes); NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes); - // Setup pre-GSOC UE measurement configuration to the eNodeBs - - // Event A2 - LteRrcSap::ReportConfigEutra reportConfigA2; - reportConfigA2.triggerType = LteRrcSap::ReportConfigEutra::EVENT; - reportConfigA2.eventId = LteRrcSap::ReportConfigEutra::EVENT_A2; - reportConfigA2.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ; - reportConfigA2.threshold1.range = 34; - reportConfigA2.hysteresis = 0; - reportConfigA2.timeToTrigger = 0; - reportConfigA2.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ; - reportConfigA2.reportQuantity = LteRrcSap::ReportConfigEutra::SAME_AS_TRIGGER_QUANTITY; - reportConfigA2.maxReportCells = LteRrcSap::MaxReportCells; - reportConfigA2.reportInterval = LteRrcSap::ReportConfigEutra::MS480; - reportConfigA2.reportAmount = 255; - - // Event A4 - LteRrcSap::ReportConfigEutra reportConfigA4; - reportConfigA4.triggerType = LteRrcSap::ReportConfigEutra::EVENT; - reportConfigA4.eventId = LteRrcSap::ReportConfigEutra::EVENT_A4; - reportConfigA4.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ; - reportConfigA4.threshold1.range = 0; - reportConfigA4.hysteresis = 0; - reportConfigA4.timeToTrigger = 0; - reportConfigA4.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ; - reportConfigA4.reportQuantity = LteRrcSap::ReportConfigEutra::SAME_AS_TRIGGER_QUANTITY; - reportConfigA4.maxReportCells = LteRrcSap::MaxReportCells; - reportConfigA4.reportInterval = LteRrcSap::ReportConfigEutra::MS480; - reportConfigA4.reportAmount = 255; - - uint8_t measId; - - for (NetDeviceContainer::Iterator it = enbLteDevs.Begin (); - it != enbLteDevs.End (); - ++it) - { - Ptr enbRrc = (*it)->GetObject ()->GetRrc (); - measId = enbRrc->AddUeMeasReportConfig (reportConfigA2); - NS_ASSERT (measId == 1); - measId = enbRrc->AddUeMeasReportConfig (reportConfigA4); - NS_ASSERT (measId == 2); - } - // Install the IP stack on the UEs internet.Install (ueNodes); Ipv4InterfaceContainer ueIpIfaces; diff --git a/src/lte/helper/lte-helper.cc b/src/lte/helper/lte-helper.cc index 1c9b7348e..d08c3cc45 100644 --- a/src/lte/helper/lte-helper.cc +++ b/src/lte/helper/lte-helper.cc @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -63,9 +64,9 @@ namespace ns3 { NS_OBJECT_ENSURE_REGISTERED (LteHelper); LteHelper::LteHelper (void) - : m_fadingStreamsAssigned (false), - m_imsiCounter (0), - m_cellIdCounter (0) + : m_fadingStreamsAssigned (false), + m_imsiCounter (0), + m_cellIdCounter (0) { NS_LOG_FUNCTION (this); m_enbNetDeviceFactory.SetTypeId (LteEnbNetDevice::GetTypeId ()); @@ -145,6 +146,13 @@ TypeId LteHelper::GetTypeId (void) StringValue ("ns3::PfFfMacScheduler"), MakeStringAccessor (&LteHelper::SetSchedulerType), MakeStringChecker ()) + .AddAttribute ("HandoverAlgorithm", + "The type of handover algorithm to be used for eNBs. " + "The allowed values for this attributes are the type names " + "of any class inheriting from ns3::HandoverAlgorithm.", + StringValue ("ns3::A2RsrqHandoverAlgorithm"), + MakeStringAccessor (&LteHelper::SetHandoverAlgorithmType), + MakeStringChecker ()) .AddAttribute ("PathlossModel", "The type of pathloss model to be used. " "The allowed values for this attributes are the type names " @@ -202,6 +210,21 @@ LteHelper::SetSchedulerAttribute (std::string n, const AttributeValue &v) m_schedulerFactory.Set (n, v); } +void +LteHelper::SetHandoverAlgorithmType (std::string type) +{ + NS_LOG_FUNCTION (this << type); + m_handoverAlgorithmFactory = ObjectFactory (); + m_handoverAlgorithmFactory.SetTypeId (type); +} + +void +LteHelper::SetHandoverAlgorithmAttribute (std::string n, const AttributeValue &v) +{ + NS_LOG_FUNCTION (this << n); + m_handoverAlgorithmFactory.Set (n, v); +} + void LteHelper::SetPathlossModelType (std::string type) @@ -367,6 +390,7 @@ LteHelper::InstallSingleEnbDevice (Ptr n) Ptr mac = CreateObject (); Ptr sched = m_schedulerFactory.Create (); + Ptr handoverAlgorithm = m_handoverAlgorithmFactory.Create (); Ptr rrc = CreateObject (); if (m_useIdealRrc) @@ -401,6 +425,9 @@ LteHelper::InstallSingleEnbDevice (Ptr n) mac->SetLteEnbCmacSapUser (rrc->GetLteEnbCmacSapUser ()); rrc->SetLteMacSapProvider (mac->GetLteMacSapProvider ()); + rrc->SetHandoverManagementSapProvider (handoverAlgorithm->GetHandoverManagementSapProvider ()); + handoverAlgorithm->SetHandoverManagementSapUser (rrc->GetHandoverManagementSapUser ()); + mac->SetFfMacSchedSapProvider (sched->GetFfMacSchedSapProvider ()); mac->SetFfMacCschedSapProvider (sched->GetFfMacCschedSapProvider ()); @@ -421,6 +448,7 @@ LteHelper::InstallSingleEnbDevice (Ptr n) dev->SetAttribute ("LteEnbMac", PointerValue (mac)); dev->SetAttribute ("FfMacScheduler", PointerValue (sched)); dev->SetAttribute ("LteEnbRrc", PointerValue (rrc)); + dev->SetAttribute ("HandoverAlgorithm", PointerValue (handoverAlgorithm)); phy->SetDevice (dev); dlPhy->SetDevice (dev); @@ -447,7 +475,7 @@ LteHelper::InstallSingleEnbDevice (Ptr n) { NS_LOG_WARN ("UL propagation model does not have a Frequency attribute"); } - + dev->Initialize (); @@ -463,7 +491,7 @@ LteHelper::InstallSingleEnbDevice (Ptr n) // S1 SAPs rrc->SetS1SapProvider (enbApp->GetS1SapProvider ()); enbApp->SetS1SapUser (rrc->GetS1SapUser ()); - + // X2 SAPs Ptr x2 = n->GetObject (); x2->SetEpcX2SapUser (rrc->GetEpcX2SapUser ()); diff --git a/src/lte/helper/lte-helper.h b/src/lte/helper/lte-helper.h index 781ef6254..a0562093b 100644 --- a/src/lte/helper/lte-helper.h +++ b/src/lte/helper/lte-helper.h @@ -106,6 +106,20 @@ public: */ void SetSchedulerAttribute (std::string n, const AttributeValue &v); + /** + * + * \param type the type of handover algorithm to be used for the eNBs + */ + void SetHandoverAlgorithmType (std::string type); + + /** + * set an attribute for the handover algorithm to be created + * + * \param n the name of the attribute + * \param v the value of the attribute + */ + void SetHandoverAlgorithmAttribute (std::string n, const AttributeValue &v); + /** * set an attribute for the LteEnbNetDevice to be created * @@ -630,6 +644,7 @@ private: Ptr m_uplinkPathlossModel; ObjectFactory m_schedulerFactory; + ObjectFactory m_handoverAlgorithmFactory; ObjectFactory m_propagationModelFactory; ObjectFactory m_enbNetDeviceFactory; ObjectFactory m_enbAntennaModelFactory; diff --git a/src/lte/model/a2-rsrq-handover-algorithm.cc b/src/lte/model/a2-rsrq-handover-algorithm.cc new file mode 100644 index 000000000..bb1aa2853 --- /dev/null +++ b/src/lte/model/a2-rsrq-handover-algorithm.cc @@ -0,0 +1,313 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 University of Jyvaskyla + * + * 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: Budiarto Herman + * + */ + + +#include "a2-rsrq-handover-algorithm.h" +#include +#include +#include + +NS_LOG_COMPONENT_DEFINE ("A2RsrqHandoverAlgorithm"); + + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (A2RsrqHandoverAlgorithm); + + +/////////////////////////////////////////// +// Handover Management SAP forwarder +/////////////////////////////////////////// + +/** + * \brief Class for forwarding Handover Management SAP Provider functions. + */ +class A2RsrqMemberHandoverManagementSapProvider : public HandoverManagementSapProvider +{ +public: + A2RsrqMemberHandoverManagementSapProvider (A2RsrqHandoverAlgorithm* handoverAlgorithm); + + // methods inherited from HandoverManagementSapProvider go here + virtual void ReportUeMeas (uint16_t rnti, LteRrcSap::MeasResults measResults); + +private: + A2RsrqHandoverAlgorithm* m_handoverAlgorithm; +}; + +A2RsrqMemberHandoverManagementSapProvider::A2RsrqMemberHandoverManagementSapProvider (A2RsrqHandoverAlgorithm* handoverAlgorithm) + : m_handoverAlgorithm (handoverAlgorithm) +{ +} + +void +A2RsrqMemberHandoverManagementSapProvider::ReportUeMeas (uint16_t rnti, + LteRrcSap::MeasResults measResults) +{ + m_handoverAlgorithm->DoReportUeMeas (rnti, measResults); +} + + + +/////////////////////////////////////////// +// A2 Based Handover Algorithm +/////////////////////////////////////////// + + +A2RsrqHandoverAlgorithm::A2RsrqHandoverAlgorithm () + : m_handoverManagementSapUser (0) +{ + NS_LOG_FUNCTION (this); + m_handoverManagementSapProvider = new A2RsrqMemberHandoverManagementSapProvider (this); +} + + +A2RsrqHandoverAlgorithm::~A2RsrqHandoverAlgorithm () +{ + NS_LOG_FUNCTION (this); +} + + +void +A2RsrqHandoverAlgorithm::DoDispose () +{ + NS_LOG_FUNCTION (this); + delete m_handoverManagementSapProvider; +} + + +TypeId +A2RsrqHandoverAlgorithm::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::A2RsrqHandoverAlgorithm") + .SetParent () + .AddConstructor () + .AddAttribute ("ServingCellThreshold", + "If serving cell is worse than this threshold, neighbour cells are consider for Handover", + UintegerValue (30), + MakeUintegerAccessor (&A2RsrqHandoverAlgorithm::m_servingCellThreshold), + MakeUintegerChecker ()) + .AddAttribute ("NeighbourCellOffset", + "Minimum offset between serving and best neighbour cell to trigger the Handover", + UintegerValue (1), + MakeUintegerAccessor (&A2RsrqHandoverAlgorithm::m_neighbourCellOffset), + MakeUintegerChecker ()) + ; + return tid; +} + + +void +A2RsrqHandoverAlgorithm::SetHandoverManagementSapUser (HandoverManagementSapUser* s) +{ + NS_LOG_FUNCTION (this << s); + m_handoverManagementSapUser = s; +} + + +HandoverManagementSapProvider* +A2RsrqHandoverAlgorithm::GetHandoverManagementSapProvider () +{ + NS_LOG_FUNCTION (this); + return m_handoverManagementSapProvider; +} + + +void +A2RsrqHandoverAlgorithm::DoInitialize () +{ + NS_LOG_FUNCTION (this); + + LteRrcSap::ReportConfigEutra reportConfigA2; + reportConfigA2.eventId = LteRrcSap::ReportConfigEutra::EVENT_A2; + reportConfigA2.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ; + reportConfigA2.threshold1.range = m_servingCellThreshold; + reportConfigA2.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ; + reportConfigA2.reportInterval = LteRrcSap::ReportConfigEutra::MS240; + m_a2measId = m_handoverManagementSapUser->AddUeMeasReportConfig (reportConfigA2); + + LteRrcSap::ReportConfigEutra reportConfigA4; + reportConfigA4.eventId = LteRrcSap::ReportConfigEutra::EVENT_A4; + reportConfigA4.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ; + reportConfigA4.threshold1.range = 0; // intentionally very low threshold + reportConfigA4.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ; + reportConfigA4.reportInterval = LteRrcSap::ReportConfigEutra::MS480; + m_a4measId = m_handoverManagementSapUser->AddUeMeasReportConfig (reportConfigA4); + + HandoverAlgorithm::DoInitialize (); +} + + +void +A2RsrqHandoverAlgorithm::DoReportUeMeas (uint16_t rnti, + LteRrcSap::MeasResults measResults) +{ + NS_LOG_FUNCTION (this << rnti << (uint16_t) measResults.measId); + + if (measResults.measId == m_a2measId) + { + NS_ASSERT_MSG (measResults.rsrqResult <= m_servingCellThreshold, + "Invalid UE measurement report"); + EvaluateHandover (rnti, measResults.rsrqResult); + } + else if (measResults.measId == m_a4measId) + { + if (measResults.haveMeasResultNeighCells + && !measResults.measResultListEutra.empty ()) + { + for (std::list ::iterator it = measResults.measResultListEutra.begin (); + it != measResults.measResultListEutra.end (); + ++it) + { + NS_ASSERT_MSG (it->haveRsrqResult == true, + "RSRQ measure missing for cellId " << it->physCellId); + UpdateNeighbourMeasurements (rnti, it->physCellId, it->rsrqResult); + } + } + else + { + NS_LOG_LOGIC ("WARNING"); + // NS_ASSERT_MSG ("Event A4 received without measure results for neighbour cells"); + // TODO Remove neighbours in the neighbourCellMeasures table + } + } + else + { + NS_LOG_WARN ("Ignoring measId " << (uint16_t) measResults.measId); + } + +} // end of DoReportUeMeas + + +void +A2RsrqHandoverAlgorithm::EvaluateHandover (uint16_t rnti, + uint8_t servingCellRsrq) +{ + NS_LOG_FUNCTION (this << rnti << (uint16_t) servingCellRsrq); + + MeasurementTable_t::iterator it1; + it1 = m_neighbourCellMeasures.find (rnti); + + if (it1 == m_neighbourCellMeasures.end ()) + { + NS_LOG_WARN ("Skipping handover evaluation for RNTI " << rnti << " because neighbour cells information is not found"); + } + else + { + // Find the best neighbour cell (eNB) + NS_LOG_LOGIC ("Number of neighbour cells = " << it1->second.size ()); + uint16_t bestNeighbourCellId = 0; + uint8_t bestNeighbourRsrq = 0; + MeasurementRow_t::iterator it2; + for (it2 = it1->second.begin (); it2 != it1->second.end (); ++it2) + { + if ((it2->second->m_rsrq > bestNeighbourRsrq) + && IsValidNeighbour (it2->first)) + { + bestNeighbourCellId = it2->first; + bestNeighbourRsrq = it2->second->m_rsrq; + } + } + + // Trigger Handover, if needed + if (bestNeighbourCellId > 0) + { + NS_LOG_LOGIC ("Best neighbour cellId " << bestNeighbourCellId); + + if ((bestNeighbourRsrq - servingCellRsrq) >= m_neighbourCellOffset) + { + NS_LOG_LOGIC ("Trigger Handover to cellId " << bestNeighbourCellId); + NS_LOG_LOGIC ("target cell RSRQ " << (uint16_t) bestNeighbourRsrq); + NS_LOG_LOGIC ("serving cell RSRQ " << (uint16_t) servingCellRsrq); + + // Inform eNodeB RRC about handover + m_handoverManagementSapUser->TriggerHandover (rnti, + bestNeighbourCellId); + } + } + + } // end of else of if (it1 == m_neighbourCellMeasures.end ()) + +} // end of EvaluateMeasurementReport + + +bool +A2RsrqHandoverAlgorithm::IsValidNeighbour (uint16_t cellId) +{ + NS_LOG_FUNCTION (this << cellId); + + // Ptr neighbourRelation = m_rrc->m_neighbourRelationTable[it->second->m_cellId]; + // if ((neighbourRelation->m_noHo == false) && + // (neighbourRelation->m_noX2 == false)) + // { + // bestNeighbour = it->second; + // bestNeighbourRsrq = it->second->m_rsrq; + // } + // TODO + + return true; +} + + +void +A2RsrqHandoverAlgorithm::UpdateNeighbourMeasurements (uint16_t rnti, + uint16_t cellId, + uint8_t rsrq) +{ + NS_LOG_FUNCTION (this << rnti << cellId << (uint16_t) rsrq); + MeasurementTable_t::iterator it1; + it1 = m_neighbourCellMeasures.find (rnti); + + if (it1 == m_neighbourCellMeasures.end ()) + { + // insert a new UE entry + MeasurementRow_t row; + std::pair ret; + ret = m_neighbourCellMeasures.insert (std::pair (rnti, row)); + NS_ASSERT (ret.second); + it1 = ret.first; + } + + NS_ASSERT (it1 != m_neighbourCellMeasures.end ()); + Ptr neighbourCellMeasures; + std::map >::iterator it2; + it2 = it1->second.find (cellId); + + if (it2 != it1->second.end ()) + { + neighbourCellMeasures = it2->second; + neighbourCellMeasures->m_cellId = cellId; + neighbourCellMeasures->m_rsrp = 0; + neighbourCellMeasures->m_rsrq = rsrq; + } + else + { + // insert a new cell entry + neighbourCellMeasures = CreateObject (); + neighbourCellMeasures->m_cellId = cellId; + neighbourCellMeasures->m_rsrp = 0; + neighbourCellMeasures->m_rsrq = rsrq; + it1->second[cellId] = neighbourCellMeasures; + } + +} // end of UpdateNeighbourMeasurements + + +} // end of namespace ns3 diff --git a/src/lte/model/a2-rsrq-handover-algorithm.h b/src/lte/model/a2-rsrq-handover-algorithm.h new file mode 100644 index 000000000..00b34be6b --- /dev/null +++ b/src/lte/model/a2-rsrq-handover-algorithm.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 University of Jyvaskyla + * + * 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: Budiarto Herman + * + */ + +#ifndef A2_RSRQ_HANDOVER_ALGORITHM_H +#define A2_RSRQ_HANDOVER_ALGORITHM_H + +#include +#include +#include + +namespace ns3 { + + +class HandoverManagementSapProvider; +class HandoverManagementSapUser; + + +/** + * \brief Implements the Handover Management SAP for a handover algorithm based + * on RSRQ and Event A2 (serving cell's RSRQ becomes worse than a + * threshold). + * + * The threshold used by the algorithm can be configured in the + * `ServingCellThreshold` attribute. + */ +class A2RsrqHandoverAlgorithm : public HandoverAlgorithm +{ +public: + A2RsrqHandoverAlgorithm (); + virtual ~A2RsrqHandoverAlgorithm (); + + // inherited from Object + virtual void DoDispose (void); + static TypeId GetTypeId (void); + + // inherited from HandoverAlgorithm + virtual void SetHandoverManagementSapUser (HandoverManagementSapUser* s); + virtual HandoverManagementSapProvider* GetHandoverManagementSapProvider (); + + friend class A2RsrqMemberHandoverManagementSapProvider; + +protected: + // inherited from Object + virtual void DoInitialize (); + +private: + + // Handover Management SAP implementation + void DoReportUeMeas (uint16_t rnti, LteRrcSap::MeasResults measResults); + + // Internal methods + void EvaluateHandover (uint16_t rnti, uint8_t servingCellRsrq); + bool IsValidNeighbour (uint16_t cellId); + void UpdateNeighbourMeasurements (uint16_t rnti, uint16_t cellId, + uint8_t rsrq); + + // The expected measurement identities + uint8_t m_a2measId; + uint8_t m_a4measId; + + /** + * \brief Measurements reported by a UE for a cell ID. + * + * The values are quantized according 3GPP TS 36.133 section 9.1.4 and 9.1.7. + */ + class UeMeasure : public Object + { + public: + uint16_t m_cellId; + uint8_t m_rsrp; + uint8_t m_rsrq; + }; + // TODO instead of class, try using struct or SimpleRefCount + + // cellId + typedef std::map > MeasurementRow_t; + // rnti + typedef std::map MeasurementTable_t; + MeasurementTable_t m_neighbourCellMeasures; + + // Class attributes + uint8_t m_servingCellThreshold; + uint8_t m_neighbourCellOffset; + + // Handover Management SAPs + HandoverManagementSapUser* m_handoverManagementSapUser; + HandoverManagementSapProvider* m_handoverManagementSapProvider; + +}; // end of class A2RsrqHandoverAlgorithm + + +} // end of namespace ns3 + + +#endif /* A2_RSRQ_HANDOVER_ALGORITHM_H */ diff --git a/src/lte/model/handover-algorithm.cc b/src/lte/model/handover-algorithm.cc new file mode 100644 index 000000000..47c6f8c63 --- /dev/null +++ b/src/lte/model/handover-algorithm.cc @@ -0,0 +1,58 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 University of Jyvaskyla + * + * 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: Budiarto Herman + * + */ + +#include "handover-algorithm.h" +#include + +NS_LOG_COMPONENT_DEFINE ("HandoverAlgorithm"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (HandoverAlgorithm); + + +HandoverAlgorithm::HandoverAlgorithm () +{ +} + + +HandoverAlgorithm::~HandoverAlgorithm () +{ +} + + +void +HandoverAlgorithm::DoDispose () +{ +} + + +TypeId +HandoverAlgorithm::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::HandoverAlgorithm") + .SetParent () + ; + return tid; +} + + +} // end of namespace ns3 diff --git a/src/lte/model/handover-algorithm.h b/src/lte/model/handover-algorithm.h new file mode 100644 index 000000000..6263db2d5 --- /dev/null +++ b/src/lte/model/handover-algorithm.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 University of Jyvaskyla + * + * 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: Budiarto Herman + * + */ + +#ifndef HANDOVER_ALGORITHM_H +#define HANDOVER_ALGORITHM_H + +#include + +namespace ns3 { + +class HandoverManagementSapProvider; +class HandoverManagementSapUser; + + +/** + * \brief This abstract base class identifies the interface by means of which + * the helper object can plug on the eNodeB RRC a handover algorithm + * implementation. + */ +class HandoverAlgorithm : public Object +{ +public: + HandoverAlgorithm (); + virtual ~HandoverAlgorithm (); + + // inherited from Object + virtual void DoDispose (void); + static TypeId GetTypeId (void); + + /** + * \brief Set the user part of the HandoverManagementSap that this handover + * algorithm will interact with. Normally this part of the SAP is + * exported by the eNodeB RRC. + * \param s + */ + virtual void SetHandoverManagementSapUser (HandoverManagementSapUser* s) = 0; + + /** + * + * \return the Provider part of the HandoverManagementSap provided by the + * handover algorithm + */ + virtual HandoverManagementSapProvider* GetHandoverManagementSapProvider () = 0; + +}; // end of class HandoverAlgorithm + + +} // end of namespace ns3 + + +#endif /* HANDOVER_ALGORITHM_H */ diff --git a/src/lte/model/handover-management-sap.cc b/src/lte/model/handover-management-sap.cc new file mode 100644 index 000000000..561532337 --- /dev/null +++ b/src/lte/model/handover-management-sap.cc @@ -0,0 +1,37 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 University of Jyvaskyla + * + * 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: Budiarto Herman + * + */ + +#include "handover-management-sap.h" + +namespace ns3 { + + +HandoverManagementSapProvider::~HandoverManagementSapProvider () +{ +} + + +HandoverManagementSapUser::~HandoverManagementSapUser () +{ +} + + +} // end of namespace ns3 diff --git a/src/lte/model/handover-management-sap.h b/src/lte/model/handover-management-sap.h new file mode 100644 index 000000000..e1c55d327 --- /dev/null +++ b/src/lte/model/handover-management-sap.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 University of Jyvaskyla + * + * 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: Budiarto Herman + * + */ + +#ifndef HANDOVER_MANAGEMENT_SAP_H +#define HANDOVER_MANAGEMENT_SAP_H + +#include + +namespace ns3 { + + +/** + * \brief Service Access Point (SAP) used by the eNodeB RRC instance to send + * messages to the handover algorithm instance. + */ +class HandoverManagementSapProvider +{ +public: + virtual ~HandoverManagementSapProvider (); + + /** + * \brief Send a UE measurement report to handover algorithm. + * \param rnti Radio Network Temporary Identity, an integer identifying the UE + * where the report originates from + * \param measResults a single report of one measurement identity + * + * The received measurement report may be stored and utilized for the purpose + * of making handover decision. + */ + virtual void ReportUeMeas (uint16_t rnti, + LteRrcSap::MeasResults measResults) = 0; + +}; // end of class HandoverManagementSapProvider + + +/** + * \brief Service Access Point (SAP) used by the handover algorithm instance to + * send messages to the eNodeB RRC instance. + */ +class HandoverManagementSapUser +{ +public: + virtual ~HandoverManagementSapUser (); + + /** + * \brief Request a certain reporting configuration to be fulfilled by the UEs + * attached to the eNodeB entity. + * \param reportConfig the UE measurement reporting configuration + * \return the measurement identity associated with this newly added + * reporting configuration + * + * The eNodeB RRC entity is expected to configure the same reporting + * configuration in each of the attached UEs. When later in the simulation a + * UE measurement report is received from a UE as a result of this + * configuration, the eNodeB RRC entity shall forward this report to the + * handover algorithm through the HandoverManagementSapProvider::ReportUeMeas + * SAP function. + * + * This function is only valid before the simulation begins. + */ + virtual uint8_t AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig) = 0; + + /** + * \brief Instruct the eNodeB RRC entity to prepare a handover. + * \param rnti Radio Network Temporary Identity, an integer identifying the + * UE which shall perform the handover + * \param targetCellId the cell ID of the target eNodeB + * + * This function is used by the handover algorithm entity when a handover + * decision has been reached. + * + * The process to produce the decision is up to the implementation of handover + * algorithm. It is typically based on the reported UE measurements, which are + * received through the HandoverManagementSapProvider::ReportUeMeas function. + */ + virtual void TriggerHandover (uint16_t rnti, uint16_t targetCellId) = 0; + +}; // end of class HandoverManagementSapUser + + +} // end of namespace ns3 + + +#endif /* HANDOVER_MANAGEMENT_SAP_H */ diff --git a/src/lte/model/lte-enb-net-device.cc b/src/lte/model/lte-enb-net-device.cc index 891bf3a73..d94d8460e 100644 --- a/src/lte/model/lte-enb-net-device.cc +++ b/src/lte/model/lte-enb-net-device.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,11 @@ TypeId LteEnbNetDevice::GetTypeId (void) PointerValue (), MakePointerAccessor (&LteEnbNetDevice::m_rrc), MakePointerChecker ()) + .AddAttribute ("HandoverAlgorithm", + "The handover algorithm associated to this EnbNetDevice", + PointerValue (), + MakePointerAccessor (&LteEnbNetDevice::m_handoverAlgorithm), + MakePointerChecker ()) .AddAttribute ("LteEnbMac", "The MAC associated to this EnbNetDevice", PointerValue (), @@ -132,6 +138,9 @@ LteEnbNetDevice::DoDispose () m_rrc->Dispose (); m_rrc = 0; + m_handoverAlgorithm->Dispose (); + m_handoverAlgorithm = 0; + m_phy->Dispose (); m_phy = 0; @@ -253,6 +262,7 @@ LteEnbNetDevice::DoInitialize (void) m_phy->Initialize (); m_mac->Initialize (); m_rrc->Initialize (); + m_handoverAlgorithm->Initialize (); } diff --git a/src/lte/model/lte-enb-net-device.h b/src/lte/model/lte-enb-net-device.h index 73cedac1e..edb4b33e0 100644 --- a/src/lte/model/lte-enb-net-device.h +++ b/src/lte/model/lte-enb-net-device.h @@ -40,6 +40,7 @@ class LteEnbPhy; class LteEnbMac; class LteEnbRrc; class FfMacScheduler; +class HandoverAlgorithm; /** @@ -146,6 +147,8 @@ private: Ptr m_scheduler; + Ptr m_handoverAlgorithm; + uint16_t m_cellId; /**< Cell Identifer. Part of the CGI, see TS 29.274, section 8.21.1 */ uint8_t m_dlBandwidth; /**< downlink bandwidth in RBs */ diff --git a/src/lte/model/lte-enb-rrc.cc b/src/lte/model/lte-enb-rrc.cc index e7533b790..2fa21179f 100644 --- a/src/lte/model/lte-enb-rrc.cc +++ b/src/lte/model/lte-enb-rrc.cc @@ -34,6 +34,7 @@ #include "lte-radio-bearer-info.h" #include "eps-bearer-tag.h" #include "ff-mac-csched-sap.h" +#include #include "epc-enb-s1-sap.h" #include "lte-rlc.h" @@ -54,10 +55,13 @@ NS_LOG_COMPONENT_DEFINE ("LteEnbRrc"); namespace ns3 { -// /////////////////////////// +/////////////////////////////////////////// // CMAC SAP forwarder -// /////////////////////////// +/////////////////////////////////////////// +/** + * \brief Class for forwarding CMAC SAP User functions. + */ class EnbRrcMemberLteEnbCmacSapUser : public LteEnbCmacSapUser { public: @@ -95,19 +99,60 @@ EnbRrcMemberLteEnbCmacSapUser::RrcConfigurationUpdateInd (UeConfig params) } + +/////////////////////////////////////////// +// Handover Management SAP forwarder +/////////////////////////////////////////// + +/** + * \brief Class for forwarding Handover Management SAP User functions. + */ +class EnbRrcMemberHandoverManagementSapUser : public HandoverManagementSapUser +{ +public: + EnbRrcMemberHandoverManagementSapUser (LteEnbRrc* rrc); + + // methods inherited from HandoverManagementSapUser go here + virtual uint8_t AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig); + virtual void TriggerHandover (uint16_t rnti, uint16_t targetCellId); + +private: + LteEnbRrc* m_rrc; +}; + +EnbRrcMemberHandoverManagementSapUser::EnbRrcMemberHandoverManagementSapUser (LteEnbRrc* rrc) + : m_rrc (rrc) +{ +} + +uint8_t +EnbRrcMemberHandoverManagementSapUser::AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig) +{ + return m_rrc->DoAddUeMeasReportConfig (reportConfig); +} + +void +EnbRrcMemberHandoverManagementSapUser::TriggerHandover (uint16_t rnti, + uint16_t targetCellId) +{ + m_rrc->DoTriggerHandover (rnti, targetCellId); +} + + + const char* g_ueManagerStateName[UeManager::NUM_STATES] = - { - "INITIAL_RANDOM_ACCESS", - "CONNECTION_SETUP", - "CONNECTION_REJECTED", - "CONNECTED_NORMALLY", - "CONNECTION_RECONFIGURATION", - "CONNECTION_REESTABLISHMENT", - "HANDOVER_PREPARATION", - "HANDOVER_JOINING", - "HANDOVER_PATH_SWITCH", - "HANDOVER_LEAVING", - }; +{ + "INITIAL_RANDOM_ACCESS", + "CONNECTION_SETUP", + "CONNECTION_REJECTED", + "CONNECTED_NORMALLY", + "CONNECTION_RECONFIGURATION", + "CONNECTION_REESTABLISHMENT", + "HANDOVER_PREPARATION", + "HANDOVER_JOINING", + "HANDOVER_PATH_SWITCH", + "HANDOVER_LEAVING", +}; std::string ToString (UeManager::State s) { @@ -490,8 +535,8 @@ UeManager::ScheduleRrcConnectionReconfiguration () // a previous reconfiguration still ongoing, we need to wait for it to be finished m_pendingRrcConnectionReconfiguration = true; break; - - case CONNECTED_NORMALLY: + + case CONNECTED_NORMALLY: { m_pendingRrcConnectionReconfiguration = false; LteRrcSap::RrcConnectionReconfiguration msg = BuildRrcConnectionReconfiguration (); @@ -499,8 +544,8 @@ UeManager::ScheduleRrcConnectionReconfiguration () RecordDataRadioBearersToBeStarted (); SwitchToState (CONNECTION_RECONFIGURATION); } - break; - + break; + default: NS_FATAL_ERROR ("method unexpected in state " << ToString (m_state)); break; @@ -509,11 +554,11 @@ UeManager::ScheduleRrcConnectionReconfiguration () void UeManager::PrepareHandover (uint16_t cellId) -{ - NS_LOG_FUNCTION (this << cellId); +{ + NS_LOG_FUNCTION (this << cellId); switch (m_state) { - case CONNECTED_NORMALLY: + case CONNECTED_NORMALLY: { m_targetCellId = cellId; EpcX2SapProvider::HandoverRequestParams params; @@ -943,68 +988,12 @@ UeManager::RecvMeasurementReport (LteRrcSap::MeasurementReport msg) << " RSRQ " << (it->haveRsrqResult ? (uint16_t) it->rsrqResult : 255)); } - m_rrc->m_recvMeasurementReportTrace (m_imsi, m_rrc->m_cellId, m_rnti, msg); - - /* - * The code below assumes event A2 at measId 1 and A4 at measId 2, which is - * the default configuration from previous release of LENA. This section will - * be moved as a separate handover algorithm. To avoid automatically invoking - * handover, disable it by setting ns3::LteEnbRrc::AdmitHandoverRequest - * attribute to false. - */ - - /// Event A2 (Serving becomes worse than threshold) - if (msg.measResults.measId == 1) - { - // Keep new RSRQ value reported for the serving cell - m_servingCellMeasures->m_rsrq = msg.measResults.rsrqResult; - m_servingCellMeasures->m_rsrp = msg.measResults.rsrpResult; - - // Serving cell is worse than a handover threshold. - // This handover threshold is independent from the event A2 threshold - if (m_servingCellMeasures->m_rsrq <= m_rrc->m_servingCellHandoverThreshold) - { - // Find the best neighbour cell (eNB) - Ptr bestNeighbour = 0; - uint8_t bestNeighbourRsrq = 0; - NS_LOG_LOGIC ("Number of neighbour cells = " << m_neighbourCellMeasures.size ()); - for (std::map >::iterator it = m_neighbourCellMeasures.begin (); - it != m_neighbourCellMeasures.end (); - ++it) - { - if (it->second->m_rsrq > bestNeighbourRsrq) - { - Ptr neighbourRelation = m_rrc->m_neighbourRelationTable[it->second->m_cellId]; - if ((neighbourRelation->m_noHo == false) && - (neighbourRelation->m_noX2 == false)) - { - bestNeighbour = it->second; - bestNeighbourRsrq = it->second->m_rsrq; - } - } - } - - // Trigger Handover, if needed - if (bestNeighbour) - { - uint16_t targetCellId = bestNeighbour->m_cellId; - NS_LOG_LOGIC ("Best neighbour cellId " << targetCellId); - if ( (bestNeighbour->m_rsrq - m_servingCellMeasures->m_rsrq >= m_rrc->m_neighbourCellHandoverOffset) && - (m_state == CONNECTED_NORMALLY) ) - { - NS_LOG_LOGIC ("Trigger Handover to cellId " << targetCellId); - NS_LOG_LOGIC ("target cell RSRQ " << (uint16_t) bestNeighbour->m_rsrq); - NS_LOG_LOGIC ("serving cell RSRQ " << (uint16_t) m_servingCellMeasures->m_rsrq); - PrepareHandover (targetCellId); - } - } - } - } /// Event A4 (Neighbour becomes better than threshold) - else if (msg.measResults.measId == 2) + if (msg.measResults.measId == 2) // TODO remove this hardcode { // Update the NRT - if (msg.measResults.haveMeasResultNeighCells && ! (msg.measResults.measResultListEutra.empty ())) + if (msg.measResults.haveMeasResultNeighCells + && !(msg.measResults.measResultListEutra.empty ())) { for (std::list ::iterator it = msg.measResults.measResultListEutra.begin (); it != msg.measResults.measResultListEutra.end (); @@ -1037,34 +1026,24 @@ UeManager::RecvMeasurementReport (LteRrcSap::MeasurementReport msg) neighbourRelation->m_detectedAsNeighbour = true; m_rrc->m_neighbourRelationTable[it->physCellId] = neighbourRelation; } - - // Update measure info of the neighbour cell - Ptr neighbourCellMeasures; - if (m_neighbourCellMeasures.find (it->physCellId) != m_neighbourCellMeasures.end ()) - { - neighbourCellMeasures = m_neighbourCellMeasures[it->physCellId]; - neighbourCellMeasures->m_cellId = it->physCellId; - neighbourCellMeasures->m_rsrq = it->rsrqResult; - neighbourCellMeasures->m_rsrp = 0; - } - else - { - neighbourCellMeasures = CreateObject (); - neighbourCellMeasures->m_cellId = it->physCellId; - neighbourCellMeasures->m_rsrq = it->rsrqResult; - neighbourCellMeasures->m_rsrp = 0; - m_neighbourCellMeasures[it->physCellId] = neighbourCellMeasures; - } } } else { - NS_LOG_LOGIC ("WARNING"); -// NS_ASSERT_MSG ("Event A4 received without measure results for neighbour cells"); - // TODO Remove neighbours in the neighbourCellMeasures table + NS_LOG_LOGIC ("WARNING"); + // NS_ASSERT_MSG ("Event A4 received without measure results for neighbour cells"); + // TODO Remove neighbours in the neighbourCellMeasures table } } -} + + // forward the UE measurements report to the active handover algorithm + m_rrc->m_handoverManagementSapProvider->ReportUeMeas (m_rnti, + msg.measResults); + + // fire a trace source + m_rrc->m_recvMeasurementReportTrace (m_imsi, m_rrc->m_cellId, m_rnti, msg); + +} // end of UeManager::RecvMeasurementReport // methods forwarded from CMAC SAP @@ -1322,16 +1301,17 @@ UeManager::SwitchToState (State newState) } - -// /////////////////////////// + +/////////////////////////////////////////// // eNB RRC methods -// /////////////////////////// +/////////////////////////////////////////// NS_OBJECT_ENSURE_REGISTERED (LteEnbRrc); LteEnbRrc::LteEnbRrc () : m_x2SapProvider (0), m_cmacSapProvider (0), + m_handoverManagementSapProvider (0), m_rrcSapUser (0), m_macSapProvider (0), m_s1SapProvider (0), @@ -1344,6 +1324,7 @@ LteEnbRrc::LteEnbRrc () { NS_LOG_FUNCTION (this); m_cmacSapUser = new EnbRrcMemberLteEnbCmacSapUser (this); + m_handoverManagementSapUser = new EnbRrcMemberHandoverManagementSapUser (this); m_rrcSapProvider = new MemberLteEnbRrcSapProvider (this); m_x2SapUser = new EpcX2SpecificEpcX2SapUser (this); m_s1SapUser = new MemberEpcEnbS1SapUser (this); @@ -1363,6 +1344,7 @@ LteEnbRrc::DoDispose () NS_LOG_FUNCTION (this); m_ueMap.clear (); delete m_cmacSapUser; + delete m_handoverManagementSapUser; delete m_rrcSapProvider; delete m_x2SapUser; delete m_s1SapUser; @@ -1440,16 +1422,6 @@ LteEnbRrc::GetTypeId (void) BooleanValue (true), MakeBooleanAccessor (&LteEnbRrc::m_admitRrcConnectionRequest), MakeBooleanChecker ()) - .AddAttribute ("ServingCellHandoverThreshold", - "If serving cell is worse than this threshold, neighbour cells are consider for Handover", - UintegerValue (15), - MakeUintegerAccessor (&LteEnbRrc::m_servingCellHandoverThreshold), - MakeUintegerChecker ()) - .AddAttribute ("NeighbourCellHandoverOffset", - "Minimum offset between serving and best neighbour cell to trigger the Handover", - UintegerValue (1), - MakeUintegerAccessor (&LteEnbRrc::m_neighbourCellHandoverOffset), - MakeUintegerChecker ()) // UE measurements related attributes .AddAttribute ("RsrpFilterCoefficient", @@ -1520,6 +1492,20 @@ LteEnbRrc::GetLteEnbCmacSapUser () return m_cmacSapUser; } +void +LteEnbRrc::SetHandoverManagementSapProvider (HandoverManagementSapProvider * s) +{ + NS_LOG_FUNCTION (this << s); + m_handoverManagementSapProvider = s; +} + +HandoverManagementSapUser* +LteEnbRrc::GetHandoverManagementSapUser () +{ + NS_LOG_FUNCTION (this); + return m_handoverManagementSapUser; +} + void LteEnbRrc::SetLteEnbRrcSapUser (LteEnbRrcSapUser * s) { @@ -1585,14 +1571,14 @@ LteEnbRrc::AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra config) NS_ASSERT_MSG (m_ueMeasConfig.measIdToAddModList.size () == m_ueMeasConfig.reportConfigToAddModList.size (), "Measurement identities and reporting configuration should not have different quantity"); - uint8_t nextId = m_ueMeasConfig.reportConfigToAddModList.size () + 1; - if (Simulator::Now () != Seconds (0)) { NS_FATAL_ERROR ("AddUeMeasReportConfig may not be called after the simulation has run"); } // TODO more asserts to validate the input + uint8_t nextId = m_ueMeasConfig.reportConfigToAddModList.size () + 1; + // create the reporting configuration LteRrcSap::ReportConfigToAddMod reportConfig; reportConfig.reportConfigId = nextId; @@ -2046,6 +2032,23 @@ LteEnbRrc::DoNotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success) } +uint8_t +LteEnbRrc::DoAddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig) +{ + NS_LOG_FUNCTION (this); + return AddUeMeasReportConfig (reportConfig); +} + +void +LteEnbRrc::DoTriggerHandover (uint16_t rnti, uint16_t targetCellId) +{ + NS_LOG_FUNCTION (this << rnti << targetCellId); + Ptr ueManager = GetUeManager (rnti); + NS_ASSERT_MSG (ueManager != 0, "Cannot find UE context with RNTI " << rnti); + ueManager->PrepareHandover (targetCellId); +} + + uint16_t LteEnbRrc::AddUe (UeManager::State state) diff --git a/src/lte/model/lte-enb-rrc.h b/src/lte/model/lte-enb-rrc.h index 06418fc91..e9ee0f538 100644 --- a/src/lte/model/lte-enb-rrc.h +++ b/src/lte/model/lte-enb-rrc.h @@ -94,19 +94,19 @@ public: * */ enum State - { - INITIAL_RANDOM_ACCESS = 0, - CONNECTION_SETUP, - CONNECTION_REJECTED, - CONNECTED_NORMALLY, - CONNECTION_RECONFIGURATION, - CONNECTION_REESTABLISHMENT, - HANDOVER_PREPARATION, - HANDOVER_JOINING, - HANDOVER_PATH_SWITCH, - HANDOVER_LEAVING, - NUM_STATES - }; + { + INITIAL_RANDOM_ACCESS = 0, + CONNECTION_SETUP, + CONNECTION_REJECTED, + CONNECTED_NORMALLY, + CONNECTION_RECONFIGURATION, + CONNECTION_REESTABLISHMENT, + HANDOVER_PREPARATION, + HANDOVER_JOINING, + HANDOVER_PATH_SWITCH, + HANDOVER_LEAVING, + NUM_STATES + }; UeManager (); @@ -437,6 +437,11 @@ private: }; + +class HandoverManagementSapProvider; +class HandoverManagementSapUser; + + /** * \ingroup lte * @@ -446,6 +451,7 @@ class LteEnbRrc : public Object { friend class EnbRrcMemberLteEnbCmacSapUser; + friend class EnbRrcMemberHandoverManagementSapUser; friend class MemberLteEnbRrcSapProvider; friend class MemberEpcEnbS1SapUser; friend class EpcX2SpecificEpcX2SapUser; @@ -498,6 +504,21 @@ public: LteEnbCmacSapUser* GetLteEnbCmacSapUser (); + /** + * set the Handover Management SAP this RRC should interact with + * + * \param s the Handover Management SAP Provider to be used by this RRC + */ + void SetHandoverManagementSapProvider (HandoverManagementSapProvider * s); + + /** + * Get the Handover Management SAP offered by this RRC + * \return s the Handover Management SAP User interface offered to the + * handover algorithm by this RRC + */ + HandoverManagementSapUser* GetHandoverManagementSapUser (); + + /** * set the RRC SAP this RRC should interact with * @@ -683,7 +704,7 @@ public: private: - // methods forwarded from RRC SAP + // RRC SAP methods void DoCompleteSetupUe (uint16_t rnti, LteEnbRrcSapProvider::CompleteSetupUeParameters params); void DoRecvRrcConnectionRequest (uint16_t rnti, LteRrcSap::RrcConnectionRequest msg); @@ -693,11 +714,13 @@ private: void DoRecvRrcConnectionReestablishmentComplete (uint16_t rnti, LteRrcSap::RrcConnectionReestablishmentComplete msg); void DoRecvMeasurementReport (uint16_t rnti, LteRrcSap::MeasurementReport msg); - // S1 SAP methods + void DoDataRadioBearerSetupRequest (EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params); - void DoPathSwitchRequestAcknowledge (EpcEnbS1SapUser::PathSwitchRequestAcknowledgeParameters params); + void DoPathSwitchRequestAcknowledge (EpcEnbS1SapUser::PathSwitchRequestAcknowledgeParameters params); + // X2 SAP methods + void DoRecvHandoverRequest (EpcX2SapUser::HandoverRequestParams params); void DoRecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params); void DoRecvHandoverPreparationFailure (EpcX2SapUser::HandoverPreparationFailureParams params); @@ -707,12 +730,17 @@ private: void DoRecvResourceStatusUpdate (EpcX2SapUser::ResourceStatusUpdateParams params); void DoRecvUeData (EpcX2SapUser::UeDataParams params); - // CMAC SAP methods + uint16_t DoAllocateTemporaryCellRnti (); void DoNotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success); void DoRrcConfigurationUpdateInd (LteEnbCmacSapUser::UeConfig params); + // Handover Management SAP methods + + uint8_t DoAddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig); + void DoTriggerHandover (uint16_t rnti, uint16_t targetCellId); + // Internal methods @@ -836,6 +864,9 @@ private: LteEnbCmacSapUser* m_cmacSapUser; LteEnbCmacSapProvider* m_cmacSapProvider; + HandoverManagementSapUser* m_handoverManagementSapUser; + HandoverManagementSapProvider* m_handoverManagementSapProvider; + LteEnbRrcSapUser* m_rrcSapUser; LteEnbRrcSapProvider* m_rrcSapProvider; @@ -890,8 +921,6 @@ private: // Handover related attributes bool m_admitHandoverRequest; bool m_admitRrcConnectionRequest; - uint8_t m_servingCellHandoverThreshold; - uint8_t m_neighbourCellHandoverOffset; // UE measurements related attributes uint8_t m_rsrpFilterCoefficient; diff --git a/src/lte/test/test-lte-x2-handover-measures.cc b/src/lte/test/test-lte-x2-handover-measures.cc index 30cdd4957..2abf86d19 100644 --- a/src/lte/test/test-lte-x2-handover-measures.cc +++ b/src/lte/test/test-lte-x2-handover-measures.cc @@ -173,8 +173,6 @@ LteX2HandoverMeasuresTestCase::DoRun () Config::SetDefault ("ns3::UdpClient::Interval", TimeValue (m_udpClientInterval)); Config::SetDefault ("ns3::UdpClient::MaxPackets", UintegerValue (1000000)); Config::SetDefault ("ns3::UdpClient::PacketSize", UintegerValue (m_udpClientPktSize)); - Config::SetDefault ("ns3::LteEnbRrc::ServingCellHandoverThreshold", UintegerValue (30)); - Config::SetDefault ("ns3::LteEnbRrc::NeighbourCellHandoverOffset", UintegerValue (1)); Config::SetDefault ("ns3::LteEnbRrc::HandoverJoiningTimeoutDuration", TimeValue (MilliSeconds (200))); Config::SetDefault ("ns3::LteEnbPhy::TxPower", DoubleValue (20)); @@ -183,8 +181,13 @@ LteX2HandoverMeasuresTestCase::DoRun () m_lteHelper = CreateObject (); m_lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel")); - m_lteHelper->SetSchedulerType (m_schedulerType); m_lteHelper->SetAttribute ("UseIdealRrc", BooleanValue (m_useIdealRrc)); + m_lteHelper->SetSchedulerType (m_schedulerType); + m_lteHelper->SetHandoverAlgorithmType ("ns3::A2RsrqHandoverAlgorithm"); + m_lteHelper->SetHandoverAlgorithmAttribute ("ServingCellThreshold", + UintegerValue (30)); + m_lteHelper->SetHandoverAlgorithmAttribute ("NeighbourCellOffset", + UintegerValue (1)); double distance = 1000.0; // m @@ -225,38 +228,6 @@ LteX2HandoverMeasuresTestCase::DoRun () ueNodes.Get (i)->GetObject ()->SetVelocity (Vector (speed, 0, 0)); } - // Setup pre-GSOC UE measurement configuration to the eNodeBs - - // Event A2 - LteRrcSap::ReportConfigEutra reportConfigA2; - reportConfigA2.triggerType = LteRrcSap::ReportConfigEutra::EVENT; - reportConfigA2.eventId = LteRrcSap::ReportConfigEutra::EVENT_A2; - reportConfigA2.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ; - reportConfigA2.threshold1.range = 34; - reportConfigA2.hysteresis = 0; - reportConfigA2.timeToTrigger = 0; - reportConfigA2.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ; - reportConfigA2.reportQuantity = LteRrcSap::ReportConfigEutra::SAME_AS_TRIGGER_QUANTITY; - reportConfigA2.maxReportCells = LteRrcSap::MaxReportCells; - reportConfigA2.reportInterval = LteRrcSap::ReportConfigEutra::MS240; - reportConfigA2.reportAmount = 255; - - // Event A4 - LteRrcSap::ReportConfigEutra reportConfigA4; - reportConfigA4.triggerType = LteRrcSap::ReportConfigEutra::EVENT; - reportConfigA4.eventId = LteRrcSap::ReportConfigEutra::EVENT_A4; - reportConfigA4.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ; - reportConfigA4.threshold1.range = 0; - reportConfigA4.hysteresis = 0; - reportConfigA4.timeToTrigger = 0; - reportConfigA4.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ; - reportConfigA4.reportQuantity = LteRrcSap::ReportConfigEutra::SAME_AS_TRIGGER_QUANTITY; - reportConfigA4.maxReportCells = LteRrcSap::MaxReportCells; - reportConfigA4.reportInterval = LteRrcSap::ReportConfigEutra::MS480; - reportConfigA4.reportAmount = 255; - - uint8_t measId; - NetDeviceContainer enbDevices; enbDevices = m_lteHelper->InstallEnbDevice (enbNodes); stream += m_lteHelper->AssignStreams (enbDevices, stream); @@ -266,11 +237,6 @@ LteX2HandoverMeasuresTestCase::DoRun () { Ptr enbRrc = (*it)->GetObject ()->GetRrc (); enbRrc->SetAttribute ("AdmitHandoverRequest", BooleanValue (m_admitHo)); - - measId = enbRrc->AddUeMeasReportConfig (reportConfigA2); - NS_ASSERT (measId == 1); - measId = enbRrc->AddUeMeasReportConfig (reportConfigA4); - NS_ASSERT (measId == 2); } NetDeviceContainer ueDevices; diff --git a/src/lte/wscript b/src/lte/wscript index a52ed4526..20adcb370 100644 --- a/src/lte/wscript +++ b/src/lte/wscript @@ -98,6 +98,9 @@ def build(bld): 'model/epc-mme.cc', 'model/lte-asn1-header.cc', 'model/lte-rrc-header.cc', + 'model/handover-management-sap.cc', + 'model/handover-algorithm.cc', + 'model/a2-rsrq-handover-algorithm.cc', ] module_test = bld.create_ns3_module_test_library('lte') @@ -243,6 +246,9 @@ def build(bld): 'model/epc-mme.h', 'model/lte-asn1-header.h', 'model/lte-rrc-header.h', + 'model/handover-management-sap.h', + 'model/handover-algorithm.h', + 'model/a2-rsrq-handover-algorithm.h', ] if (bld.env['ENABLE_EXAMPLES']):