A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lte-ue-rrc.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011, 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 * Copyright (c) 2018 Fraunhofer ESK : RLF extensions
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Author: Nicola Baldo <nbaldo@cttc.es>
8 * Budiarto Herman <budiarto.herman@magister.fi>
9 * Modified by:
10 * Danilo Abrignani <danilo.abrignani@unibo.it> (Carrier Aggregation - GSoC 2015)
11 * Biljana Bojovic <biljana.bojovic@cttc.es> (Carrier Aggregation)
12 * Vignesh Babu <ns3-dev@esk.fraunhofer.de> (RLF extensions)
13 */
14
15#include "lte-ue-rrc.h"
16
17#include "lte-common.h"
18#include "lte-pdcp.h"
20#include "lte-rlc-am.h"
21#include "lte-rlc-tm.h"
22#include "lte-rlc-um.h"
23#include "lte-rlc.h"
24
25#include "ns3/fatal-error.h"
26#include "ns3/log.h"
27#include "ns3/object-factory.h"
28#include "ns3/object-map.h"
29#include "ns3/simulator.h"
30
31#include <cmath>
32
33namespace ns3
34{
36
37NS_LOG_COMPONENT_DEFINE("LteUeRrc");
38
39/////////////////////////////
40// CMAC SAP forwarder
41/////////////////////////////
42
43/// UeMemberLteUeCmacSapUser class
45{
46 public:
47 /**
48 * Constructor
49 *
50 * @param rrc the RRC class
51 */
53
54 void SetTemporaryCellRnti(uint16_t rnti) override;
55 void NotifyRandomAccessSuccessful() override;
56 void NotifyRandomAccessFailed() override;
57
58 private:
59 LteUeRrc* m_rrc; ///< the RRC class
60};
61
66
67void
72
73void
78
79void
84
85/////////////////////////////
86// ue RRC methods
87/////////////////////////////
88
90
92 : m_cmacSapProvider(0),
93 m_rrcSapUser(nullptr),
94 m_macSapProvider(nullptr),
95 m_asSapUser(nullptr),
96 m_ccmRrcSapProvider(nullptr),
97 m_state(IDLE_START),
98 m_imsi(0),
99 m_rnti(0),
100 m_cellId(0),
101 m_useRlcSm(true),
102 m_connectionPending(false),
103 m_hasReceivedMib(false),
104 m_hasReceivedSib1(false),
105 m_hasReceivedSib2(false),
106 m_csgWhiteList(0),
107 m_noOfSyncIndications(0),
108 m_leaveConnectedMode(false),
109 m_previousCellId(0),
110 m_connEstFailCountLimit(0),
111 m_connEstFailCount(0),
112 m_numberOfComponentCarriers(MIN_NO_CC)
113{
114 NS_LOG_FUNCTION(this);
116 m_cmacSapUser.push_back(new UeMemberLteUeCmacSapUser(this));
117 m_cphySapProvider.push_back(nullptr);
118 m_cmacSapProvider.push_back(nullptr);
123}
124
129
130void
132{
133 NS_LOG_FUNCTION(this);
134 for (uint16_t i = 0; i < m_numberOfComponentCarriers; i++)
135 {
136 delete m_cphySapUser.at(i);
137 delete m_cmacSapUser.at(i);
138 }
139 m_cphySapUser.clear();
140 m_cmacSapUser.clear();
141 delete m_rrcSapProvider;
142 delete m_drbPdcpSapUser;
143 delete m_asSapProvider;
144 delete m_ccmRrcSapUser;
146 m_cphySapProvider.clear();
148 m_cmacSapProvider.clear();
149 m_drbMap.clear();
150}
151
152TypeId
154{
155 static TypeId tid =
156 TypeId("ns3::LteUeRrc")
157 .SetParent<Object>()
158 .SetGroupName("Lte")
159 .AddConstructor<LteUeRrc>()
160 .AddAttribute("DataRadioBearerMap",
161 "List of UE RadioBearerInfo for Data Radio Bearers by LCID.",
165 .AddAttribute("Srb0",
166 "SignalingRadioBearerInfo for SRB0",
167 PointerValue(),
170 .AddAttribute("Srb1",
171 "SignalingRadioBearerInfo for SRB1",
172 PointerValue(),
175 .AddAttribute("CellId",
176 "Serving cell identifier",
177 UintegerValue(0), // unused, read-only attribute
180 .AddAttribute("C-RNTI",
181 "Cell Radio Network Temporary Identifier",
182 UintegerValue(0), // unused, read-only attribute
185 .AddAttribute(
186 "T300",
187 "Timer for the RRC Connection Establishment procedure "
188 "(i.e., the procedure is deemed as failed if it takes longer than this). "
189 "Standard values: 100ms, 200ms, 300ms, 400ms, 600ms, 1000ms, 1500ms, 2000ms",
191 100)), // see 3GPP 36.331 UE-TimersAndConstants & RLF-TimersAndConstants
194 .AddAttribute(
195 "T310",
196 "Timer for detecting the Radio link failure "
197 "(i.e., the radio link is deemed as failed if this timer expires). "
198 "Standard values: 0ms 50ms, 100ms, 200ms, 500ms, 1000ms, 2000ms",
200 1000)), // see 3GPP 36.331 UE-TimersAndConstants & RLF-TimersAndConstants
203 .AddAttribute(
204 "N310",
205 "This specifies the maximum number of out-of-sync indications. "
206 "Standard values: 1, 2, 3, 4, 6, 8, 10, 20",
207 UintegerValue(6), // see 3GPP 36.331 UE-TimersAndConstants & RLF-TimersAndConstants
210 .AddAttribute(
211 "N311",
212 "This specifies the maximum number of in-sync indications. "
213 "Standard values: 1, 2, 3, 4, 5, 6, 8, 10",
214 UintegerValue(2), // see 3GPP 36.331 UE-TimersAndConstants & RLF-TimersAndConstants
217 .AddTraceSource("MibReceived",
218 "trace fired upon reception of Master Information Block",
220 "ns3::LteUeRrc::MibSibHandoverTracedCallback")
221 .AddTraceSource("Sib1Received",
222 "trace fired upon reception of System Information Block Type 1",
224 "ns3::LteUeRrc::MibSibHandoverTracedCallback")
225 .AddTraceSource("Sib2Received",
226 "trace fired upon reception of System Information Block Type 2",
228 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
229 .AddTraceSource("StateTransition",
230 "trace fired upon every UE RRC state transition",
232 "ns3::LteUeRrc::StateTracedCallback")
233 .AddTraceSource("InitialCellSelectionEndOk",
234 "trace fired upon successful initial cell selection procedure",
236 "ns3::LteUeRrc::CellSelectionTracedCallback")
237 .AddTraceSource("InitialCellSelectionEndError",
238 "trace fired upon failed initial cell selection procedure",
240 "ns3::LteUeRrc::CellSelectionTracedCallback")
241 .AddTraceSource("RandomAccessSuccessful",
242 "trace fired upon successful completion of the random access procedure",
244 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
245 .AddTraceSource("RandomAccessError",
246 "trace fired upon failure of the random access procedure",
248 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
249 .AddTraceSource("ConnectionEstablished",
250 "trace fired upon successful RRC connection establishment",
252 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
253 .AddTraceSource("ConnectionTimeout",
254 "trace fired upon timeout RRC connection establishment because of T300",
256 "ns3::LteUeRrc::ImsiCidRntiCountTracedCallback")
257 .AddTraceSource("ConnectionReconfiguration",
258 "trace fired upon RRC connection reconfiguration",
260 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
261 .AddTraceSource("HandoverStart",
262 "trace fired upon start of a handover procedure",
264 "ns3::LteUeRrc::MibSibHandoverTracedCallback")
265 .AddTraceSource("HandoverEndOk",
266 "trace fired upon successful termination of a handover procedure",
268 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
269 .AddTraceSource("HandoverEndError",
270 "trace fired upon failure of a handover procedure",
272 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
273 .AddTraceSource("SCarrierConfigured",
274 "trace fired after configuring secondary carriers",
276 "ns3::LteUeRrc::SCarrierConfiguredTracedCallback")
277 .AddTraceSource("Srb1Created",
278 "trace fired after SRB1 is created",
280 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
281 .AddTraceSource("DrbCreated",
282 "trace fired after DRB is created",
284 "ns3::LteUeRrc::ImsiCidRntiLcIdTracedCallback")
285 .AddTraceSource("RadioLinkFailure",
286 "trace fired upon failure of radio link",
288 "ns3::LteUeRrc::ImsiCidRntiTracedCallback")
289 .AddTraceSource(
290 "PhySyncDetection",
291 "trace fired upon receiving in Sync or out of Sync indications from UE PHY",
293 "ns3::LteUeRrc::PhySyncDetectionTracedCallback");
294 return tid;
295}
296
297void
303
304void
306{
307 NS_LOG_FUNCTION(this << s);
308 m_cphySapProvider.at(index) = s;
309}
310
313{
314 NS_LOG_FUNCTION(this);
315 return m_cphySapUser.at(0);
316}
317
320{
321 NS_LOG_FUNCTION(this);
322 return m_cphySapUser.at(index);
323}
324
325void
331
332void
334{
335 NS_LOG_FUNCTION(this << s);
336 m_cmacSapProvider.at(index) = s;
337}
338
341{
342 NS_LOG_FUNCTION(this);
343 return m_cmacSapUser.at(0);
344}
345
348{
349 NS_LOG_FUNCTION(this);
350 return m_cmacSapUser.at(index);
351}
352
353void
359
366
367void
373
374void
380
387
388void
393
399
400void
401LteUeRrc::SetImsi(uint64_t imsi)
402{
403 NS_LOG_FUNCTION(this << imsi);
404 m_imsi = imsi;
405
406 // Communicate the IMSI to MACs and PHYs for all the component carriers
407 for (uint16_t i = 0; i < m_numberOfComponentCarriers; i++)
408 {
409 m_cmacSapProvider.at(i)->SetImsi(m_imsi);
410 m_cphySapProvider.at(i)->SetImsi(m_imsi);
411 }
412}
413
414void
416{
417 NS_LOG_FUNCTION(this << cellId);
418 m_previousCellId = cellId;
419}
420
421uint64_t
423{
424 return m_imsi;
425}
426
427uint16_t
429{
430 NS_LOG_FUNCTION(this);
431 return m_rnti;
432}
433
434uint16_t
436{
437 NS_LOG_FUNCTION(this);
438 return m_cellId;
439}
440
441bool
442LteUeRrc::IsServingCell(uint16_t cellId) const
443{
444 NS_LOG_FUNCTION(this);
445 for (auto& cphySap : m_cphySapProvider)
446 {
447 if (cellId == cphySap->GetCellId())
448 {
449 return true;
450 }
451 }
452 return false;
453}
454
455uint8_t
457{
458 NS_LOG_FUNCTION(this);
459 return m_ulBandwidth;
460}
461
462uint8_t
464{
465 NS_LOG_FUNCTION(this);
466 return m_dlBandwidth;
467}
468
471{
472 return m_dlEarfcn;
473}
474
477{
478 NS_LOG_FUNCTION(this);
479 return m_ulEarfcn;
480}
481
484{
485 NS_LOG_FUNCTION(this);
486 return m_state;
487}
488
489uint16_t
491{
492 NS_LOG_FUNCTION(this);
493 return m_previousCellId;
494}
495
496void
498{
499 NS_LOG_FUNCTION(this);
500 m_useRlcSm = val;
501}
502
503void
505{
506 NS_LOG_FUNCTION(this);
507
508 // setup the UE side of SRB0
509 uint8_t lcid = 0;
510
511 Ptr<LteRlc> rlc = CreateObject<LteRlcTm>()->GetObject<LteRlc>();
512 rlc->SetLteMacSapProvider(m_macSapProvider);
513 rlc->SetRnti(m_rnti);
514 rlc->SetLcId(lcid);
515
517 m_srb0->m_rlc = rlc;
518 m_srb0->m_srbIdentity = 0;
520 ueParams.srb0SapProvider = m_srb0->m_rlc->GetLteRlcSapProvider();
521 ueParams.srb1SapProvider = nullptr;
522 m_rrcSapUser->Setup(ueParams);
523
524 // CCCH (LCID 0) is pre-configured, here is the hardcoded configuration:
526 lcConfig.priority = 0; // highest priority
527 lcConfig.prioritizedBitRateKbps = 65535; // maximum
528 lcConfig.bucketSizeDurationMs = 65535; // maximum
529 lcConfig.logicalChannelGroup = 0; // all SRBs mapped to LCG 0
530 LteMacSapUser* msu =
531 m_ccmRrcSapProvider->ConfigureSignalBearer(lcid, lcConfig, rlc->GetLteMacSapUser());
532 m_cmacSapProvider.at(0)->AddLc(lcid, lcConfig, msu);
533}
534
535void
537{
539 {
540 // this check is needed in order to maintain backward compatibility with scripts and tests
541 // if case lte-helper is not used (like in several tests) the m_numberOfComponentCarriers
542 // is not set and then an error is raised
543 // In this case m_numberOfComponentCarriers is set to 1
545 }
547 {
548 for (uint16_t i = 1; i < m_numberOfComponentCarriers; i++)
549 {
551 m_cmacSapUser.push_back(new UeMemberLteUeCmacSapUser(this));
552 m_cphySapProvider.push_back(nullptr);
553 m_cmacSapProvider.push_back(nullptr);
554 }
555 }
556}
557
558void
560{
561 NS_LOG_FUNCTION(this << packet);
562
563 uint8_t drbid = Bid2Drbid(bid);
564
565 if (drbid != 0)
566 {
567 auto it = m_drbMap.find(drbid);
568 NS_ASSERT_MSG(it != m_drbMap.end(), "could not find bearer with drbid == " << drbid);
569
571 params.pdcpSdu = packet;
572 params.rnti = m_rnti;
573 params.lcid = it->second->m_logicalChannelIdentity;
574
575 NS_LOG_LOGIC(this << " RNTI=" << m_rnti << " sending packet " << packet << " on DRBID "
576 << (uint32_t)drbid << " (LCID " << (uint32_t)params.lcid << ")"
577 << " (" << packet->GetSize() << " bytes)");
578 it->second->m_pdcp->GetLtePdcpSapProvider()->TransmitPdcpSdu(params);
579 }
580}
581
582void
584{
585 NS_LOG_FUNCTION(this);
586
587 switch (m_state)
588 {
589 case IDLE_START:
590 case IDLE_CELL_SEARCH:
592 case IDLE_WAIT_MIB:
593 case IDLE_WAIT_SIB1:
595 NS_LOG_INFO("already disconnected");
596 break;
597
598 case IDLE_WAIT_SIB2:
599 case IDLE_CONNECTING:
600 NS_FATAL_ERROR("cannot abort connection setup procedure");
601 break;
602
608 break;
609
610 default: // i.e. IDLE_RANDOM_ACCESS
611 NS_FATAL_ERROR("method unexpected in state " << m_state);
612 break;
613 }
614}
615
616void
622
623void
625{
626 NS_LOG_FUNCTION(this << rnti);
627 m_rnti = rnti;
628 m_srb0->m_rlc->SetRnti(m_rnti);
629 m_cphySapProvider.at(0)->SetRnti(m_rnti);
630}
631
632void
634{
635 NS_LOG_FUNCTION(this << m_imsi << m_state);
637
638 switch (m_state)
639 {
640 case IDLE_RANDOM_ACCESS: {
641 // we just received a RAR with a T-C-RNTI and an UL grant
642 // send RRC connection request as message 3 of the random access procedure
645 msg.ueIdentity = m_imsi;
648 }
649 break;
650
651 case CONNECTED_HANDOVER: {
655
656 // 3GPP TS 36.331 section 5.5.6.1 Measurements related actions upon handover
657 for (auto measIdIt = m_varMeasConfig.measIdList.begin();
658 measIdIt != m_varMeasConfig.measIdList.end();
659 ++measIdIt)
660 {
661 VarMeasReportListClear(measIdIt->second.measId);
662 }
663
665 m_cmacSapProvider.at(0)->NotifyConnectionSuccessful(); // RA successful during handover
667 }
668 break;
669
670 default:
671 NS_FATAL_ERROR("unexpected event in state " << m_state);
672 break;
673 }
674}
675
676void
678{
679 NS_LOG_FUNCTION(this << m_imsi << m_state);
681
682 switch (m_state)
683 {
684 case IDLE_RANDOM_ACCESS: {
687 }
688 break;
689
690 case CONNECTED_HANDOVER: {
692 /**
693 * @todo After a handover failure because of a random access failure,
694 * send an RRC Connection Re-establishment and switch to
695 * CONNECTED_REESTABLISHING state.
696 */
698 {
702 // we should have called NotifyConnectionFailed
703 // but that method would immediately ask you UE to
704 // connect rather than doing cell selection again.
706 }
707 }
708 break;
709
710 default:
711 NS_FATAL_ERROR("unexpected event in state " << m_state);
712 break;
713 }
714}
715
716void
718{
719 NS_LOG_FUNCTION(this << m_imsi << csgId);
720 m_csgWhiteList = csgId;
721}
722
723void
725{
726 NS_LOG_FUNCTION(this << m_imsi << dlEarfcn);
727 NS_ASSERT_MSG(m_state == IDLE_START, "cannot start cell selection from state " << m_state);
728 m_dlEarfcn = dlEarfcn;
729 m_cphySapProvider.at(0)->StartCellSearch(dlEarfcn);
731}
732
733void
734LteUeRrc::DoForceCampedOnEnb(uint16_t cellId, uint32_t dlEarfcn)
735{
736 NS_LOG_FUNCTION(this << m_imsi << cellId << dlEarfcn);
737
738 switch (m_state)
739 {
740 case IDLE_START:
741 m_cellId = cellId;
742 m_dlEarfcn = dlEarfcn;
743 m_cphySapProvider.at(0)->SynchronizeWithEnb(m_cellId, m_dlEarfcn);
745 break;
746
747 case IDLE_CELL_SEARCH:
749 case IDLE_WAIT_SIB1:
750 NS_FATAL_ERROR("cannot abort cell selection " << m_state);
751 break;
752
753 case IDLE_WAIT_MIB:
754 NS_LOG_INFO("already forced to camp to cell " << m_cellId);
755 break;
756
758 case IDLE_WAIT_SIB2:
760 case IDLE_CONNECTING:
761 NS_LOG_INFO("already camped to cell " << m_cellId);
762 break;
763
768 NS_LOG_INFO("already connected to cell " << m_cellId);
769 break;
770
771 default:
772 NS_FATAL_ERROR("unexpected event in state " << m_state);
773 break;
774 }
775}
776
777void
779{
780 NS_LOG_FUNCTION(this << m_imsi);
781
782 switch (m_state)
783 {
784 case IDLE_START:
785 case IDLE_CELL_SEARCH:
787 case IDLE_WAIT_SIB1:
788 case IDLE_WAIT_MIB:
789 m_connectionPending = true;
790 break;
791
793 m_connectionPending = true;
795 break;
796
797 case IDLE_WAIT_SIB2:
799 case IDLE_CONNECTING:
800 NS_LOG_INFO("already connecting");
801 break;
802
806 NS_LOG_INFO("already connected");
807 break;
808
809 default:
810 NS_FATAL_ERROR("unexpected event in state " << m_state);
811 break;
812 }
813}
814
815// CPHY SAP methods
816
817void
819{
821 m_cphySapProvider.at(0)->SetDlBandwidth(msg.dlBandwidth);
822 m_hasReceivedMib = true;
824
825 switch (m_state)
826 {
827 case IDLE_WAIT_MIB:
828 // manual attachment
830 break;
831
833 // automatic attachment from Idle mode cell selection
835 break;
836
837 default:
838 // do nothing extra
839 break;
840 }
841}
842
843void
846{
847 NS_LOG_FUNCTION(this);
848 switch (m_state)
849 {
850 case IDLE_WAIT_SIB1:
852 "Cell identity in SIB1 does not match with the originating cell");
853 m_hasReceivedSib1 = true;
854 m_lastSib1 = msg;
857 break;
858
861 case IDLE_CONNECTING:
867 "Cell identity in SIB1 does not match with the originating cell");
868 m_hasReceivedSib1 = true;
869 m_lastSib1 = msg;
871 break;
872
874 // MIB has not been received, so ignore this SIB1
875
876 default: // e.g. IDLE_START, IDLE_CELL_SEARCH, IDLE_WAIT_MIB, IDLE_WAIT_SIB2
877 // do nothing
878 break;
879 }
880}
881
882void
884{
885 NS_LOG_FUNCTION(this);
886
887 // layer 3 filtering does not apply in IDLE mode
888 bool useLayer3Filtering = (m_state == CONNECTED_NORMALLY);
889 bool triggering = true;
890 for (auto newMeasIt = params.m_ueMeasurementsList.begin();
891 newMeasIt != params.m_ueMeasurementsList.end();
892 ++newMeasIt)
893 {
894 if (params.m_componentCarrierId != 0)
895 {
896 triggering = false; // report is triggered only when an event is on the primary carrier
897 // in this case the measurement received is related to secondary carriers
898 }
899 SaveUeMeasurements(newMeasIt->m_cellId,
900 newMeasIt->m_rsrp,
901 newMeasIt->m_rsrq,
902 useLayer3Filtering,
903 params.m_componentCarrierId);
904 }
905
907 {
908 // start decoding BCH
910 }
911 else
912 {
913 if (triggering)
914 {
915 for (auto measIdIt = m_varMeasConfig.measIdList.begin();
916 measIdIt != m_varMeasConfig.measIdList.end();
917 ++measIdIt)
918 {
919 MeasurementReportTriggering(measIdIt->first);
920 }
921 }
922 }
923}
924
925// RRC SAP methods
926
927void
929{
930 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
931 m_srb0->m_rlc->SetLteRlcSapUser(params.srb0SapUser);
932 if (m_srb1)
933 {
934 m_srb1->m_pdcp->SetLtePdcpSapUser(params.srb1SapUser);
935 }
936}
937
938void
940{
941 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
942
943 if (msg.haveSib2)
944 {
945 switch (m_state)
946 {
948 case IDLE_WAIT_SIB2:
950 case IDLE_CONNECTING:
955 m_hasReceivedSib2 = true;
960 rc.numberOfRaPreambles = msg.sib2.radioResourceConfigCommon.rachConfigCommon
962 rc.preambleTransMax = msg.sib2.radioResourceConfigCommon.rachConfigCommon
964 rc.raResponseWindowSize = msg.sib2.radioResourceConfigCommon.rachConfigCommon
966 rc.connEstFailCount =
968 m_connEstFailCountLimit = rc.connEstFailCount;
970 "SIB2 msg contains wrong value " << m_connEstFailCountLimit
971 << "of connEstFailCount");
972 m_cmacSapProvider.at(0)->ConfigureRach(rc);
973 m_cphySapProvider.at(0)->ConfigureUplink(m_ulEarfcn, m_ulBandwidth);
974 m_cphySapProvider.at(0)->ConfigureReferenceSignalPower(
976 if (m_state == IDLE_WAIT_SIB2)
977 {
980 }
981 break;
982
983 default: // IDLE_START, IDLE_CELL_SEARCH, IDLE_WAIT_MIB, IDLE_WAIT_MIB_SIB1, IDLE_WAIT_SIB1
984 // do nothing
985 break;
986 }
987 }
988}
989
990void
992{
993 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
994 switch (m_state)
995 {
996 case IDLE_CONNECTING: {
1001 m_leaveConnectedMode = false;
1006 m_cmacSapProvider.at(0)->NotifyConnectionSuccessful();
1009 "Sync indications should be zero "
1010 "when a new RRC connection is established. Current value = "
1011 << (uint16_t)m_noOfSyncIndications);
1012 }
1013 break;
1014
1015 default:
1016 NS_FATAL_ERROR("method unexpected in state " << m_state);
1017 break;
1018 }
1019}
1020
1021void
1023{
1024 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
1025 NS_LOG_INFO("DoRecvRrcConnectionReconfiguration haveNonCriticalExtension:"
1027 switch (m_state)
1028 {
1029 case CONNECTED_NORMALLY:
1031 {
1032 NS_LOG_INFO("haveMobilityControlInfo == true");
1035 {
1037 }
1040 // We should reset the MACs and PHYs for all the component carriers
1041 for (auto cmacSapProvider : m_cmacSapProvider)
1042 {
1043 cmacSapProvider->Reset();
1044 }
1045 for (auto cphySapProvider : m_cphySapProvider)
1046 {
1047 cphySapProvider->Reset();
1048 }
1054 m_cphySapProvider.at(0)->SynchronizeWithEnb(m_cellId, mci.carrierFreq.dlCarrierFreq);
1055 m_cphySapProvider.at(0)->SetDlBandwidth(mci.carrierBandwidth.dlBandwidth);
1056 m_cphySapProvider.at(0)->ConfigureUplink(mci.carrierFreq.ulCarrierFreq,
1059 m_srb0->m_rlc->SetRnti(m_rnti);
1062 "handover is only supported with non-contention-based random access procedure");
1063 m_cmacSapProvider.at(0)->StartNonContentionBasedRandomAccessProcedure(
1064 m_rnti,
1067 m_cphySapProvider.at(0)->SetRnti(m_rnti);
1070
1071 // we re-establish SRB1 by creating a new entity
1072 // note that we can't dispose the old entity now, because
1073 // it's in the current stack, so we would corrupt the stack
1074 // if we did so. Hence we schedule it for later disposal
1075 m_srb1Old = m_srb1;
1077 m_srb1 =
1078 nullptr; // new instance will be be created within ApplyRadioResourceConfigDedicated
1079
1080 m_drbMap.clear(); // dispose all DRBs
1083 {
1084 NS_LOG_DEBUG(this << "RNTI " << m_rnti
1085 << " Handover. Configuring secondary carriers");
1087 }
1088
1089 if (msg.haveMeasConfig)
1090 {
1092 }
1093 // RRC connection reconfiguration completed will be sent
1094 // after handover is complete
1095 }
1096 else
1097 {
1098 NS_LOG_INFO("haveMobilityControlInfo == false");
1100 {
1102 NS_LOG_DEBUG(this << "RNTI " << m_rnti << " Configured for CA");
1103 }
1105 {
1107 }
1108 if (msg.haveMeasConfig)
1109 {
1111 }
1116 }
1117 break;
1118
1119 default:
1120 NS_FATAL_ERROR("method unexpected in state " << m_state);
1121 break;
1122 }
1123}
1124
1125void
1127{
1128 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
1129 switch (m_state)
1130 {
1132 /**
1133 * @todo After receiving RRC Connection Re-establishment, stop timer
1134 * T301, fire a new trace source, reply with RRC Connection
1135 * Re-establishment Complete, and finally switch to
1136 * CONNECTED_NORMALLY state. See Section 5.3.7.5 of 3GPP TS
1137 * 36.331.
1138 */
1139 }
1140 break;
1141
1142 default:
1143 NS_FATAL_ERROR("method unexpected in state " << m_state);
1144 break;
1145 }
1146}
1147
1148void
1151{
1152 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
1153 switch (m_state)
1154 {
1156 /**
1157 * @todo After receiving RRC Connection Re-establishment Reject, stop
1158 * timer T301. See Section 5.3.7.8 of 3GPP TS 36.331.
1159 */
1160 m_asSapUser->NotifyConnectionReleased(); // Inform upper layers
1161 }
1162 break;
1163
1164 default:
1165 NS_FATAL_ERROR("method unexpected in state " << m_state);
1166 break;
1167 }
1168}
1169
1170void
1172{
1173 NS_LOG_FUNCTION(this << " RNTI " << m_rnti);
1174 /// @todo Currently not implemented, see Section 5.3.8 of 3GPP TS 36.331.
1175
1177 // release resources at UE
1179 {
1180 m_leaveConnectedMode = true;
1184 }
1185}
1186
1187void
1189{
1190 NS_LOG_FUNCTION(this);
1192 for (uint16_t i = 0; i < m_numberOfComponentCarriers; i++)
1193 {
1194 m_cmacSapProvider.at(i)->Reset(); // reset the MAC
1195 }
1196 m_hasReceivedSib2 = false; // invalidate the previously received SIB2
1198 m_asSapUser->NotifyConnectionFailed(); // inform upper layer
1199}
1200
1201void
1202LteUeRrc::DoSetNumberOfComponentCarriers(uint16_t noOfComponentCarriers)
1203{
1204 NS_LOG_FUNCTION(this);
1205 m_numberOfComponentCarriers = noOfComponentCarriers;
1206}
1207
1208void
1210{
1211 NS_LOG_FUNCTION(this);
1213
1214 uint16_t maxRsrpCellId = 0;
1215 double maxRsrp = -std::numeric_limits<double>::infinity();
1216 double minRsrp = -140.0; // Minimum RSRP in dBm a UE can report
1217
1218 for (auto it = m_storedMeasValues.begin(); it != m_storedMeasValues.end(); it++)
1219 {
1220 /*
1221 * This block attempts to find a cell with strongest RSRP and has not
1222 * yet been identified as "acceptable cell".
1223 */
1224 if (maxRsrp < it->second.rsrp && it->second.rsrp > minRsrp)
1225 {
1226 auto itCell = m_acceptableCell.find(it->first);
1227 if (itCell == m_acceptableCell.end())
1228 {
1229 maxRsrpCellId = it->first;
1230 maxRsrp = it->second.rsrp;
1231 }
1232 }
1233 }
1234
1235 if (maxRsrpCellId == 0)
1236 {
1237 NS_LOG_WARN(this << " Cell search is unable to detect surrounding cell to attach to");
1238 }
1239 else
1240 {
1241 NS_LOG_LOGIC(this << " cell " << maxRsrpCellId
1242 << " is the strongest untried surrounding cell");
1243 m_cphySapProvider.at(0)->SynchronizeWithEnb(maxRsrpCellId, m_dlEarfcn);
1245 }
1246}
1247
1248void
1250{
1251 NS_LOG_FUNCTION(this);
1256
1257 // Cell selection criteria evaluation
1258
1259 bool isSuitableCell = false;
1260 bool isAcceptableCell = false;
1261 auto storedMeasIt = m_storedMeasValues.find(cellId);
1262 double qRxLevMeas = storedMeasIt->second.rsrp;
1263 double qRxLevMin =
1265 NS_LOG_LOGIC(this << " cell selection to cellId=" << cellId << " qrxlevmeas=" << qRxLevMeas
1266 << " dBm"
1267 << " qrxlevmin=" << qRxLevMin << " dBm");
1268
1269 if (qRxLevMeas - qRxLevMin > 0)
1270 {
1271 isAcceptableCell = true;
1272
1274 bool cellCsgIndication = m_lastSib1.cellAccessRelatedInfo.csgIndication;
1275
1276 isSuitableCell = (!cellCsgIndication || cellCsgId == m_csgWhiteList);
1277
1278 NS_LOG_LOGIC(this << " csg(ue/cell/indication)=" << m_csgWhiteList << "/" << cellCsgId
1279 << "/" << cellCsgIndication);
1280 }
1281
1282 // Cell selection decision
1283
1284 if (isSuitableCell)
1285 {
1286 m_cellId = cellId;
1287 m_cphySapProvider.at(0)->SynchronizeWithEnb(cellId, m_dlEarfcn);
1288 m_cphySapProvider.at(0)->SetDlBandwidth(m_dlBandwidth);
1290 // Once the UE is connected, m_connectionPending is
1291 // set to false. So, when RLF occurs and UE performs
1292 // cell selection upon leaving RRC_CONNECTED state,
1293 // the following call to DoConnect will make the
1294 // m_connectionPending to be true again. Thus,
1295 // upon calling SwitchToState (IDLE_CAMPED_NORMALLY)
1296 // UE state is instantly change to IDLE_WAIT_SIB2.
1297 // This will make the UE to read the SIB2 message
1298 // and start random access.
1300 {
1301 NS_LOG_DEBUG("Calling DoConnect in state = " << m_state);
1302 DoConnect();
1303 }
1305 }
1306 else
1307 {
1308 // ignore the MIB and SIB1 received from this cell
1309 m_hasReceivedMib = false;
1310 m_hasReceivedSib1 = false;
1311
1313
1314 if (isAcceptableCell)
1315 {
1316 /*
1317 * The cells inserted into this list will not be considered for
1318 * subsequent cell search attempt.
1319 */
1320 m_acceptableCell.insert(cellId);
1321 }
1322
1324 SynchronizeToStrongestCell(); // retry to a different cell
1325 }
1326}
1327
1328void
1331{
1332 NS_LOG_FUNCTION(this);
1333
1335
1336 for (uint32_t sCellIndex : nonCec.sCellToReleaseList)
1337 {
1338 m_cphySapProvider.at(sCellIndex)->Reset();
1339 m_cmacSapProvider.at(sCellIndex)->Reset();
1340 }
1341
1342 for (auto& scell : nonCec.sCellToAddModList)
1343 {
1344 uint8_t ccId = scell.sCellIndex;
1345
1346 uint16_t physCellId = scell.cellIdentification.physCellId;
1347 uint16_t ulBand =
1348 scell.radioResourceConfigCommonSCell.ulConfiguration.ulFreqInfo.ulBandwidth;
1349 uint32_t ulEarfcn =
1350 scell.radioResourceConfigCommonSCell.ulConfiguration.ulFreqInfo.ulCarrierFreq;
1351 uint16_t dlBand = scell.radioResourceConfigCommonSCell.nonUlConfiguration.dlBandwidth;
1352 uint32_t dlEarfcn = scell.cellIdentification.dlCarrierFreq;
1353 uint8_t txMode = scell.radioResourceConfigDedicatedSCell.physicalConfigDedicatedSCell
1354 .antennaInfo.transmissionMode;
1355 uint16_t srsIndex = scell.radioResourceConfigDedicatedSCell.physicalConfigDedicatedSCell
1356 .soundingRsUlConfigDedicated.srsConfigIndex;
1357
1358 m_cphySapProvider.at(ccId)->SynchronizeWithEnb(physCellId, dlEarfcn);
1359 m_cphySapProvider.at(ccId)->SetDlBandwidth(dlBand);
1360 m_cphySapProvider.at(ccId)->ConfigureUplink(ulEarfcn, ulBand);
1361 m_cphySapProvider.at(ccId)->ConfigureReferenceSignalPower(
1362 scell.radioResourceConfigCommonSCell.nonUlConfiguration.pdschConfigCommon
1363 .referenceSignalPower);
1364 m_cphySapProvider.at(ccId)->SetTransmissionMode(txMode);
1365 m_cphySapProvider.at(ccId)->SetRnti(m_rnti);
1366 m_cmacSapProvider.at(ccId)->SetRnti(m_rnti);
1367 // update PdschConfigDedicated (i.e. P_A value)
1368 LteRrcSap::PdschConfigDedicated pdschConfigDedicated =
1369 scell.radioResourceConfigDedicatedSCell.physicalConfigDedicatedSCell
1370 .pdschConfigDedicated;
1371 double paDouble = LteRrcSap::ConvertPdschConfigDedicated2Double(pdschConfigDedicated);
1372 m_cphySapProvider.at(ccId)->SetPa(paDouble);
1373 m_cphySapProvider.at(ccId)->SetSrsConfigurationIndex(srsIndex);
1374 }
1375
1377}
1378
1379void
1381{
1382 NS_LOG_FUNCTION(this);
1384
1386 {
1387 m_cphySapProvider.at(0)->SetTransmissionMode(pcd.antennaInfo.transmissionMode);
1388 }
1390 {
1391 m_cphySapProvider.at(0)->SetSrsConfigurationIndex(
1393 }
1394
1396 {
1397 // update PdschConfigDedicated (i.e. P_A value)
1400 m_cphySapProvider.at(0)->SetPa(paDouble);
1401 }
1402
1403 auto stamIt = rrcd.srbToAddModList.begin();
1404 if (stamIt != rrcd.srbToAddModList.end())
1405 {
1406 if (!m_srb1)
1407 {
1408 // SRB1 not setup yet
1410 "unexpected state " << m_state);
1411 NS_ASSERT_MSG(stamIt->srbIdentity == 1, "only SRB1 supported");
1412
1413 const uint8_t lcid = 1; // fixed LCID for SRB1
1414
1416 rlc->SetLteMacSapProvider(m_macSapProvider);
1417 rlc->SetRnti(m_rnti);
1418 rlc->SetLcId(lcid);
1419
1421 pdcp->SetRnti(m_rnti);
1422 pdcp->SetLcId(lcid);
1423 pdcp->SetLtePdcpSapUser(m_drbPdcpSapUser);
1424 pdcp->SetLteRlcSapProvider(rlc->GetLteRlcSapProvider());
1425 rlc->SetLteRlcSapUser(pdcp->GetLteRlcSapUser());
1426
1428 m_srb1->m_rlc = rlc;
1429 m_srb1->m_pdcp = pdcp;
1430 m_srb1->m_srbIdentity = 1;
1432
1433 m_srb1->m_logicalChannelConfig.priority = stamIt->logicalChannelConfig.priority;
1434 m_srb1->m_logicalChannelConfig.prioritizedBitRateKbps =
1435 stamIt->logicalChannelConfig.prioritizedBitRateKbps;
1436 m_srb1->m_logicalChannelConfig.bucketSizeDurationMs =
1437 stamIt->logicalChannelConfig.bucketSizeDurationMs;
1438 m_srb1->m_logicalChannelConfig.logicalChannelGroup =
1439 stamIt->logicalChannelConfig.logicalChannelGroup;
1440
1442 lcConfig.priority = stamIt->logicalChannelConfig.priority;
1443 lcConfig.prioritizedBitRateKbps = stamIt->logicalChannelConfig.prioritizedBitRateKbps;
1444 lcConfig.bucketSizeDurationMs = stamIt->logicalChannelConfig.bucketSizeDurationMs;
1445 lcConfig.logicalChannelGroup = stamIt->logicalChannelConfig.logicalChannelGroup;
1446 LteMacSapUser* msu =
1447 m_ccmRrcSapProvider->ConfigureSignalBearer(lcid, lcConfig, rlc->GetLteMacSapUser());
1448 m_cmacSapProvider.at(0)->AddLc(lcid, lcConfig, msu);
1449 ++stamIt;
1450 NS_ASSERT_MSG(stamIt == rrcd.srbToAddModList.end(), "at most one SrbToAdd supported");
1451
1453 ueParams.srb0SapProvider = m_srb0->m_rlc->GetLteRlcSapProvider();
1454 ueParams.srb1SapProvider = m_srb1->m_pdcp->GetLtePdcpSapProvider();
1455 m_rrcSapUser->Setup(ueParams);
1456 }
1457 else
1458 {
1459 NS_LOG_INFO("request to modify SRB1 (skipping as currently not implemented)");
1460 // would need to modify m_srb1, and then propagate changes to the MAC
1461 }
1462 }
1463
1464 for (auto dtamIt = rrcd.drbToAddModList.begin(); dtamIt != rrcd.drbToAddModList.end(); ++dtamIt)
1465 {
1466 NS_LOG_INFO(this << " IMSI " << m_imsi << " adding/modifying DRBID "
1467 << (uint32_t)dtamIt->drbIdentity << " LC "
1468 << (uint32_t)dtamIt->logicalChannelIdentity);
1469 NS_ASSERT_MSG(dtamIt->logicalChannelIdentity > 2,
1470 "LCID value " << dtamIt->logicalChannelIdentity << " is reserved for SRBs");
1471
1472 auto drbMapIt = m_drbMap.find(dtamIt->drbIdentity);
1473 if (drbMapIt == m_drbMap.end())
1474 {
1475 NS_LOG_INFO("New Data Radio Bearer");
1476
1477 TypeId rlcTypeId;
1478 if (m_useRlcSm)
1479 {
1480 rlcTypeId = LteRlcSm::GetTypeId();
1481 }
1482 else
1483 {
1484 switch (dtamIt->rlcConfig.choice)
1485 {
1487 rlcTypeId = LteRlcAm::GetTypeId();
1488 break;
1489
1491 rlcTypeId = LteRlcUm::GetTypeId();
1492 break;
1493
1494 default:
1495 NS_FATAL_ERROR("unsupported RLC configuration");
1496 break;
1497 }
1498 }
1499
1500 ObjectFactory rlcObjectFactory;
1501 rlcObjectFactory.SetTypeId(rlcTypeId);
1502 Ptr<LteRlc> rlc = rlcObjectFactory.Create()->GetObject<LteRlc>();
1503 rlc->SetLteMacSapProvider(m_macSapProvider);
1504 rlc->SetRnti(m_rnti);
1505 rlc->SetLcId(dtamIt->logicalChannelIdentity);
1506
1508 drbInfo->m_rlc = rlc;
1509 drbInfo->m_epsBearerIdentity = dtamIt->epsBearerIdentity;
1510 drbInfo->m_logicalChannelIdentity = dtamIt->logicalChannelIdentity;
1511 drbInfo->m_drbIdentity = dtamIt->drbIdentity;
1512
1513 // we need PDCP only for real RLC, i.e., RLC/UM or RLC/AM
1514 // if we are using RLC/SM we don't care of anything above RLC
1515 if (rlcTypeId != LteRlcSm::GetTypeId())
1516 {
1518 pdcp->SetRnti(m_rnti);
1519 pdcp->SetLcId(dtamIt->logicalChannelIdentity);
1520 pdcp->SetLtePdcpSapUser(m_drbPdcpSapUser);
1521 pdcp->SetLteRlcSapProvider(rlc->GetLteRlcSapProvider());
1522 rlc->SetLteRlcSapUser(pdcp->GetLteRlcSapUser());
1523 drbInfo->m_pdcp = pdcp;
1524 }
1525
1526 m_bid2DrbidMap[dtamIt->epsBearerIdentity] = dtamIt->drbIdentity;
1527
1528 m_drbMap.insert(
1529 std::pair<uint8_t, Ptr<LteDataRadioBearerInfo>>(dtamIt->drbIdentity, drbInfo));
1530
1531 m_drbCreatedTrace(m_imsi, m_cellId, m_rnti, dtamIt->drbIdentity);
1532
1534 lcConfig.priority = dtamIt->logicalChannelConfig.priority;
1535 lcConfig.prioritizedBitRateKbps = dtamIt->logicalChannelConfig.prioritizedBitRateKbps;
1536 lcConfig.bucketSizeDurationMs = dtamIt->logicalChannelConfig.bucketSizeDurationMs;
1537 lcConfig.logicalChannelGroup = dtamIt->logicalChannelConfig.logicalChannelGroup;
1538
1539 NS_LOG_DEBUG(this << " UE RRC RNTI " << m_rnti << " Number Of Component Carriers "
1540 << m_numberOfComponentCarriers << " lcID "
1541 << (uint16_t)dtamIt->logicalChannelIdentity);
1542 // Call AddLc of UE component carrier manager
1543 std::vector<LteUeCcmRrcSapProvider::LcsConfig> lcOnCcMapping =
1544 m_ccmRrcSapProvider->AddLc(dtamIt->logicalChannelIdentity,
1545 lcConfig,
1546 rlc->GetLteMacSapUser());
1547
1548 NS_LOG_DEBUG("Size of lcOnCcMapping vector " << lcOnCcMapping.size());
1549 auto itLcOnCcMapping = lcOnCcMapping.begin();
1550 NS_ASSERT_MSG(itLcOnCcMapping != lcOnCcMapping.end(),
1551 "Component carrier manager failed to add LC for data radio bearer");
1552
1553 for (itLcOnCcMapping = lcOnCcMapping.begin(); itLcOnCcMapping != lcOnCcMapping.end();
1554 ++itLcOnCcMapping)
1555 {
1556 NS_LOG_DEBUG("RNTI " << m_rnti << " LCG id "
1557 << (uint16_t)itLcOnCcMapping->lcConfig.logicalChannelGroup
1558 << " ComponentCarrierId "
1559 << (uint16_t)itLcOnCcMapping->componentCarrierId);
1560 uint8_t index = itLcOnCcMapping->componentCarrierId;
1562 itLcOnCcMapping->lcConfig;
1563 LteMacSapUser* msu = itLcOnCcMapping->msu;
1564 m_cmacSapProvider.at(index)->AddLc(dtamIt->logicalChannelIdentity,
1565 lcConfigFromCcm,
1566 msu);
1567 }
1568
1569 rlc->Initialize();
1570 }
1571 else
1572 {
1573 NS_LOG_INFO("request to modify existing DRBID");
1574 Ptr<LteDataRadioBearerInfo> drbInfo = drbMapIt->second;
1575 /// @todo currently not implemented. Would need to modify drbInfo, and then propagate
1576 /// changes to the MAC
1577 }
1578 }
1579
1580 for (auto dtdmIt = rrcd.drbToReleaseList.begin(); dtdmIt != rrcd.drbToReleaseList.end();
1581 ++dtdmIt)
1582 {
1583 uint8_t drbid = *dtdmIt;
1584 NS_LOG_INFO(this << " IMSI " << m_imsi << " releasing DRB " << (uint32_t)drbid);
1585 auto it = m_drbMap.find(drbid);
1586 NS_ASSERT_MSG(it != m_drbMap.end(), "could not find bearer with given lcid");
1587 m_drbMap.erase(it);
1588 m_bid2DrbidMap.erase(drbid);
1589 // Remove LCID
1590 for (uint32_t i = 0; i < m_numberOfComponentCarriers; i++)
1591 {
1592 m_cmacSapProvider.at(i)->RemoveLc(drbid + 2);
1593 }
1594 }
1595}
1596
1597void
1599{
1600 NS_LOG_FUNCTION(this);
1601
1602 // perform the actions specified in 3GPP TS 36.331 section 5.5.2.1
1603
1604 // 3GPP TS 36.331 section 5.5.2.4 Measurement object removal
1605 for (auto it = mc.measObjectToRemoveList.begin(); it != mc.measObjectToRemoveList.end(); ++it)
1606 {
1607 uint8_t measObjectId = *it;
1608 NS_LOG_LOGIC(this << " deleting measObjectId " << (uint32_t)measObjectId);
1609 m_varMeasConfig.measObjectList.erase(measObjectId);
1610 auto measIdIt = m_varMeasConfig.measIdList.begin();
1611 while (measIdIt != m_varMeasConfig.measIdList.end())
1612 {
1613 if (measIdIt->second.measObjectId == measObjectId)
1614 {
1615 uint8_t measId = measIdIt->second.measId;
1616 NS_ASSERT(measId == measIdIt->first);
1617 NS_LOG_LOGIC(this << " deleting measId " << (uint32_t)measId
1618 << " because referring to measObjectId "
1619 << (uint32_t)measObjectId);
1620 // note: postfix operator preserves iterator validity
1621 m_varMeasConfig.measIdList.erase(measIdIt++);
1622 VarMeasReportListClear(measId);
1623 }
1624 else
1625 {
1626 ++measIdIt;
1627 }
1628 }
1629 }
1630
1631 // 3GPP TS 36.331 section 5.5.2.5 Measurement object addition/ modification
1632 for (auto it = mc.measObjectToAddModList.begin(); it != mc.measObjectToAddModList.end(); ++it)
1633 {
1634 // simplifying assumptions
1635 NS_ASSERT_MSG(it->measObjectEutra.cellsToRemoveList.empty(),
1636 "cellsToRemoveList not supported");
1637 NS_ASSERT_MSG(it->measObjectEutra.cellsToAddModList.empty(),
1638 "cellsToAddModList not supported");
1639 NS_ASSERT_MSG(it->measObjectEutra.cellsToRemoveList.empty(),
1640 "blackCellsToRemoveList not supported");
1641 NS_ASSERT_MSG(it->measObjectEutra.blackCellsToAddModList.empty(),
1642 "blackCellsToAddModList not supported");
1643 NS_ASSERT_MSG(it->measObjectEutra.haveCellForWhichToReportCGI == false,
1644 "cellForWhichToReportCGI is not supported");
1645
1646 uint8_t measObjectId = it->measObjectId;
1647 auto measObjectIt = m_varMeasConfig.measObjectList.find(measObjectId);
1648 if (measObjectIt != m_varMeasConfig.measObjectList.end())
1649 {
1650 NS_LOG_LOGIC("measObjectId " << (uint32_t)measObjectId << " exists, updating entry");
1651 measObjectIt->second = *it;
1652 for (auto measIdIt = m_varMeasConfig.measIdList.begin();
1653 measIdIt != m_varMeasConfig.measIdList.end();
1654 ++measIdIt)
1655 {
1656 if (measIdIt->second.measObjectId == measObjectId)
1657 {
1658 uint8_t measId = measIdIt->second.measId;
1659 NS_LOG_LOGIC(this << " found measId " << (uint32_t)measId
1660 << " referring to measObjectId " << (uint32_t)measObjectId);
1661 VarMeasReportListClear(measId);
1662 }
1663 }
1664 }
1665 else
1666 {
1667 NS_LOG_LOGIC("measObjectId " << (uint32_t)measObjectId << " is new, adding entry");
1668 m_varMeasConfig.measObjectList[measObjectId] = *it;
1669 }
1670 }
1671
1672 // 3GPP TS 36.331 section 5.5.2.6 Reporting configuration removal
1673 for (auto it = mc.reportConfigToRemoveList.begin(); it != mc.reportConfigToRemoveList.end();
1674 ++it)
1675 {
1676 uint8_t reportConfigId = *it;
1677 NS_LOG_LOGIC(this << " deleting reportConfigId " << (uint32_t)reportConfigId);
1678 m_varMeasConfig.reportConfigList.erase(reportConfigId);
1679 auto measIdIt = m_varMeasConfig.measIdList.begin();
1680 while (measIdIt != m_varMeasConfig.measIdList.end())
1681 {
1682 if (measIdIt->second.reportConfigId == reportConfigId)
1683 {
1684 uint8_t measId = measIdIt->second.measId;
1685 NS_ASSERT(measId == measIdIt->first);
1686 NS_LOG_LOGIC(this << " deleting measId " << (uint32_t)measId
1687 << " because referring to reportConfigId "
1688 << (uint32_t)reportConfigId);
1689 // note: postfix operator preserves iterator validity
1690 m_varMeasConfig.measIdList.erase(measIdIt++);
1691 VarMeasReportListClear(measId);
1692 }
1693 else
1694 {
1695 ++measIdIt;
1696 }
1697 }
1698 }
1699
1700 // 3GPP TS 36.331 section 5.5.2.7 Reporting configuration addition/ modification
1701 for (auto it = mc.reportConfigToAddModList.begin(); it != mc.reportConfigToAddModList.end();
1702 ++it)
1703 {
1704 // simplifying assumptions
1705 NS_ASSERT_MSG(it->reportConfigEutra.triggerType == LteRrcSap::ReportConfigEutra::EVENT,
1706 "only trigger type EVENT is supported");
1707
1708 uint8_t reportConfigId = it->reportConfigId;
1709 auto reportConfigIt = m_varMeasConfig.reportConfigList.find(reportConfigId);
1710 if (reportConfigIt != m_varMeasConfig.reportConfigList.end())
1711 {
1712 NS_LOG_LOGIC("reportConfigId " << (uint32_t)reportConfigId
1713 << " exists, updating entry");
1714 m_varMeasConfig.reportConfigList[reportConfigId] = *it;
1715 for (auto measIdIt = m_varMeasConfig.measIdList.begin();
1716 measIdIt != m_varMeasConfig.measIdList.end();
1717 ++measIdIt)
1718 {
1719 if (measIdIt->second.reportConfigId == reportConfigId)
1720 {
1721 uint8_t measId = measIdIt->second.measId;
1722 NS_LOG_LOGIC(this << " found measId " << (uint32_t)measId
1723 << " referring to reportConfigId "
1724 << (uint32_t)reportConfigId);
1725 VarMeasReportListClear(measId);
1726 }
1727 }
1728 }
1729 else
1730 {
1731 NS_LOG_LOGIC("reportConfigId " << (uint32_t)reportConfigId << " is new, adding entry");
1732 m_varMeasConfig.reportConfigList[reportConfigId] = *it;
1733 }
1734 }
1735
1736 // 3GPP TS 36.331 section 5.5.2.8 Quantity configuration
1737 if (mc.haveQuantityConfig)
1738 {
1739 NS_LOG_LOGIC(this << " setting quantityConfig");
1741 // Convey the filter coefficient to PHY layer so it can configure the power control
1742 // parameter
1743 for (uint16_t i = 0; i < m_numberOfComponentCarriers; i++)
1744 {
1745 m_cphySapProvider.at(i)->SetRsrpFilterCoefficient(
1747 }
1748 // we calculate here the coefficient a used for Layer 3 filtering, see 3GPP TS 36.331
1749 // section 5.5.3.2
1752 NS_LOG_LOGIC(this << " new filter coefficients: aRsrp=" << m_varMeasConfig.aRsrp
1753 << ", aRsrq=" << m_varMeasConfig.aRsrq);
1754
1755 for (auto measIdIt = m_varMeasConfig.measIdList.begin();
1756 measIdIt != m_varMeasConfig.measIdList.end();
1757 ++measIdIt)
1758 {
1759 VarMeasReportListClear(measIdIt->second.measId);
1760 }
1761 }
1762
1763 // 3GPP TS 36.331 section 5.5.2.2 Measurement identity removal
1764 for (auto it = mc.measIdToRemoveList.begin(); it != mc.measIdToRemoveList.end(); ++it)
1765 {
1766 uint8_t measId = *it;
1767 NS_LOG_LOGIC(this << " deleting measId " << (uint32_t)measId);
1768 m_varMeasConfig.measIdList.erase(measId);
1769 VarMeasReportListClear(measId);
1770
1771 // removing time-to-trigger queues
1772 m_enteringTriggerQueue.erase(measId);
1773 m_leavingTriggerQueue.erase(measId);
1774 }
1775
1776 // 3GPP TS 36.331 section 5.5.2.3 Measurement identity addition/ modification
1777 for (auto it = mc.measIdToAddModList.begin(); it != mc.measIdToAddModList.end(); ++it)
1778 {
1779 NS_LOG_LOGIC(this << " measId " << (uint32_t)it->measId
1780 << " (measObjectId=" << (uint32_t)it->measObjectId
1781 << ", reportConfigId=" << (uint32_t)it->reportConfigId << ")");
1782 NS_ASSERT(m_varMeasConfig.measObjectList.find(it->measObjectId) !=
1784 NS_ASSERT(m_varMeasConfig.reportConfigList.find(it->reportConfigId) !=
1786 m_varMeasConfig.measIdList[it->measId] = *it; // side effect: create new entry if not exists
1787 auto measReportIt = m_varMeasReportList.find(it->measId);
1788 if (measReportIt != m_varMeasReportList.end())
1789 {
1790 measReportIt->second.periodicReportTimer.Cancel();
1791 m_varMeasReportList.erase(measReportIt);
1792 }
1793 NS_ASSERT(m_varMeasConfig.reportConfigList.find(it->reportConfigId)
1794 ->second.reportConfigEutra.triggerType !=
1796
1797 // new empty queues for time-to-trigger
1798 std::list<PendingTrigger_t> s;
1799 m_enteringTriggerQueue[it->measId] = s;
1800 m_leavingTriggerQueue[it->measId] = s;
1801 }
1802
1803 if (mc.haveMeasGapConfig)
1804 {
1805 NS_FATAL_ERROR("measurement gaps are currently not supported");
1806 }
1807
1808 if (mc.haveSmeasure)
1809 {
1810 NS_FATAL_ERROR("s-measure is currently not supported");
1811 }
1812
1813 if (mc.haveSpeedStatePars)
1814 {
1815 NS_FATAL_ERROR("SpeedStatePars are currently not supported");
1816 }
1817}
1818
1819void
1821 double rsrp,
1822 double rsrq,
1823 bool useLayer3Filtering,
1824 uint8_t componentCarrierId)
1825{
1826 NS_LOG_FUNCTION(this << cellId << +componentCarrierId << rsrp << rsrq << useLayer3Filtering);
1827
1828 auto storedMeasIt = m_storedMeasValues.find(cellId);
1829
1830 if (storedMeasIt != m_storedMeasValues.end())
1831 {
1832 if (useLayer3Filtering)
1833 {
1834 // F_n = (1-a) F_{n-1} + a M_n
1835 storedMeasIt->second.rsrp = (1 - m_varMeasConfig.aRsrp) * storedMeasIt->second.rsrp +
1836 m_varMeasConfig.aRsrp * rsrp;
1837
1838 if (std::isnan(storedMeasIt->second.rsrq))
1839 {
1840 // the previous RSRQ measurements provided UE PHY are invalid
1841 storedMeasIt->second.rsrq = rsrq; // replace it with unfiltered value
1842 }
1843 else
1844 {
1845 storedMeasIt->second.rsrq =
1846 (1 - m_varMeasConfig.aRsrq) * storedMeasIt->second.rsrq +
1847 m_varMeasConfig.aRsrq * rsrq;
1848 }
1849 }
1850 else
1851 {
1852 storedMeasIt->second.rsrp = rsrp;
1853 storedMeasIt->second.rsrq = rsrq;
1854 }
1855 }
1856 else
1857 {
1858 // first value is always unfiltered
1859 MeasValues v;
1860 v.rsrp = rsrp;
1861 v.rsrq = rsrq;
1862 v.carrierFreq = m_cphySapProvider.at(componentCarrierId)->GetDlEarfcn();
1863
1864 std::pair<uint16_t, MeasValues> val(cellId, v);
1865 auto ret = m_storedMeasValues.insert(val);
1866 NS_ASSERT_MSG(ret.second == true, "element already existed");
1867 storedMeasIt = ret.first;
1868 }
1869
1870 NS_LOG_DEBUG(this << " IMSI " << m_imsi << " state " << m_state << ", measured cell " << cellId
1871 << ", carrier component Id " << componentCarrierId << ", new RSRP " << rsrp
1872 << " stored " << storedMeasIt->second.rsrp << ", new RSRQ " << rsrq
1873 << " stored " << storedMeasIt->second.rsrq);
1874}
1875
1876void
1878{
1879 NS_LOG_FUNCTION(this << (uint16_t)measId);
1880
1881 auto measIdIt = m_varMeasConfig.measIdList.find(measId);
1882 NS_ASSERT(measIdIt != m_varMeasConfig.measIdList.end());
1883 NS_ASSERT(measIdIt->first == measIdIt->second.measId);
1884
1885 auto reportConfigIt = m_varMeasConfig.reportConfigList.find(measIdIt->second.reportConfigId);
1886 NS_ASSERT(reportConfigIt != m_varMeasConfig.reportConfigList.end());
1887 LteRrcSap::ReportConfigEutra& reportConfigEutra = reportConfigIt->second.reportConfigEutra;
1888
1889 auto measObjectIt = m_varMeasConfig.measObjectList.find(measIdIt->second.measObjectId);
1890 NS_ASSERT(measObjectIt != m_varMeasConfig.measObjectList.end());
1891 LteRrcSap::MeasObjectEutra& measObjectEutra = measObjectIt->second.measObjectEutra;
1892
1893 auto measReportIt = m_varMeasReportList.find(measId);
1894 bool isMeasIdInReportList = (measReportIt != m_varMeasReportList.end());
1895
1896 // we don't check the purpose field, as it is only included for
1897 // triggerType == periodical, which is not supported
1899 "only triggerType == event is supported");
1900 // only EUTRA is supported, no need to check for it
1901
1902 NS_LOG_LOGIC(this << " considering measId " << (uint32_t)measId);
1903 bool eventEntryCondApplicable = false;
1904 bool eventLeavingCondApplicable = false;
1905 ConcernedCells_t concernedCellsEntry;
1906 ConcernedCells_t concernedCellsLeaving;
1907
1908 /*
1909 * Find which serving cell corresponds to measObjectEutra.carrierFreq
1910 * It is used, for example, by A1 event:
1911 * See TS 36.331 5.5.4.2: "for this measurement, consider the primary or
1912 * secondary cell that is configured on the frequency indicated in the
1913 * associated measObjectEUTRA to be the serving cell"
1914 */
1915 uint16_t servingCellId = 0;
1916 for (auto cphySapProvider : m_cphySapProvider)
1917 {
1918 if (cphySapProvider->GetDlEarfcn() == measObjectEutra.carrierFreq)
1919 {
1920 servingCellId = cphySapProvider->GetCellId();
1921 }
1922 }
1923
1924 if (servingCellId == 0)
1925 {
1926 return;
1927 }
1928
1929 switch (reportConfigEutra.eventId)
1930 {
1932 /*
1933 * Event A1 (Serving becomes better than threshold)
1934 * Please refer to 3GPP TS 36.331 Section 5.5.4.2
1935 */
1936
1937 double ms; // Ms, the measurement result of the serving cell
1938 double thresh; // Thresh, the threshold parameter for this event
1939 // Hys, the hysteresis parameter for this event.
1940 double hys =
1942
1943 switch (reportConfigEutra.triggerQuantity)
1944 {
1946 ms = m_storedMeasValues[servingCellId].rsrp;
1947
1948 NS_ASSERT(reportConfigEutra.threshold1.choice ==
1950 thresh = EutranMeasurementMapping::RsrpRange2Dbm(reportConfigEutra.threshold1.range);
1951 break;
1953 ms = m_storedMeasValues[servingCellId].rsrq;
1954 NS_ASSERT(reportConfigEutra.threshold1.choice ==
1956 thresh = EutranMeasurementMapping::RsrqRange2Db(reportConfigEutra.threshold1.range);
1957 break;
1958 default:
1959 NS_FATAL_ERROR("unsupported triggerQuantity");
1960 break;
1961 }
1962
1963 // Inequality A1-1 (Entering condition): Ms - Hys > Thresh
1964 bool entryCond = ms - hys > thresh;
1965
1966 if (entryCond)
1967 {
1968 if (!isMeasIdInReportList)
1969 {
1970 concernedCellsEntry.push_back(servingCellId);
1971 eventEntryCondApplicable = true;
1972 }
1973 else
1974 {
1975 /*
1976 * This is to check that the triggered cell recorded in the
1977 * VarMeasReportList is the serving cell.
1978 */
1979 NS_ASSERT(measReportIt->second.cellsTriggeredList.find(servingCellId) !=
1980 measReportIt->second.cellsTriggeredList.end());
1981 }
1982 }
1983 else if (reportConfigEutra.timeToTrigger > 0)
1984 {
1985 CancelEnteringTrigger(measId);
1986 }
1987
1988 // Inequality A1-2 (Leaving condition): Ms + Hys < Thresh
1989 bool leavingCond = ms + hys < thresh;
1990
1991 if (leavingCond)
1992 {
1993 if (isMeasIdInReportList)
1994 {
1995 /*
1996 * This is to check that the triggered cell recorded in the
1997 * VarMeasReportList is the serving cell.
1998 */
1999 NS_ASSERT(measReportIt->second.cellsTriggeredList.find(m_cellId) !=
2000 measReportIt->second.cellsTriggeredList.end());
2001 concernedCellsLeaving.push_back(m_cellId);
2002 eventLeavingCondApplicable = true;
2003 }
2004 }
2005 else if (reportConfigEutra.timeToTrigger > 0)
2006 {
2007 CancelLeavingTrigger(measId);
2008 }
2009
2010 NS_LOG_LOGIC(this << " event A1: serving cell " << servingCellId << " ms=" << ms
2011 << " thresh=" << thresh << " entryCond=" << entryCond
2012 << " leavingCond=" << leavingCond);
2013 }
2014
2015 break;
2016
2018 /*
2019 * Event A2 (Serving becomes worse than threshold)
2020 * Please refer to 3GPP TS 36.331 Section 5.5.4.3
2021 */
2022
2023 double ms; // Ms, the measurement result of the serving cell
2024 double thresh; // Thresh, the threshold parameter for this event
2025 // Hys, the hysteresis parameter for this event.
2026 double hys =
2028
2029 switch (reportConfigEutra.triggerQuantity)
2030 {
2032 ms = m_storedMeasValues[servingCellId].rsrp;
2033 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2035 thresh = EutranMeasurementMapping::RsrpRange2Dbm(reportConfigEutra.threshold1.range);
2036 break;
2038 ms = m_storedMeasValues[servingCellId].rsrq;
2039 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2041 thresh = EutranMeasurementMapping::RsrqRange2Db(reportConfigEutra.threshold1.range);
2042 break;
2043 default:
2044 NS_FATAL_ERROR("unsupported triggerQuantity");
2045 break;
2046 }
2047
2048 // Inequality A2-1 (Entering condition): Ms + Hys < Thresh
2049 bool entryCond = ms + hys < thresh;
2050
2051 if (entryCond)
2052 {
2053 if (!isMeasIdInReportList)
2054 {
2055 concernedCellsEntry.push_back(servingCellId);
2056 eventEntryCondApplicable = true;
2057 }
2058 else
2059 {
2060 /*
2061 * This is to check that the triggered cell recorded in the
2062 * VarMeasReportList is the serving cell.
2063 */
2064 NS_ASSERT(measReportIt->second.cellsTriggeredList.find(servingCellId) !=
2065 measReportIt->second.cellsTriggeredList.end());
2066 }
2067 }
2068 else if (reportConfigEutra.timeToTrigger > 0)
2069 {
2070 CancelEnteringTrigger(measId);
2071 }
2072
2073 // Inequality A2-2 (Leaving condition): Ms - Hys > Thresh
2074 bool leavingCond = ms - hys > thresh;
2075
2076 if (leavingCond)
2077 {
2078 if (isMeasIdInReportList)
2079 {
2080 /*
2081 * This is to check that the triggered cell recorded in the
2082 * VarMeasReportList is the serving cell.
2083 */
2084 NS_ASSERT(measReportIt->second.cellsTriggeredList.find(servingCellId) !=
2085 measReportIt->second.cellsTriggeredList.end());
2086 concernedCellsLeaving.push_back(servingCellId);
2087 eventLeavingCondApplicable = true;
2088 }
2089 }
2090 else if (reportConfigEutra.timeToTrigger > 0)
2091 {
2092 CancelLeavingTrigger(measId);
2093 }
2094
2095 NS_LOG_LOGIC(this << " event A2: serving cell " << servingCellId << " ms=" << ms
2096 << " thresh=" << thresh << " entryCond=" << entryCond
2097 << " leavingCond=" << leavingCond);
2098 }
2099
2100 break;
2101
2103 /*
2104 * Event A3 (Neighbour becomes offset better than PCell)
2105 * Please refer to 3GPP TS 36.331 Section 5.5.4.4
2106 */
2107
2108 double mn; // Mn, the measurement result of the neighbouring cell
2109 double ofn = measObjectEutra
2110 .offsetFreq; // Ofn, the frequency specific offset of the frequency of the
2111 double ocn = 0.0; // Ocn, the cell specific offset of the neighbour cell
2112 double mp; // Mp, the measurement result of the PCell
2113 double ofp = measObjectEutra
2114 .offsetFreq; // Ofp, the frequency specific offset of the primary frequency
2115 double ocp = 0.0; // Ocp, the cell specific offset of the PCell
2116 // Off, the offset parameter for this event.
2117 double off = EutranMeasurementMapping::IeValue2ActualA3Offset(reportConfigEutra.a3Offset);
2118 // Hys, the hysteresis parameter for this event.
2119 double hys =
2121
2122 switch (reportConfigEutra.triggerQuantity)
2123 {
2125 mp = m_storedMeasValues[m_cellId].rsrp;
2126 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2128 break;
2130 mp = m_storedMeasValues[m_cellId].rsrq;
2131 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2133 break;
2134 default:
2135 NS_FATAL_ERROR("unsupported triggerQuantity");
2136 break;
2137 }
2138
2139 for (auto storedMeasIt = m_storedMeasValues.begin();
2140 storedMeasIt != m_storedMeasValues.end();
2141 ++storedMeasIt)
2142 {
2143 uint16_t cellId = storedMeasIt->first;
2144 if (cellId == m_cellId)
2145 {
2146 continue;
2147 }
2148
2149 // Only cell(s) on the frequency indicated in the associated measObject can trigger
2150 // event.
2151 if (m_storedMeasValues.at(cellId).carrierFreq != measObjectEutra.carrierFreq)
2152 {
2153 continue;
2154 }
2155
2156 switch (reportConfigEutra.triggerQuantity)
2157 {
2159 mn = storedMeasIt->second.rsrp;
2160 break;
2162 mn = storedMeasIt->second.rsrq;
2163 break;
2164 default:
2165 NS_FATAL_ERROR("unsupported triggerQuantity");
2166 break;
2167 }
2168
2169 bool hasTriggered =
2170 isMeasIdInReportList && (measReportIt->second.cellsTriggeredList.find(cellId) !=
2171 measReportIt->second.cellsTriggeredList.end());
2172
2173 // Inequality A3-1 (Entering condition): Mn + Ofn + Ocn - Hys > Mp + Ofp + Ocp + Off
2174 bool entryCond = mn + ofn + ocn - hys > mp + ofp + ocp + off;
2175
2176 if (entryCond)
2177 {
2178 if (!hasTriggered)
2179 {
2180 concernedCellsEntry.push_back(cellId);
2181 eventEntryCondApplicable = true;
2182 }
2183 }
2184 else if (reportConfigEutra.timeToTrigger > 0)
2185 {
2186 CancelEnteringTrigger(measId, cellId);
2187 }
2188
2189 // Inequality A3-2 (Leaving condition): Mn + Ofn + Ocn + Hys < Mp + Ofp + Ocp + Off
2190 bool leavingCond = mn + ofn + ocn + hys < mp + ofp + ocp + off;
2191
2192 if (leavingCond)
2193 {
2194 if (hasTriggered)
2195 {
2196 concernedCellsLeaving.push_back(cellId);
2197 eventLeavingCondApplicable = true;
2198 }
2199 }
2200 else if (reportConfigEutra.timeToTrigger > 0)
2201 {
2202 CancelLeavingTrigger(measId, cellId);
2203 }
2204
2205 NS_LOG_LOGIC(this << " event A3: neighbor cell " << cellId << " mn=" << mn
2206 << " mp=" << mp << " offset=" << off << " entryCond=" << entryCond
2207 << " leavingCond=" << leavingCond);
2208 }
2209 }
2210
2211 break;
2212
2214 /*
2215 * Event A4 (Neighbour becomes better than threshold)
2216 * Please refer to 3GPP TS 36.331 Section 5.5.4.5
2217 */
2218
2219 double mn; // Mn, the measurement result of the neighbouring cell
2220 double ofn = measObjectEutra
2221 .offsetFreq; // Ofn, the frequency specific offset of the frequency of the
2222 double ocn = 0.0; // Ocn, the cell specific offset of the neighbour cell
2223 double thresh; // Thresh, the threshold parameter for this event
2224 // Hys, the hysteresis parameter for this event.
2225 double hys =
2227
2228 switch (reportConfigEutra.triggerQuantity)
2229 {
2231 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2233 thresh = EutranMeasurementMapping::RsrpRange2Dbm(reportConfigEutra.threshold1.range);
2234 break;
2236 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2238 thresh = EutranMeasurementMapping::RsrqRange2Db(reportConfigEutra.threshold1.range);
2239 break;
2240 default:
2241 NS_FATAL_ERROR("unsupported triggerQuantity");
2242 break;
2243 }
2244
2245 for (auto storedMeasIt = m_storedMeasValues.begin();
2246 storedMeasIt != m_storedMeasValues.end();
2247 ++storedMeasIt)
2248 {
2249 uint16_t cellId = storedMeasIt->first;
2250 if (cellId == m_cellId)
2251 {
2252 continue;
2253 }
2254
2255 switch (reportConfigEutra.triggerQuantity)
2256 {
2258 mn = storedMeasIt->second.rsrp;
2259 break;
2261 mn = storedMeasIt->second.rsrq;
2262 break;
2263 default:
2264 NS_FATAL_ERROR("unsupported triggerQuantity");
2265 break;
2266 }
2267
2268 bool hasTriggered =
2269 isMeasIdInReportList && (measReportIt->second.cellsTriggeredList.find(cellId) !=
2270 measReportIt->second.cellsTriggeredList.end());
2271
2272 // Inequality A4-1 (Entering condition): Mn + Ofn + Ocn - Hys > Thresh
2273 bool entryCond = mn + ofn + ocn - hys > thresh;
2274
2275 if (entryCond)
2276 {
2277 if (!hasTriggered)
2278 {
2279 concernedCellsEntry.push_back(cellId);
2280 eventEntryCondApplicable = true;
2281 }
2282 }
2283 else if (reportConfigEutra.timeToTrigger > 0)
2284 {
2285 CancelEnteringTrigger(measId, cellId);
2286 }
2287
2288 // Inequality A4-2 (Leaving condition): Mn + Ofn + Ocn + Hys < Thresh
2289 bool leavingCond = mn + ofn + ocn + hys < thresh;
2290
2291 if (leavingCond)
2292 {
2293 if (hasTriggered)
2294 {
2295 concernedCellsLeaving.push_back(cellId);
2296 eventLeavingCondApplicable = true;
2297 }
2298 }
2299 else if (reportConfigEutra.timeToTrigger > 0)
2300 {
2301 CancelLeavingTrigger(measId, cellId);
2302 }
2303
2304 NS_LOG_LOGIC(this << " event A4: neighbor cell " << cellId << " mn=" << mn
2305 << " thresh=" << thresh << " entryCond=" << entryCond
2306 << " leavingCond=" << leavingCond);
2307 }
2308 }
2309
2310 break;
2311
2313 /*
2314 * Event A5 (PCell becomes worse than threshold1 and neighbour
2315 * becomes better than threshold2)
2316 * Please refer to 3GPP TS 36.331 Section 5.5.4.6
2317 */
2318
2319 double mp; // Mp, the measurement result of the PCell
2320 double mn; // Mn, the measurement result of the neighbouring cell
2321 double ofn = measObjectEutra
2322 .offsetFreq; // Ofn, the frequency specific offset of the frequency of the
2323 double ocn = 0.0; // Ocn, the cell specific offset of the neighbour cell
2324 double thresh1; // Thresh1, the threshold parameter for this event
2325 double thresh2; // Thresh2, the threshold parameter for this event
2326 // Hys, the hysteresis parameter for this event.
2327 double hys =
2329
2330 switch (reportConfigEutra.triggerQuantity)
2331 {
2333 mp = m_storedMeasValues[m_cellId].rsrp;
2334 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2336 NS_ASSERT(reportConfigEutra.threshold2.choice ==
2338 thresh1 = EutranMeasurementMapping::RsrpRange2Dbm(reportConfigEutra.threshold1.range);
2339 thresh2 = EutranMeasurementMapping::RsrpRange2Dbm(reportConfigEutra.threshold2.range);
2340 break;
2342 mp = m_storedMeasValues[m_cellId].rsrq;
2343 NS_ASSERT(reportConfigEutra.threshold1.choice ==
2345 NS_ASSERT(reportConfigEutra.threshold2.choice ==
2347 thresh1 = EutranMeasurementMapping::RsrqRange2Db(reportConfigEutra.threshold1.range);
2348 thresh2 = EutranMeasurementMapping::RsrqRange2Db(reportConfigEutra.threshold2.range);
2349 break;
2350 default:
2351 NS_FATAL_ERROR("unsupported triggerQuantity");
2352 break;
2353 }
2354
2355 // Inequality A5-1 (Entering condition 1): Mp + Hys < Thresh1
2356 bool entryCond = mp + hys < thresh1;
2357
2358 if (entryCond)
2359 {
2360 for (auto storedMeasIt = m_storedMeasValues.begin();
2361 storedMeasIt != m_storedMeasValues.end();
2362 ++storedMeasIt)
2363 {
2364 uint16_t cellId = storedMeasIt->first;
2365 if (cellId == m_cellId)
2366 {
2367 continue;
2368 }
2369
2370 switch (reportConfigEutra.triggerQuantity)
2371 {
2373 mn = storedMeasIt->second.rsrp;
2374 break;
2376 mn = storedMeasIt->second.rsrq;
2377 break;
2378 default:
2379 NS_FATAL_ERROR("unsupported triggerQuantity");
2380 break;
2381 }
2382
2383 bool hasTriggered =
2384 isMeasIdInReportList && (measReportIt->second.cellsTriggeredList.find(cellId) !=
2385 measReportIt->second.cellsTriggeredList.end());
2386
2387 // Inequality A5-2 (Entering condition 2): Mn + Ofn + Ocn - Hys > Thresh2
2388
2389 entryCond = mn + ofn + ocn - hys > thresh2;
2390
2391 if (entryCond)
2392 {
2393 if (!hasTriggered)
2394 {
2395 concernedCellsEntry.push_back(cellId);
2396 eventEntryCondApplicable = true;
2397 }
2398 }
2399 else if (reportConfigEutra.timeToTrigger > 0)
2400 {
2401 CancelEnteringTrigger(measId, cellId);
2402 }
2403
2404 NS_LOG_LOGIC(this << " event A5: neighbor cell " << cellId << " mn=" << mn
2405 << " mp=" << mp << " thresh2=" << thresh2
2406 << " thresh1=" << thresh1 << " entryCond=" << entryCond);
2407 }
2408 }
2409 else
2410 {
2411 NS_LOG_LOGIC(this << " event A5: serving cell " << m_cellId << " mp=" << mp
2412 << " thresh1=" << thresh1 << " entryCond=" << entryCond);
2413
2414 if (reportConfigEutra.timeToTrigger > 0)
2415 {
2416 CancelEnteringTrigger(measId);
2417 }
2418 }
2419
2420 if (isMeasIdInReportList)
2421 {
2422 // Inequality A5-3 (Leaving condition 1): Mp - Hys > Thresh1
2423 bool leavingCond = mp - hys > thresh1;
2424
2425 if (leavingCond)
2426 {
2427 if (reportConfigEutra.timeToTrigger == 0)
2428 {
2429 // leaving condition #2 does not have to be checked
2430
2431 for (auto storedMeasIt = m_storedMeasValues.begin();
2432 storedMeasIt != m_storedMeasValues.end();
2433 ++storedMeasIt)
2434 {
2435 uint16_t cellId = storedMeasIt->first;
2436 if (cellId == m_cellId)
2437 {
2438 continue;
2439 }
2440
2441 if (measReportIt->second.cellsTriggeredList.find(cellId) !=
2442 measReportIt->second.cellsTriggeredList.end())
2443 {
2444 concernedCellsLeaving.push_back(cellId);
2445 eventLeavingCondApplicable = true;
2446 }
2447 }
2448 }
2449 else
2450 {
2451 // leaving condition #2 has to be checked to cancel time-to-trigger
2452
2453 for (auto storedMeasIt = m_storedMeasValues.begin();
2454 storedMeasIt != m_storedMeasValues.end();
2455 ++storedMeasIt)
2456 {
2457 uint16_t cellId = storedMeasIt->first;
2458 if (cellId == m_cellId)
2459 {
2460 continue;
2461 }
2462
2463 if (measReportIt->second.cellsTriggeredList.find(cellId) !=
2464 measReportIt->second.cellsTriggeredList.end())
2465 {
2466 switch (reportConfigEutra.triggerQuantity)
2467 {
2469 mn = storedMeasIt->second.rsrp;
2470 break;
2472 mn = storedMeasIt->second.rsrq;
2473 break;
2474 default:
2475 NS_FATAL_ERROR("unsupported triggerQuantity");
2476 break;
2477 }
2478
2479 // Inequality A5-4 (Leaving condition 2): Mn + Ofn + Ocn + Hys < Thresh2
2480
2481 leavingCond = mn + ofn + ocn + hys < thresh2;
2482
2483 if (!leavingCond)
2484 {
2485 CancelLeavingTrigger(measId, cellId);
2486 }
2487
2488 /*
2489 * Whatever the result of leaving condition #2, this
2490 * cell is still "in", because leaving condition #1
2491 * is already true.
2492 */
2493 concernedCellsLeaving.push_back(cellId);
2494 eventLeavingCondApplicable = true;
2495
2496 NS_LOG_LOGIC(this << " event A5: neighbor cell " << cellId
2497 << " mn=" << mn << " mp=" << mp
2498 << " thresh2=" << thresh2 << " thresh1=" << thresh1
2499 << " leavingCond=" << leavingCond);
2500 }
2501 }
2502 }
2503
2504 NS_LOG_LOGIC(this << " event A5: serving cell " << m_cellId << " mp=" << mp
2505 << " thresh1=" << thresh1 << " leavingCond=" << leavingCond);
2506 }
2507 else
2508 {
2509 if (reportConfigEutra.timeToTrigger > 0)
2510 {
2511 CancelLeavingTrigger(measId);
2512 }
2513
2514 // check leaving condition #2
2515
2516 for (auto storedMeasIt = m_storedMeasValues.begin();
2517 storedMeasIt != m_storedMeasValues.end();
2518 ++storedMeasIt)
2519 {
2520 uint16_t cellId = storedMeasIt->first;
2521 if (cellId == m_cellId)
2522 {
2523 continue;
2524 }
2525
2526 if (measReportIt->second.cellsTriggeredList.find(cellId) !=
2527 measReportIt->second.cellsTriggeredList.end())
2528 {
2529 switch (reportConfigEutra.triggerQuantity)
2530 {
2532 mn = storedMeasIt->second.rsrp;
2533 break;
2535 mn = storedMeasIt->second.rsrq;
2536 break;
2537 default:
2538 NS_FATAL_ERROR("unsupported triggerQuantity");
2539 break;
2540 }
2541
2542 // Inequality A5-4 (Leaving condition 2): Mn + Ofn + Ocn + Hys < Thresh2
2543 leavingCond = mn + ofn + ocn + hys < thresh2;
2544
2545 if (leavingCond)
2546 {
2547 concernedCellsLeaving.push_back(cellId);
2548 eventLeavingCondApplicable = true;
2549 }
2550
2551 NS_LOG_LOGIC(this << " event A5: neighbor cell " << cellId << " mn=" << mn
2552 << " mp=" << mp << " thresh2=" << thresh2 << " thresh1="
2553 << thresh1 << " leavingCond=" << leavingCond);
2554 }
2555 }
2556 }
2557 }
2558 }
2559
2560 break;
2561
2562 default:
2563 NS_FATAL_ERROR("unsupported eventId " << reportConfigEutra.eventId);
2564 break;
2565 }
2566
2567 NS_LOG_LOGIC(this << " eventEntryCondApplicable=" << eventEntryCondApplicable
2568 << " eventLeavingCondApplicable=" << eventLeavingCondApplicable);
2569
2570 if (eventEntryCondApplicable)
2571 {
2572 if (reportConfigEutra.timeToTrigger == 0)
2573 {
2574 VarMeasReportListAdd(measId, concernedCellsEntry);
2575 }
2576 else
2577 {
2579 t.measId = measId;
2580 t.concernedCells = concernedCellsEntry;
2581 t.timer = Simulator::Schedule(MilliSeconds(reportConfigEutra.timeToTrigger),
2583 this,
2584 measId,
2585 concernedCellsEntry);
2586 auto enteringTriggerIt = m_enteringTriggerQueue.find(measId);
2587 NS_ASSERT(enteringTriggerIt != m_enteringTriggerQueue.end());
2588 enteringTriggerIt->second.push_back(t);
2589 }
2590 }
2591
2592 if (eventLeavingCondApplicable)
2593 {
2594 // reportOnLeave will only be set when eventId = eventA3
2595 bool reportOnLeave =
2596 (reportConfigEutra.eventId == LteRrcSap::ReportConfigEutra::EVENT_A3) &&
2597 reportConfigEutra.reportOnLeave;
2598
2599 if (reportConfigEutra.timeToTrigger == 0)
2600 {
2601 VarMeasReportListErase(measId, concernedCellsLeaving, reportOnLeave);
2602 }
2603 else
2604 {
2606 t.measId = measId;
2607 t.concernedCells = concernedCellsLeaving;
2608 t.timer = Simulator::Schedule(MilliSeconds(reportConfigEutra.timeToTrigger),
2610 this,
2611 measId,
2612 concernedCellsLeaving,
2613 reportOnLeave);
2614 auto leavingTriggerIt = m_leavingTriggerQueue.find(measId);
2615 NS_ASSERT(leavingTriggerIt != m_leavingTriggerQueue.end());
2616 leavingTriggerIt->second.push_back(t);
2617 }
2618 }
2619}
2620
2621void
2623{
2624 NS_LOG_FUNCTION(this << (uint16_t)measId);
2625
2626 auto it1 = m_enteringTriggerQueue.find(measId);
2627 NS_ASSERT(it1 != m_enteringTriggerQueue.end());
2628
2629 if (!it1->second.empty())
2630 {
2631 for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
2632 {
2633 NS_ASSERT(it2->measId == measId);
2634 NS_LOG_LOGIC(this << " canceling entering time-to-trigger event at "
2635 << Simulator::GetDelayLeft(it2->timer).GetSeconds());
2636 Simulator::Cancel(it2->timer);
2637 }
2638
2639 it1->second.clear();
2640 }
2641}
2642
2643void
2644LteUeRrc::CancelEnteringTrigger(uint8_t measId, uint16_t cellId)
2645{
2646 NS_LOG_FUNCTION(this << (uint16_t)measId << cellId);
2647
2648 auto it1 = m_enteringTriggerQueue.find(measId);
2649 NS_ASSERT(it1 != m_enteringTriggerQueue.end());
2650
2651 auto it2 = it1->second.begin();
2652 while (it2 != it1->second.end())
2653 {
2654 NS_ASSERT(it2->measId == measId);
2655
2656 it2->concernedCells.remove_if([cellId](auto cell) { return cellId == cell; });
2657
2658 if (it2->concernedCells.empty())
2659 {
2660 NS_LOG_LOGIC(this << " canceling entering time-to-trigger event at "
2661 << Simulator::GetDelayLeft(it2->timer).GetSeconds());
2662 Simulator::Cancel(it2->timer);
2663 it2 = it1->second.erase(it2);
2664 }
2665 else
2666 {
2667 it2++;
2668 }
2669 }
2670}
2671
2672void
2674{
2675 NS_LOG_FUNCTION(this << (uint16_t)measId);
2676
2677 auto it1 = m_leavingTriggerQueue.find(measId);
2678 NS_ASSERT(it1 != m_leavingTriggerQueue.end());
2679
2680 if (!it1->second.empty())
2681 {
2682 for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
2683 {
2684 NS_ASSERT(it2->measId == measId);
2685 NS_LOG_LOGIC(this << " canceling leaving time-to-trigger event at "
2686 << Simulator::GetDelayLeft(it2->timer).GetSeconds());
2687 Simulator::Cancel(it2->timer);
2688 }
2689
2690 it1->second.clear();
2691 }
2692}
2693
2694void
2695LteUeRrc::CancelLeavingTrigger(uint8_t measId, uint16_t cellId)
2696{
2697 NS_LOG_FUNCTION(this << (uint16_t)measId << cellId);
2698
2699 auto it1 = m_leavingTriggerQueue.find(measId);
2700 NS_ASSERT(it1 != m_leavingTriggerQueue.end());
2701
2702 auto it2 = it1->second.begin();
2703 while (it2 != it1->second.end())
2704 {
2705 NS_ASSERT(it2->measId == measId);
2706
2707 it2->concernedCells.remove_if([cellId](auto cell) { return cellId == cell; });
2708
2709 if (it2->concernedCells.empty())
2710 {
2711 NS_LOG_LOGIC(this << " canceling leaving time-to-trigger event at "
2712 << Simulator::GetDelayLeft(it2->timer).GetSeconds());
2713 Simulator::Cancel(it2->timer);
2714 it2 = it1->second.erase(it2);
2715 }
2716 else
2717 {
2718 it2++;
2719 }
2720 }
2721}
2722
2723void
2725{
2726 NS_LOG_FUNCTION(this << (uint16_t)measId);
2727 NS_ASSERT(!enteringCells.empty());
2728
2729 auto measReportIt = m_varMeasReportList.find(measId);
2730
2731 if (measReportIt == m_varMeasReportList.end())
2732 {
2733 VarMeasReport r;
2734 r.measId = measId;
2735 std::pair<uint8_t, VarMeasReport> val(measId, r);
2736 auto ret = m_varMeasReportList.insert(val);
2737 NS_ASSERT_MSG(ret.second == true, "element already existed");
2738 measReportIt = ret.first;
2739 }
2740
2741 NS_ASSERT(measReportIt != m_varMeasReportList.end());
2742
2743 for (auto it = enteringCells.begin(); it != enteringCells.end(); ++it)
2744 {
2745 measReportIt->second.cellsTriggeredList.insert(*it);
2746 }
2747
2748 NS_ASSERT(!measReportIt->second.cellsTriggeredList.empty());
2749
2750 // #issue 224, schedule only when there is no periodic event scheduled already
2751 if (!measReportIt->second.periodicReportTimer.IsPending())
2752 {
2753 measReportIt->second.numberOfReportsSent = 0;
2754 measReportIt->second.periodicReportTimer =
2757 this,
2758 measId);
2759 }
2760
2761 auto enteringTriggerIt = m_enteringTriggerQueue.find(measId);
2762 NS_ASSERT(enteringTriggerIt != m_enteringTriggerQueue.end());
2763 if (!enteringTriggerIt->second.empty())
2764 {
2765 /*
2766 * Assumptions at this point:
2767 * - the call to this function was delayed by time-to-trigger;
2768 * - the time-to-trigger delay is fixed (not adaptive/dynamic); and
2769 * - the first element in the list is associated with this function call.
2770 */
2771 enteringTriggerIt->second.pop_front();
2772
2773 if (!enteringTriggerIt->second.empty())
2774 {
2775 /*
2776 * To prevent the same set of cells triggering again in the future,
2777 * we clean up the time-to-trigger queue. This case might occur when
2778 * time-to-trigger > 200 ms.
2779 */
2780 for (auto it = enteringCells.begin(); it != enteringCells.end(); ++it)
2781 {
2782 CancelEnteringTrigger(measId, *it);
2783 }
2784 }
2785 }
2786}
2787
2788void
2789LteUeRrc::VarMeasReportListErase(uint8_t measId, ConcernedCells_t leavingCells, bool reportOnLeave)
2790{
2791 NS_LOG_FUNCTION(this << (uint16_t)measId);
2792 NS_ASSERT(!leavingCells.empty());
2793
2794 auto measReportIt = m_varMeasReportList.find(measId);
2795 NS_ASSERT(measReportIt != m_varMeasReportList.end());
2796
2797 for (auto it = leavingCells.begin(); it != leavingCells.end(); ++it)
2798 {
2799 measReportIt->second.cellsTriggeredList.erase(*it);
2800 }
2801
2802 if (reportOnLeave)
2803 {
2804 // runs immediately without UE_MEASUREMENT_REPORT_DELAY
2805 SendMeasurementReport(measId);
2806 }
2807
2808 if (measReportIt->second.cellsTriggeredList.empty())
2809 {
2810 measReportIt->second.periodicReportTimer.Cancel();
2811 m_varMeasReportList.erase(measReportIt);
2812 }
2813
2814 auto leavingTriggerIt = m_leavingTriggerQueue.find(measId);
2815 NS_ASSERT(leavingTriggerIt != m_leavingTriggerQueue.end());
2816 if (!leavingTriggerIt->second.empty())
2817 {
2818 /*
2819 * Assumptions at this point:
2820 * - the call to this function was delayed by time-to-trigger; and
2821 * - the time-to-trigger delay is fixed (not adaptive/dynamic); and
2822 * - the first element in the list is associated with this function call.
2823 */
2824 leavingTriggerIt->second.pop_front();
2825
2826 if (!leavingTriggerIt->second.empty())
2827 {
2828 /*
2829 * To prevent the same set of cells triggering again in the future,
2830 * we clean up the time-to-trigger queue. This case might occur when
2831 * time-to-trigger > 200 ms.
2832 */
2833 for (auto it = leavingCells.begin(); it != leavingCells.end(); ++it)
2834 {
2835 CancelLeavingTrigger(measId, *it);
2836 }
2837 }
2838 }
2839}
2840
2841void
2843{
2844 NS_LOG_FUNCTION(this << (uint16_t)measId);
2845
2846 // remove the measurement reporting entry for this measId from the VarMeasReportList
2847 auto measReportIt = m_varMeasReportList.find(measId);
2848 if (measReportIt != m_varMeasReportList.end())
2849 {
2850 NS_LOG_LOGIC(this << " deleting existing report for measId " << (uint16_t)measId);
2851 measReportIt->second.periodicReportTimer.Cancel();
2852 m_varMeasReportList.erase(measReportIt);
2853 }
2854
2855 CancelEnteringTrigger(measId);
2856 CancelLeavingTrigger(measId);
2857}
2858
2859void
2861{
2862 NS_LOG_FUNCTION(this << (uint16_t)measId);
2863 // 3GPP TS 36.331 section 5.5.5 Measurement reporting
2864
2865 auto measIdIt = m_varMeasConfig.measIdList.find(measId);
2866 NS_ASSERT(measIdIt != m_varMeasConfig.measIdList.end());
2867
2868 auto reportConfigIt = m_varMeasConfig.reportConfigList.find(measIdIt->second.reportConfigId);
2869 NS_ASSERT(reportConfigIt != m_varMeasConfig.reportConfigList.end());
2870 LteRrcSap::ReportConfigEutra& reportConfigEutra = reportConfigIt->second.reportConfigEutra;
2871
2872 LteRrcSap::MeasurementReport measurementReport;
2873 LteRrcSap::MeasResults& measResults = measurementReport.measResults;
2874 measResults.measId = measId;
2875
2876 auto measReportIt = m_varMeasReportList.find(measId);
2877 if (measReportIt == m_varMeasReportList.end())
2878 {
2879 NS_LOG_ERROR("no entry found in m_varMeasReportList for measId " << (uint32_t)measId);
2880 }
2881 else
2882 {
2883 auto servingMeasIt = m_storedMeasValues.find(m_cellId);
2884 NS_ASSERT(servingMeasIt != m_storedMeasValues.end());
2885 measResults.measResultPCell.rsrpResult =
2886 EutranMeasurementMapping::Dbm2RsrpRange(servingMeasIt->second.rsrp);
2887 measResults.measResultPCell.rsrqResult =
2888 EutranMeasurementMapping::Db2RsrqRange(servingMeasIt->second.rsrq);
2889 NS_LOG_INFO(this << " reporting serving cell "
2890 "RSRP "
2891 << +measResults.measResultPCell.rsrpResult << " ("
2892 << servingMeasIt->second.rsrp
2893 << " dBm) "
2894 "RSRQ "
2895 << +measResults.measResultPCell.rsrqResult << " ("
2896 << servingMeasIt->second.rsrq << " dB)");
2897
2898 measResults.haveMeasResultServFreqList = false;
2899 for (uint16_t componentCarrierId = 1; componentCarrierId < m_numberOfComponentCarriers;
2900 componentCarrierId++)
2901 {
2902 const uint16_t cellId = m_cphySapProvider.at(componentCarrierId)->GetCellId();
2903 auto measValuesIt = m_storedMeasValues.find(cellId);
2904 if (measValuesIt != m_storedMeasValues.end())
2905 {
2906 measResults.haveMeasResultServFreqList = true;
2907 LteRrcSap::MeasResultServFreq measResultServFreq;
2908 measResultServFreq.servFreqId = componentCarrierId;
2909 measResultServFreq.haveMeasResultSCell = true;
2910 measResultServFreq.measResultSCell.rsrpResult =
2911 EutranMeasurementMapping::Dbm2RsrpRange(measValuesIt->second.rsrp);
2912 measResultServFreq.measResultSCell.rsrqResult =
2913 EutranMeasurementMapping::Db2RsrqRange(measValuesIt->second.rsrq);
2914 measResultServFreq.haveMeasResultBestNeighCell = false;
2915 measResults.measResultServFreqList.push_back(measResultServFreq);
2916 }
2917 }
2918
2919 measResults.haveMeasResultNeighCells = false;
2920
2921 if (!(measReportIt->second.cellsTriggeredList.empty()))
2922 {
2923 std::multimap<double, uint16_t> sortedNeighCells;
2924 for (auto cellsTriggeredIt = measReportIt->second.cellsTriggeredList.begin();
2925 cellsTriggeredIt != measReportIt->second.cellsTriggeredList.end();
2926 ++cellsTriggeredIt)
2927 {
2928 uint16_t cellId = *cellsTriggeredIt;
2929 if (cellId != m_cellId)
2930 {
2931 auto neighborMeasIt = m_storedMeasValues.find(cellId);
2932 double triggerValue;
2933 switch (reportConfigEutra.triggerQuantity)
2934 {
2936 triggerValue = neighborMeasIt->second.rsrp;
2937 break;
2939 triggerValue = neighborMeasIt->second.rsrq;
2940 break;
2941 default:
2942 NS_FATAL_ERROR("unsupported triggerQuantity");
2943 break;
2944 }
2945 sortedNeighCells.insert(std::pair<double, uint16_t>(triggerValue, cellId));
2946 }
2947 }
2948
2949 std::multimap<double, uint16_t>::reverse_iterator sortedNeighCellsIt;
2950 uint32_t count;
2951 for (sortedNeighCellsIt = sortedNeighCells.rbegin(), count = 0;
2952 sortedNeighCellsIt != sortedNeighCells.rend() &&
2953 count < reportConfigEutra.maxReportCells;
2954 ++sortedNeighCellsIt, ++count)
2955 {
2956 uint16_t cellId = sortedNeighCellsIt->second;
2957 auto neighborMeasIt = m_storedMeasValues.find(cellId);
2958 NS_ASSERT(neighborMeasIt != m_storedMeasValues.end());
2959 LteRrcSap::MeasResultEutra measResultEutra;
2960 measResultEutra.physCellId = cellId;
2961 measResultEutra.haveCgiInfo = false;
2962 measResultEutra.haveRsrpResult = true;
2963 measResultEutra.rsrpResult =
2964 EutranMeasurementMapping::Dbm2RsrpRange(neighborMeasIt->second.rsrp);
2965 measResultEutra.haveRsrqResult = true;
2966 measResultEutra.rsrqResult =
2967 EutranMeasurementMapping::Db2RsrqRange(neighborMeasIt->second.rsrq);
2968 NS_LOG_INFO(this << " reporting neighbor cell "
2969 << (uint32_t)measResultEutra.physCellId << " RSRP "
2970 << (uint32_t)measResultEutra.rsrpResult << " ("
2971 << neighborMeasIt->second.rsrp << " dBm)"
2972 << " RSRQ " << (uint32_t)measResultEutra.rsrqResult << " ("
2973 << neighborMeasIt->second.rsrq << " dB)");
2974 measResults.measResultListEutra.push_back(measResultEutra);
2975 measResults.haveMeasResultNeighCells = true;
2976 }
2977 }
2978 else
2979 {
2980 NS_LOG_WARN(this << " cellsTriggeredList is empty");
2981 }
2982
2983 /*
2984 * The current LteRrcSap implementation is broken in that it does not
2985 * allow for infinite values of reportAmount, which is probably the most
2986 * reasonable setting. So we just always assume infinite reportAmount.
2987 */
2988 measReportIt->second.numberOfReportsSent++;
2989 measReportIt->second.periodicReportTimer.Cancel();
2990
2991 Time reportInterval;
2992 switch (reportConfigEutra.reportInterval)
2993 {
2995 reportInterval = MilliSeconds(120);
2996 break;
2998 reportInterval = MilliSeconds(240);
2999 break;
3001 reportInterval = MilliSeconds(480);
3002 break;
3004 reportInterval = MilliSeconds(640);
3005 break;
3007 reportInterval = MilliSeconds(1024);
3008 break;
3010 reportInterval = MilliSeconds(2048);
3011 break;
3013 reportInterval = MilliSeconds(5120);
3014 break;
3016 reportInterval = MilliSeconds(10240);
3017 break;
3019 reportInterval = Seconds(60);
3020 break;
3022 reportInterval = Seconds(360);
3023 break;
3025 reportInterval = Seconds(720);
3026 break;
3028 reportInterval = Seconds(1800);
3029 break;
3031 reportInterval = Seconds(3600);
3032 break;
3033 default:
3034 NS_FATAL_ERROR("Unsupported reportInterval "
3035 << (uint16_t)reportConfigEutra.reportInterval);
3036 break;
3037 }
3038
3039 // schedule the next measurement reporting
3040 measReportIt->second.periodicReportTimer =
3041 Simulator::Schedule(reportInterval, &LteUeRrc::SendMeasurementReport, this, measId);
3042
3043 // send the measurement report to eNodeB
3044 m_rrcSapUser->SendMeasurementReport(measurementReport);
3045 }
3046}
3047
3048void
3050{
3051 NS_LOG_FUNCTION(this << m_imsi);
3054 m_connectionPending = false; // reset the flag
3056 m_cmacSapProvider.at(0)->StartContentionBasedRandomAccessProcedure();
3057}
3058
3059void
3061{
3062 NS_LOG_FUNCTION(this << m_imsi);
3063 m_leaveConnectedMode = true;
3064 m_storedMeasValues.clear();
3066
3067 for (auto measIdIt = m_varMeasConfig.measIdList.begin();
3068 measIdIt != m_varMeasConfig.measIdList.end();
3069 ++measIdIt)
3070 {
3071 VarMeasReportListClear(measIdIt->second.measId);
3072 }
3074
3076
3077 for (uint32_t i = 0; i < m_numberOfComponentCarriers; i++)
3078 {
3079 m_cmacSapProvider.at(i)->Reset(); // reset the MAC
3080 }
3081
3082 m_drbMap.clear();
3083 m_bid2DrbidMap.clear();
3084 m_srb1 = nullptr;
3085 m_hasReceivedMib = false;
3086 m_hasReceivedSib1 = false;
3087 m_hasReceivedSib2 = false;
3088
3089 for (uint32_t i = 0; i < m_numberOfComponentCarriers; i++)
3090 {
3091 m_cphySapProvider.at(i)->ResetPhyAfterRlf(); // reset the PHY
3092 }
3095 // Save the cell id UE was attached to
3097 m_cellId = 0;
3098 m_rnti = 0;
3099 m_srb0->m_rlc->SetRnti(m_rnti);
3100}
3101
3102void
3104{
3105 NS_LOG_FUNCTION(this << m_imsi);
3108 {
3111 // Assumption: The eNB connection request timer would expire
3112 // before the expiration of T300 at UE. Upon which, the eNB deletes
3113 // the UE context. Therefore, here we don't need to send the UE context
3114 // deletion request to the eNB.
3117 }
3118 else
3119 {
3120 for (uint16_t i = 0; i < m_numberOfComponentCarriers; i++)
3121 {
3122 m_cmacSapProvider.at(i)->Reset(); // reset the MAC
3123 }
3124 m_hasReceivedSib2 = false; // invalidate the previously received SIB2
3127 // Following call to UE NAS will force the UE to immediately
3128 // perform the random access to the same cell again.
3129 m_asSapUser->NotifyConnectionFailed(); // inform upper layer
3130 }
3131}
3132
3133void
3135{
3136 NS_LOG_FUNCTION(this);
3137 m_srb1Old = nullptr;
3138}
3139
3140uint8_t
3142{
3143 auto it = m_bid2DrbidMap.find(bid);
3144 // NS_ASSERT_MSG (it != m_bid2DrbidMap.end (), "could not find BID " << bid);
3145 if (it == m_bid2DrbidMap.end())
3146 {
3147 return 0;
3148 }
3149 else
3150 {
3151 return it->second;
3152 }
3153}
3154
3155void
3157{
3158 NS_LOG_FUNCTION(this << newState);
3159 State oldState = m_state;
3160 m_state = newState;
3161 NS_LOG_INFO(this << " IMSI " << m_imsi << " RNTI " << m_rnti << " UeRrc " << oldState << " --> "
3162 << newState);
3163 m_stateTransitionTrace(m_imsi, m_cellId, m_rnti, oldState, newState);
3164
3165 switch (newState)
3166 {
3167 case IDLE_START:
3169 {
3170 NS_LOG_INFO("Starting initial cell selection after RLF");
3171 }
3172 else
3173 {
3174 NS_FATAL_ERROR("cannot switch to an initial state");
3175 }
3176 break;
3177
3178 case IDLE_CELL_SEARCH:
3179 case IDLE_WAIT_MIB_SIB1:
3180 case IDLE_WAIT_MIB:
3181 case IDLE_WAIT_SIB1:
3182 break;
3183
3186 {
3188 }
3189 break;
3190
3191 case IDLE_WAIT_SIB2:
3193 {
3196 }
3197 break;
3198
3199 case IDLE_RANDOM_ACCESS:
3200 case IDLE_CONNECTING:
3201 case CONNECTED_NORMALLY:
3202 case CONNECTED_HANDOVER:
3205 default:
3206 break;
3207 }
3208}
3209
3210void
3219
3220void
3222{
3223 NS_LOG_FUNCTION(this << m_imsi);
3225 NS_LOG_INFO("noOfSyncIndications " << (uint16_t)m_noOfSyncIndications);
3228 {
3230 }
3231}
3232
3233void
3235{
3236 NS_LOG_FUNCTION(this << m_imsi);
3238 NS_LOG_INFO(this << " Total Number of Sync indications from PHY "
3239 << (uint16_t)m_noOfSyncIndications << "N310 value : " << (uint16_t)m_n310);
3242 {
3246 {
3247 NS_LOG_INFO("t310 started");
3248 }
3249 m_cphySapProvider.at(0)->StartInSyncDetection();
3251 }
3252}
3253
3254void
3256{
3257 NS_LOG_FUNCTION(this << m_imsi);
3258
3259 NS_LOG_DEBUG("The number of sync indication received by RRC from PHY: "
3260 << (uint16_t)m_noOfSyncIndications);
3262}
3263
3264void
3266{
3267 NS_LOG_FUNCTION(this << m_imsi);
3270 m_cphySapProvider.at(0)->ResetRlfParams();
3271}
3272
3273const std::string
3275{
3276 std::ostringstream ss;
3277 ss << s;
3278 return ss.str();
3279}
3280
3281std::ostream&
3282operator<<(std::ostream& os, LteUeRrc::State state)
3283{
3284 switch (state)
3285 {
3287 return os << "IDLE_START";
3289 return os << "IDLE_CELL_SEARCH";
3291 return os << "IDLE_WAIT_MIB_SIB1";
3293 return os << "IDLE_WAIT_MIB";
3295 return os << "IDLE_WAIT_SIB1";
3297 return os << "IDLE_CAMPED_NORMALLY";
3299 return os << "IDLE_WAIT_SIB2";
3301 return os << "IDLE_RANDOM_ACCESS";
3303 return os << "IDLE_CONNECTING";
3305 return os << "CONNECTED_NORMALLY";
3307 return os << "CONNECTED_HANDOVER";
3309 return os << "CONNECTED_PHY_PROBLEM";
3311 return os << "CONNECTED_REESTABLISHING";
3313 return os << "NUM_STATES";
3314 };
3315 return os << "UNKNOWN(" << static_cast<uint32_t>(state) << ")";
3316}
3317
3318} // namespace ns3
static uint8_t Dbm2RsrpRange(double dbm)
convert an RSRP value in dBm to the corresponding range as per 3GPP TS 36.133 section 9....
static double RsrpRange2Dbm(uint8_t range)
converts an RSRP range to dBm as per 3GPP TS 36.133 section 9.1.4 RSRP Measurement Report Mapping
static double RsrqRange2Db(uint8_t range)
converts an RSRQ range to dB as per 3GPP TS 36.133 section 9.1.7 RSRQ Measurement Report Mapping
static double IeValue2ActualQRxLevMin(int8_t qRxLevMinIeValue)
Returns the actual value of an Q-RxLevMin parameter.
static double IeValue2ActualHysteresis(uint8_t hysteresisIeValue)
Returns the actual value of a hysteresis parameter.
static uint8_t Db2RsrqRange(double db)
convert an RSRQ value in dB to the corresponding range as per 3GPP TS 36.133 section 9....
static double IeValue2ActualA3Offset(int8_t a3OffsetIeValue)
Returns the actual value of an a3-Offset parameter.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
This class implements the Access Stratum (AS) Service Access Point (SAP), i.e., the interface between...
Definition lte-as-sap.h:28
This class implements the Access Stratum (AS) Service Access Point (SAP), i.e., the interface between...
Definition lte-as-sap.h:87
virtual void NotifyConnectionFailed()=0
Notify the NAS that RRC Connection Establishment failed.
virtual void NotifyConnectionSuccessful()=0
Notify the NAS that RRC Connection Establishment was successful.
virtual void NotifyConnectionReleased()=0
Notify the NAS that RRC Connection was released.
virtual void RecvData(Ptr< Packet > packet)=0
receive a data packet
Service Access Point (SAP) offered by the MAC to the RLC See Femto Forum MAC Scheduler Interface Spec...
Definition lte-mac-sap.h:25
Service Access Point (SAP) offered by the MAC to the RLC See Femto Forum MAC Scheduler Interface Spec...
Definition lte-mac-sap.h:85
static TypeId GetTypeId()
Get the type ID.
Definition lte-rlc-am.cc:76
This abstract base class defines the API to interact with the Radio Link Control (LTE_RLC) in LTE,...
Definition lte-rlc.h:38
static TypeId GetTypeId()
Get the type ID.
Definition lte-rlc.cc:186
static TypeId GetTypeId()
Get the type ID.
Definition lte-rlc-um.cc:45
static double ConvertPdschConfigDedicated2Double(PdschConfigDedicated pdschConfigDedicated)
Convert PDSCH config dedicated function.
Service Access Point (SAP) offered by the UE component carrier manager to the UE RRC.
virtual void Reset()=0
Reset LC maps.
virtual LteMacSapUser * ConfigureSignalBearer(uint8_t lcid, LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser *msu)=0
Add the Signal Bearer for a specific Ue in LteUeComponenCarrierManager.
virtual std::vector< LteUeCcmRrcSapProvider::LcsConfig > AddLc(uint8_t lcId, LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser *msu)=0
add a new Logical Channel (LC)
Service Access Point (SAP) offered by the UE RRC to the UE CCM.
Service Access Point (SAP) offered by the UE MAC to the UE RRC.
Service Access Point (SAP) offered by the UE MAC to the UE RRC.
Service Access Point (SAP) offered by the UE PHY to the UE RRC for control purposes.
Service Access Point (SAP) offered by the UE PHY to the UE RRC for control purposes.
friend class MemberLteUeCcmRrcSapUser< LteUeRrc >
allow MemberLteUeCcmRrcSapUser<LteUeRrc> class friend access
Definition lte-ue-rrc.h:82
void DoRecvRrcConnectionReconfiguration(LteRrcSap::RrcConnectionReconfiguration msg)
Part of the RRC protocol.
uint8_t m_lastRrcTransactionIdentifier
last RRC transaction identifier
Definition lte-ue-rrc.h:811
bool m_connectionPending
True if a connection request by upper layers is pending.
Definition lte-ue-rrc.h:926
bool m_hasReceivedSib1
True if SIB1 was received for the current cell.
Definition lte-ue-rrc.h:930
void SendMeasurementReport(uint8_t measId)
Produce a proper measurement report from the given measurement identity's reporting entry in m_varMea...
std::map< uint8_t, std::list< PendingTrigger_t > > m_enteringTriggerQueue
List of triggers that were raised because entering condition have been true, but are still delayed fr...
void DoCompleteSetup(LteUeRrcSapProvider::CompleteSetupParameters params)
Part of the RRC protocol.
void DoNotifyOutOfSync()
Do notify out of sync function.
LteUeCcmRrcSapUser * GetLteCcmRrcSapUser()
Get the Component Carrier Management SAP offered by this RRC.
void DoRecvRrcConnectionReject(LteRrcSap::RrcConnectionReject msg)
Part of the RRC protocol.
uint16_t m_previousCellId
the cell id of the previous cell UE was attached to
Ptr< LteSignalingRadioBearerInfo > m_srb1Old
SRB1 configuration before RRC connection reconfiguration.
Definition lte-ue-rrc.h:798
static TypeId GetTypeId()
Get the type ID.
void SwitchToState(State s)
Switch the UE RRC to the given state.
uint16_t GetRnti() const
void DoDisconnect()
Disconnect function.
LteMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition lte-ue-rrc.h:760
void DoNotifyRandomAccessFailed()
Notify random access failed function.
TracedCallback< uint64_t, uint16_t, uint16_t, uint16_t > m_mibReceivedTrace
The MibReceived trace source.
Definition lte-ue-rrc.h:826
LteUeCmacSapUser * GetLteUeCmacSapUser()
This function is overloaded to maintain backward compatibility.
void SetLteUeCmacSapProvider(LteUeCmacSapProvider *s)
set the CMAC SAP this RRC should interact with
uint64_t m_imsi
The unique UE identifier.
Definition lte-ue-rrc.h:776
uint8_t m_n311
The 'N311' attribute.
Ptr< LteSignalingRadioBearerInfo > m_srb0
The Srb0 attribute.
Definition lte-ue-rrc.h:789
uint8_t m_connEstFailCountLimit
the counter value for T300 timer expiration received from the eNB
LteUeCphySapUser * GetLteUeCphySapUser()
void DoConnect()
Connect function.
TracedCallback< uint64_t, uint16_t, uint16_t > m_handoverEndErrorTrace
The HandoverEndError trace source.
Definition lte-ue-rrc.h:894
State
The states of the UE RRC entity.
Definition lte-ue-rrc.h:90
@ CONNECTED_REESTABLISHING
Definition lte-ue-rrc.h:103
TracedCallback< uint64_t, uint16_t, uint16_t, State, State > m_stateTransitionTrace
The StateTransition trace source.
Definition lte-ue-rrc.h:843
VarMeasConfig m_varMeasConfig
Includes the accumulated configuration of the measurements to be performed by the UE.
Definition lte-ue-rrc.h:968
friend class MemberLteUeRrcSapProvider< LteUeRrc >
allow MemberLteUeRrcSapProvider<LteUeRrc> class friend access
Definition lte-ue-rrc.h:80
void ApplyMeasConfig(LteRrcSap::MeasConfig mc)
Update the current measurement configuration m_varMeasConfig.
LteRrcSap::PdschConfigDedicated m_pdschConfigDedicated
the PDSCH config dedicated
Definition lte-ue-rrc.h:813
uint8_t m_n310
The 'N310' attribute.
void SetUseRlcSm(bool val)
TracedCallback< uint64_t, uint16_t > m_initialCellSelectionEndErrorTrace
The InitialCellSelectionEndError trace source.
Definition lte-ue-rrc.h:853
EventId m_radioLinkFailureDetected
Time limit (given by m_t310) before the radio link is considered to have failed.
void DoRecvRrcConnectionReestablishmentReject(LteRrcSap::RrcConnectionReestablishmentReject msg)
Part of the RRC protocol.
void DoNotifyRandomAccessSuccessful()
Notify random access successful function.
LteUeRrcSapProvider * m_rrcSapProvider
RRC SAP provider.
Definition lte-ue-rrc.h:758
void VarMeasReportListErase(uint8_t measId, ConcernedCells_t leavingCells, bool reportOnLeave)
Remove some cells from an existing reporting entry in m_varMeasReportList.
void DoRecvRrcConnectionSetup(LteRrcSap::RrcConnectionSetup msg)
Part of the RRC protocol.
void CancelLeavingTrigger(uint8_t measId)
Clear all the waiting triggers in m_leavingTriggerQueue which are associated with the given measureme...
bool m_leaveConnectedMode
true if UE NAS ask UE RRC to leave connected mode, e.g., after RLF, i.e.
void DoRecvRrcConnectionReestablishment(LteRrcSap::RrcConnectionReestablishment msg)
Part of the RRC protocol.
bool m_hasReceivedSib2
True if SIB2 was received for the current cell.
Definition lte-ue-rrc.h:932
void SynchronizeToStrongestCell()
Go through the list of measurement results, choose the one with the strongest RSRP,...
std::map< uint8_t, uint8_t > m_bid2DrbidMap
bid to DR bid map
Definition lte-ue-rrc.h:749
void SetLteUeCphySapProvider(LteUeCphySapProvider *s)
set the CPHY SAP this RRC should use to interact with the PHY
std::vector< LteUeCmacSapProvider * > m_cmacSapProvider
UE CMac SAP provider.
Definition lte-ue-rrc.h:755
State GetState() const
uint32_t m_dlEarfcn
Downlink carrier frequency.
Definition lte-ue-rrc.h:818
LteUeCcmRrcSapProvider * m_ccmRrcSapProvider
Interface to the LteUeComponentCarrierManage instance.
Definition lte-ue-rrc.h:769
void DoSetCsgWhiteList(uint32_t csgId)
Set CSG white list function.
void ApplyRadioResourceConfigDedicatedSecondaryCarrier(LteRrcSap::NonCriticalExtensionConfiguration nonCec)
Apply radio resource config dedicated secondary carrier.
LteAsSapProvider * GetAsSapProvider()
void DoSetTemporaryCellRnti(uint16_t rnti)
Set temporary cell rnti function.
void SetLteMacSapProvider(LteMacSapProvider *s)
set the MAC SAP provider.
TracedCallback< uint64_t, uint16_t, uint16_t > m_radioLinkFailureTrace
The 'RadioLinkFailure' trace source.
Definition lte-ue-rrc.h:923
uint64_t GetImsi() const
uint32_t m_ulEarfcn
Uplink carrier frequency.
Definition lte-ue-rrc.h:819
TracedCallback< uint64_t, uint16_t, uint16_t > m_connectionEstablishedTrace
The ConnectionEstablished trace source.
Definition lte-ue-rrc.h:869
uint8_t GetDlBandwidth() const
TracedCallback< uint64_t, uint16_t, uint16_t, uint16_t > m_sib1ReceivedTrace
The Sib1Received trace source.
Definition lte-ue-rrc.h:832
TracedCallback< uint64_t, uint16_t, uint16_t > m_randomAccessErrorTrace
The RandomAccessError trace source.
Definition lte-ue-rrc.h:864
uint32_t GetDlEarfcn() const
std::list< LteRrcSap::SCellToAddMod > m_sCellToAddModList
Secondary carriers.
Definition lte-ue-rrc.h:820
LtePdcpSapUser * m_drbPdcpSapUser
DRB PDCP SAP user.
Definition lte-ue-rrc.h:761
TracedCallback< Ptr< LteUeRrc >, std::list< LteRrcSap::SCellToAddMod > > m_sCarrierConfiguredTrace
The SCarrierConfigured trace source.
Definition lte-ue-rrc.h:900
void DoStartCellSelection(uint32_t dlEarfcn)
Start cell selection function.
friend class MemberLteAsSapProvider< LteUeRrc >
allow MemberLteAsSapProvider<LteUeRrc> class friend access
Definition lte-ue-rrc.h:76
bool m_useRlcSm
True if RLC SM is to be used, false if RLC UM/AM are to be used.
Definition lte-ue-rrc.h:809
TracedCallback< uint64_t, uint16_t, uint16_t > m_handoverEndOkTrace
The HandoverEndOk trace source.
Definition lte-ue-rrc.h:889
TracedCallback< uint64_t, uint16_t, uint16_t, std::string, uint8_t > m_phySyncDetectionTrace
The 'PhySyncDetection' trace source.
Definition lte-ue-rrc.h:918
std::map< uint8_t, std::list< PendingTrigger_t > > m_leavingTriggerQueue
List of triggers that were raised because leaving condition have been true, but are still delayed fro...
Time m_t310
The 'T310' attribute.
friend class UeMemberLteUeCmacSapUser
allow UeMemberLteUeCmacSapUser class friend access
Definition lte-ue-rrc.h:70
void RadioLinkFailureDetected()
Radio link failure detected function.
State m_state
The current UE RRC state.
Definition lte-ue-rrc.h:773
std::vector< LteUeCphySapProvider * > m_cphySapProvider
UE CPhy SAP provider.
Definition lte-ue-rrc.h:752
LteUeCcmRrcSapUser * m_ccmRrcSapUser
CCM RRC SAP user.
Definition lte-ue-rrc.h:770
TracedCallback< uint64_t, uint16_t, uint16_t, uint8_t > m_drbCreatedTrace
The DrbCreated trace source.
Definition lte-ue-rrc.h:912
uint16_t m_numberOfComponentCarriers
The number of component carriers.
std::map< uint8_t, VarMeasReport > m_varMeasReportList
The list of active reporting entries, indexed by the measurement identity which triggered the reporti...
Definition lte-ue-rrc.h:990
std::vector< LteUeCmacSapUser * > m_cmacSapUser
UE CMac SAP user.
Definition lte-ue-rrc.h:754
TracedCallback< uint64_t, uint16_t, uint16_t > m_srb1CreatedTrace
The Srb1Created trace source.
Definition lte-ue-rrc.h:906
TracedCallback< uint64_t, uint16_t > m_initialCellSelectionEndOkTrace
The InitialCellSelectionEndOk trace source.
Definition lte-ue-rrc.h:848
uint8_t GetUlBandwidth() const
void DoSendData(Ptr< Packet > packet, uint8_t bid)
Send data function.
LteAsSapProvider * m_asSapProvider
AS SAP provider.
Definition lte-ue-rrc.h:763
uint16_t m_rnti
The C-RNTI attribute.
Definition lte-ue-rrc.h:780
uint8_t m_noOfSyncIndications
number of in-sync or out-of-sync indications coming from PHY layer
uint16_t GetCellId() const
void DoSetNumberOfComponentCarriers(uint16_t noOfComponentCarriers)
RRC CCM SAP USER Method.
~LteUeRrc() override
Destructor.
void CancelEnteringTrigger(uint8_t measId)
Clear all the waiting triggers in m_enteringTriggerQueue which are associated with the given measurem...
std::map< uint16_t, MeasValues > m_storedMeasValues
Internal storage of the latest measurement results from all detected detected cells,...
void DoReportUeMeasurements(LteUeCphySapUser::UeMeasurementsParameters params)
Report UE measurements function.
LteUeRrcSapUser * m_rrcSapUser
RRC SAP user.
Definition lte-ue-rrc.h:757
TracedCallback< uint64_t, uint16_t, uint16_t > m_connectionReconfigurationTrace
The ConnectionReconfiguration trace source.
Definition lte-ue-rrc.h:879
void MeasurementReportTriggering(uint8_t measId)
Evaluate the reporting criteria of a measurement identity and invoke some reporting actions based on ...
void SaveUeMeasurements(uint16_t cellId, double rsrp, double rsrq, bool useLayer3Filtering, uint8_t componentCarrierId)
Keep the given measurement result as the latest measurement figures, to be utilised by UE RRC functio...
void SetLteCcmRrcSapProvider(LteUeCcmRrcSapProvider *s)
set the Component Carrier Management SAP this RRC should interact with
TracedCallback< uint64_t, uint16_t, uint16_t > m_sib2ReceivedTrace
The Sib2Received trace source.
Definition lte-ue-rrc.h:837
void LeaveConnectedMode()
Leave connected mode method Resets the UE back to an appropriate state depending on the nature of cau...
uint32_t GetUlEarfcn() const
void VarMeasReportListClear(uint8_t measId)
Remove the reporting entry of the given measurement identity from m_varMeasReportList.
LteUeRrcSapProvider * GetLteUeRrcSapProvider()
std::map< uint8_t, Ptr< LteDataRadioBearerInfo > > m_drbMap
The DataRadioBearerMap attribute.
Definition lte-ue-rrc.h:803
uint16_t m_cellId
The CellId attribute.
Definition lte-ue-rrc.h:784
uint8_t m_connEstFailCount
the counter to count T300 timer expiration
void DoRecvMasterInformationBlock(uint16_t cellId, LteRrcSap::MasterInformationBlock msg)
Receive master information block function.
void DoReceivePdcpSdu(LtePdcpSapUser::ReceivePdcpSduParameters params)
Receive PDCP SDU function.
TracedCallback< uint64_t, uint16_t, uint16_t, uint8_t > m_connectionTimeoutTrace
The ConnectionTimeout trace source.
Definition lte-ue-rrc.h:874
std::set< uint16_t > m_acceptableCell
List of cell ID of acceptable cells for cell selection that have been detected.
Definition lte-ue-rrc.h:938
Time m_t300
The T300 attribute.
EventId m_connectionTimeout
Invokes ConnectionEstablishmentTimeout() if RRC connection establishment procedure for this UE takes ...
void VarMeasReportListAdd(uint8_t measId, ConcernedCells_t enteringCells)
Compose a new reporting entry of the given measurement identity, insert it into m_varMeasReportList,...
std::vector< LteUeCphySapUser * > m_cphySapUser
UE CPhy SAP user.
Definition lte-ue-rrc.h:751
void ConnectionTimeout()
Invoked after timer T300 expires, notifying upper layers that RRC connection establishment procedure ...
bool m_hasReceivedMib
True if MIB was received for the current cell.
Definition lte-ue-rrc.h:928
void DoRecvRrcConnectionRelease(LteRrcSap::RrcConnectionRelease msg)
Part of the RRC protocol.
std::list< uint16_t > ConcernedCells_t
List of cell IDs which are responsible for a certain trigger.
Definition lte-ue-rrc.h:995
void EvaluateCellForSelection()
Performs cell selection evaluation to the current serving cell.
void DoRecvSystemInformationBlockType1(uint16_t cellId, LteRrcSap::SystemInformationBlockType1 msg)
Receive system information block type 1 function.
void StartConnection()
Start connection function.
void DoRecvSystemInformation(LteRrcSap::SystemInformation msg)
Part of the RRC protocol.
void DoNotifyInSync()
Do notify in sync function.
uint16_t m_ulBandwidth
Uplink bandwidth in RBs.
Definition lte-ue-rrc.h:816
LteUeRrc()
create an RRC instance for use within an ue
Definition lte-ue-rrc.cc:91
uint32_t m_csgWhiteList
List of CSG ID which this UE entity has access to.
Definition lte-ue-rrc.h:941
uint16_t GetPreviousCellId() const
Get the previous cell id.
void InitializeSap()
Initialize SAP.
void DisposeOldSrb1()
Dispose old SRB1.
void DoInitialize() override
Initialize() implementation.
friend class LtePdcpSpecificLtePdcpSapUser< LteUeRrc >
allow LtePdcpSpecificLtePdcpSapUser<LteUeRrc> class friend access
Definition lte-ue-rrc.h:74
TracedCallback< uint64_t, uint16_t, uint16_t > m_randomAccessSuccessfulTrace
The RandomAccessSuccessful trace source.
Definition lte-ue-rrc.h:859
bool IsServingCell(uint16_t cellId) const
LteRrcSap::SystemInformationBlockType1 m_lastSib1
Stored content of the last SIB1 received.
Definition lte-ue-rrc.h:935
static const std::string ToString(LteUeRrc::State s)
void SetAsSapUser(LteAsSapUser *s)
Set the AS SAP user to interact with the NAS entity.
void SetLteUeRrcSapUser(LteUeRrcSapUser *s)
set the RRC SAP this RRC should interact with
uint16_t m_dlBandwidth
Downlink bandwidth in RBs.
Definition lte-ue-rrc.h:815
Ptr< LteSignalingRadioBearerInfo > m_srb1
The Srb1 attribute.
Definition lte-ue-rrc.h:793
LteAsSapUser * m_asSapUser
AS SAP user.
Definition lte-ue-rrc.h:764
void SetImsi(uint64_t imsi)
void DoForceCampedOnEnb(uint16_t cellId, uint32_t dlEarfcn)
Force camped on ENB function.
void DoDispose() override
Destructor implementation.
void StorePreviousCellId(uint16_t cellId)
Store the previous cell id.
void ResetRlfParams()
Reset radio link failure parameters.
void DoResetSyncIndicationCounter()
Do reset sync indication counter function.
void ApplyRadioResourceConfigDedicated(LteRrcSap::RadioResourceConfigDedicated rrcd)
Apply radio resource config dedicated.
uint8_t Bid2Drbid(uint8_t bid)
Bid 2 DR bid.
TracedCallback< uint64_t, uint16_t, uint16_t, uint16_t > m_handoverStartTrace
The HandoverStart trace source.
Definition lte-ue-rrc.h:884
Part of the RRC protocol.
Part of the RRC protocol.
virtual void Setup(SetupParameters params)=0
Setup function.
virtual void SendRrcConnectionReconfigurationCompleted(RrcConnectionReconfigurationCompleted msg)=0
Send an RRCConnectionReconfigurationComplete message to the serving eNodeB during an RRC connection r...
virtual void SendMeasurementReport(MeasurementReport msg)=0
Send a MeasurementReport message to the serving eNodeB during a measurement reporting procedure (Sect...
virtual void SendIdealUeContextRemoveRequest(uint16_t rnti)=0
Send UE context remove request function.
virtual void SendRrcConnectionRequest(RrcConnectionRequest msg)=0
Send an _RRCConnectionRequest message to the serving eNodeB during an RRC connection establishment pr...
virtual void SendRrcConnectionSetupCompleted(RrcConnectionSetupCompleted msg)=0
Send an RRCConnectionSetupComplete message to the serving eNodeB during an RRC connection establishme...
Template for the implementation of the LteUeCphySapUser as a member of an owner class of type C to wh...
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
A base class which provides memory management and object aggregation.
Definition object.h:78
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Definition simulator.cc:274
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
UeMemberLteUeCmacSapUser class.
Definition lte-ue-rrc.cc:45
UeMemberLteUeCmacSapUser(LteUeRrc *rrc)
Constructor.
Definition lte-ue-rrc.cc:62
LteUeRrc * m_rrc
the RRC class
Definition lte-ue-rrc.cc:59
void SetTemporaryCellRnti(uint16_t rnti) override
Definition lte-ue-rrc.cc:68
void NotifyRandomAccessSuccessful() override
Notify the RRC that the MAC Random Access procedure completed successfully.
Definition lte-ue-rrc.cc:74
void NotifyRandomAccessFailed() override
Notify the RRC that the MAC Random Access procedure failed.
Definition lte-ue-rrc.cc:80
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
ObjectPtrContainerValue ObjectMapValue
ObjectMapValue is an alias for ObjectPtrContainerValue.
Definition object-map.h:29
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition object-map.h:65
Ptr< const AttributeChecker > MakeObjectMapChecker()
Definition object-map.h:110
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
const Time UE_MEASUREMENT_REPORT_DELAY
Artificial delay of UE measurements procedure.
Definition lte-ue-rrc.cc:35
constexpr uint32_t MIN_NO_CC
Minimum number of carrier components allowed by 3GPP up to R13.
Definition lte-common.h:25
constexpr uint32_t MAX_NO_CC
Maximum number of carrier components allowed by 3GPP up to R13.
Definition lte-common.h:28
Parameters for LtePdcpSapProvider::TransmitPdcpSdu.
Parameters for LtePdcpSapUser::ReceivePdcpSdu.
uint8_t transmissionMode
transmission mode
uint32_t dlCarrierFreq
DL carrier frequency.
uint32_t ulCarrierFreq
UL carrier frequency.
int8_t qRxLevMin
INTEGER (-70..-22), actual value = IE value * 2 [dBm].
Definition lte-rrc-sap.h:70
uint32_t ulCarrierFreq
UL carrier frequency.
Definition lte-rrc-sap.h:77
uint16_t ulBandwidth
UL bandwidth.
Definition lte-rrc-sap.h:78
MasterInformationBlock structure.
MeasConfig structure.
std::list< uint8_t > measIdToRemoveList
measure ID to remove list
std::list< MeasObjectToAddMod > measObjectToAddModList
measure object to add mod list
std::list< uint8_t > reportConfigToRemoveList
report config to remove list
std::list< uint8_t > measObjectToRemoveList
measure object to remove list
bool haveMeasGapConfig
have measure gap config?
QuantityConfig quantityConfig
quantity config
bool haveSmeasure
have S measure?
bool haveSpeedStatePars
have speed state parameters?
std::list< ReportConfigToAddMod > reportConfigToAddModList
report config to add mod list
std::list< MeasIdToAddMod > measIdToAddModList
measure ID to add mod list
bool haveQuantityConfig
have quantity config?
MeasObjectEutra structure.
int8_t offsetFreq
offset frequency
uint32_t carrierFreq
carrier frequency
MeasResultEutra structure.
uint8_t rsrqResult
RSRQ result.
uint8_t rsrpResult
RSRP result.
bool haveRsrpResult
have RSRP result
bool haveRsrqResult
have RSRQ result?
uint16_t physCellId
Phy cell ID.
bool haveCgiInfo
have CGI info?
uint8_t rsrqResult
the RSRQ result
uint8_t rsrpResult
the RSRP result
uint8_t rsrpResult
the RSRP result
uint8_t rsrqResult
the RSRQ result
MeasResultServFreq structure.
bool haveMeasResultSCell
have measResultSCell?
bool haveMeasResultBestNeighCell
have measResultBestNeighCell?
uint16_t servFreqId
serving cell index
MeasResultSCell measResultSCell
SCell measurement results.
MeasResults structure.
uint8_t measId
measure ID
bool haveMeasResultNeighCells
have measure result neighbor cells
std::list< MeasResultEutra > measResultListEutra
measure result list eutra
bool haveMeasResultServFreqList
has measResultServFreqList-r10
std::list< MeasResultServFreq > measResultServFreqList
MeasResultServFreqList-r10.
MeasResultPCell measResultPCell
measurement result primary cell
MeasurementReport structure.
MeasResults measResults
measure results
MobilityControlInfo structure.
RachConfigDedicated rachConfigDedicated
RACH config dedicated.
bool haveRachConfigDedicated
Have RACH config dedicated?
uint16_t newUeIdentity
new UE identity
bool haveCarrierBandwidth
have carrier bandwidth?
bool haveCarrierFreq
have carrier frequency?
CarrierBandwidthEutra carrierBandwidth
carrier bandwidth
CarrierFreqEutra carrierFreq
carrier frequency
uint16_t targetPhysCellId
target Phy cell ID
NonCriticalExtensionConfiguration structure.
std::list< uint8_t > sCellToReleaseList
SCell to release list.
std::list< SCellToAddMod > sCellToAddModList
SCell to add mod list.
int8_t referenceSignalPower
INTEGER (-60..50),.
PdschConfigDedicated structure.
PhysicalConfigDedicated structure.
PdschConfigDedicated pdschConfigDedicated
PDSCH config dedicated.
bool haveAntennaInfoDedicated
have antenna info dedicated?
SoundingRsUlConfigDedicated soundingRsUlConfigDedicated
sounding RS UL config dedicated
bool haveSoundingRsUlConfigDedicated
have sounding RS UL config dedicated?
bool havePdschConfigDedicated
have PDSCH config dedicated?
AntennaInfoDedicated antennaInfo
antenna info
uint8_t numberOfRaPreambles
number of RA preambles
uint8_t filterCoefficientRSRQ
filter coefficient RSRQ
uint8_t filterCoefficientRSRP
filter coefficient RSRP
uint8_t raResponseWindowSize
RA response window size.
uint8_t preambleTransMax
preamble transmit maximum
TxFailParam txFailParam
txFailParams
PreambleInfo preambleInfo
preamble info
RaSupervisionInfo raSupervisionInfo
RA supervision info.
uint8_t raPreambleIndex
RA preamble index.
uint8_t raPrachMaskIndex
RA PRACH mask index.
RachConfigCommon rachConfigCommon
RACH config common.
PdschConfigCommon pdschConfigCommon
PDSCH config common.
RadioResourceConfigDedicated structure.
PhysicalConfigDedicated physicalConfigDedicated
physical config dedicated
std::list< uint8_t > drbToReleaseList
DRB to release list.
std::list< DrbToAddMod > drbToAddModList
DRB to add mod list.
std::list< SrbToAddMod > srbToAddModList
SRB to add mod list.
Specifies criteria for triggering of an E-UTRA measurement reporting event.
bool reportOnLeave
Indicates whether or not the UE shall initiate the measurement reporting procedure when the leaving c...
uint8_t maxReportCells
Maximum number of cells, excluding the serving cell, to be included in the measurement report.
enum ns3::LteRrcSap::ReportConfigEutra::@62 eventId
Event enumeration.
enum ns3::LteRrcSap::ReportConfigEutra::@61 triggerType
Trigger enumeration.
uint8_t hysteresis
Parameter used within the entry and leave condition of an event triggered reporting condition.
@ RSRP
Reference Signal Received Power.
@ RSRQ
Reference Signal Received Quality.
@ EVENT_A2
Event A2: Serving becomes worse than absolute threshold.
@ EVENT_A3
Event A3: Neighbour becomes amount of offset better than PCell.
@ EVENT_A4
Event A4: Neighbour becomes better than absolute threshold.
@ EVENT_A1
Event A1: Serving becomes better than absolute threshold.
@ EVENT_A5
Event A5: PCell becomes worse than absolute threshold1 AND Neighbour becomes better than another abso...
enum ns3::LteRrcSap::ReportConfigEutra::@65 reportInterval
Report interval enumeration.
ThresholdEutra threshold2
Threshold for event A5.
enum ns3::LteRrcSap::ReportConfigEutra::@63 triggerQuantity
Trigger type enumeration.
ThresholdEutra threshold1
Threshold for event A1, A2, A4, and A5.
int8_t a3Offset
Offset value for Event A3.
uint16_t timeToTrigger
Time during which specific criteria for the event needs to be met in order to trigger a measurement r...
RrcConnectionReconfigurationCompleted structure.
uint8_t rrcTransactionIdentifier
RRC transaction identifier.
RrcConnectionReconfiguration structure.
uint8_t rrcTransactionIdentifier
RRC transaction identifier.
bool haveMobilityControlInfo
have mobility control info
NonCriticalExtensionConfiguration nonCriticalExtension
3GPP TS 36.331 v.11.10 R11 Sec.
bool haveRadioResourceConfigDedicated
have radio resource config dedicated
RadioResourceConfigDedicated radioResourceConfigDedicated
radio resource config dedicated
bool haveNonCriticalExtension
have critical extension?
MobilityControlInfo mobilityControlInfo
mobility control info
RrcConnectionReestablishment structure.
RrcConnectionReestablishmentReject structure.
RrcConnectionReject structure.
RrcConnectionRelease structure.
uint8_t rrcTransactionIdentifier
RRC transaction identifier.
RrcConnectionRequest structure.
RrcConnectionSetupCompleted structure.
uint8_t rrcTransactionIdentifier
RRC transaction identifier.
RrcConnectionSetup structure.
uint8_t rrcTransactionIdentifier
RRC transaction identifier.
RadioResourceConfigDedicated radioResourceConfigDedicated
radio resource config dedicated
uint16_t srsConfigIndex
SRS config index.
SystemInformationBlockType1 structure.
CellSelectionInfo cellSelectionInfo
cell selection info
CellAccessRelatedInfo cellAccessRelatedInfo
cell access related info
RadioResourceConfigCommonSib radioResourceConfigCommon
radio resource config common
SystemInformation structure.
SystemInformationBlockType2 sib2
SIB2.
@ THRESHOLD_RSRP
RSRP is used for the threshold.
@ THRESHOLD_RSRQ
RSRQ is used for the threshold.
enum ns3::LteRrcSap::ThresholdEutra::@60 choice
Threshold enumeration.
uint8_t range
Value range used in RSRP/RSRQ threshold.
uint8_t connEstFailCount
Number of times that the UE detects T300 expiry on the same cell.
uint16_t prioritizedBitRateKbps
prioritize bit rate Kbps
uint16_t bucketSizeDurationMs
bucket size duration ms
uint8_t logicalChannelGroup
logical channel group
UeMeasurementsParameters structure.
Represents a measurement result from a certain cell.
uint32_t carrierFreq
Measurement object frequency.
double rsrp
Measured RSRP in dBm.
double rsrq
Measured RSRQ in dB.
Represents a single triggered event from a measurement identity which reporting criteria have been fu...
ConcernedCells_t concernedCells
The list of cells responsible for this trigger.
EventId timer
The pending reporting event, scheduled at the end of the time-to-trigger.
uint8_t measId
The measurement identity which raised the trigger.
std::map< uint8_t, LteRrcSap::ReportConfigToAddMod > reportConfigList
report config list
Definition lte-ue-rrc.h:956
LteRrcSap::QuantityConfig quantityConfig
quantity config
Definition lte-ue-rrc.h:957
std::map< uint8_t, LteRrcSap::MeasObjectToAddMod > measObjectList
measure object list
Definition lte-ue-rrc.h:955
std::map< uint8_t, LteRrcSap::MeasIdToAddMod > measIdList
measure ID list
Definition lte-ue-rrc.h:954
Represents a single measurement reporting entry., which includes information about a measurement for ...
Definition lte-ue-rrc.h:978
uint8_t measId
measure ID
Definition lte-ue-rrc.h:979
CompleteSetupParameters structure.
SetupParameters structure.
LteRlcSapProvider * srb0SapProvider
SRB0 SAP provider.
LtePdcpSapProvider * srb1SapProvider
SRB1 SAP provider.