1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
|
2 /* |
|
3 * Copyright (c) 2005 INRIA |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License version 2 as |
|
7 * published by the Free Software Foundation; |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 * |
|
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
|
19 */ |
|
20 |
|
21 #include <math.h> |
|
22 |
|
23 #include "ns3/simulator.h" |
|
24 #include "ns3/assert.h" |
|
25 #include "ns3/log.h" |
|
26 |
|
27 #include "dcf.h" |
|
28 #include "random-stream.h" |
|
29 #include "mac-parameters.h" |
|
30 |
|
31 |
|
32 NS_LOG_COMPONENT_DEFINE ("Dcf"); |
|
33 |
|
34 namespace ns3 { |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 DcfAccessListener::DcfAccessListener () |
|
40 {} |
|
41 DcfAccessListener::~DcfAccessListener () |
|
42 {} |
|
43 |
|
44 |
|
45 |
|
46 Dcf::Dcf (uint32_t min, uint32_t max) |
|
47 : m_accessTimerEvent (), |
|
48 m_cwMin (min), |
|
49 m_cwMax (max), |
|
50 m_backoffStart (MicroSeconds (0)), |
|
51 m_backoffLeft (MicroSeconds (0)), |
|
52 m_lastNavStart (MicroSeconds (0)), |
|
53 m_lastNavDuration (MicroSeconds (0)), |
|
54 m_lastRxStart (MicroSeconds (0)), |
|
55 m_lastRxDuration (MicroSeconds (0)), |
|
56 m_lastRxReceivedOk (true), |
|
57 m_lastRxEnd (MicroSeconds (0)), |
|
58 m_lastTxStart (MicroSeconds (0)), |
|
59 m_lastTxDuration (MicroSeconds (0)), |
|
60 m_lastBusyStart (MicroSeconds (0)), |
|
61 m_lastBusyDuration (MicroSeconds (0)), |
|
62 m_rxing (false) |
|
63 { |
|
64 ResetCw (); |
|
65 m_rng = new RealRandomStream (); |
|
66 } |
|
67 |
|
68 Dcf::~Dcf () |
|
69 { |
|
70 delete m_rng; |
|
71 } |
|
72 |
|
73 void |
|
74 Dcf::ResetRngForTest (RandomStream *stream) |
|
75 { |
|
76 delete m_rng; |
|
77 m_rng = stream; |
|
78 } |
|
79 void |
|
80 Dcf::SetParameters (MacParameters const*parameters) |
|
81 { |
|
82 m_parameters = parameters; |
|
83 } |
|
84 |
|
85 void |
|
86 Dcf::SetDifs (Time difs) |
|
87 { |
|
88 m_difs = difs; |
|
89 } |
|
90 void |
|
91 Dcf::SetEifs (Time eifs) |
|
92 { |
|
93 m_eifs = eifs; |
|
94 } |
|
95 void |
|
96 Dcf::SetCwBounds (uint32_t min, uint32_t max) |
|
97 { |
|
98 m_cwMin = min; |
|
99 m_cwMax = max; |
|
100 m_cw = min; |
|
101 } |
|
102 void |
|
103 Dcf::RegisterAccessListener (DcfAccessListener *listener) |
|
104 { |
|
105 m_listener = listener; |
|
106 } |
|
107 |
|
108 |
|
109 /*************************************************************** |
|
110 * public API. |
|
111 ***************************************************************/ |
|
112 |
|
113 void |
|
114 Dcf::RequestAccess (void) |
|
115 { |
|
116 Time delayUntilAccessGranted = GetDelayUntilAccessGranted (Now ()); |
|
117 if (m_listener->AccessingAndWillNotify ()) |
|
118 { |
|
119 /* don't do anything. We will start a backoff and maybe |
|
120 * a timer when the txop notifies us of the end-of-access. |
|
121 */ |
|
122 NS_LOG_DEBUG ("accessing. will be notified."); |
|
123 } |
|
124 else if (m_accessTimerEvent.IsRunning ()) |
|
125 { |
|
126 /* we don't need to do anything because we have an access |
|
127 * timer which will expire soon. |
|
128 */ |
|
129 NS_LOG_DEBUG ("access timer running. will be notified"); |
|
130 } |
|
131 else if (IsBackoffNotCompleted (Now ()) && m_accessTimerEvent.IsExpired ()) |
|
132 { |
|
133 /* start timer for ongoing backoff. |
|
134 */ |
|
135 NS_LOG_DEBUG ("request access X delayed for="<<delayUntilAccessGranted); |
|
136 m_accessTimerEvent = Simulator::Schedule (delayUntilAccessGranted, |
|
137 &Dcf::AccessTimeout, this); |
|
138 } |
|
139 else if (IsPhyBusy () || IsNavBusy ()) |
|
140 { |
|
141 /* someone else has accessed the medium. |
|
142 * generate a backoff, start timer. |
|
143 */ |
|
144 StartBackoff (); |
|
145 } |
|
146 else if (delayUntilAccessGranted.IsStrictlyPositive ()) |
|
147 { |
|
148 /* medium is IDLE, we have no backoff running but we |
|
149 * need to wait a bit before accessing the medium. |
|
150 */ |
|
151 NS_LOG_DEBUG ("request access Y delayed for="<< delayUntilAccessGranted); |
|
152 NS_ASSERT (m_accessTimerEvent.IsExpired ()); |
|
153 m_accessTimerEvent = Simulator::Schedule (delayUntilAccessGranted, |
|
154 &Dcf::AccessTimeout, this); |
|
155 } |
|
156 else |
|
157 { |
|
158 /* we can access the medium now. |
|
159 */ |
|
160 NS_LOG_DEBUG ("access granted immediatly"); |
|
161 m_listener->AccessGrantedNow (); |
|
162 } |
|
163 } |
|
164 |
|
165 /*************************************************************** |
|
166 * Timeout method. Notifies when Access is Granted. |
|
167 ***************************************************************/ |
|
168 |
|
169 |
|
170 void |
|
171 Dcf::AccessTimeout () |
|
172 { |
|
173 UpdateBackoff (Now ()); |
|
174 if (m_backoffLeft.IsZero ()) |
|
175 { |
|
176 NS_LOG_DEBUG ("timeout access granted"); |
|
177 m_listener->AccessGrantedNow (); |
|
178 } |
|
179 else |
|
180 { |
|
181 Time delayUntilAccessGranted = GetDelayUntilAccessGranted (Now ()); |
|
182 NS_LOG_DEBUG ("timeout access delayed for "<< delayUntilAccessGranted); |
|
183 m_accessTimerEvent = Simulator::Schedule (delayUntilAccessGranted, |
|
184 &Dcf::AccessTimeout, this); |
|
185 } |
|
186 } |
|
187 |
|
188 |
|
189 /*************************************************************** |
|
190 * Random trivial helper methods. |
|
191 ***************************************************************/ |
|
192 |
|
193 Time |
|
194 Dcf::PickBackoffDelay (void) |
|
195 { |
|
196 uint32_t pickedCw = m_rng->GetNext (0, m_cw); |
|
197 NS_LOG_DEBUG ("cw="<<GetCwMin ()<< |
|
198 "<"<<m_cw<<"<"<<GetCwMax ()<< |
|
199 ", picked="<<pickedCw); |
|
200 Time delay = Scalar (pickedCw) * m_parameters->GetSlotTime (); |
|
201 return delay; |
|
202 } |
|
203 void |
|
204 Dcf::ResetCw (void) |
|
205 { |
|
206 m_cw = GetCwMin (); |
|
207 } |
|
208 void |
|
209 Dcf::UpdateFailedCw (void) |
|
210 { |
|
211 uint32_t cw = m_cw; |
|
212 cw *= 2; |
|
213 if (cw > GetCwMax ()) |
|
214 { |
|
215 cw = GetCwMax (); |
|
216 } |
|
217 m_cw = cw; |
|
218 } |
|
219 |
|
220 Time |
|
221 Dcf::MostRecent (Time a, Time b) const |
|
222 { |
|
223 return Max (a, b); |
|
224 } |
|
225 Time |
|
226 Dcf::MostRecent (Time a, Time b, Time c) const |
|
227 { |
|
228 Time retval; |
|
229 retval = Max (a, b); |
|
230 retval = Max (retval, c); |
|
231 return retval; |
|
232 } |
|
233 Time |
|
234 Dcf::MostRecent (Time a, Time b, Time c, Time d) const |
|
235 { |
|
236 Time e = Max (a, b); |
|
237 Time f = Max (c, d); |
|
238 Time retval = Max (e, f); |
|
239 return retval; |
|
240 } |
|
241 |
|
242 Time |
|
243 Dcf::GetDifs (void) const |
|
244 { |
|
245 return m_difs; |
|
246 } |
|
247 Time |
|
248 Dcf::GetEifs (void) const |
|
249 { |
|
250 return m_eifs; |
|
251 } |
|
252 uint32_t |
|
253 Dcf::GetCwMin (void) const |
|
254 { |
|
255 return m_cwMin; |
|
256 } |
|
257 uint32_t |
|
258 Dcf::GetCwMax (void) const |
|
259 { |
|
260 return m_cwMax; |
|
261 } |
|
262 |
|
263 /*************************************************************** |
|
264 * Complicated timekeeping backoff methods. |
|
265 ***************************************************************/ |
|
266 |
|
267 bool |
|
268 Dcf::IsPhyBusy (void) const |
|
269 { |
|
270 if (m_rxing) |
|
271 { |
|
272 return true; |
|
273 } |
|
274 Time lastTxEnd = m_lastTxStart + m_lastTxDuration; |
|
275 if (lastTxEnd > Simulator::Now ()) |
|
276 { |
|
277 return true; |
|
278 } |
|
279 return false; |
|
280 } |
|
281 |
|
282 bool |
|
283 Dcf::IsNavBusy (void) const |
|
284 { |
|
285 Time lastNavEnd = m_lastNavStart + m_lastNavDuration; |
|
286 if (lastNavEnd > Simulator::Now ()) |
|
287 { |
|
288 return true; |
|
289 } |
|
290 return false; |
|
291 } |
|
292 |
|
293 void |
|
294 Dcf::StartBackoff (void) |
|
295 { |
|
296 Time backoffStart = Now (); |
|
297 Time backoffDuration = PickBackoffDelay (); |
|
298 m_backoffTrace (backoffDuration); |
|
299 NS_ASSERT (m_backoffStart <= backoffStart); |
|
300 m_backoffStart = backoffStart; |
|
301 m_backoffLeft = backoffDuration; |
|
302 if (m_listener->AccessNeeded () && m_accessTimerEvent.IsExpired ()) |
|
303 { |
|
304 Time delayUntilAccessGranted = GetDelayUntilAccessGranted (Now ()); |
|
305 if (delayUntilAccessGranted.IsStrictlyPositive ()) |
|
306 { |
|
307 NS_LOG_DEBUG ("start at "<<backoffStart<<", for "<<backoffDuration); |
|
308 m_accessTimerEvent = Simulator::Schedule (delayUntilAccessGranted, |
|
309 &Dcf::AccessTimeout, this); |
|
310 } |
|
311 else |
|
312 { |
|
313 NS_LOG_DEBUG ("access granted now"); |
|
314 m_listener->AccessGrantedNow (); |
|
315 } |
|
316 } |
|
317 else |
|
318 { |
|
319 if (m_accessTimerEvent.IsRunning ()) |
|
320 { |
|
321 NS_LOG_DEBUG ("no access needed because timer running."); |
|
322 } |
|
323 if (!m_listener->AccessNeeded ()) |
|
324 { |
|
325 NS_LOG_DEBUG ("no access needed."); |
|
326 } |
|
327 NS_LOG_DEBUG ("no access needed for now."); |
|
328 } |
|
329 } |
|
330 Time |
|
331 Dcf::GetAccessGrantedStart (void) const |
|
332 { |
|
333 /* This method evaluates the time where access to the |
|
334 * medium is allowed. The return value could be |
|
335 * somewhere in the past or in the future. |
|
336 */ |
|
337 Time rxAccessStart; |
|
338 if (m_lastRxEnd >= m_lastRxStart) |
|
339 { |
|
340 if (m_lastRxReceivedOk) |
|
341 { |
|
342 rxAccessStart = m_lastRxEnd + GetDifs (); |
|
343 } |
|
344 else |
|
345 { |
|
346 rxAccessStart = m_lastRxEnd + GetEifs (); |
|
347 } |
|
348 } |
|
349 else |
|
350 { |
|
351 rxAccessStart = m_lastRxStart + m_lastRxDuration + GetDifs (); |
|
352 } |
|
353 Time busyAccessStart = m_lastBusyStart + m_lastBusyDuration + GetDifs (); |
|
354 Time txAccessStart = m_lastTxStart + m_lastTxDuration + GetDifs (); |
|
355 Time navAccessStart = m_lastNavStart + m_lastNavDuration + GetDifs (); |
|
356 Time accessGrantedStart = MostRecent (rxAccessStart, |
|
357 busyAccessStart, |
|
358 txAccessStart, |
|
359 navAccessStart); |
|
360 NS_LOG_DEBUG ("access granted start=" << accessGrantedStart); |
|
361 return accessGrantedStart; |
|
362 } |
|
363 |
|
364 bool |
|
365 Dcf::IsBackoffNotCompleted (Time now) |
|
366 { |
|
367 UpdateBackoff (now); |
|
368 if (m_backoffLeft.IsStrictlyPositive ()) |
|
369 { |
|
370 return true; |
|
371 } |
|
372 else |
|
373 { |
|
374 return false; |
|
375 } |
|
376 } |
|
377 |
|
378 |
|
379 Time |
|
380 Dcf::GetDelayUntilAccessGranted (Time now) |
|
381 { |
|
382 Time deltaTo = GetAccessGrantedStart () - now; |
|
383 Time retval = Max (deltaTo, Seconds (0)); |
|
384 UpdateBackoff (now); |
|
385 retval += m_backoffLeft; |
|
386 return retval; |
|
387 } |
|
388 void |
|
389 Dcf::UpdateBackoff (Time time) |
|
390 { |
|
391 if (m_backoffLeft.IsZero ()) |
|
392 { |
|
393 return; |
|
394 } |
|
395 |
|
396 //NS_LOG_DEBUG ("time: %f, backoffstart: %f\n", time, m_backoffStart); |
|
397 NS_ASSERT (time >= m_backoffStart); |
|
398 |
|
399 Time mostRecentEvent = MostRecent (m_backoffStart, |
|
400 GetAccessGrantedStart ()); |
|
401 if (mostRecentEvent < time) |
|
402 { |
|
403 Time newBackoffLeft = m_backoffLeft - (time - mostRecentEvent); |
|
404 m_backoffLeft = Max (newBackoffLeft, Seconds (0)); |
|
405 m_backoffStart = time; |
|
406 } |
|
407 NS_LOG_DEBUG ("backoff at="<<m_backoffStart<<", left="<< m_backoffLeft); |
|
408 } |
|
409 |
|
410 /*************************************************************** |
|
411 * Notification methods. |
|
412 ***************************************************************/ |
|
413 void |
|
414 Dcf::NotifyNavReset (Time navStart, Time duration) |
|
415 { |
|
416 NS_LOG_DEBUG ("nav reset at="<<navStart<<", for="<<duration); |
|
417 m_lastNavStart = navStart; |
|
418 m_lastNavDuration = duration; |
|
419 Time navEnd = navStart + duration; |
|
420 Time newDelayUntilAccessGranted = GetDelayUntilAccessGranted (navEnd); |
|
421 NS_ASSERT (newDelayUntilAccessGranted.IsStrictlyPositive ()); |
|
422 /* This is quite unfortunate but we need to cancel the access timer |
|
423 * because this nav reset might have brought the time of |
|
424 * possible access closer to us than expected. |
|
425 */ |
|
426 if (m_accessTimerEvent.IsRunning ()) |
|
427 { |
|
428 m_accessTimerEvent.Cancel (); |
|
429 m_accessTimerEvent = Simulator::Schedule (newDelayUntilAccessGranted, |
|
430 &Dcf::AccessTimeout, this); |
|
431 } |
|
432 } |
|
433 void |
|
434 Dcf::NotifyNavStart (Time navStart, Time duration) |
|
435 { |
|
436 NS_ASSERT (m_lastNavStart < navStart); |
|
437 NS_LOG_DEBUG ("nav start at="<<navStart<<", for="<<duration); |
|
438 UpdateBackoff (navStart); |
|
439 m_lastNavStart = navStart; |
|
440 m_lastNavDuration = duration; |
|
441 } |
|
442 void |
|
443 Dcf::NotifyNavContinue (Time navStart, Time duration) |
|
444 { |
|
445 NotifyNavStart (navStart, duration); |
|
446 } |
|
447 |
|
448 void |
|
449 Dcf::NotifyRxStartNow (Time duration) |
|
450 { |
|
451 Time now = Now (); |
|
452 NS_LOG_DEBUG ("rx start at="<<now<<", for="<<duration); |
|
453 UpdateBackoff (now); |
|
454 m_lastRxStart = now; |
|
455 m_lastRxDuration = duration; |
|
456 m_rxing = true; |
|
457 } |
|
458 void |
|
459 Dcf::NotifyRxEndOkNow (void) |
|
460 { |
|
461 Time now = Now (); |
|
462 NS_LOG_DEBUG ("rx end ok at="<<now); |
|
463 m_lastRxEnd = now; |
|
464 m_lastRxReceivedOk = true; |
|
465 m_rxing = false; |
|
466 } |
|
467 void |
|
468 Dcf::NotifyRxEndErrorNow (void) |
|
469 { |
|
470 Time now = Now (); |
|
471 NS_LOG_DEBUG ("rx end error at="); |
|
472 m_lastRxEnd = now; |
|
473 m_lastRxReceivedOk = false; |
|
474 m_rxing = false; |
|
475 } |
|
476 void |
|
477 Dcf::NotifyTxStartNow (Time duration) |
|
478 { |
|
479 Time now = Now (); |
|
480 NS_LOG_DEBUG ("tx start at="<<now<<" for "<<duration); |
|
481 UpdateBackoff (now); |
|
482 m_lastTxStart = now; |
|
483 m_lastTxDuration = duration; |
|
484 } |
|
485 |
|
486 void |
|
487 Dcf::NotifyCcaBusyStartNow (Time duration) |
|
488 { |
|
489 Time now = Now (); |
|
490 NS_LOG_DEBUG ("busy start at="<<now<<" for "<<duration); |
|
491 UpdateBackoff (now); |
|
492 m_lastBusyStart = now; |
|
493 m_lastBusyDuration = duration; |
|
494 } |
|
495 |
|
496 } // namespace ns3 |
|
497 |
|
498 #ifdef RUN_SELF_TESTS |
|
499 #include "ns3/test.h" |
|
500 #include <list> |
|
501 |
|
502 namespace ns3 { |
|
503 |
|
504 class DcfTest : public Test { |
|
505 public: |
|
506 DcfTest (); |
|
507 virtual bool RunTests (void); |
|
508 |
|
509 // callback from DcfListener |
|
510 void AccessGrantedNow (void); |
|
511 bool AccessNeeded (void); |
|
512 bool AccessingAndWillNotify (void); |
|
513 private: |
|
514 |
|
515 void AddRxOkEvt (uint64_t at, uint64_t duration); |
|
516 void AddRxErrorEvt (uint64_t at, uint64_t duration); |
|
517 void AddTxEvt (uint64_t at, uint64_t duration); |
|
518 void AddNavReset (uint64_t at, uint64_t start, uint64_t duration); |
|
519 void AddNavStart (uint64_t at, uint64_t start, uint64_t duration); |
|
520 void AddNavContinue (uint64_t at, uint64_t start, uint64_t duration); |
|
521 void AddAccessRequest (uint64_t time); |
|
522 void AddAccessError (uint64_t time); |
|
523 void AddAccessErrorButOk (uint64_t time); |
|
524 void AddAccessOk (uint64_t time); |
|
525 |
|
526 void ExpectAccessGranted (uint64_t time); |
|
527 |
|
528 // callback to forward to DCF |
|
529 void AccessError (uint64_t time); |
|
530 void AccessErrorButOk (uint64_t time); |
|
531 void AccessOk (uint64_t time); |
|
532 |
|
533 void StartTest (void); |
|
534 void EndTest (void); |
|
535 |
|
536 Dcf *m_dcf; |
|
537 MacParameters *m_parameters; |
|
538 class TestAccessListener *m_listener; |
|
539 std::list<uint64_t> m_accessGrantedExpected; |
|
540 bool m_failed; |
|
541 }; |
|
542 |
|
543 class TestAccessListener : public DcfAccessListener { |
|
544 public: |
|
545 TestAccessListener (DcfTest *test) |
|
546 : m_test (test) {} |
|
547 virtual ~TestAccessListener () {} |
|
548 virtual void AccessGrantedNow (void) { |
|
549 m_test->AccessGrantedNow (); |
|
550 } |
|
551 virtual bool AccessNeeded (void) { |
|
552 return m_test->AccessNeeded (); |
|
553 } |
|
554 virtual bool AccessingAndWillNotify (void) { |
|
555 return m_test->AccessingAndWillNotify (); |
|
556 } |
|
557 private: |
|
558 DcfTest *m_test; |
|
559 }; |
|
560 |
|
561 |
|
562 |
|
563 DcfTest::DcfTest () |
|
564 : Test ("Dcf") {} |
|
565 |
|
566 void |
|
567 DcfTest::AccessGrantedNow (void) |
|
568 { |
|
569 if (m_accessGrantedExpected.empty ()) |
|
570 { |
|
571 Failure () << "DCF " |
|
572 << "Failure: unexpected access granted at="<<Simulator::Now () |
|
573 << std::endl; |
|
574 m_failed = true; |
|
575 return; |
|
576 } |
|
577 uint64_t expected = m_accessGrantedExpected.front (); |
|
578 uint64_t actual = Simulator::Now ().GetMicroSeconds (); |
|
579 if (expected != actual) |
|
580 { |
|
581 Failure () << "DCF " |
|
582 << "Failure: access granted at=" << Simulator::Now () |
|
583 << ", expected at="<<expected<<"us" |
|
584 << std::endl; |
|
585 m_failed = true; |
|
586 return; |
|
587 } |
|
588 m_accessGrantedExpected.erase (m_accessGrantedExpected.begin ()); |
|
589 } |
|
590 bool |
|
591 DcfTest::AccessNeeded (void) |
|
592 { |
|
593 return true; |
|
594 } |
|
595 bool |
|
596 DcfTest::AccessingAndWillNotify (void) |
|
597 { |
|
598 return false; |
|
599 } |
|
600 |
|
601 void |
|
602 DcfTest::AddRxOkEvt (uint64_t at, uint64_t duration) |
|
603 { |
|
604 Simulator::Schedule (MicroSeconds (at) - Now (), |
|
605 &Dcf::NotifyRxStartNow, m_dcf, |
|
606 MicroSeconds (duration)); |
|
607 Simulator::Schedule (MicroSeconds (at+duration) - Now (), |
|
608 &Dcf::NotifyRxEndOkNow, m_dcf); |
|
609 } |
|
610 void |
|
611 DcfTest::AddRxErrorEvt (uint64_t at, uint64_t duration) |
|
612 { |
|
613 Simulator::Schedule (MicroSeconds (at) - Now (), |
|
614 &Dcf::NotifyRxStartNow, m_dcf, |
|
615 MicroSeconds (duration)); |
|
616 Simulator::Schedule (MicroSeconds (at+duration) - Now (), |
|
617 &Dcf::NotifyRxEndErrorNow, m_dcf); |
|
618 } |
|
619 void |
|
620 DcfTest::AddTxEvt (uint64_t at, uint64_t duration) |
|
621 { |
|
622 Simulator::Schedule (MicroSeconds (at) - Now (), |
|
623 &Dcf::NotifyTxStartNow, m_dcf, |
|
624 MicroSeconds (duration)); |
|
625 } |
|
626 void |
|
627 DcfTest::AddNavReset (uint64_t at, uint64_t start, uint64_t duration) |
|
628 { |
|
629 Simulator::Schedule (MicroSeconds (at) - Now (), |
|
630 &Dcf::NotifyNavReset, m_dcf, |
|
631 MicroSeconds (start), |
|
632 MicroSeconds (duration)); |
|
633 } |
|
634 void |
|
635 DcfTest::AddNavStart (uint64_t at, uint64_t start, uint64_t duration) |
|
636 { |
|
637 Simulator::Schedule (MicroSeconds (at) - Now (), |
|
638 &Dcf::NotifyNavStart, m_dcf, |
|
639 MicroSeconds (start), MicroSeconds (duration)); |
|
640 } |
|
641 void |
|
642 DcfTest::AddNavContinue (uint64_t at, uint64_t start, uint64_t duration) |
|
643 { |
|
644 Simulator::Schedule (MicroSeconds (at) - Now (), |
|
645 &Dcf::NotifyNavContinue, m_dcf, |
|
646 MicroSeconds (start), |
|
647 MicroSeconds (duration)); |
|
648 } |
|
649 void |
|
650 DcfTest::AddAccessRequest (uint64_t time) |
|
651 { |
|
652 Simulator::Schedule (MicroSeconds (time) - Now (), |
|
653 &Dcf::RequestAccess, m_dcf); |
|
654 } |
|
655 void |
|
656 DcfTest::AddAccessError (uint64_t time) |
|
657 { |
|
658 Simulator::Schedule (MicroSeconds (time) - Now (), |
|
659 &DcfTest::AccessError, this, |
|
660 time); |
|
661 } |
|
662 void |
|
663 DcfTest::AddAccessErrorButOk (uint64_t time) |
|
664 { |
|
665 Simulator::Schedule (MicroSeconds (time) - Now (), |
|
666 &DcfTest::AccessErrorButOk, this, |
|
667 time); |
|
668 } |
|
669 void |
|
670 DcfTest::AddAccessOk (uint64_t time) |
|
671 { |
|
672 Simulator::Schedule (MicroSeconds (time) - Now (), |
|
673 &DcfTest::AccessOk, this, |
|
674 time); |
|
675 } |
|
676 |
|
677 void |
|
678 DcfTest::AccessError (uint64_t time) |
|
679 { |
|
680 m_dcf->UpdateFailedCw (); |
|
681 m_dcf->StartBackoff (); |
|
682 } |
|
683 void |
|
684 DcfTest::AccessErrorButOk (uint64_t time) |
|
685 { |
|
686 m_dcf->ResetCw (); |
|
687 m_dcf->StartBackoff (); |
|
688 } |
|
689 void |
|
690 DcfTest::AccessOk (uint64_t time) |
|
691 { |
|
692 m_dcf->ResetCw (); |
|
693 m_dcf->StartBackoff (); |
|
694 } |
|
695 |
|
696 void |
|
697 DcfTest::ExpectAccessGranted (uint64_t time) |
|
698 { |
|
699 m_accessGrantedExpected.push_back (time); |
|
700 } |
|
701 |
|
702 void |
|
703 DcfTest::StartTest (void) |
|
704 { |
|
705 m_dcf = new Dcf (8, 64); |
|
706 TestRandomStream *stream = new TestRandomStream (); |
|
707 stream->AddNext (1); |
|
708 stream->AddNext (1); |
|
709 stream->AddNext (1); |
|
710 stream->AddNext (1); |
|
711 stream->AddNext (1); |
|
712 stream->AddNext (1); |
|
713 m_dcf->ResetRngForTest (stream); |
|
714 m_parameters = new MacParameters (); |
|
715 m_listener = new TestAccessListener (this); |
|
716 m_dcf->SetParameters (m_parameters); |
|
717 m_dcf->RegisterAccessListener (m_listener); |
|
718 |
|
719 m_parameters->SetSlotTime (MicroSeconds (1)); |
|
720 m_dcf->SetDifs (MicroSeconds (3)); |
|
721 m_dcf->SetEifs (MicroSeconds (4)); |
|
722 } |
|
723 void |
|
724 DcfTest::EndTest (void) |
|
725 { |
|
726 if (!m_accessGrantedExpected.empty ()) |
|
727 { |
|
728 Failure () << "DCF: access not granted as expected" |
|
729 << std::endl; |
|
730 } |
|
731 m_accessGrantedExpected.erase (m_accessGrantedExpected.begin (), |
|
732 m_accessGrantedExpected.end ()); |
|
733 Simulator::Destroy (); |
|
734 delete m_dcf; |
|
735 delete m_parameters; |
|
736 delete m_listener; |
|
737 } |
|
738 |
|
739 bool |
|
740 DcfTest::RunTests (void) |
|
741 { |
|
742 m_failed = false; |
|
743 |
|
744 // 32 37 |
|
745 // | rx ok | |
|
746 // | idle | rx ok | nav busy | difs | backoff | |
|
747 // 0 10 30 40 43 44 |
|
748 // |
|
749 StartTest (); |
|
750 AddRxOkEvt (10, 20); |
|
751 AddNavStart (30, 30, 2+8); |
|
752 AddRxOkEvt (32, 5); |
|
753 AddAccessRequest (15); |
|
754 AddAccessRequest (16); |
|
755 AddAccessRequest (20); |
|
756 ExpectAccessGranted (44); |
|
757 Simulator::Run (); |
|
758 EndTest (); |
|
759 |
|
760 // 32 39 |
|
761 // | rx ok | |
|
762 // | idle | rx ok | nav busy | | difs | backoff | |
|
763 // 0 10 30 37 42 43 |
|
764 // |
|
765 StartTest (); |
|
766 AddRxOkEvt (10, 20); |
|
767 AddNavStart (30, 30, 2+5); |
|
768 AddRxOkEvt (32, 7); |
|
769 AddAccessRequest (15); |
|
770 AddAccessRequest (16); |
|
771 AddAccessRequest (20); |
|
772 ExpectAccessGranted (43); |
|
773 Simulator::Run (); |
|
774 EndTest (); |
|
775 |
|
776 StartTest (); |
|
777 AddAccessRequest (10); |
|
778 ExpectAccessGranted (10); |
|
779 Simulator::Run (); |
|
780 EndTest (); |
|
781 |
|
782 // 32 39 |
|
783 // | rx ok | |
|
784 // | idle | rx ok | nav busy | difs | |
|
785 // 0 10 30 40 43 |
|
786 // |
|
787 StartTest (); |
|
788 AddRxOkEvt (10, 20); |
|
789 AddNavStart (30, 30, 2+8); |
|
790 AddRxOkEvt (32, 7); |
|
791 AddAccessRequest (40); |
|
792 ExpectAccessGranted (43); |
|
793 Simulator::Run (); |
|
794 EndTest (); |
|
795 |
|
796 // 32 39 |
|
797 // | rx ok | |
|
798 // | idle | rx ok | nav busy | difs | |
|
799 // 0 10 30 40 43 |
|
800 // |
|
801 StartTest (); |
|
802 AddRxOkEvt (10, 20); |
|
803 AddNavStart (30, 30, 2+8); |
|
804 AddRxOkEvt (32, 7); |
|
805 AddAccessRequest (41); |
|
806 ExpectAccessGranted (43); |
|
807 Simulator::Run (); |
|
808 EndTest (); |
|
809 |
|
810 // 32 39 |
|
811 // | rx ok | |
|
812 // | idle | rx ok | nav busy | difs | |
|
813 // 0 10 30 40 43 |
|
814 // |
|
815 StartTest (); |
|
816 AddRxOkEvt (10, 20); |
|
817 AddNavStart (30, 30, 2+8); |
|
818 AddRxOkEvt (32, 7); |
|
819 AddAccessRequest (43); |
|
820 ExpectAccessGranted (43); |
|
821 Simulator::Run (); |
|
822 EndTest (); |
|
823 |
|
824 // |
|
825 // | idle | rx error | idle | rx ok | difs | |
|
826 // 0 10 30 31 38 41 |
|
827 // |
|
828 StartTest (); |
|
829 AddRxErrorEvt (10, 20); |
|
830 AddRxOkEvt (31, 7); |
|
831 AddAccessRequest (39); |
|
832 ExpectAccessGranted (41); |
|
833 Simulator::Run (); |
|
834 EndTest (); |
|
835 |
|
836 // |
|
837 // | idle | rx error | idle | rx error | eifs | |
|
838 // 0 10 30 31 38 42 |
|
839 // |
|
840 StartTest (); |
|
841 AddRxErrorEvt (10, 20); |
|
842 AddRxErrorEvt (31, 7); |
|
843 AddAccessRequest (39); |
|
844 ExpectAccessGranted (42); |
|
845 Simulator::Run (); |
|
846 EndTest (); |
|
847 |
|
848 |
|
849 // |
|
850 // 30 45 |
|
851 // | nav busy | |
|
852 // | idle | rx ok | idle | rx ok | difs | backoff | |
|
853 // 0 10 30 35 45 48 49 |
|
854 // |
|
855 StartTest (); |
|
856 AddRxOkEvt (10, 20); |
|
857 AddNavStart (30, 30, 200); |
|
858 AddRxOkEvt (35, 10); |
|
859 AddNavReset (45, 45, 0); |
|
860 AddAccessRequest (32); |
|
861 ExpectAccessGranted (49); |
|
862 Simulator::Run (); |
|
863 EndTest (); |
|
864 |
|
865 // |
|
866 // 30 45 |
|
867 // | nav busy | |
|
868 // | idle | rx ok | idle | rx ok | |
|
869 // 0 10 30 35 45 |
|
870 // |
|
871 StartTest (); |
|
872 AddRxOkEvt (10, 20); |
|
873 AddNavStart (30, 30, 200); |
|
874 AddRxOkEvt (35, 10); |
|
875 AddNavReset (45, 45, 0); |
|
876 Simulator::Run (); |
|
877 EndTest (); |
|
878 |
|
879 // |
|
880 // 30 45 |
|
881 // | nav busy | |
|
882 // | idle | rx ok | idle | rx ok | difs | |
|
883 // 0 10 30 35 45 48 |
|
884 // |
|
885 StartTest (); |
|
886 AddRxOkEvt (10, 20); |
|
887 AddNavStart (30, 30, 200); |
|
888 AddRxOkEvt (35, 10); |
|
889 AddNavReset (45, 45, 0); |
|
890 AddAccessRequest (49); |
|
891 ExpectAccessGranted (49); |
|
892 Simulator::Run (); |
|
893 EndTest (); |
|
894 |
|
895 |
|
896 return !m_failed; |
|
897 } |
|
898 |
|
899 static DcfTest gDcfTest; |
|
900 |
|
901 } // namespace ns3 |
|
902 |
|
903 |
|
904 #endif /* RUN_SELF_TESTS */ |
|