1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation;
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Author: Junling Bu <linlinjavaer@gmail.com>
17 */
18 #include "channel-coordinator.h"
19 #include "ns3/log.h"
20 #include "ns3/simulator.h"
21
22 namespace ns3 {
23
24 NS_LOG_COMPONENT_DEFINE ("ChannelCoordinator");
25
26 /****************************************************************
27 * This destructor is needed.
28 ****************************************************************/
29
~ChannelCoordinationListener(void)30 ChannelCoordinationListener::~ChannelCoordinationListener (void)
31 {
32 }
33
34 /****************************************************************/
35
36 NS_OBJECT_ENSURE_REGISTERED (ChannelCoordinator);
37
38 TypeId
GetTypeId(void)39 ChannelCoordinator::GetTypeId (void)
40 {
41 static TypeId tid = TypeId ("ns3::ChannelCoordinator")
42 .SetParent<Object> ()
43 .SetGroupName ("Wave")
44 .AddConstructor<ChannelCoordinator> ()
45 .AddAttribute ("CchInterval", "CCH Interval, default value is 50ms.",
46 TimeValue (GetDefaultCchInterval ()),
47 MakeTimeAccessor (&ChannelCoordinator::m_cchi),
48 MakeTimeChecker ())
49 .AddAttribute ("SchInterval", "SCH Interval, default value is 50ms.",
50 TimeValue (GetDefaultSchInterval ()),
51 MakeTimeAccessor (&ChannelCoordinator::m_schi),
52 MakeTimeChecker ())
53 .AddAttribute ("GuardInterval", "Guard Interval, default value is 4ms.",
54 TimeValue (GetDefaultGuardInterval ()),
55 MakeTimeAccessor (&ChannelCoordinator::m_gi),
56 MakeTimeChecker ())
57 ;
58 return tid;
59 }
60
ChannelCoordinator()61 ChannelCoordinator::ChannelCoordinator ()
62 : m_guardCount (0)
63 {
64 NS_LOG_FUNCTION (this);
65 }
66
~ChannelCoordinator()67 ChannelCoordinator::~ChannelCoordinator ()
68 {
69 NS_LOG_FUNCTION (this);
70 }
71
72 void
DoInitialize(void)73 ChannelCoordinator::DoInitialize (void)
74 {
75 NS_LOG_FUNCTION (this);
76 StartChannelCoordination ();
77 }
78
79 void
DoDispose(void)80 ChannelCoordinator::DoDispose (void)
81 {
82 NS_LOG_FUNCTION (this);
83 StopChannelCoordination ();
84 UnregisterAllListeners ();
85 }
86
87 Time
GetDefaultCchInterval(void)88 ChannelCoordinator::GetDefaultCchInterval (void)
89 {
90 NS_LOG_FUNCTION_NOARGS ();
91 // refer to Annex H of IEEE 1609.4-2010
92 const static uint8_t DEFAULT_CCH_INTERVAL = 50;
93 return MilliSeconds (DEFAULT_CCH_INTERVAL);
94 }
95
96 Time
GetDefaultSchInterval(void)97 ChannelCoordinator::GetDefaultSchInterval (void)
98 {
99 NS_LOG_FUNCTION_NOARGS ();
100 // refer to Annex H of IEEE 1609.4-2010
101 const static uint8_t DEFAULT_SCH_INTERVAL = 50;
102 return MilliSeconds (DEFAULT_SCH_INTERVAL);
103 }
104
105 Time
GetDefaultSyncInterval(void)106 ChannelCoordinator::GetDefaultSyncInterval (void)
107 {
108 NS_LOG_FUNCTION_NOARGS ();
109 return GetDefaultCchInterval () + GetDefaultSchInterval ();
110 }
111
112 Time
GetDefaultGuardInterval(void)113 ChannelCoordinator::GetDefaultGuardInterval (void)
114 {
115 NS_LOG_FUNCTION_NOARGS ();
116 // refer to Annex H of IEEE 1609.4-2010
117 const static uint8_t SyncTolerance = 2;
118 const static uint8_t MaxChSwitchTime = 2;
119 const static uint8_t DEFAULT_GUARD_INTERVAL = SyncTolerance + MaxChSwitchTime;
120 return MilliSeconds (DEFAULT_GUARD_INTERVAL);
121 }
122
123 void
SetCchInterval(Time cchInterval)124 ChannelCoordinator::SetCchInterval (Time cchInterval)
125 {
126 NS_LOG_FUNCTION (this << cchInterval);
127 m_cchi = cchInterval;
128 }
129
130 Time
GetCchInterval(void) const131 ChannelCoordinator::GetCchInterval (void) const
132 {
133 NS_LOG_FUNCTION (this);
134 return m_cchi;
135 }
136
137 void
SetSchInterval(Time schInterval)138 ChannelCoordinator::SetSchInterval (Time schInterval)
139 {
140 NS_LOG_FUNCTION (this << schInterval);
141 m_schi = schInterval;
142 }
143
144 Time
GetSchInterval(void) const145 ChannelCoordinator::GetSchInterval (void) const
146 {
147 NS_LOG_FUNCTION (this);
148 return m_schi;
149 }
150
151 Time
GetSyncInterval(void) const152 ChannelCoordinator::GetSyncInterval (void) const
153 {
154 NS_LOG_FUNCTION (this);
155 return GetCchInterval () + GetSchInterval ();
156 }
157
158 void
SetGuardInterval(Time guard)159 ChannelCoordinator::SetGuardInterval (Time guard)
160 {
161 NS_LOG_FUNCTION (this);
162 m_gi = guard;
163 }
164
165 Time
GetGuardInterval(void) const166 ChannelCoordinator::GetGuardInterval (void) const
167 {
168 NS_LOG_FUNCTION (this);
169 return m_gi;
170 }
171
172 Time
GetSchSlot(void) const173 ChannelCoordinator::GetSchSlot (void) const
174 {
175 NS_LOG_FUNCTION (this);
176 return m_schi - m_gi;
177 }
178
179 Time
GetCchSlot(void) const180 ChannelCoordinator::GetCchSlot (void) const
181 {
182 NS_LOG_FUNCTION (this);
183 return m_cchi - m_gi;
184 }
185
186 bool
IsCchInterval(Time duration) const187 ChannelCoordinator::IsCchInterval (Time duration) const
188 {
189 NS_LOG_FUNCTION (this << duration);
190 Time future = GetIntervalTime (duration);
191 return (future < m_cchi);
192 }
193
194 bool
IsSchInterval(Time duration) const195 ChannelCoordinator::IsSchInterval (Time duration) const
196 {
197 NS_LOG_FUNCTION (this << duration);
198 return !IsCchInterval (duration);
199 }
200
201 bool
IsGuardInterval(Time duration) const202 ChannelCoordinator::IsGuardInterval (Time duration) const
203 {
204 NS_LOG_FUNCTION (this << duration);
205 Time future = GetIntervalTime (duration);
206 // the interval is either in CchInterval or SchInterval
207 Time interval = future < m_cchi ? future : future - m_cchi;
208 return interval < m_gi;
209 }
210
211 bool
IsValidConfig(void) const212 ChannelCoordinator::IsValidConfig (void) const
213 {
214 NS_LOG_FUNCTION (this);
215 if (GetCchInterval ().GetMilliSeconds () == 0 || GetSchInterval ().GetMilliSeconds () == 0
216 || GetGuardInterval ().GetMilliSeconds () == 0)
217 {
218 NS_LOG_WARN ("the channel interval should not be zero");
219 return false;
220 }
221 // 1000 is 1000ms which is one UTC second
222 if ((1000 % GetSyncInterval ().GetMilliSeconds ()) != 0)
223 {
224 NS_LOG_WARN ("every UTC second shall be an integer number of SyncInterval");
225 return false;
226 }
227 if (GetCchInterval () <= GetGuardInterval ())
228 {
229 NS_LOG_WARN ("CCH Interval should be large than GuardInterval");
230 return false;
231 }
232 if (GetSchInterval () <= GetGuardInterval ())
233 {
234 NS_LOG_WARN ("SCH Interval should be large than GuardInterval");
235 return false;
236 }
237 // at last, GguardInterval should be larger than real channel switch time of PHY layer.
238 // However there is no method such as GetChannelSwitchTime in the WifiPhy to support test here.
239 return true;
240 }
241
242 Time
NeedTimeToCchInterval(Time duration) const243 ChannelCoordinator::NeedTimeToCchInterval (Time duration) const
244 {
245 NS_LOG_FUNCTION (this << duration);
246 if (IsCchInterval (duration))
247 {
248 return MilliSeconds (0);
249 }
250 return GetSyncInterval () - GetIntervalTime (duration);
251 }
252
253 Time
NeedTimeToSchInterval(Time duration) const254 ChannelCoordinator::NeedTimeToSchInterval (Time duration) const
255 {
256 NS_LOG_FUNCTION (this << duration);
257 if (IsSchInterval (duration))
258 {
259 return MilliSeconds (0);
260 }
261 return GetCchInterval () - GetIntervalTime (duration);
262 }
263
264 Time
NeedTimeToGuardInterval(Time duration) const265 ChannelCoordinator::NeedTimeToGuardInterval (Time duration) const
266 {
267 NS_LOG_FUNCTION (this << duration);
268 if (IsGuardInterval (duration))
269 {
270 return MilliSeconds (0);
271 }
272 if (IsCchInterval (duration))
273 {
274 // the time to Guard Interval of SCH Interval
275 return (GetCchInterval () - GetIntervalTime (duration));
276 }
277 // the time to Guard Interval of next CCH Interval
278 return (GetSyncInterval () - GetIntervalTime (duration));
279 }
280
281 Time
GetIntervalTime(Time duration) const282 ChannelCoordinator::GetIntervalTime (Time duration) const
283 {
284 NS_LOG_FUNCTION (this << duration);
285 Time future = Now () + duration;
286 Time sync = GetSyncInterval ();
287 uint32_t n = future.GetMilliSeconds () / sync.GetMilliSeconds ();
288 return future - MilliSeconds (n * sync.GetMilliSeconds ());
289 }
290
291 Time
GetRemainTime(Time duration) const292 ChannelCoordinator::GetRemainTime (Time duration) const
293 {
294 NS_LOG_FUNCTION (this << duration);
295 return GetSyncInterval () - GetIntervalTime (duration);
296 }
297
298 void
RegisterListener(Ptr<ChannelCoordinationListener> listener)299 ChannelCoordinator::RegisterListener (Ptr<ChannelCoordinationListener> listener)
300 {
301 NS_LOG_FUNCTION (this << listener);
302 NS_ASSERT (listener != 0);
303 m_listeners.push_back (listener);
304 }
305
306 void
UnregisterListener(Ptr<ChannelCoordinationListener> listener)307 ChannelCoordinator::UnregisterListener (Ptr<ChannelCoordinationListener> listener)
308 {
309 NS_LOG_FUNCTION (this << listener);
310 NS_ASSERT (listener != 0);
311 for (ListenersI i = m_listeners.begin (); i != m_listeners.end (); ++i)
312 {
313 if ((*i) == listener)
314 {
315 m_listeners.erase (i);
316 return;
317 }
318 }
319 }
320
321 void
UnregisterAllListeners(void)322 ChannelCoordinator::UnregisterAllListeners (void)
323 {
324 NS_LOG_FUNCTION (this);
325 m_listeners.clear ();
326 }
327
328 void
StartChannelCoordination(void)329 ChannelCoordinator::StartChannelCoordination (void)
330 {
331 NS_LOG_FUNCTION (this);
332 Time now = Now ();
333 if ((now.GetMilliSeconds () % 1000) != 0)
334 {
335 // see chapter 5.5.2
336 NS_FATAL_ERROR ("the coordination event order should start with the beginning of 1 second");
337 }
338 if (!IsValidConfig ())
339 {
340 NS_FATAL_ERROR ("the channel intervals configured for channel coordination events are invalid");
341 }
342 m_guardCount = 0;
343 NotifyGuardSlot ();
344 }
345
346 void
StopChannelCoordination(void)347 ChannelCoordinator::StopChannelCoordination (void)
348 {
349 if (!m_coordination.IsExpired ())
350 {
351 m_coordination.Cancel ();
352 }
353 m_guardCount = 0;
354 }
355
356 void
NotifySchSlot(void)357 ChannelCoordinator::NotifySchSlot (void)
358 {
359 NS_LOG_FUNCTION (this);
360 m_coordination = Simulator::Schedule (GetSchSlot (), &ChannelCoordinator::NotifyGuardSlot, this);
361 for (ListenersI i = m_listeners.begin (); i != m_listeners.end (); ++i)
362 {
363 (*i)->NotifySchSlotStart (GetSchSlot ());
364 }
365 }
366
367 void
NotifyCchSlot(void)368 ChannelCoordinator::NotifyCchSlot (void)
369 {
370 NS_LOG_FUNCTION (this);
371 m_coordination = Simulator::Schedule (GetCchSlot (), &ChannelCoordinator::NotifyGuardSlot, this);
372 for (ListenersI i = m_listeners.begin (); i != m_listeners.end (); ++i)
373 {
374 (*i)->NotifyCchSlotStart (GetCchSlot ());
375 }
376 }
377
378 void
NotifyGuardSlot(void)379 ChannelCoordinator::NotifyGuardSlot (void)
380 {
381 NS_LOG_FUNCTION (this);
382 Time guardSlot = GetGuardInterval ();
383 bool inCchi = ((m_guardCount % 2) == 0);
384 if (inCchi)
385 {
386 m_coordination = Simulator::Schedule (guardSlot, &ChannelCoordinator::NotifyCchSlot, this);
387 }
388 else
389 {
390 m_coordination = Simulator::Schedule (guardSlot, &ChannelCoordinator::NotifySchSlot, this);
391 }
392 for (ListenersI i = m_listeners.begin (); i != m_listeners.end (); ++i)
393 {
394 (*i)->NotifyGuardSlotStart (guardSlot, inCchi);
395 }
396 m_guardCount++;
397 }
398
399 } // namespace ns3
400