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