/* * Copyright (c) 2017 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "lte-tap-helper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lte-tap-ue-net-device.h" #define ALPHA 0.999 /** * \brief this file has been modified from that of lte-helper.cpp in ns3 lte module to support emulation of lte channel */ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("LteTapHelper"); NS_OBJECT_ENSURE_REGISTERED (LteTapHelper); LteTapHelper::LteTapHelper (void) : m_fadingStreamsAssigned (false), m_imsiCounter (0), m_cellIdCounter (0) { NS_LOG_FUNCTION (this); m_enbNetDeviceFactory.SetTypeId (LteEnbNetDevice::GetTypeId ()); m_enbAntennaModelFactory.SetTypeId (IsotropicAntennaModel::GetTypeId ()); m_ueNetDeviceFactory.SetTypeId (LteTapUeNetDevice::GetTypeId ()); m_ueAntennaModelFactory.SetTypeId (IsotropicAntennaModel::GetTypeId ()); m_channelFactory.SetTypeId (MultiModelSpectrumChannel::GetTypeId ()); } void LteTapHelper::DoInitialize (void) { NS_LOG_FUNCTION (this); m_downlinkChannel = m_channelFactory.Create (); m_uplinkChannel = m_channelFactory.Create (); m_downlinkPathlossModel = m_dlPathlossModelFactory.Create (); Ptr dlSplm = m_downlinkPathlossModel->GetObject (); if (dlSplm != 0) { NS_LOG_LOGIC (this << " using a SpectrumPropagationLossModel in DL"); m_downlinkChannel->AddSpectrumPropagationLossModel (dlSplm); } else { NS_LOG_LOGIC (this << " using a PropagationLossModel in DL"); Ptr dlPlm = m_downlinkPathlossModel->GetObject (); NS_ASSERT_MSG (dlPlm != 0, " " << m_downlinkPathlossModel << " is neither PropagationLossModel nor SpectrumPropagationLossModel"); m_downlinkChannel->AddPropagationLossModel (dlPlm); } m_uplinkPathlossModel = m_ulPathlossModelFactory.Create (); Ptr ulSplm = m_uplinkPathlossModel->GetObject (); if (ulSplm != 0) { NS_LOG_LOGIC (this << " using a SpectrumPropagationLossModel in UL"); m_uplinkChannel->AddSpectrumPropagationLossModel (ulSplm); } else { NS_LOG_LOGIC (this << " using a PropagationLossModel in UL"); Ptr ulPlm = m_uplinkPathlossModel->GetObject (); NS_ASSERT_MSG (ulPlm != 0, " " << m_uplinkPathlossModel << " is neither PropagationLossModel nor SpectrumPropagationLossModel"); m_uplinkChannel->AddPropagationLossModel (ulPlm); } if (!m_fadingModelType.empty ()) { m_fadingModule = m_fadingModelFactory.Create (); m_fadingModule->Initialize (); m_downlinkChannel->AddSpectrumPropagationLossModel (m_fadingModule); m_uplinkChannel->AddSpectrumPropagationLossModel (m_fadingModule); } m_phyStats = CreateObject (); m_phyTxStats = CreateObject (); m_phyRxStats = CreateObject (); m_macStats = CreateObject (); Object::DoInitialize (); } LteTapHelper::~LteTapHelper (void) { NS_LOG_FUNCTION (this); } TypeId LteTapHelper::GetTypeId (void) { static TypeId tid = TypeId ("ns3::LteTapHelper") .SetParent () .AddConstructor () .AddAttribute ("Scheduler", "The type of scheduler to be used for eNBs. " "The allowed values for this attributes are the type names " "of any class inheriting from ns3::FfMacScheduler.", StringValue ("ns3::PfFfMacScheduler"), MakeStringAccessor (&LteTapHelper::SetSchedulerType, &LteTapHelper::GetSchedulerType), MakeStringChecker ()) .AddAttribute ("FfrAlgorithm", "The type of FFR algorithm to be used for eNBs. " "The allowed values for this attributes are the type names " "of any class inheriting from ns3::LteFfrAlgorithm.", StringValue ("ns3::LteFrNoOpAlgorithm"), MakeStringAccessor (&LteTapHelper::SetFfrAlgorithmType, &LteTapHelper::GetFfrAlgorithmType), 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::LteHandoverAlgorithm.", StringValue ("ns3::NoOpHandoverAlgorithm"), MakeStringAccessor (&LteTapHelper::SetHandoverAlgorithmType, &LteTapHelper::GetHandoverAlgorithmType), MakeStringChecker ()) .AddAttribute ("PathlossModel", "The type of pathloss model to be used. " "The allowed values for this attributes are the type names " "of any class inheriting from ns3::PropagationLossModel.", StringValue ("ns3::FriisPropagationLossModel"), MakeStringAccessor (&LteTapHelper::SetPathlossModelType), MakeStringChecker ()) .AddAttribute ("FadingModel", "The type of fading model to be used." "The allowed values for this attributes are the type names " "of any class inheriting from ns3::SpectrumPropagationLossModel." "If the type is set to an empty string, no fading model is used.", StringValue (""), MakeStringAccessor (&LteTapHelper::SetFadingModel), MakeStringChecker ()) .AddAttribute ("UseIdealRrc", "If true, LteRrcProtocolIdeal will be used for RRC signaling. " "If false, LteRrcProtocolReal will be used.", BooleanValue (true), MakeBooleanAccessor (&LteTapHelper::m_useIdealRrc), MakeBooleanChecker ()) .AddAttribute ("AnrEnabled", "Activate or deactivate Automatic Neighbour Relation function", BooleanValue (true), MakeBooleanAccessor (&LteTapHelper::m_isAnrEnabled), MakeBooleanChecker ()) .AddAttribute ("UsePdschForCqiGeneration", "If true, DL-CQI will be calculated from PDCCH as signal and PDSCH as interference " "If false, DL-CQI will be calculated from PDCCH as signal and PDCCH as interference ", BooleanValue (true), MakeBooleanAccessor (&LteTapHelper::m_usePdschForCqiGeneration), MakeBooleanChecker ()) ; return tid; } void LteTapHelper::DoDispose () { NS_LOG_FUNCTION (this); m_downlinkChannel = 0; m_uplinkChannel = 0; Object::DoDispose (); } void LteTapHelper::SetEpcHelper (Ptr h) { NS_LOG_FUNCTION (this << h); m_epcHelper = h; } void LteTapHelper::SetSchedulerType (std::string type) { NS_LOG_FUNCTION (this << type); m_schedulerFactory = ObjectFactory (); m_schedulerFactory.SetTypeId (type); } std::string LteTapHelper::GetSchedulerType () const { return m_schedulerFactory.GetTypeId ().GetName (); } void LteTapHelper::SetSchedulerAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this << n); m_schedulerFactory.Set (n, v); } std::string LteTapHelper::GetFfrAlgorithmType () const { return m_ffrAlgorithmFactory.GetTypeId ().GetName (); } void LteTapHelper::SetFfrAlgorithmType (std::string type) { NS_LOG_FUNCTION (this << type); m_ffrAlgorithmFactory = ObjectFactory (); m_ffrAlgorithmFactory.SetTypeId (type); } void LteTapHelper::SetFfrAlgorithmAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this << n); m_ffrAlgorithmFactory.Set (n, v); } std::string LteTapHelper::GetHandoverAlgorithmType () const { return m_handoverAlgorithmFactory.GetTypeId ().GetName (); } void LteTapHelper::SetHandoverAlgorithmType (std::string type) { NS_LOG_FUNCTION (this << type); m_handoverAlgorithmFactory = ObjectFactory (); m_handoverAlgorithmFactory.SetTypeId (type); } void LteTapHelper::SetHandoverAlgorithmAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this << n); m_handoverAlgorithmFactory.Set (n, v); } void LteTapHelper::SetPathlossModelType (std::string type) { NS_LOG_FUNCTION (this << type); m_dlPathlossModelFactory = ObjectFactory (); m_dlPathlossModelFactory.SetTypeId (type); m_ulPathlossModelFactory = ObjectFactory (); m_ulPathlossModelFactory.SetTypeId (type); } void LteTapHelper::SetPathlossModelAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this << n); m_dlPathlossModelFactory.Set (n, v); m_ulPathlossModelFactory.Set (n, v); } void LteTapHelper::SetEnbDeviceAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this); m_enbNetDeviceFactory.Set (n, v); } void LteTapHelper::SetEnbAntennaModelType (std::string type) { NS_LOG_FUNCTION (this); m_enbAntennaModelFactory.SetTypeId (type); } void LteTapHelper::SetEnbAntennaModelAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this); m_enbAntennaModelFactory.Set (n, v); } void LteTapHelper::SetUeDeviceAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this); m_ueNetDeviceFactory.Set (n, v); } void LteTapHelper::SetUeAntennaModelType (std::string type) { NS_LOG_FUNCTION (this); m_ueAntennaModelFactory.SetTypeId (type); } void LteTapHelper::SetUeAntennaModelAttribute (std::string n, const AttributeValue &v) { NS_LOG_FUNCTION (this); m_ueAntennaModelFactory.Set (n, v); } void LteTapHelper::SetFadingModel (std::string type) { NS_LOG_FUNCTION (this << type); m_fadingModelType = type; if (!type.empty ()) { m_fadingModelFactory = ObjectFactory (); m_fadingModelFactory.SetTypeId (type); } } void LteTapHelper::SetFadingModelAttribute (std::string n, const AttributeValue &v) { m_fadingModelFactory.Set (n, v); } void LteTapHelper::SetSpectrumChannelType (std::string type) { NS_LOG_FUNCTION (this << type); m_channelFactory.SetTypeId (type); } void LteTapHelper::SetSpectrumChannelAttribute (std::string n, const AttributeValue &v) { m_channelFactory.Set (n, v); } NetDeviceContainer LteTapHelper::InstallEnbDevice (NodeContainer c) { NS_LOG_FUNCTION (this); Initialize (); // will run DoInitialize () if necessary NetDeviceContainer devices; for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) { Ptr node = *i; Ptr device = InstallSingleEnbDevice (node); devices.Add (device); } return devices; } NetDeviceContainer LteTapHelper::InstallUeDevice (NodeContainer c) { NS_LOG_FUNCTION (this); NetDeviceContainer devices; for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) { Ptr node = *i; Ptr device = InstallSingleUeDevice (node); devices.Add (device); } return devices; } Ptr LteTapHelper::InstallSingleEnbDevice (Ptr n) { NS_ABORT_MSG_IF (m_cellIdCounter == 65535, "max num eNBs exceeded"); uint16_t cellId = ++m_cellIdCounter; Ptr dlPhy = CreateObject (); Ptr ulPhy = CreateObject (); Ptr phy = CreateObject (dlPhy, ulPhy); Ptr harq = Create (); dlPhy->SetHarqPhyModule (harq); ulPhy->SetHarqPhyModule (harq); phy->SetHarqPhyModule (harq); Ptr pCtrl = Create (); pCtrl->AddCallback (MakeCallback (&LteEnbPhy::GenerateCtrlCqiReport, phy)); ulPhy->AddCtrlSinrChunkProcessor (pCtrl); // for evaluating SRS UL-CQI Ptr pData = Create (); pData->AddCallback (MakeCallback (&LteEnbPhy::GenerateDataCqiReport, phy)); pData->AddCallback (MakeCallback (&LteSpectrumPhy::UpdateSinrPerceived, ulPhy)); ulPhy->AddDataSinrChunkProcessor (pData); // for evaluating PUSCH UL-CQI Ptr pInterf = Create (); pInterf->AddCallback (MakeCallback (&LteEnbPhy::ReportInterference, phy)); ulPhy->AddInterferenceDataChunkProcessor (pInterf); // for interference power tracing dlPhy->SetChannel (m_downlinkChannel); ulPhy->SetChannel (m_uplinkChannel); Ptr mm = n->GetObject (); NS_ASSERT_MSG (mm, "MobilityModel needs to be set on node before calling LteTapHelper::InstallUeDevice ()"); dlPhy->SetMobility (mm); ulPhy->SetMobility (mm); Ptr antenna = (m_enbAntennaModelFactory.Create ())->GetObject (); NS_ASSERT_MSG (antenna, "error in creating the AntennaModel object"); dlPhy->SetAntenna (antenna); ulPhy->SetAntenna (antenna); Ptr mac = CreateObject (); Ptr sched = m_schedulerFactory.Create (); Ptr ffrAlgorithm = m_ffrAlgorithmFactory.Create (); Ptr handoverAlgorithm = m_handoverAlgorithmFactory.Create (); Ptr rrc = CreateObject (); if (m_useIdealRrc) { Ptr rrcProtocol = CreateObject (); rrcProtocol->SetLteEnbRrcSapProvider (rrc->GetLteEnbRrcSapProvider ()); rrc->SetLteEnbRrcSapUser (rrcProtocol->GetLteEnbRrcSapUser ()); rrc->AggregateObject (rrcProtocol); rrcProtocol->SetCellId (cellId); } else { Ptr rrcProtocol = CreateObject (); rrcProtocol->SetLteEnbRrcSapProvider (rrc->GetLteEnbRrcSapProvider ()); rrc->SetLteEnbRrcSapUser (rrcProtocol->GetLteEnbRrcSapUser ()); rrc->AggregateObject (rrcProtocol); rrcProtocol->SetCellId (cellId); } if (m_epcHelper != 0) { EnumValue epsBearerToRlcMapping; rrc->GetAttribute ("EpsBearerToRlcMapping", epsBearerToRlcMapping); // it does not make sense to use RLC/SM when also using the EPC if (epsBearerToRlcMapping.Get () == LteEnbRrc::RLC_SM_ALWAYS) { rrc->SetAttribute ("EpsBearerToRlcMapping", EnumValue (LteEnbRrc::RLC_UM_ALWAYS)); } } rrc->SetLteEnbCmacSapProvider (mac->GetLteEnbCmacSapProvider ()); mac->SetLteEnbCmacSapUser (rrc->GetLteEnbCmacSapUser ()); rrc->SetLteMacSapProvider (mac->GetLteMacSapProvider ()); rrc->SetLteHandoverManagementSapProvider (handoverAlgorithm->GetLteHandoverManagementSapProvider ()); handoverAlgorithm->SetLteHandoverManagementSapUser (rrc->GetLteHandoverManagementSapUser ()); mac->SetFfMacSchedSapProvider (sched->GetFfMacSchedSapProvider ()); mac->SetFfMacCschedSapProvider (sched->GetFfMacCschedSapProvider ()); sched->SetFfMacSchedSapUser (mac->GetFfMacSchedSapUser ()); sched->SetFfMacCschedSapUser (mac->GetFfMacCschedSapUser ()); phy->SetLteEnbPhySapUser (mac->GetLteEnbPhySapUser ()); mac->SetLteEnbPhySapProvider (phy->GetLteEnbPhySapProvider ()); phy->SetLteEnbCphySapUser (rrc->GetLteEnbCphySapUser ()); rrc->SetLteEnbCphySapProvider (phy->GetLteEnbCphySapProvider ()); //FFR SAP sched->SetLteFfrSapProvider (ffrAlgorithm->GetLteFfrSapProvider ()); ffrAlgorithm->SetLteFfrSapUser (sched->GetLteFfrSapUser ()); rrc->SetLteFfrRrcSapProvider (ffrAlgorithm->GetLteFfrRrcSapProvider ()); ffrAlgorithm->SetLteFfrRrcSapUser (rrc->GetLteFfrRrcSapUser ()); //FFR SAP END Ptr dev = m_enbNetDeviceFactory.Create (); dev->SetNode (n); dev->SetAttribute ("CellId", UintegerValue (cellId)); dev->SetAttribute ("LteEnbPhy", PointerValue (phy)); dev->SetAttribute ("LteEnbMac", PointerValue (mac)); dev->SetAttribute ("FfMacScheduler", PointerValue (sched)); dev->SetAttribute ("LteEnbRrc", PointerValue (rrc)); dev->SetAttribute ("LteHandoverAlgorithm", PointerValue (handoverAlgorithm)); dev->SetAttribute ("LteFfrAlgorithm", PointerValue (ffrAlgorithm)); if (m_isAnrEnabled) { Ptr anr = CreateObject (cellId); rrc->SetLteAnrSapProvider (anr->GetLteAnrSapProvider ()); anr->SetLteAnrSapUser (rrc->GetLteAnrSapUser ()); dev->SetAttribute ("LteAnr", PointerValue (anr)); } phy->SetDevice (dev); dlPhy->SetDevice (dev); ulPhy->SetDevice (dev); n->AddDevice (dev); ulPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteEnbPhy::PhyPduReceived, phy)); ulPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteEnbPhy::ReceiveLteControlMessageList, phy)); ulPhy->SetLtePhyUlHarqFeedbackCallback (MakeCallback (&LteEnbPhy::ReceiveLteUlHarqFeedback, phy)); rrc->SetForwardUpCallback (MakeCallback (&LteEnbNetDevice::Receive, dev)); NS_LOG_LOGIC ("set the propagation model frequencies"); double dlFreq = LteSpectrumValueHelper::GetCarrierFrequency (dev->GetDlEarfcn ()); NS_LOG_LOGIC ("DL freq: " << dlFreq); bool dlFreqOk = m_downlinkPathlossModel->SetAttributeFailSafe ("Frequency", DoubleValue (dlFreq)); if (!dlFreqOk) { NS_LOG_WARN ("DL propagation model does not have a Frequency attribute"); } double ulFreq = LteSpectrumValueHelper::GetCarrierFrequency (dev->GetUlEarfcn ()); NS_LOG_LOGIC ("UL freq: " << ulFreq); bool ulFreqOk = m_uplinkPathlossModel->SetAttributeFailSafe ("Frequency", DoubleValue (ulFreq)); if (!ulFreqOk) { NS_LOG_WARN ("UL propagation model does not have a Frequency attribute"); } dev->Initialize (); m_uplinkChannel->AddRx (ulPhy); if (m_epcHelper != 0) { NS_LOG_INFO ("adding this eNB to the EPC"); m_epcHelper->AddEnb (n, dev, dev->GetCellId ()); Ptr enbApp = n->GetApplication (0)->GetObject (); NS_ASSERT_MSG (enbApp != 0, "cannot retrieve EpcEnbApplication"); // S1 SAPs rrc->SetS1SapProvider (enbApp->GetS1SapProvider ()); enbApp->SetS1SapUser (rrc->GetS1SapUser ()); // X2 SAPs Ptr x2 = n->GetObject (); x2->SetEpcX2SapUser (rrc->GetEpcX2SapUser ()); rrc->SetEpcX2SapProvider (x2->GetEpcX2SapProvider ()); } return dev; } Ptr LteTapHelper::InstallSingleUeDevice (Ptr n) { NS_LOG_FUNCTION (this); Ptr dlPhy = CreateObject (); Ptr ulPhy = CreateObject (); Ptr phy = CreateObject (dlPhy, ulPhy); Ptr harq = Create (); dlPhy->SetHarqPhyModule (harq); ulPhy->SetHarqPhyModule (harq); phy->SetHarqPhyModule (harq); Ptr pRs = Create (); pRs->AddCallback (MakeCallback (&LteUePhy::ReportRsReceivedPower, phy)); dlPhy->AddRsPowerChunkProcessor (pRs); Ptr pInterf = Create (); pInterf->AddCallback (MakeCallback (&LteUePhy::ReportInterference, phy)); dlPhy->AddInterferenceCtrlChunkProcessor (pInterf); // for RSRQ evaluation of UE Measurements Ptr pCtrl = Create (); pCtrl->AddCallback (MakeCallback (&LteSpectrumPhy::UpdateSinrPerceived, dlPhy)); dlPhy->AddCtrlSinrChunkProcessor (pCtrl); Ptr pData = Create (); pData->AddCallback (MakeCallback (&LteSpectrumPhy::UpdateSinrPerceived, dlPhy)); dlPhy->AddDataSinrChunkProcessor (pData); if (m_usePdschForCqiGeneration) { // CQI calculation based on PDCCH for signal and PDSCH for interference pCtrl->AddCallback (MakeCallback (&LteUePhy::GenerateMixedCqiReport, phy)); Ptr pDataInterf = Create (); pDataInterf->AddCallback (MakeCallback (&LteUePhy::ReportDataInterference, phy)); dlPhy->AddInterferenceDataChunkProcessor (pDataInterf); } else { // CQI calculation based on PDCCH for both signal and interference pCtrl->AddCallback (MakeCallback (&LteUePhy::GenerateCtrlCqiReport, phy)); } dlPhy->SetChannel (m_downlinkChannel); ulPhy->SetChannel (m_uplinkChannel); Ptr mm = n->GetObject (); NS_ASSERT_MSG (mm, "MobilityModel needs to be set on node before calling LteTapHelper::InstallUeDevice ()"); dlPhy->SetMobility (mm); ulPhy->SetMobility (mm); Ptr antenna = (m_ueAntennaModelFactory.Create ())->GetObject (); NS_ASSERT_MSG (antenna, "error in creating the AntennaModel object"); dlPhy->SetAntenna (antenna); ulPhy->SetAntenna (antenna); Ptr mac = CreateObject (); Ptr rrc = CreateObject (); if (m_useIdealRrc) { Ptr rrcProtocol = CreateObject (); rrcProtocol->SetUeRrc (rrc); rrc->AggregateObject (rrcProtocol); rrcProtocol->SetLteUeRrcSapProvider (rrc->GetLteUeRrcSapProvider ()); rrc->SetLteUeRrcSapUser (rrcProtocol->GetLteUeRrcSapUser ()); } else { Ptr rrcProtocol = CreateObject (); rrcProtocol->SetUeRrc (rrc); rrc->AggregateObject (rrcProtocol); rrcProtocol->SetLteUeRrcSapProvider (rrc->GetLteUeRrcSapProvider ()); rrc->SetLteUeRrcSapUser (rrcProtocol->GetLteUeRrcSapUser ()); } if (m_epcHelper != 0) { rrc->SetUseRlcSm (false); } Ptr nas = CreateObject (); nas->SetAsSapProvider (rrc->GetAsSapProvider ()); rrc->SetAsSapUser (nas->GetAsSapUser ()); rrc->SetLteUeCmacSapProvider (mac->GetLteUeCmacSapProvider ()); mac->SetLteUeCmacSapUser (rrc->GetLteUeCmacSapUser ()); rrc->SetLteMacSapProvider (mac->GetLteMacSapProvider ()); phy->SetLteUePhySapUser (mac->GetLteUePhySapUser ()); mac->SetLteUePhySapProvider (phy->GetLteUePhySapProvider ()); phy->SetLteUeCphySapUser (rrc->GetLteUeCphySapUser ()); rrc->SetLteUeCphySapProvider (phy->GetLteUeCphySapProvider ()); NS_ABORT_MSG_IF (m_imsiCounter >= 0xFFFFFFFF, "max num UEs exceeded"); uint64_t imsi = ++m_imsiCounter; Ptr dev = m_ueNetDeviceFactory.Create (); dev->SetNode (n); dev->SetAttribute ("Imsi", UintegerValue (imsi)); dev->SetAttribute ("LteUePhy", PointerValue (phy)); dev->SetAttribute ("LteUeMac", PointerValue (mac)); dev->SetAttribute ("LteUeRrc", PointerValue (rrc)); dev->SetAttribute ("EpcUeNas", PointerValue (nas)); phy->SetDevice (dev); dlPhy->SetDevice (dev); ulPhy->SetDevice (dev); nas->SetDevice (dev); n->AddDevice (dev); dlPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteUePhy::PhyPduReceived, phy)); dlPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteUePhy::ReceiveLteControlMessageList, phy)); dlPhy->SetLtePhyRxPssCallback (MakeCallback (&LteUePhy::ReceivePss, phy)); dlPhy->SetLtePhyDlHarqFeedbackCallback (MakeCallback (&LteUePhy::ReceiveLteDlHarqFeedback, phy)); nas->SetForwardUpCallback (MakeCallback (&LteTapUeNetDevice::Receive, dev)); if (m_epcHelper != 0) { m_epcHelper->AddUe (dev, dev->GetImsi ()); } dev->Initialize (); return dev; } void LteTapHelper::Attach (NetDeviceContainer ueDevices) { NS_LOG_FUNCTION (this); for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) { Attach (*i); } } void LteTapHelper::Attach (Ptr ueDevice) { NS_LOG_FUNCTION (this); if (m_epcHelper == 0) { NS_FATAL_ERROR ("This function is not valid without properly configured EPC"); } Ptr ueLteDevice = ueDevice->GetObject (); if (ueLteDevice == 0) { NS_FATAL_ERROR ("The passed NetDevice must be an LteUeNetDevice"); } // initiate cell selection Ptr ueNas = ueLteDevice->GetNas (); NS_ASSERT (ueNas != 0); uint16_t dlEarfcn = ueLteDevice->GetDlEarfcn (); ueNas->StartCellSelection (dlEarfcn); // instruct UE to immediately enter CONNECTED mode after camping ueNas->Connect (); // activate default EPS bearer m_epcHelper->ActivateEpsBearer (ueDevice, ueLteDevice->GetImsi (), EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT)); } void LteTapHelper::Attach (NetDeviceContainer ueDevices, Ptr enbDevice) { NS_LOG_FUNCTION (this); for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) { Attach (*i, enbDevice); } } void LteTapHelper::Attach (Ptr ueDevice, Ptr enbDevice) { NS_LOG_FUNCTION (this); //enbRrc->SetCellId (enbDevice->GetObject ()->GetCellId ()); Ptr ueLteDevice = ueDevice->GetObject (); Ptr enbLteDevice = enbDevice->GetObject (); Ptr ueNas = ueLteDevice->GetNas (); ueNas->Connect (enbLteDevice->GetCellId (), enbLteDevice->GetDlEarfcn ()); if (m_epcHelper != 0) { // activate default EPS bearer m_epcHelper->ActivateEpsBearer (ueDevice, ueLteDevice->GetImsi (), EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT)); } // tricks needed for the simplified LTE-only simulations if (m_epcHelper == 0) { ueDevice->GetObject ()->SetTargetEnb (enbDevice->GetObject ()); } } void LteTapHelper::AttachToClosestEnb (NetDeviceContainer ueDevices, NetDeviceContainer enbDevices) { NS_LOG_FUNCTION (this); for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) { AttachToClosestEnb (*i, enbDevices); } } void LteTapHelper::AttachToClosestEnb (Ptr ueDevice, NetDeviceContainer enbDevices) { NS_LOG_FUNCTION (this); NS_ASSERT_MSG (enbDevices.GetN () > 0, "empty enb device container"); Vector uepos = ueDevice->GetNode ()->GetObject ()->GetPosition (); double minDistance = std::numeric_limits::infinity (); Ptr closestEnbDevice; for (NetDeviceContainer::Iterator i = enbDevices.Begin (); i != enbDevices.End (); ++i) { Vector enbpos = (*i)->GetNode ()->GetObject ()->GetPosition (); double distance = CalculateDistance (uepos, enbpos); if (distance < minDistance) { minDistance = distance; closestEnbDevice = *i; } } NS_ASSERT (closestEnbDevice != 0); Attach (ueDevice, closestEnbDevice); } uint8_t LteTapHelper::ActivateDedicatedEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer, Ptr tft) { NS_LOG_FUNCTION (this); for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) { uint8_t bearerId = ActivateDedicatedEpsBearer (*i, bearer, tft); return bearerId; } return 0; } uint8_t LteTapHelper::ActivateDedicatedEpsBearer (Ptr ueDevice, EpsBearer bearer, Ptr tft) { NS_LOG_FUNCTION (this); NS_ASSERT_MSG (m_epcHelper != 0, "dedicated EPS bearers cannot be set up when the EPC is not used"); uint64_t imsi = ueDevice->GetObject ()->GetImsi (); uint8_t bearerId = m_epcHelper->ActivateEpsBearer (ueDevice, imsi, tft, bearer); return bearerId; } /** * \ingroup lte * * TapDrbActivatior allows user to activate bearers for UEs * when EPC is not used. Activation function is hooked to * the Enb RRC Connection Estabilished trace source. When * UE change its RRC state to CONNECTED_NORMALLY, activation * function is called and bearer is activated. */ class TapDrbActivator : public SimpleRefCount { public: /** * TapDrbActivator Constructor * * \param ueDevice the UeNetDevice for which bearer will be activated * \param bearer the bearer configuration */ TapDrbActivator (Ptr ueDevice, EpsBearer bearer); /** * Function hooked to the Enb RRC Connection Established trace source * Fired upon successful RRC connection establishment. * * \param a TapDrbActivator object * \param context * \param imsi * \param cellId * \param rnti */ static void ActivateCallback (Ptr a, std::string context, uint64_t imsi, uint16_t cellId, uint16_t rnti); /** * Procedure firstly checks if bearer was not activated, if IMSI * from trace source equals configured one and if UE is really * in RRC connected state. If all requirements are met, it performs * bearer activation. * * \param imsi * \param cellId * \param rnti */ void ActivateTapDrb (uint64_t imsi, uint16_t cellId, uint16_t rnti); private: /** * Bearer can be activated only once. This value stores state of * bearer. Initially is set to false and changed to true during * bearer activation. */ bool m_active; /** * UeNetDevice for which bearer will be activated */ Ptr m_ueDevice; /** * Configuration of bearer which will be activated */ EpsBearer m_bearer; /** * imsi the unique UE identifier */ uint64_t m_imsi; }; TapDrbActivator::TapDrbActivator (Ptr ueDevice, EpsBearer bearer) : m_active (false), m_ueDevice (ueDevice), m_bearer (bearer), m_imsi (m_ueDevice->GetObject ()->GetImsi ()) { } void TapDrbActivator::ActivateCallback (Ptr a, std::string context, uint64_t imsi, uint16_t cellId, uint16_t rnti) { NS_LOG_FUNCTION (a << context << imsi << cellId << rnti); a->ActivateTapDrb (imsi, cellId, rnti); } void TapDrbActivator::ActivateTapDrb (uint64_t imsi, uint16_t cellId, uint16_t rnti) { NS_LOG_FUNCTION (this << imsi << cellId << rnti << m_active); if ((!m_active) && (imsi == m_imsi)) { Ptr ueRrc = m_ueDevice->GetObject ()->GetRrc (); NS_ASSERT (ueRrc->GetState () == LteUeRrc::CONNECTED_NORMALLY); uint16_t rnti = ueRrc->GetRnti (); Ptr enbLteDevice = m_ueDevice->GetObject ()->GetTargetEnb (); Ptr enbRrc = enbLteDevice->GetObject ()->GetRrc (); NS_ASSERT (ueRrc->GetCellId () == enbLteDevice->GetCellId ()); Ptr ueManager = enbRrc->GetUeManager (rnti); NS_ASSERT (ueManager->GetState () == UeManager::CONNECTED_NORMALLY || ueManager->GetState () == UeManager::CONNECTION_RECONFIGURATION); EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params; params.rnti = rnti; params.bearer = m_bearer; params.bearerId = 0; params.gtpTeid = 0; // don't care enbRrc->GetS1SapUser ()->DataRadioBearerSetupRequest (params); m_active = true; } } void LteTapHelper::ActivateDataRadioBearer (Ptr ueDevice, EpsBearer bearer) { NS_LOG_FUNCTION (this << ueDevice); NS_ASSERT_MSG (m_epcHelper == 0, "this method must not be used when the EPC is being used"); // Normally it is the EPC that takes care of activating DRBs // when the UE gets connected. When the EPC is not used, we achieve // the same behavior by hooking a dedicated DRB activation function // to the Enb RRC Connection Established trace source Ptr enbLteDevice = ueDevice->GetObject ()->GetTargetEnb (); std::ostringstream path; path << "/NodeList/" << enbLteDevice->GetNode ()->GetId () << "/DeviceList/" << enbLteDevice->GetIfIndex () << "/LteEnbRrc/ConnectionEstablished"; Ptr arg = Create (ueDevice, bearer); Config::Connect (path.str (), MakeBoundCallback (&TapDrbActivator::ActivateCallback, arg)); } void LteTapHelper::AddX2Interface (NodeContainer enbNodes) { NS_LOG_FUNCTION (this); NS_ASSERT_MSG (m_epcHelper != 0, "X2 interfaces cannot be set up when the EPC is not used"); for (NodeContainer::Iterator i = enbNodes.Begin (); i != enbNodes.End (); ++i) { for (NodeContainer::Iterator j = i + 1; j != enbNodes.End (); ++j) { AddX2Interface (*i, *j); } } } void LteTapHelper::AddX2Interface (Ptr enbNode1, Ptr enbNode2) { NS_LOG_FUNCTION (this); NS_LOG_INFO ("setting up the X2 interface"); m_epcHelper->AddX2Interface (enbNode1, enbNode2); } void LteTapHelper::HandoverRequest (Time hoTime, Ptr ueDev, Ptr sourceEnbDev, Ptr targetEnbDev) { NS_LOG_FUNCTION (this << ueDev << sourceEnbDev << targetEnbDev); NS_ASSERT_MSG (m_epcHelper, "Handover requires the use of the EPC - did you forget to call LteTapHelper::SetEpcHelper () ?"); Simulator::Schedule (hoTime, &LteTapHelper::DoHandoverRequest, this, ueDev, sourceEnbDev, targetEnbDev); } void LteTapHelper::DoHandoverRequest (Ptr ueDev, Ptr sourceEnbDev, Ptr targetEnbDev) { NS_LOG_FUNCTION (this << ueDev << sourceEnbDev << targetEnbDev); uint16_t targetCellId = targetEnbDev->GetObject ()->GetCellId (); Ptr sourceRrc = sourceEnbDev->GetObject ()->GetRrc (); uint16_t rnti = ueDev->GetObject ()->GetRrc ()->GetRnti (); sourceRrc->SendHandoverRequest (rnti, targetCellId); } void LteTapHelper::DeActivateDedicatedEpsBearer (Ptr ueDevice,Ptr enbDevice, uint8_t bearerId) { NS_LOG_FUNCTION (this << ueDevice << bearerId); NS_ASSERT_MSG (m_epcHelper != 0, "Dedicated EPS bearers cannot be de-activated when the EPC is not used"); NS_ASSERT_MSG (bearerId != 1, "Default bearer cannot be de-activated until and unless and UE is released"); DoDeActivateDedicatedEpsBearer (ueDevice, enbDevice, bearerId); } void LteTapHelper::DoDeActivateDedicatedEpsBearer (Ptr ueDevice, Ptr enbDevice, uint8_t bearerId) { NS_LOG_FUNCTION (this << ueDevice << bearerId); //Extract IMSI and rnti uint64_t imsi = ueDevice->GetObject ()->GetImsi (); uint16_t rnti = ueDevice->GetObject ()->GetRrc ()->GetRnti (); Ptr enbRrc = enbDevice->GetObject ()->GetRrc (); enbRrc->DoSendReleaseDataRadioBearer (imsi,rnti,bearerId); } void LteTapHelper::ActivateDataRadioBearer (NetDeviceContainer ueDevices, EpsBearer bearer) { NS_LOG_FUNCTION (this); for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) { ActivateDataRadioBearer (*i, bearer); } } void LteTapHelper::EnableLogComponents (void) { LogComponentEnable ("LteTapHelper", LOG_LEVEL_ALL); LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL); LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL); LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL); LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL); LogComponentEnable ("LteRlc", LOG_LEVEL_ALL); LogComponentEnable ("LteRlcUm", LOG_LEVEL_ALL); LogComponentEnable ("LteRlcAm", LOG_LEVEL_ALL); LogComponentEnable ("RrFfMacScheduler", LOG_LEVEL_ALL); LogComponentEnable ("PfFfMacScheduler", LOG_LEVEL_ALL); LogComponentEnable ("LtePhy", LOG_LEVEL_ALL); LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL); LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL); LogComponentEnable ("LteSpectrumValueHelper", LOG_LEVEL_ALL); LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL); LogComponentEnable ("LteInterference", LOG_LEVEL_ALL); LogComponentEnable ("LteChunkProcessor", LOG_LEVEL_ALL); std::string propModelStr = m_dlPathlossModelFactory.GetTypeId ().GetName ().erase (0,5).c_str (); LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL); LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL); LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL); LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL); LogComponentEnable ("LteStatsCalculator", LOG_LEVEL_ALL); LogComponentEnable ("MacStatsCalculator", LOG_LEVEL_ALL); LogComponentEnable ("PhyTxStatsCalculator", LOG_LEVEL_ALL); LogComponentEnable ("PhyRxStatsCalculator", LOG_LEVEL_ALL); LogComponentEnable ("PhyStatsCalculator", LOG_LEVEL_ALL); } void LteTapHelper::EnableTraces (void) { EnablePhyTraces (); EnableMacTraces (); EnableRlcTraces (); EnablePdcpTraces (); } void LteTapHelper::EnableRlcTraces (void) { NS_ASSERT_MSG (m_rlcStats == 0, "please make sure that LteTapHelper::EnableRlcTraces is called at most once"); m_rlcStats = CreateObject ("RLC"); m_radioBearerStatsConnector.EnableRlcStats (m_rlcStats); } int64_t LteTapHelper::AssignStreams (NetDeviceContainer c, int64_t stream) { int64_t currentStream = stream; if ((m_fadingModule != 0) && (m_fadingStreamsAssigned == false)) { Ptr tflm = m_fadingModule->GetObject (); if (tflm != 0) { currentStream += tflm->AssignStreams (currentStream); m_fadingStreamsAssigned = true; } } Ptr netDevice; for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i) { netDevice = (*i); Ptr lteEnb = DynamicCast (netDevice); if (lteEnb) { Ptr dlPhy = lteEnb->GetPhy ()->GetDownlinkSpectrumPhy (); Ptr ulPhy = lteEnb->GetPhy ()->GetUplinkSpectrumPhy (); currentStream += dlPhy->AssignStreams (currentStream); currentStream += ulPhy->AssignStreams (currentStream); } Ptr lteUe = DynamicCast (netDevice); if (lteUe) { Ptr dlPhy = lteUe->GetPhy ()->GetDownlinkSpectrumPhy (); Ptr ulPhy = lteUe->GetPhy ()->GetUplinkSpectrumPhy (); Ptr ueMac = lteUe->GetMac (); currentStream += dlPhy->AssignStreams (currentStream); currentStream += ulPhy->AssignStreams (currentStream); currentStream += ueMac->AssignStreams (currentStream); } } return (currentStream - stream); } void LteTapHelper::EnablePhyTraces (void) { EnableDlPhyTraces (); EnableUlPhyTraces (); EnableDlTxPhyTraces (); EnableUlTxPhyTraces (); EnableDlRxPhyTraces (); EnableUlRxPhyTraces (); } void LteTapHelper::EnableTxPhyTraces (void) { EnableDlTxPhyTraces (); EnableUlTxPhyTraces (); } void LteTapHelper::NewEnableTxPhyTraces (void) { NewEnableDlTxPhyTraces (); NewEnableUlTxPhyTraces (); } void LteTapHelper::EnableDlTxPhyTraces (void) { Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/DlPhyTransmission", MakeBoundCallback (&PhyTxStatsCalculator::DlPhyTransmissionCallback, m_phyTxStats)); } void LteTapHelper::EnableUlTxPhyTraces (void) { Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/UlPhyTransmission", MakeBoundCallback (&PhyTxStatsCalculator::UlPhyTransmissionCallback, m_phyTxStats)); } void LteTapHelper::NewEnableUlTxPhyTraces(void) { Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/UlPhyTransmission", MakeCallback (&LteTapHelper::WriteUlPhyTransmissionMcsCallback, this)); } void LteTapHelper::NewEnableDlTxPhyTraces(void) { Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/DlPhyTransmission", MakeCallback (&LteTapHelper::WriteDlPhyTransmissionMcsCallback, this)); } void LteTapHelper::WriteDlPhyTransmissionMcsCallback(std::string path, PhyTransmissionStatParameters params) { NS_LOG_FUNCTION (params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi); if(m_dlMcsStats.node_id==-1)//new element { m_dlMcsStats.node_id=Mcs_stats::Get_node(path); m_dlMcsStats.avgMcs=(double)(params.m_mcs); // m_dlMcsStats.avgThroughput=Mcs_stats::ConnvertMcsToRate (params.m_mcs); m_dlMcsStats.avgThroughput=(double)(params.m_size)/125*2; } else { NS_ASSERT( m_dlMcsStats.node_id==Mcs_stats::Get_node(path)); m_dlMcsStats.avgMcs=(double)(params.m_mcs)*(1-ALPHA)+m_dlMcsStats.avgMcs*ALPHA; //m_dlMcsStats.avgThroughput=Mcs_stats::ConnvertMcsToRate (params.m_mcs)*(1-ALPHA)+m_dlMcsStats.avgThroughput; m_dlMcsStats.avgThroughput=(double)(params.m_size)/125*2*(1-ALPHA)+m_dlMcsStats.avgThroughput*ALPHA; } } void LteTapHelper::WriteUlPhyTransmissionMcsCallback(std::string path, PhyTransmissionStatParameters params) { NS_LOG_FUNCTION ( params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi); int nodeId=Mcs_stats::Get_node(path); unsigned i; for(i=0;i LteTapHelper::GetRlcStats (void) { return m_rlcStats; } void LteTapHelper::EnablePdcpTraces (void) { NS_ASSERT_MSG (m_pdcpStats == 0, "please make sure that LteTapHelper::EnablePdcpTraces is called at most once"); m_pdcpStats = CreateObject ("PDCP"); m_radioBearerStatsConnector.EnablePdcpStats (m_pdcpStats); } Ptr LteTapHelper::GetPdcpStats (void) { return m_pdcpStats; } } // namespace ns3