A Discrete-Event Network Simulator
API
minstrel-wifi-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 Duy Nguyen
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: Duy Nguyen <duy@soe.ucsc.edu>
19  * Matías Richart <mrichart@fing.edu.uy>
20  *
21  * Some Comments:
22  *
23  * 1) Segment Size is declared for completeness but not used because it has
24  * to do more with the requirement of the specific hardware.
25  *
26  * 2) By default, Minstrel applies the multi-rate retry (the core of Minstrel
27  * algorithm). Otherwise, please use ConstantRateWifiManager instead.
28  *
29  * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
30  */
31 
32 #include "minstrel-wifi-manager.h"
33 #include "wifi-phy.h"
34 #include "ns3/simulator.h"
35 #include "ns3/log.h"
36 #include "ns3/uinteger.h"
37 #include "ns3/double.h"
38 #include "ns3/boolean.h"
39 #include "ns3/wifi-mac.h"
40 #include "ns3/assert.h"
41 #include <vector>
42 #include <iomanip>
43 
44 #define Min(a,b) ((a < b) ? a : b)
45 
46 namespace ns3 {
47 
48 NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
49 
50 NS_OBJECT_ENSURE_REGISTERED (MinstrelWifiManager);
51 
52 TypeId
54 {
55  static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
57  .SetGroupName ("Wifi")
58  .AddConstructor<MinstrelWifiManager> ()
59  .AddAttribute ("UpdateStatistics",
60  "The interval between updating statistics table ",
61  TimeValue (Seconds (0.1)),
63  MakeTimeChecker ())
64  .AddAttribute ("LookAroundRate",
65  "the percentage to try other rates",
66  DoubleValue (10),
68  MakeDoubleChecker<double> ())
69  .AddAttribute ("EWMA",
70  "EWMA level",
71  DoubleValue (75),
73  MakeDoubleChecker<double> ())
74  .AddAttribute ("SampleColumn",
75  "The number of columns used for sampling",
76  UintegerValue (10),
78  MakeUintegerChecker <uint32_t> ())
79  .AddAttribute ("PacketLength",
80  "The packet length used for calculating mode TxTime",
81  UintegerValue (1200),
83  MakeUintegerChecker <uint32_t> ())
84  .AddAttribute ("PrintStats",
85  "Print statistics table",
86  BooleanValue (false),
89  ;
90  return tid;
91 }
92 
94 {
95  NS_LOG_FUNCTION (this);
96  m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
97 }
98 
100 {
101  NS_LOG_FUNCTION (this);
102 }
103 
104 void
106 {
107  NS_LOG_FUNCTION (this << phy);
108  uint32_t nModes = phy->GetNModes ();
109  for (uint32_t i = 0; i < nModes; i++)
110  {
111  WifiMode mode = phy->GetMode (i);
112  WifiTxVector txVector;
113  txVector.SetMode (mode);
114  AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()));
115  }
117 }
118 
119 void
121 {
122  NS_LOG_FUNCTION (this << mac);
124 }
125 
126 int64_t
128 {
129  NS_LOG_FUNCTION (this << stream);
131  return 1;
132 }
133 
134 Time
136 {
137  NS_LOG_FUNCTION (this << mode);
138  for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
139  {
140  if (mode == i->second)
141  {
142  return i->first;
143  }
144  }
145  NS_ASSERT (false);
146  return Seconds (0);
147 }
148 
149 void
151 {
152  NS_LOG_FUNCTION (this << mode << t);
153  m_calcTxTime.push_back (std::make_pair (t, mode));
154 }
155 
158 {
159  NS_LOG_FUNCTION (this);
161 
163  station->m_col = 0;
164  station->m_index = 0;
165  station->m_maxTpRate = 0;
166  station->m_maxTpRate2 = 0;
167  station->m_maxProbRate = 0;
168  station->m_nModes = 0;
169  station->m_totalPacketsCount = 0;
170  station->m_samplePacketsCount = 0;
171  station->m_isSampling = false;
172  station->m_sampleRate = 0;
173  station->m_sampleDeferred = false;
174  station->m_shortRetry = 0;
175  station->m_longRetry = 0;
176  station->m_retry = 0;
177  station->m_txrate = 0;
178  station->m_initialized = false;
179 
180  return station;
181 }
182 
183 void
185 {
186  NS_LOG_FUNCTION (this << station);
187  if (!station->m_initialized && GetNSupported (station) > 1)
188  {
189  //Note: we appear to be doing late initialization of the table
190  //to make sure that the set of supported rates has been initialized
191  //before we perform our own initialization.
192  station->m_nModes = GetNSupported (station);
193  station->m_minstrelTable = MinstrelRate (station->m_nModes);
194  station->m_sampleTable = SampleRate (station->m_nModes, std::vector<uint32_t> (m_sampleCol));
195  InitSampleTable (station);
196  RateInit (station);
197  station->m_initialized = true;
198  std::ostringstream tmp;
199  tmp << "minstrel-stats-" << station->m_state->m_address << ".txt";
200  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
201  }
202 }
203 
219 void
221 {
222  NS_LOG_FUNCTION (this << station);
223  station->m_longRetry++;
224  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
225 
226  NS_LOG_DEBUG ("DoReportDataFailed " << station << " rate " << station->m_txrate << " longRetry " << station->m_longRetry);
227 
228  //for normal rate, we're not currently sampling random rates
229  if (!station->m_isSampling)
230  {
231  NS_LOG_DEBUG ("Failed with normal rate: current=" << station->m_txrate << ", sample=" << station->m_sampleRate << ", maxTp=" << station->m_maxTpRate << ", maxTp2=" << station->m_maxTpRate2 << ", maxProb=" << station->m_maxProbRate);
232  //use best throughput rate
233  if (station->m_longRetry < station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount)
234  {
235  NS_LOG_DEBUG (" More retries left for the maximum throughput rate.");
236  station->m_txrate = station->m_maxTpRate;
237  }
238 
239  //use second best throughput rate
240  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
241  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount))
242  {
243  NS_LOG_DEBUG (" More retries left for the second maximum throughput rate.");
244  station->m_txrate = station->m_maxTpRate2;
245  }
246 
247  //use best probability rate
248  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
249  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
250  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
251  {
252  NS_LOG_DEBUG (" More retries left for the maximum probability rate.");
253  station->m_txrate = station->m_maxProbRate;
254  }
255 
256  //use lowest base rate
257  else if (station->m_longRetry > (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
258  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
259  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
260  {
261  NS_LOG_DEBUG (" More retries left for the base rate.");
262  station->m_txrate = 0;
263  }
264  }
265 
266  //for look-around rate, we're currently sampling random rates
267  else
268  {
269  NS_LOG_DEBUG ("Failed with look around rate: current=" << station->m_txrate << ", sample=" << station->m_sampleRate << ", maxTp=" << station->m_maxTpRate << ", maxTp2=" << station->m_maxTpRate2 << ", maxProb=" << station->m_maxProbRate);
270  //current sampling rate is slower than the current best rate
271  if (station->m_sampleDeferred)
272  {
273  NS_LOG_DEBUG ("Look around rate is slower than the maximum throughput rate.");
274  //use best throughput rate
275  if (station->m_longRetry < station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount)
276  {
277  NS_LOG_DEBUG (" More retries left for the maximum throughput rate.");
278  station->m_txrate = station->m_maxTpRate;
279  }
280 
281  //use random rate
282  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
283  station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount))
284  {
285  NS_LOG_DEBUG (" More retries left for the sampling rate.");
286  station->m_txrate = station->m_sampleRate;
287  }
288 
289  //use max probability rate
290  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
291  station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
292  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount ))
293  {
294  NS_LOG_DEBUG (" More retries left for the maximum probability rate.");
295  station->m_txrate = station->m_maxProbRate;
296  }
297 
298  //use lowest base rate
299  else if (station->m_longRetry > (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
300  station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
301  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
302  {
303  NS_LOG_DEBUG (" More retries left for the base rate.");
304  station->m_txrate = 0;
305  }
306  }
307  //current sampling rate is better than current best rate
308  else
309  {
310  NS_LOG_DEBUG ("Look around rate is faster than the maximum throughput rate.");
311  //use random rate
312  if (station->m_longRetry < station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount)
313  {
314  NS_LOG_DEBUG (" More retries left for the sampling rate.");
315  station->m_txrate = station->m_sampleRate;
316  }
317 
318  //use the best throughput rate
319  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
320  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount))
321  {
322  NS_LOG_DEBUG (" More retries left for the maximum throughput rate.");
323  station->m_txrate = station->m_maxTpRate;
324  }
325 
326  //use the best probability rate
327  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
328  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
329  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
330  {
331  NS_LOG_DEBUG (" More retries left for the maximum probability rate.");
332  station->m_txrate = station->m_maxProbRate;
333  }
334 
335  //use the lowest base rate
336  else if (station->m_longRetry > (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
337  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
338  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
339  {
340  NS_LOG_DEBUG (" More retries left for the base rate.");
341  station->m_txrate = 0;
342  }
343  }
344  }
345 }
346 
349 {
350  NS_LOG_FUNCTION (this << station);
351  uint32_t channelWidth = GetChannelWidth (station);
352  if (channelWidth > 20 && channelWidth != 22)
353  {
354  //avoid to use legacy rate adaptation algorithms for IEEE 802.11n/ac
355  channelWidth = 20;
356  }
357  if (!station->m_initialized)
358  {
359  CheckInit (station);
360 
361  //start the rate at half way
362  station->m_txrate = station->m_nModes / 2;
363  }
364  return WifiTxVector (GetSupported (station, station->m_txrate), GetDefaultTxPowerLevel (), GetLongRetryCount (station), false, 1, 0, channelWidth, GetAggregation (station), false);
365 }
366 
369 {
370  NS_LOG_FUNCTION (this << station);
371  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
372  uint32_t channelWidth = GetChannelWidth (station);
373  if (channelWidth > 20 && channelWidth != 22)
374  {
375  //avoid to use legacy rate adaptation algorithms for IEEE 802.11n/ac
376  channelWidth = 20;
377  }
378  WifiTxVector rtsTxVector;
379  if (GetUseNonErpProtection () == false)
380  {
381  rtsTxVector = WifiTxVector (GetSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station), false, 1, 0, channelWidth, GetAggregation (station), false);
382  }
383  else
384  {
385  rtsTxVector = WifiTxVector (GetNonErpSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station), false, 1, 0, channelWidth, GetAggregation (station), false);
386  }
387  return rtsTxVector;
388 }
389 
390 uint32_t
392 {
393  if (!station->m_isSampling)
394  {
395  return station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
396  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
397  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount +
398  station->m_minstrelTable[0].adjustedRetryCount;
399  }
400  else
401  {
402  return station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
403  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
404  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount +
405  station->m_minstrelTable[0].adjustedRetryCount;
406  }
407 }
408 
409 uint32_t
411 {
412  NS_LOG_FUNCTION (this << station);
413 
414  if (station->m_totalPacketsCount == 0)
415  {
416  return 0;
417  }
418 
419 
420  uint32_t idx;
421 
422  int delta = (station->m_totalPacketsCount * m_lookAroundRate / 100) - (station->m_samplePacketsCount + station->m_numSamplesDeferred / 2);
423 
424  NS_LOG_DEBUG ("Decide sampling. Delta: " << delta << " lookAroundRatio: " << m_lookAroundRate);
425 
426  /* delta < 0: no sampling required */
427  if (delta >= 0)
428  {
429  NS_LOG_DEBUG ("Search next sampling rate");
430  int ratesSupported = station->m_nModes;
431  if (delta > ratesSupported * 2)
432  {
433  /* From Linux implementation:
434  * With multi-rate retry, not every planned sample
435  * attempt actually gets used, due to the way the retry
436  * chain is set up - [max_tp,sample,prob,lowest] for
437  * sample_rate < max_tp.
438  *
439  * If there's too much sampling backlog and the link
440  * starts getting worse, minstrel would start bursting
441  * out lots of sampling frames, which would result
442  * in a large throughput loss. */
443  station->m_samplePacketsCount += (delta - ratesSupported * 2);
444  }
445 
446  //now go through the table and find an index rate
447  idx = GetNextSample (station);
448 
449  //error check
450  if (idx >= station->m_nModes)
451  {
452  NS_LOG_DEBUG ("ALERT!!! ERROR");
453  }
454 
455  //set the rate that we're currently sampling
456  station->m_sampleRate = idx;
457 
458  /* From Linux implementation:
459  * Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
460  * rate sampling method should be used.
461  * Respect such rates that are not sampled for 20 iterations.
462  */
463  if ((station->m_minstrelTable[idx].perfectTxTime > station->m_minstrelTable[station->m_maxTpRate].perfectTxTime)
464  && (station->m_minstrelTable[idx].numSamplesSkipped < 20))
465  {
466  // If the rate is slower and we have sample it enough, defer to second stage
467  station->m_sampleDeferred = true;
468  station->m_numSamplesDeferred++;
469 
470  //set flag that we are currently sampling
471  station->m_isSampling = true;
472  }
473  else
474  {
475  // if samplieLimit is zero, then don't sample this rate
476  if (!station->m_minstrelTable[idx].sampleLimit)
477  {
478  idx = station->m_maxTpRate;
479  station->m_isSampling = false;
480  }
481  else
482  {
483  //set flag that we are currently sampling
484  station->m_isSampling = true;
485  if (station->m_minstrelTable[idx].sampleLimit > 0)
486  {
487  station->m_minstrelTable[idx].sampleLimit--;
488  }
489  }
490  }
491 
492  //using the best rate instead
493  if (station->m_sampleDeferred)
494  {
495  NS_LOG_DEBUG ("The next look around rate is slower than the maximum throughput rate, continue with the maximum throughput rate: " << station->m_maxTpRate << "(" << GetSupported (station, station->m_maxTpRate) << ")");
496  idx = station->m_maxTpRate;
497  }
498  }
499  //continue using the best rate
500  else
501  {
502  NS_LOG_DEBUG ("Continue using the maximum throughput rate: " << station->m_maxTpRate << "(" << GetSupported (station, station->m_maxTpRate) << ")");
503  idx = station->m_maxTpRate;
504  }
505 
506  NS_LOG_DEBUG ("Rate = " << idx << "(" << GetSupported (station, idx) << ")");
507 
508  return idx;
509 }
510 
511 void
513 {
514  NS_LOG_FUNCTION (this << station);
515  if (Simulator::Now () < station->m_nextStatsUpdate)
516  {
517  return;
518  }
519 
520  if (!station->m_initialized)
521  {
522  return;
523  }
524  NS_LOG_FUNCTION (this);
526  NS_LOG_DEBUG ("Next update at " << station->m_nextStatsUpdate);
527  NS_LOG_DEBUG ("Currently using rate: " << station->m_txrate << " (" << GetSupported (station, station->m_txrate) << ")");
528 
529  Time txTime;
530  uint32_t tempProb;
531 
532  NS_LOG_DEBUG ("Index-Rate\t\tAttempt\tSuccess");
533  for (uint32_t i = 0; i < station->m_nModes; i++)
534  {
535 
536  //calculate the perfect tx time for this rate
537  txTime = station->m_minstrelTable[i].perfectTxTime;
538 
539  //just for initialization
540  if (txTime.GetMicroSeconds () == 0)
541  {
542  txTime = Seconds (1);
543  }
544 
545  NS_LOG_DEBUG (i << " " << GetSupported (station, i) <<
546  "\t" << station->m_minstrelTable[i].numRateAttempt <<
547  "\t" << station->m_minstrelTable[i].numRateSuccess);
548 
549  //if we've attempted something
550  if (station->m_minstrelTable[i].numRateAttempt)
551  {
552  station->m_minstrelTable[i].numSamplesSkipped = 0;
557  tempProb = (station->m_minstrelTable[i].numRateSuccess * 18000) / station->m_minstrelTable[i].numRateAttempt;
558 
559  //bookeeping
560  station->m_minstrelTable[i].prob = tempProb;
561 
562  if (station->m_minstrelTable[i].successHist == 0)
563  {
564  station->m_minstrelTable[i].ewmaProb = tempProb;
565  }
566  else
567  {
568  //ewma probability (cast for gcc 3.4 compatibility)
569  tempProb = static_cast<uint32_t> (((tempProb * (100 - m_ewmaLevel)) + (station->m_minstrelTable[i].ewmaProb * m_ewmaLevel) ) / 100);
570 
571  station->m_minstrelTable[i].ewmaProb = tempProb;
572  }
573 
574  //calculating throughput
575  station->m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds ());
576 
577  }
578  else
579  {
580  station->m_minstrelTable[i].numSamplesSkipped++;
581  }
582 
583  //bookeeping
584  station->m_minstrelTable[i].successHist += station->m_minstrelTable[i].numRateSuccess;
585  station->m_minstrelTable[i].attemptHist += station->m_minstrelTable[i].numRateAttempt;
586  station->m_minstrelTable[i].prevNumRateSuccess = station->m_minstrelTable[i].numRateSuccess;
587  station->m_minstrelTable[i].prevNumRateAttempt = station->m_minstrelTable[i].numRateAttempt;
588  station->m_minstrelTable[i].numRateSuccess = 0;
589  station->m_minstrelTable[i].numRateAttempt = 0;
590 
591  //Sample less often below 10% and above 95% of success
592  if ((station->m_minstrelTable[i].ewmaProb > 17100) || (station->m_minstrelTable[i].ewmaProb < 1800))
593  {
601  if (station->m_minstrelTable[i].retryCount > 2)
602  {
603  station->m_minstrelTable[i].adjustedRetryCount = 2;
604  }
605  station->m_minstrelTable[i].sampleLimit = 4;
606  }
607  else
608  {
609  // no sampling limit.
610  station->m_minstrelTable[i].sampleLimit = -1;
611  station->m_minstrelTable[i].adjustedRetryCount = station->m_minstrelTable[i].retryCount;
612  }
613 
614  //if it's 0 allow two retries.
615  if (station->m_minstrelTable[i].adjustedRetryCount == 0)
616  {
617  station->m_minstrelTable[i].adjustedRetryCount = 2;
618  }
619  }
620 
621  NS_LOG_DEBUG ("Attempt/success resetted to 0");
622 
623  uint32_t max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
624 
625  //go find max throughput, second maximum throughput, high probability succ
626  NS_LOG_DEBUG ("Finding the maximum throughput, second maximum throughput, and highest probability");
627  NS_LOG_DEBUG ("Index-Rate\t\tT-put\tEWMA");
628  for (uint32_t i = 0; i < station->m_nModes; i++)
629  {
630  NS_LOG_DEBUG (i << " " << GetSupported (station, i) <<
631  "\t" << station->m_minstrelTable[i].throughput <<
632  "\t" << station->m_minstrelTable[i].ewmaProb);
633 
634  if (max_tp < station->m_minstrelTable[i].throughput)
635  {
636  index_max_tp = i;
637  max_tp = station->m_minstrelTable[i].throughput;
638  }
639  }
640 
641  max_tp = 0;
642  //find the second highest max
643  for (uint32_t i = 0; i < station->m_nModes; i++)
644  {
645  if ((i != index_max_tp) && (max_tp < station->m_minstrelTable[i].throughput))
646  {
647  index_max_tp2 = i;
648  max_tp = station->m_minstrelTable[i].throughput;
649  }
650  }
651 
652  uint32_t max_prob = 0, index_max_prob = 0;
653  for (uint32_t i = 0; i < station->m_nModes; i++)
654  {
655  if ((station->m_minstrelTable[i].ewmaProb >= 95 * 180) && (station->m_minstrelTable[i].throughput >= station->m_minstrelTable[index_max_prob].throughput))
656  {
657  index_max_prob = i;
658  max_prob = station->m_minstrelTable[i].ewmaProb;
659  }
660  else if (station->m_minstrelTable[i].ewmaProb >= max_prob)
661  {
662  index_max_prob = i;
663  max_prob = station->m_minstrelTable[i].ewmaProb;
664  }
665  }
666 
667  station->m_maxTpRate = index_max_tp;
668  station->m_maxTpRate2 = index_max_tp2;
669  station->m_maxProbRate = index_max_prob;
670 
671  if (index_max_tp > station->m_txrate)
672  {
673  station->m_txrate = index_max_tp;
674  }
675 
676  NS_LOG_DEBUG ("max throughput=" << index_max_tp << "(" << GetSupported (station, index_max_tp) <<
677  ")\tsecond max throughput=" << index_max_tp2 << "(" << GetSupported (station, index_max_tp2) <<
678  ")\tmax prob=" << index_max_prob << "(" << GetSupported (station, index_max_prob) << ")");
679  if (m_printStats)
680  {
681  PrintTable (station);
682  }
683 }
684 
685 void
687  double rxSnr, WifiMode txMode)
688 {
689  NS_LOG_FUNCTION (this << st << rxSnr << txMode);
690 }
691 
692 void
694 {
695  NS_LOG_FUNCTION (this << st);
697  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate=" << station->m_txrate);
698 
699  station->m_shortRetry++;
700 }
701 
702 void
703 MinstrelWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
704 {
705  NS_LOG_FUNCTION (this << st);
706  NS_LOG_DEBUG ("self=" << st << " rts ok");
707 }
708 
709 void
711 {
712  NS_LOG_FUNCTION (this << st);
714  UpdateRetry (station);
715 }
716 
717 void
719 {
720  NS_LOG_FUNCTION (this << st);
722  CheckInit (station);
723  if (!station->m_initialized)
724  {
725  return;
726  }
727 
728  UpdateRate (station);
729 }
730 
731 void
733  double ackSnr, WifiMode ackMode, double dataSnr)
734 {
735  NS_LOG_FUNCTION (st << ackSnr << ackMode << dataSnr);
737 
738  CheckInit (station);
739  if (!station->m_initialized)
740  {
741  return;
742  }
743 
744  NS_LOG_DEBUG ("DoReportDataOk m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (before update).");
745 
746  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
747  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
748 
749  UpdatePacketCounters (station);
750 
751  NS_LOG_DEBUG ("DoReportDataOk m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (after update).");
752 
753  UpdateRetry (station);
754  UpdateStats (station);
755 
756  if (station->m_nModes >= 1)
757  {
758  station->m_txrate = FindRate (station);
759  }
760 }
761 
762 void
764 {
765  NS_LOG_FUNCTION (this << st);
767 
768  CheckInit (station);
769  if (!station->m_initialized)
770  {
771  return;
772  }
773 
774  NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (before update).");
775 
776  UpdatePacketCounters (station);
777 
778  UpdateRetry (station);
779  UpdateStats (station);
780 
781  NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (after update).");
782 
783  if (station->m_nModes >= 1)
784  {
785  station->m_txrate = FindRate (station);
786  }
787 }
788 
789 void
791 {
792  NS_LOG_FUNCTION (this << station);
793 
794  station->m_totalPacketsCount++;
795  // If it is a sampling frame and the sampleRate was used, increase counter
796  if (station->m_isSampling && (!station->m_sampleDeferred || station->m_longRetry >= station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount))
797  {
798  station->m_samplePacketsCount++;
799  }
800 
801  if (station->m_numSamplesDeferred > 0)
802  {
803  station->m_numSamplesDeferred--;
804  }
805 
806  if (station->m_totalPacketsCount == ~0)
807  {
808  station->m_numSamplesDeferred = 0;
809  station->m_samplePacketsCount = 0;
810  station->m_totalPacketsCount = 0;
811  }
812  station->m_isSampling = false;
813  station->m_sampleDeferred = false;
814 }
815 
816 void
818 {
819  NS_LOG_FUNCTION (this << station);
820  station->m_retry = station->m_shortRetry + station->m_longRetry;
821  station->m_shortRetry = 0;
822  station->m_longRetry = 0;
823 }
824 
827 {
828  NS_LOG_FUNCTION (this << st);
830  return GetDataTxVector (station);
831 }
832 
835 {
836  NS_LOG_FUNCTION (this << st);
838  return GetRtsTxVector (station);
839 }
840 
841 bool
843 {
844  NS_LOG_FUNCTION (this << st << packet << normally);
846 
847  CheckInit (station);
848  if (!station->m_initialized)
849  {
850  return normally;
851  }
852  if (station->m_longRetry > CountRetries (station))
853  {
854  return false;
855  }
856  else
857  {
858  return true;
859  }
860 }
861 
862 bool
864 {
865  NS_LOG_FUNCTION (this);
866  return true;
867 }
868 
869 uint32_t
871 {
872  NS_LOG_FUNCTION (this << station);
873  uint32_t bitrate;
874  bitrate = station->m_sampleTable[station->m_index][station->m_col];
875  station->m_index++;
876 
877  //bookeeping for m_index and m_col variables
878  if (station->m_index > (station->m_nModes - 2))
879  {
880  station->m_index = 0;
881  station->m_col++;
882  if (station->m_col >= m_sampleCol)
883  {
884  station->m_col = 0;
885  }
886  }
887  return bitrate;
888 }
889 
890 void
892 {
893  NS_LOG_FUNCTION (station);
894 
895  for (uint32_t i = 0; i < station->m_nModes; i++)
896  {
897  NS_LOG_DEBUG ("Initializing rate index " << i << " " << GetSupported (station, i));
898  station->m_minstrelTable[i].numRateAttempt = 0;
899  station->m_minstrelTable[i].numRateSuccess = 0;
900  station->m_minstrelTable[i].prevNumRateSuccess = 0;
901  station->m_minstrelTable[i].prevNumRateAttempt = 0;
902  station->m_minstrelTable[i].successHist = 0;
903  station->m_minstrelTable[i].attemptHist = 0;
904  station->m_minstrelTable[i].numSamplesSkipped = 0;
905  station->m_minstrelTable[i].prob = 0;
906  station->m_minstrelTable[i].ewmaProb = 0;
907  station->m_minstrelTable[i].throughput = 0;
908  station->m_minstrelTable[i].perfectTxTime = GetCalcTxTime (GetSupported (station, i));
909  NS_LOG_DEBUG (" perfectTxTime = " << station->m_minstrelTable[i].perfectTxTime);
910  station->m_minstrelTable[i].retryCount = 1;
911  station->m_minstrelTable[i].adjustedRetryCount = 1;
912  //Emulating minstrel.c::ath_rate_ctl_reset
913  //We only check from 2 to 10 retries. This guarantee that
914  //at least one retry is permitter.
915  Time totalTxTimeWithGivenRetries = Seconds (0.0); //tx_time in minstrel.c
916  NS_LOG_DEBUG (" Calculating the number of retries");
917  for (uint32_t retries = 2; retries < 11; retries++)
918  {
919  NS_LOG_DEBUG (" Checking " << retries << " retries");
920  totalTxTimeWithGivenRetries = CalculateTimeUnicastPacket (station->m_minstrelTable[i].perfectTxTime, 0, retries);
921  NS_LOG_DEBUG (" totalTxTimeWithGivenRetries = " << totalTxTimeWithGivenRetries);
922  if (totalTxTimeWithGivenRetries > MilliSeconds (6))
923  {
924  break;
925  }
926  station->m_minstrelTable[i].sampleLimit = -1;
927  station->m_minstrelTable[i].retryCount = retries;
928  station->m_minstrelTable[i].adjustedRetryCount = retries;
929  }
930  }
931  UpdateStats (station);
932 }
933 
934 Time
935 MinstrelWifiManager::CalculateTimeUnicastPacket (Time dataTransmissionTime, uint32_t shortRetries, uint32_t longRetries)
936 {
937  NS_LOG_FUNCTION (this << dataTransmissionTime << shortRetries << longRetries);
938  //See rc80211_minstrel.c
939 
940  //First transmission (DATA + ACK timeout)
941  Time tt = dataTransmissionTime + GetMac ()->GetAckTimeout ();
942 
943  uint32_t cwMax = 1023;
944  uint32_t cw = 31;
945  for (uint32_t retry = 0; retry < longRetries; retry++)
946  {
947  //Add one re-transmission (DATA + ACK timeout)
948  tt += dataTransmissionTime + GetMac ()->GetAckTimeout ();
949 
950  //Add average back off (half the current contention window)
951  tt += NanoSeconds ((cw / 2) * GetMac ()->GetSlot ());
952 
953  //Update contention window
954  cw = std::min (cwMax, (cw + 1) * 2);
955  }
956 
957  return tt;
958 }
959 
960 void
962 {
963  NS_LOG_DEBUG ("InitSampleTable=" << this);
964 
965  station->m_col = station->m_index = 0;
966 
967  //for off-setting to make rates fall between 0 and nModes
968  uint32_t numSampleRates = station->m_nModes;
969 
970  uint32_t newIndex;
971  for (uint32_t col = 0; col < m_sampleCol; col++)
972  {
973  for (uint32_t i = 0; i < numSampleRates; i++ )
974  {
979  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
980  newIndex = (i + uv) % numSampleRates;
981 
982  //this loop is used for filling in other uninitialized places
983  while (station->m_sampleTable[newIndex][col] != 0)
984  {
985  newIndex = (newIndex + 1) % station->m_nModes;
986  }
987  station->m_sampleTable[newIndex][col] = i;
988  }
989  }
990 }
991 
992 void
994 {
995  NS_LOG_DEBUG ("PrintSampleTable=" << station);
996 
997  uint32_t numSampleRates = station->m_nModes;
998  std::stringstream table;
999  for (uint32_t i = 0; i < numSampleRates; i++)
1000  {
1001  for (uint32_t j = 0; j < m_sampleCol; j++)
1002  {
1003  table << station->m_sampleTable[i][j] << "\t";
1004  }
1005  table << std::endl;
1006  }
1007  NS_LOG_DEBUG (table.str ());
1008 }
1009 
1010 void
1012 {
1013  NS_LOG_FUNCTION (this << station);
1014  NS_LOG_DEBUG ("PrintTable=" << station);
1015 
1016  station->m_statsFile << "best _______________rate________________ ________statistics________ ________last_______ ______sum-of________\n" <<
1017  "rate [ name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1018 
1019  uint32_t maxTpRate = station->m_maxTpRate;
1020  uint32_t maxTpRate2 = station->m_maxTpRate2;
1021  uint32_t maxProbRate = station->m_maxProbRate;
1022 
1023  for (uint32_t i = 0; i < station->m_nModes; i++)
1024  {
1025  RateInfo rate = station->m_minstrelTable[i];
1026 
1027  if (i == maxTpRate)
1028  {
1029  station->m_statsFile << 'A';
1030  }
1031  else
1032  {
1033  station->m_statsFile << ' ';
1034  }
1035  if (i == maxTpRate2)
1036  {
1037  station->m_statsFile << 'B';
1038  }
1039  else
1040  {
1041  station->m_statsFile << ' ';
1042  }
1043  if (i == maxProbRate)
1044  {
1045  station->m_statsFile << 'P';
1046  }
1047  else
1048  {
1049  station->m_statsFile << ' ';
1050  }
1051 
1052  float tmpTh = rate.throughput / 100000.0;
1053  station->m_statsFile << " " <<
1054  std::setw (17) << GetSupported (station, i) << " " <<
1055  std::setw (2) << i << " " <<
1056  std::setw (4) << rate.perfectTxTime.GetMicroSeconds () <<
1057  std::setw (8) << " ----- " <<
1058  std::setw (8) << tmpTh << " " <<
1059  std::setw (3) << rate.ewmaProb / 180 <<
1060  std::setw (3) << " --- " <<
1061  std::setw (3) << rate.prob / 180 << " " <<
1062  std::setw (1) << rate.adjustedRetryCount << " " <<
1063  std::setw (3) << rate.prevNumRateSuccess << " " <<
1064  std::setw (3) << rate.prevNumRateAttempt << " " <<
1065  std::setw (9) << rate.successHist << " " <<
1066  std::setw (9) << rate.attemptHist << "\n";
1067  }
1068  station->m_statsFile << "\nTotal packet count: ideal " << station->m_totalPacketsCount - station->m_samplePacketsCount
1069  << " lookaround " << station->m_samplePacketsCount << "\n\n";
1070 
1071  station->m_statsFile.flush ();
1072 }
1073 
1074 
1075 void
1077 {
1078  //HT is not supported by this algorithm.
1079  if (enable)
1080  {
1081  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support HT rates");
1082  }
1083 }
1084 
1085 void
1087 {
1088  //VHT is not supported by this algorithm.
1089  if (enable)
1090  {
1091  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support VHT rates");
1092  }
1093 }
1094 
1095 } //namespace ns3
void CheckInit(MinstrelWifiRemoteStation *station)
check for initializations
void PrintTable(MinstrelWifiRemoteStation *station)
uint32_t GetNSupported(const WifiRemoteStation *station) const
Return the number of modes supported by the given station.
virtual WifiTxVector DoGetDataTxVector(WifiRemoteStation *station)
virtual void SetupMac(Ptr< WifiMac > mac)
Set up MAC associated with this device since it is the object that knows the full set of timing param...
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void SetStream(int64_t stream)
Specifies the stream number for this RNG stream.
bool m_printStats
If statistics table should be printed.
AttributeValue implementation for Boolean.
Definition: boolean.h:34
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
Time perfectTxTime
Perfect transmission time calculation, or frame calculation Given a bit rate and a packet length n by...
#define min(a, b)
Definition: 80211b.c:44
Implementation of Minstrel Rate Control AlgorithmMinstrel is a rate control algorithm implemented in ...
bool GetUseNonErpProtection(void) const
Return whether the device supports protection of non-ERP stations.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: boolean.h:81
virtual void DoReportFinalDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
hold per-remote-station state for Minstrel Wifi manager.
Time m_updateStats
how frequent do we calculate the stats (1/10 seconds)
void UpdateStats(MinstrelWifiRemoteStation *station)
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
uint32_t m_sampleRate
current sample rate
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:903
uint32_t GetNextSample(MinstrelWifiRemoteStation *station)
Mac48Address m_address
Mac48Address of the remote station.
virtual bool DoNeedDataRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
uint32_t m_txrate
current transmit rate
MinstrelRate m_minstrelTable
minstrel table
bool m_sampleDeferred
a flag to indicate sample rate is on the second stage
virtual void SetupPhy(Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:99
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
WifiMode GetSupported(const WifiRemoteStation *station, uint32_t i) const
Return whether mode associated with the specified station at the specified index. ...
uint32_t FindRate(MinstrelWifiRemoteStation *station)
uint32_t m_pktLen
packet length used for calculate mode TxTime
WifiRemoteStationState * m_state
Remote station state.
uint32_t adjustedRetryCount
adjust the retry limit for this rate
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:446
virtual void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr)
This method is a pure virtual method that must be implemented by the sub-class.
virtual void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode)
This method is a pure virtual method that must be implemented by the sub-class.
uint32_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
A struct to contain all information related to a data rate.
virtual uint32_t GetInteger(void)=0
Get the next random value as an integer drawn from the distribution.
tuple phy
Definition: third.py:86
bool m_isSampling
a flag to indicate we are currently sampling
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:349
virtual void SetHtSupported(bool enable)
Enable or disable HT capability support.
AttributeValue implementation for Time.
Definition: nstime.h:957
SampleRate m_sampleTable
sample table
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:919
uint32_t prevNumRateSuccess
Number of successful frames transmitted with previous rate.
Hold an unsigned integer type.
Definition: uinteger.h:44
WifiMode GetNonErpSupported(const WifiRemoteStation *station, uint32_t i) const
Return whether non-ERP mode associated with the specified station at the specified index...
void PrintSampleTable(MinstrelWifiRemoteStation *station)
uint32_t prevNumRateAttempt
Number of transmission attempts with previous rate.
virtual void SetupPhy(Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
uint64_t attemptHist
Aggregate of all transmission attempts.
double m_ewmaLevel
exponential weighted moving average
uint64_t successHist
Aggregate of all transmission successes.
Time CalculateTxDuration(uint32_t size, WifiTxVector txVector, enum WifiPreamble preamble, double frequency)
Definition: wifi-phy.cc:1942
virtual uint32_t GetFrequency(void) const
Definition: wifi-phy.cc:1143
virtual WifiRemoteStation * DoCreateStation(void) const
void AddCalcTxTime(WifiMode mode, Time t)
Add transmission time for the given mode to an internal list.
virtual uint32_t GetNModes(void) const
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Definition: wifi-phy.cc:2850
tuple mac
Definition: third.py:92
virtual void DoReportFinalRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
hold a list of per-remote-station state.
virtual WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station)
uint32_t m_longRetry
long retries such as data packets
bool m_initialized
for initializing tables
uint32_t ewmaProb
EWMA calculation ewma_prob =[prob *(100 - ewma_level) + (ewma_prob_old * ewma_level)]/100.
TxTime m_calcTxTime
to hold all the calculated TxTime for all modes
virtual bool IsLowLatency(void) const
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void UpdateRate(MinstrelWifiRemoteStation *station)
Retry Chain table is implemented here.
uint32_t m_maxTpRate2
second highest throughput rate
WifiTxVector GetDataTxVector(MinstrelWifiRemoteStation *station)
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
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:958
uint32_t throughput
throughput of a rate
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:224
uint32_t m_retry
total retries short + long
int m_totalPacketsCount
total number of packets as of now
virtual void SetupMac(Ptr< WifiMac > mac)
Set up MAC associated with this device since it is the object that knows the full set of timing param...
Ptr< UniformRandomVariable > m_uniformRandomVariable
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void UpdateRetry(MinstrelWifiRemoteStation *station)
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: double.h:42
double m_lookAroundRate
the % to try other rates than our current rate
int m_samplePacketsCount
how many packets we have sample so far
void InitSampleTable(MinstrelWifiRemoteStation *station)
uint32_t m_maxProbRate
rate with highest prob of success
uint32_t GetLongRetryCount(const WifiRemoteStation *station) const
Return the long retry limit of the given station.
virtual void DoReportRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
uint32_t m_nModes
number of modes supported
WifiTxVector GetRtsTxVector(MinstrelWifiRemoteStation *station)
virtual void SetVhtSupported(bool enable)
Enable or disable VHT capability support.
uint32_t m_maxTpRate
the current throughput rate
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:236
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:895
uint32_t CountRetries(MinstrelWifiRemoteStation *station)
Time GetCalcTxTime(WifiMode mode) const
virtual void DoReportDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
std::vector< struct RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
uint32_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint32_t GetShortRetryCount(const WifiRemoteStation *station) const
Return the short retry limit of the given station.
uint32_t m_sampleCol
number of sample columns
uint32_t m_shortRetry
short retries such as control packts
This class can be used to hold variables of floating point type such as 'double' or 'float'...
Definition: double.h:41
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:45
virtual void DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr)
This method is a pure virtual method that must be implemented by the sub-class.
a unique identifier for an interface.
Definition: type-id.h:58
Time CalculateTimeUnicastPacket(Time dataTransmissionTime, uint32_t shortRetries, uint32_t longRetries)
Estimate the time to transmit the given packet with the given number of retries.
void RateInit(MinstrelWifiRemoteStation *station)
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
std::vector< std::vector< uint32_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint32_t.
hold per-remote-station state.
uint32_t prob
(# pkts success )/(# total pkts)
Ptr< WifiMac > GetMac(void) const
Return the WifiMac.
virtual WifiMode GetMode(uint32_t mode) const
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Definition: wifi-phy.cc:2856
void UpdatePacketCounters(MinstrelWifiRemoteStation *station)
Time m_nextStatsUpdate
10 times every second