A Discrete-Event Network Simulator
API
minstrel-ht-wifi-manager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 Duy Nguyen
3  * Copyright (c) 2015 Ghada Badawy
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  * Authors: Duy Nguyen <duy@soe.ucsc.edu>
19  * Ghada Badawy <gbadawy@gmail.com>
20  * Matias Richart <mrichart@fing.edu.uy>
21  *
22  * Some Comments:
23  *
24  * 1) By default, Minstrel applies the multi-rate retry (the core of Minstrel
25  * algorithm). Otherwise, please use ConstantRateWifiManager instead.
26  *
27  * 2) Sampling is done differently from legacy Minstrel. Minstrel-HT tries
28  * to sample all rates in all groups at least once and to avoid many
29  * consecutive samplings.
30  *
31  * 3) Sample rate is tried only once, at first place of the MRR chain.
32  *
33  * reference: http://lwn.net/Articles/376765/
34  */
35 
37 
38 #include "ns3/log.h"
39 #include "ns3/packet.h"
40 #include "ns3/random-variable-stream.h"
41 #include "ns3/simulator.h"
42 #include "ns3/wifi-mac.h"
43 #include "ns3/wifi-phy.h"
44 
45 #include <iomanip>
46 
47 #define Min(a, b) ((a < b) ? a : b)
48 #define Max(a, b) ((a > b) ? a : b)
49 
50 NS_LOG_COMPONENT_DEFINE("MinstrelHtWifiManager");
51 
52 namespace ns3
53 {
54 
57 {
58  uint8_t m_sampleGroup;
59 
60  uint32_t m_sampleWait;
61  uint32_t m_sampleTries;
62  uint32_t m_sampleCount;
63  uint32_t m_numSamplesSlow;
64 
65  uint32_t m_avgAmpduLen;
66  uint32_t m_ampduLen;
67  uint32_t m_ampduPacketCount;
68 
70  bool m_isHt;
71 
72  std::ofstream m_statsFile;
73 };
74 
76 
77 TypeId
79 {
80  static TypeId tid =
81  TypeId("ns3::MinstrelHtWifiManager")
83  .AddConstructor<MinstrelHtWifiManager>()
84  .SetGroupName("Wifi")
85  .AddAttribute("UpdateStatistics",
86  "The interval between updating statistics table",
90  .AddAttribute("LegacyUpdateStatistics",
91  "The interval between updating statistics table (for legacy Minstrel)",
92  TimeValue(MilliSeconds(100)),
95  .AddAttribute("LookAroundRate",
96  "The percentage to try other rates (for legacy Minstrel)",
97  UintegerValue(10),
99  MakeUintegerChecker<uint8_t>(0, 100))
100  .AddAttribute("EWMA",
101  "EWMA level",
102  UintegerValue(75),
104  MakeUintegerChecker<uint8_t>(0, 100))
105  .AddAttribute("SampleColumn",
106  "The number of columns used for sampling",
107  UintegerValue(10),
109  MakeUintegerChecker<uint8_t>())
110  .AddAttribute("PacketLength",
111  "The packet length used for calculating mode TxTime (bytes)",
112  UintegerValue(1200),
114  MakeUintegerChecker<uint32_t>())
115  .AddAttribute("UseLatestAmendmentOnly",
116  "Use only the latest amendment when it is supported by both peers",
117  BooleanValue(true),
120  .AddAttribute("PrintStats",
121  "Control the printing of the statistics table",
122  BooleanValue(false),
125  .AddTraceSource("Rate",
126  "Traced value for rate changes (b/s)",
128  "ns3::TracedValueCallback::Uint64");
129  return tid;
130 }
131 
133  : m_numGroups(0),
134  m_numRates(0),
135  m_currentRate(0)
136 {
137  NS_LOG_FUNCTION(this);
138  m_uniformRandomVariable = CreateObject<UniformRandomVariable>();
143  m_legacyManager = CreateObject<MinstrelWifiManager>();
144 }
145 
147 {
148  NS_LOG_FUNCTION(this);
149  for (uint8_t i = 0; i < m_numGroups; i++)
150  {
151  m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear();
152  m_minstrelGroups[i].ratesTxTimeTable.clear();
153  }
154 }
155 
156 int64_t
158 {
159  NS_LOG_FUNCTION(this << stream);
160  int64_t numStreamsAssigned = 0;
162  numStreamsAssigned++;
163  numStreamsAssigned += m_legacyManager->AssignStreams(stream);
164  return numStreamsAssigned;
165 }
166 
167 void
169 {
170  NS_LOG_FUNCTION(this << phy);
171  // Setup PHY for legacy manager.
172  m_legacyManager->SetupPhy(phy);
174 }
175 
176 void
178 {
179  NS_LOG_FUNCTION(this << mac);
180  m_legacyManager->SetupMac(mac);
182 }
183 
184 void
186 {
187  NS_LOG_FUNCTION(this);
195  if (GetHtSupported())
196  {
199  if (GetVhtSupported())
200  {
203  }
204  if (GetHeSupported())
205  {
208  }
209 
222  NS_LOG_DEBUG("Initialize MCS Groups:");
224 
225  // Initialize all HT groups
226  for (uint16_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
227  {
228  for (int gi = 800; gi >= 400;)
229  {
230  for (uint8_t streams = 1; streams <= MAX_HT_SUPPORTED_STREAMS; streams++)
231  {
232  uint8_t groupId = GetHtGroupId(streams, gi, chWidth);
233 
234  m_minstrelGroups[groupId].streams = streams;
235  m_minstrelGroups[groupId].gi = gi;
236  m_minstrelGroups[groupId].chWidth = chWidth;
238  m_minstrelGroups[groupId].isSupported = false;
239 
240  // Check capabilities of the device
242  (gi == 400))
243  && (GetPhy()->GetChannelWidth() >=
244  chWidth)
245  && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
246  streams))
247  {
248  m_minstrelGroups[groupId].isSupported = true;
249 
250  // Calculate TX time for all rates of the group
251  WifiModeList htMcsList = GetHtDeviceMcsList();
252  for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
253  {
254  uint16_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
255  WifiMode mode = htMcsList[deviceIndex];
256  AddFirstMpduTxTime(groupId,
257  mode,
259  streams,
260  gi,
261  chWidth,
262  mode,
264  AddMpduTxTime(groupId,
265  mode,
267  streams,
268  gi,
269  chWidth,
270  mode,
272  }
273  NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams << ","
274  << gi << "," << chWidth << ")");
275  }
276  }
277  gi /= 2;
278  }
279  }
280 
281  if (GetVhtSupported())
282  {
283  // Initialize all VHT groups
284  for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
285  {
286  for (int gi = 800; gi >= 400;)
287  {
288  for (uint8_t streams = 1; streams <= MAX_VHT_SUPPORTED_STREAMS; streams++)
289  {
290  uint8_t groupId = GetVhtGroupId(streams, gi, chWidth);
291 
292  m_minstrelGroups[groupId].streams = streams;
293  m_minstrelGroups[groupId].gi = gi;
294  m_minstrelGroups[groupId].chWidth = chWidth;
296  m_minstrelGroups[groupId].isSupported = false;
297 
298  // Check capabilities of the device
300  (gi == 400))
301  && (GetPhy()->GetChannelWidth() >=
302  chWidth)
303  && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
304  streams))
305  {
306  m_minstrelGroups[groupId].isSupported = true;
307 
308  // Calculate TX time for all rates of the group
309  WifiModeList vhtMcsList = GetVhtDeviceMcsList();
310  for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
311  {
312  WifiMode mode = vhtMcsList[i];
313  // Check for invalid VHT MCSs and do not add time to array.
314  if (IsValidMcs(GetPhy(), streams, chWidth, mode))
315  {
317  groupId,
318  mode,
320  streams,
321  gi,
322  chWidth,
323  mode,
326  groupId,
327  mode,
329  streams,
330  gi,
331  chWidth,
332  mode,
334  }
335  }
336  NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams
337  << "," << gi << "," << chWidth
338  << ")");
339  }
340  }
341  gi /= 2;
342  }
343  }
344  }
345 
346  if (GetHeSupported())
347  {
348  // Initialize all HE groups
349  for (uint16_t chWidth = 20; chWidth <= MAX_HE_WIDTH; chWidth *= 2)
350  {
351  for (int gi = 3200; gi >= 800;)
352  {
353  for (uint8_t streams = 1; streams <= MAX_HE_SUPPORTED_STREAMS; streams++)
354  {
355  uint8_t groupId = GetHeGroupId(streams, gi, chWidth);
356 
357  m_minstrelGroups[groupId].streams = streams;
358  m_minstrelGroups[groupId].gi = gi;
359  m_minstrelGroups[groupId].chWidth = chWidth;
361  m_minstrelGroups[groupId].isSupported = false;
362 
363  // Check capabilities of the device
364  if ((GetGuardInterval() <= gi)
365  && (GetPhy()->GetChannelWidth() >=
366  chWidth)
367  && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
368  streams))
369  {
370  m_minstrelGroups[groupId].isSupported = true;
371 
372  // Calculate tx time for all rates of the group
373  WifiModeList heMcsList = GetHeDeviceMcsList();
374  for (uint8_t i = 0; i < MAX_HE_GROUP_RATES; i++)
375  {
376  WifiMode mode = heMcsList.at(i);
377  // Check for invalid HE MCSs and do not add time to array.
378  if (IsValidMcs(GetPhy(), streams, chWidth, mode))
379  {
381  groupId,
382  mode,
384  streams,
385  gi,
386  chWidth,
387  mode,
390  groupId,
391  mode,
393  streams,
394  gi,
395  chWidth,
396  mode,
398  }
399  }
400  NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams
401  << "," << gi << "," << chWidth
402  << ")");
403  }
404  }
405  gi /= 2;
406  }
407  }
408  }
409  }
410 }
411 
412 bool
414  uint8_t streams,
415  uint16_t chWidth,
416  WifiMode mode)
417 {
418  NS_LOG_FUNCTION(this << phy << +streams << chWidth << mode);
419  WifiTxVector txvector;
420  txvector.SetNss(streams);
421  txvector.SetChannelWidth(chWidth);
422  txvector.SetMode(mode);
423  return txvector.IsValid();
424 }
425 
426 Time
428  uint8_t streams,
429  uint16_t gi,
430  uint16_t chWidth,
431  WifiMode mode,
432  MpduType mpduType)
433 {
434  NS_LOG_FUNCTION(this << phy << +streams << gi << chWidth << mode << mpduType);
435  WifiTxVector txvector;
436  txvector.SetNss(streams);
437  txvector.SetGuardInterval(gi);
438  txvector.SetChannelWidth(chWidth);
439  txvector.SetNess(0);
440  txvector.SetStbc(0);
441  txvector.SetMode(mode);
444  WifiPhy::GetPayloadDuration(m_frameLength, txvector, phy->GetPhyBand(), mpduType);
445 }
446 
447 Time
449 {
450  NS_LOG_FUNCTION(this << +groupId << mode);
451  auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find(mode);
452  NS_ASSERT(it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end());
453  return it->second;
454 }
455 
456 void
458 {
459  NS_LOG_FUNCTION(this << +groupId << mode << t);
460  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert(std::make_pair(mode, t));
461 }
462 
463 Time
464 MinstrelHtWifiManager::GetMpduTxTime(uint8_t groupId, WifiMode mode) const
465 {
466  NS_LOG_FUNCTION(this << +groupId << mode);
467  auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find(mode);
468  NS_ASSERT(it != m_minstrelGroups[groupId].ratesTxTimeTable.end());
469  return it->second;
470 }
471 
472 void
474 {
475  NS_LOG_FUNCTION(this << +groupId << mode << t);
476  m_minstrelGroups[groupId].ratesTxTimeTable.insert(std::make_pair(mode, t));
477 }
478 
481 {
482  NS_LOG_FUNCTION(this);
484 
485  // Initialize variables common to both stations.
487  station->m_col = 0;
488  station->m_index = 0;
489  station->m_maxTpRate = 0;
490  station->m_maxTpRate2 = 0;
491  station->m_maxProbRate = 0;
492  station->m_nModes = 0;
493  station->m_totalPacketsCount = 0;
494  station->m_samplePacketsCount = 0;
495  station->m_isSampling = false;
496  station->m_sampleRate = 0;
497  station->m_sampleDeferred = false;
498  station->m_shortRetry = 0;
499  station->m_longRetry = 0;
500  station->m_txrate = 0;
501  station->m_initialized = false;
502 
503  // Variables specific to HT station
504  station->m_sampleGroup = 0;
505  station->m_numSamplesSlow = 0;
506  station->m_sampleCount = 16;
507  station->m_sampleWait = 0;
508  station->m_sampleTries = 4;
509 
510  station->m_avgAmpduLen = 1;
511  station->m_ampduLen = 0;
512  station->m_ampduPacketCount = 0;
513 
514  // If the device supports HT
515  if (GetHtSupported())
516  {
521  station->m_isHt = true;
522  }
523  // Use the variable in the station to indicate that the device do not support HT
524  else
525  {
526  station->m_isHt = false;
527  }
528 
529  return station;
530 }
531 
532 void
534 {
535  NS_LOG_FUNCTION(this << station);
536  // Note: we appear to be doing late initialization of the table
537  // to make sure that the set of supported rates has been initialized
538  // before we perform our own initialization.
539  if (!station->m_initialized)
540  {
547  if (!GetHtSupported(station))
548  {
549  NS_LOG_INFO("non-HT station " << station);
550  station->m_isHt = false;
551  // We will use non-HT minstrel for this station. Initialize the manager.
552  m_legacyManager->SetAttribute("UpdateStatistics", TimeValue(m_legacyUpdateStats));
553  m_legacyManager->SetAttribute("LookAroundRate", UintegerValue(m_lookAroundRate));
554  m_legacyManager->SetAttribute("EWMA", UintegerValue(m_ewmaLevel));
555  m_legacyManager->SetAttribute("SampleColumn", UintegerValue(m_nSampleCol));
556  m_legacyManager->SetAttribute("PacketLength", UintegerValue(m_frameLength));
557  m_legacyManager->SetAttribute("PrintStats", BooleanValue(m_printStats));
558  m_legacyManager->CheckInit(station);
559  }
560  else
561  {
562  NS_LOG_DEBUG("HT station " << station);
563  station->m_isHt = true;
564  station->m_nModes = GetNMcsSupported(station);
565  station->m_minstrelTable = MinstrelRate(station->m_nModes);
566  station->m_sampleTable = SampleRate(m_numRates, std::vector<uint8_t>(m_nSampleCol));
567  InitSampleTable(station);
568  RateInit(station);
569  station->m_initialized = true;
570  }
571  }
572 }
573 
574 void
576 {
577  NS_LOG_FUNCTION(this << st);
578  NS_LOG_DEBUG(
579  "DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*>(st)->m_txrate);
580 }
581 
582 void
584 {
585  NS_LOG_FUNCTION(this << st);
586  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
587  CheckInit(station);
588  if (!station->m_initialized)
589  {
590  return;
591  }
592  NS_LOG_DEBUG("DoReportRtsFailed m_txrate = " << station->m_txrate);
593  station->m_shortRetry++;
594 }
595 
596 void
598  double ctsSnr,
599  WifiMode ctsMode,
600  double rtsSnr)
601 {
602  NS_LOG_FUNCTION(this << st);
603 }
604 
605 void
607 {
608  NS_LOG_FUNCTION(this << st);
609  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
610  NS_LOG_DEBUG("Final RTS failed");
611  CheckInit(station);
612  if (!station->m_initialized)
613  {
614  return;
615  }
616  UpdateRetry(station);
617 }
618 
619 void
621 {
622  NS_LOG_FUNCTION(this << st);
623  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
624 
625  CheckInit(station);
626  if (!station->m_initialized)
627  {
628  return;
629  }
630 
631  NS_LOG_DEBUG("DoReportDataFailed " << station << "\t rate " << station->m_txrate
632  << "\tlongRetry \t" << station->m_longRetry);
633 
634  if (!station->m_isHt)
635  {
636  m_legacyManager->UpdateRate(station);
637  }
638  else if (station->m_longRetry < CountRetries(station))
639  {
640  uint8_t rateId = GetRateId(station->m_txrate);
641  uint8_t groupId = GetGroupId(station->m_txrate);
642  station->m_groupsTable[groupId]
643  .m_ratesTable[rateId]
644  .numRateAttempt++; // Increment the attempts counter for the rate used.
645  UpdateRate(station);
646  }
647 }
648 
649 void
651  double ackSnr,
652  WifiMode ackMode,
653  double dataSnr,
654  uint16_t dataChannelWidth,
655  uint8_t dataNss)
656 {
657  NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
658  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
659 
660  CheckInit(station);
661  if (!station->m_initialized)
662  {
663  return;
664  }
665 
666  NS_LOG_DEBUG("DoReportDataOk m_txrate = "
667  << station->m_txrate
668  << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
669  << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
670  << " (before update).");
671 
672  if (!station->m_isHt)
673  {
674  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
675  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
676 
677  m_legacyManager->UpdatePacketCounters(station);
678 
679  NS_LOG_DEBUG("DoReportDataOk m_txrate = "
680  << station->m_txrate
681  << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
682  << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
683  << " (after update).");
684 
685  UpdateRetry(station);
686  m_legacyManager->UpdateStats(station);
687 
688  if (station->m_nModes >= 1)
689  {
690  station->m_txrate = m_legacyManager->FindRate(station);
691  }
692  }
693  else
694  {
695  uint8_t rateId = GetRateId(station->m_txrate);
696  uint8_t groupId = GetGroupId(station->m_txrate);
697  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
698  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
699 
700  UpdatePacketCounters(station, 1, 0);
701 
702  NS_LOG_DEBUG("DoReportDataOk m_txrate = "
703  << station->m_txrate
704  << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
705  << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
706  << " (after update).");
707 
708  station->m_isSampling = false;
709  station->m_sampleDeferred = false;
710 
711  UpdateRetry(station);
712  if (Simulator::Now() >= station->m_nextStatsUpdate)
713  {
714  UpdateStats(station);
715  }
716 
717  if (station->m_nModes >= 1)
718  {
719  station->m_txrate = FindRate(station);
720  }
721  }
722 
723  NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
724 }
725 
726 void
728 {
729  NS_LOG_FUNCTION(this << st);
730  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
731 
732  CheckInit(station);
733  if (!station->m_initialized)
734  {
735  return;
736  }
737 
738  NS_LOG_DEBUG("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
739 
740  if (!station->m_isHt)
741  {
742  m_legacyManager->UpdatePacketCounters(station);
743 
744  UpdateRetry(station);
745 
746  m_legacyManager->UpdateStats(station);
747  if (station->m_nModes >= 1)
748  {
749  station->m_txrate = m_legacyManager->FindRate(station);
750  }
751  }
752  else
753  {
754  UpdatePacketCounters(station, 0, 1);
755 
756  station->m_isSampling = false;
757  station->m_sampleDeferred = false;
758 
759  UpdateRetry(station);
760  if (Simulator::Now() >= station->m_nextStatsUpdate)
761  {
762  UpdateStats(station);
763  }
764 
765  if (station->m_nModes >= 1)
766  {
767  station->m_txrate = FindRate(station);
768  }
769  }
770  NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
771 }
772 
773 void
775  uint16_t nSuccessfulMpdus,
776  uint16_t nFailedMpdus,
777  double rxSnr,
778  double dataSnr,
779  uint16_t dataChannelWidth,
780  uint8_t dataNss)
781 {
782  NS_LOG_FUNCTION(this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
783  << dataChannelWidth << +dataNss);
784  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
785 
786  CheckInit(station);
787  if (!station->m_initialized)
788  {
789  return;
790  }
791 
792  NS_ASSERT_MSG(station->m_isHt, "A-MPDU Tx Status called but this is a non-HT STA.");
793 
794  NS_LOG_DEBUG("DoReportAmpduTxStatus. TxRate=" << station->m_txrate
795  << " SuccMpdus=" << nSuccessfulMpdus
796  << " FailedMpdus=" << nFailedMpdus);
797 
798  station->m_ampduPacketCount++;
799  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
800 
801  UpdatePacketCounters(station, nSuccessfulMpdus, nFailedMpdus);
802 
803  uint8_t rateId = GetRateId(station->m_txrate);
804  uint8_t groupId = GetGroupId(station->m_txrate);
805  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
806  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt +=
807  nSuccessfulMpdus + nFailedMpdus;
808 
809  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries(station))
810  {
811  // We do not receive a BlockAck. The entire AMPDU fail.
812  UpdateRate(station);
813  }
814  else
815  {
816  station->m_isSampling = false;
817  station->m_sampleDeferred = false;
818 
819  UpdateRetry(station);
820  if (Simulator::Now() >= station->m_nextStatsUpdate)
821  {
822  UpdateStats(station);
823  }
824 
825  if (station->m_nModes >= 1)
826  {
827  station->m_txrate = FindRate(station);
828  }
829  NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
830  }
831 }
832 
833 void
835 {
836  NS_LOG_FUNCTION(this << station);
837 
859  CheckInit(station);
860  if (!station->m_initialized)
861  {
862  return;
863  }
864  station->m_longRetry++;
865 
869  uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
870  uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
871  uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
872  uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
873  uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
874  uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
875 
877  if (!station->m_isSampling)
878  {
880  if (station->m_longRetry <
881  station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
882  {
883  NS_LOG_DEBUG("Not Sampling; use the same rate again");
884  station->m_txrate = station->m_maxTpRate;
885  }
886 
888  else if (station->m_longRetry <
889  (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
890  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
891  {
892  NS_LOG_DEBUG("Not Sampling; use the Max TP2");
893  station->m_txrate = station->m_maxTpRate2;
894  }
895 
897  else if (station->m_longRetry <=
898  (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
899  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
900  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
901  {
902  NS_LOG_DEBUG("Not Sampling; use Max Prob");
903  station->m_txrate = station->m_maxProbRate;
904  }
905  else
906  {
907  NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
908  << station->m_longRetry);
909  }
910  }
911 
913  else
914  {
917  if (station->m_longRetry <
918  1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
919  {
920  NS_LOG_DEBUG("Sampling use the MaxTP rate");
921  station->m_txrate = station->m_maxTpRate2;
922  }
923 
925  else if (station->m_longRetry <=
926  1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
927  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
928  {
929  NS_LOG_DEBUG("Sampling use the MaxProb rate");
930  station->m_txrate = station->m_maxProbRate;
931  }
932  else
933  {
934  NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
935  << station->m_longRetry);
936  }
937  }
938  NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
939 }
940 
941 void
943 {
944  NS_LOG_FUNCTION(this << station);
945  station->m_shortRetry = 0;
946  station->m_longRetry = 0;
947 }
948 
949 void
951  uint16_t nSuccessfulMpdus,
952  uint16_t nFailedMpdus)
953 {
954  NS_LOG_FUNCTION(this << station << nSuccessfulMpdus << nFailedMpdus);
955 
956  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
957  if (station->m_isSampling)
958  {
959  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
960  }
961  if (station->m_totalPacketsCount == ~0)
962  {
963  station->m_samplePacketsCount = 0;
964  station->m_totalPacketsCount = 0;
965  }
966 
967  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
968  {
969  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
970  station->m_sampleTries = 1;
971  station->m_sampleCount--;
972  }
973 }
974 
975 uint16_t
976 MinstrelHtWifiManager::UpdateRateAfterAllowedWidth(uint16_t txRate, uint16_t allowedWidth)
977 {
978  NS_LOG_FUNCTION(this << txRate << allowedWidth);
979 
980  auto groupId = GetGroupId(txRate);
981  McsGroup group = m_minstrelGroups[groupId];
982 
983  if (group.chWidth <= allowedWidth)
984  {
985  NS_LOG_DEBUG("Channel width is not greater than allowed width, nothing to do");
986  return txRate;
987  }
988 
990  NS_ASSERT(group.chWidth % 20 == 0);
991  // try halving the channel width and check if the group with the same number of
992  // streams and same GI is supported, until either a supported group is found or
993  // the width becomes lower than 20 MHz
994  uint16_t width = group.chWidth / 2;
995 
996  while (width >= 20)
997  {
998  if (width > allowedWidth)
999  {
1000  width /= 2;
1001  continue;
1002  }
1003 
1004  switch (group.type)
1005  {
1007  groupId = GetHtGroupId(group.streams, group.gi, width);
1008  break;
1010  groupId = GetVhtGroupId(group.streams, group.gi, width);
1011  break;
1013  groupId = GetHeGroupId(group.streams, group.gi, width);
1014  break;
1015  default:
1016  NS_ABORT_MSG("Unknown group type: " << group.type);
1017  }
1018 
1019  group = m_minstrelGroups[groupId];
1020  if (group.isSupported)
1021  {
1022  break;
1023  }
1024 
1025  width /= 2;
1026  }
1027 
1028  NS_ABORT_MSG_IF(width < 20, "No rate compatible with the allowed width found");
1029 
1030  return GetIndex(groupId, GetRateId(txRate));
1031 }
1032 
1035 {
1036  NS_LOG_FUNCTION(this << st << allowedWidth);
1037  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1038 
1039  if (!station->m_initialized)
1040  {
1041  CheckInit(station);
1042  }
1043 
1044  if (!station->m_isHt)
1045  {
1046  WifiTxVector vector = m_legacyManager->GetDataTxVector(station);
1047  uint64_t dataRate = vector.GetMode().GetDataRate(vector);
1048  if (m_currentRate != dataRate && !station->m_isSampling)
1049  {
1050  NS_LOG_DEBUG("New datarate: " << dataRate);
1051  m_currentRate = dataRate;
1052  }
1053  return vector;
1054  }
1055  else
1056  {
1057  station->m_txrate = UpdateRateAfterAllowedWidth(station->m_txrate, allowedWidth);
1058  NS_LOG_DEBUG("DoGetDataMode m_txrate= " << station->m_txrate);
1059 
1060  uint8_t rateId = GetRateId(station->m_txrate);
1061  uint8_t groupId = GetGroupId(station->m_txrate);
1062  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1063 
1064  NS_LOG_DEBUG("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId
1065  << " mode= " << GetMcsSupported(station, mcsIndex));
1066 
1067  McsGroup group = m_minstrelGroups[groupId];
1068 
1069  // Check consistency of rate selected.
1070  if (((group.type == WIFI_MINSTREL_GROUP_HE) && (group.gi < GetGuardInterval(station))) ||
1071  (((group.type == WIFI_MINSTREL_GROUP_HT) || (group.type == WIFI_MINSTREL_GROUP_VHT)) &&
1072  (group.gi == 400) && !GetShortGuardIntervalSupported(station)) ||
1073  (group.chWidth > GetChannelWidth(station)) ||
1074  (group.streams > GetNumberOfSupportedStreams(station)))
1075  {
1076  NS_FATAL_ERROR("Inconsistent group selected. Group: ("
1077  << +group.streams << "," << group.gi << "," << group.chWidth << ")"
1078  << " Station capabilities: (" << GetNumberOfSupportedStreams(station)
1079  << ","
1080  << ((group.type == WIFI_MINSTREL_GROUP_HE)
1081  ? GetGuardInterval(station)
1082  : (GetShortGuardIntervalSupported(station) ? 400 : 800))
1083  << "," << GetChannelWidth(station) << ")");
1084  }
1085  WifiMode mode = GetMcsSupported(station, mcsIndex);
1086  WifiTxVector txVector{
1087  mode,
1090  group.gi,
1092  group.streams,
1093  GetNess(station),
1094  GetPhy()->GetTxBandwidth(mode, group.chWidth),
1095  GetAggregation(station) && !station->m_isSampling};
1096  uint64_t dataRate = mode.GetDataRate(txVector);
1097  if (m_currentRate != dataRate && !station->m_isSampling)
1098  {
1099  NS_LOG_DEBUG("New datarate: " << dataRate);
1100  m_currentRate = dataRate;
1101  }
1102  return txVector;
1103  }
1104 }
1105 
1108 {
1109  NS_LOG_FUNCTION(this << st);
1110  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1111 
1112  if (!station->m_initialized)
1113  {
1114  CheckInit(station);
1115  }
1116 
1117  if (!station->m_isHt)
1118  {
1119  return m_legacyManager->GetRtsTxVector(station);
1120  }
1121  else
1122  {
1123  NS_LOG_DEBUG("DoGetRtsMode m_txrate=" << station->m_txrate);
1124 
1125  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
1126  * When supported, decision of using HT has to follow rules in Section 9.7.6 from
1127  * 802.11-2012. From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is
1128  * carried in a non-HT PPDU shall be transmitted by the STA using a rate no higher than the
1129  * highest rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
1130  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1131  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
1132  * these conditions, the control frame shall be transmitted at a rate no higher than the
1133  * highest mandatory rate of the attached PHY that is less than or equal to the rate
1134  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1135  * directed to the same receiving STA."
1136  */
1137 
1138  // As we are in Minstrel HT, assume the last rate was an HT rate.
1139  uint8_t rateId = GetRateId(station->m_txrate);
1140  uint8_t groupId = GetGroupId(station->m_txrate);
1141  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1142 
1143  WifiMode lastRate = GetMcsSupported(station, mcsIndex);
1144  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate();
1145  uint8_t nBasicRates = GetNBasicModes();
1146 
1147  WifiMode rtsRate;
1148  bool rateFound = false;
1149 
1150  for (uint8_t i = 0; i < nBasicRates; i++)
1151  {
1152  uint64_t rate = GetBasicMode(i).GetDataRate(20);
1153  if (rate <= lastDataRate)
1154  {
1155  rtsRate = GetBasicMode(i);
1156  rateFound = true;
1157  }
1158  }
1159 
1160  if (!rateFound)
1161  {
1162  Ptr<WifiPhy> phy = GetPhy();
1163  for (const auto& mode : phy->GetModeList())
1164  {
1165  uint64_t rate = mode.GetDataRate(20);
1166  if (rate <= lastDataRate)
1167  {
1168  rtsRate = mode;
1169  rateFound = true;
1170  }
1171  }
1172  }
1173 
1174  NS_ASSERT(rateFound);
1175 
1176  return WifiTxVector(
1177  rtsRate,
1180  800,
1181  1,
1182  1,
1183  0,
1184  GetPhy()->GetTxBandwidth(rtsRate, GetChannelWidth(station)),
1185  GetAggregation(station));
1186  }
1187 }
1188 
1189 bool
1191  Ptr<const Packet> packet,
1192  bool normally)
1193 {
1194  NS_LOG_FUNCTION(this << st << packet << normally);
1195 
1196  MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1197 
1198  CheckInit(station);
1199  if (!station->m_initialized)
1200  {
1201  return normally;
1202  }
1203 
1204  uint32_t maxRetries;
1205 
1206  if (!station->m_isHt)
1207  {
1208  maxRetries = m_legacyManager->CountRetries(station);
1209  }
1210  else
1211  {
1212  maxRetries = CountRetries(station);
1213  }
1214 
1215  if (station->m_longRetry >= maxRetries)
1216  {
1217  NS_LOG_DEBUG("No re-transmission allowed. Retries: " << station->m_longRetry
1218  << " Max retries: " << maxRetries);
1219  return false;
1220  }
1221  else
1222  {
1223  NS_LOG_DEBUG("Re-transmit. Retries: " << station->m_longRetry
1224  << " Max retries: " << maxRetries);
1225  return true;
1226  }
1227 }
1228 
1229 uint32_t
1231 {
1232  uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1233  uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1234  uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
1235  uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1236  uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1237  uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1238 
1239  if (!station->m_isSampling)
1240  {
1241  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1242  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1243  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1244  }
1245  else
1246  {
1247  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1248  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1249  }
1250 }
1251 
1252 uint16_t
1254 {
1255  NS_LOG_FUNCTION(this << station);
1256  uint8_t sampleGroup = station->m_sampleGroup;
1257  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1258  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1259  uint8_t sampleIndex = station->m_sampleTable[index][col];
1260  uint16_t rateIndex = GetIndex(sampleGroup, sampleIndex);
1261  NS_LOG_DEBUG("Next Sample is " << rateIndex);
1262  SetNextSample(station); // Calculate the next sample rate.
1263  return rateIndex;
1264 }
1265 
1266 void
1268 {
1269  NS_LOG_FUNCTION(this << station);
1270  do
1271  {
1272  station->m_sampleGroup++;
1273  station->m_sampleGroup %= m_numGroups;
1274  } while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1275 
1276  station->m_groupsTable[station->m_sampleGroup].m_index++;
1277 
1278  uint8_t sampleGroup = station->m_sampleGroup;
1279  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1280  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1281 
1282  if (index >= m_numRates)
1283  {
1284  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1285  station->m_groupsTable[station->m_sampleGroup].m_col++;
1286  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1287  {
1288  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1289  }
1290  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1291  col = station->m_groupsTable[sampleGroup].m_col;
1292  }
1293  NS_LOG_DEBUG("New sample set: group= " << +sampleGroup
1294  << " index= " << +station->m_sampleTable[index][col]);
1295 }
1296 
1297 uint16_t
1299 {
1300  NS_LOG_FUNCTION(this << station);
1301  NS_LOG_DEBUG("FindRate packet=" << station->m_totalPacketsCount);
1302 
1303  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1304  {
1305  return station->m_maxTpRate;
1306  }
1307 
1308  // If we have waited enough, then sample.
1309  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1310  {
1311  // SAMPLING
1312  NS_LOG_DEBUG("Obtaining a sampling rate");
1314  uint16_t sampleIdx = GetNextSample(station);
1315  NS_LOG_DEBUG("Sampling rate = " << sampleIdx);
1316 
1317  // Evaluate if the sampling rate selected should be used.
1318  uint8_t sampleGroupId = GetGroupId(sampleIdx);
1319  uint8_t sampleRateId = GetRateId(sampleIdx);
1320 
1321  // If the rate selected is not supported, then don't sample.
1322  if (station->m_groupsTable[sampleGroupId].m_supported &&
1323  station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1324  {
1332  MinstrelHtRateInfo sampleRateInfo =
1333  station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1334 
1335  NS_LOG_DEBUG("Use sample rate? MaxTpRate= "
1336  << station->m_maxTpRate << " CurrentRate= " << station->m_txrate
1337  << " SampleRate= " << sampleIdx
1338  << " SampleProb= " << sampleRateInfo.ewmaProb);
1339 
1340  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2 &&
1341  sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1342  {
1348  uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1349  uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1350  uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1351  uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1352  uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1353 
1354  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1355  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1356 
1357  Time sampleDuration = sampleRateInfo.perfectTxTime;
1358  Time maxTp2Duration =
1359  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1360  Time maxProbDuration = station->m_groupsTable[maxProbGroupId]
1361  .m_ratesTable[maxProbRateId]
1362  .perfectTxTime;
1363 
1364  NS_LOG_DEBUG("Use sample rate? SampleDuration= "
1365  << sampleDuration << " maxTp2Duration= " << maxTp2Duration
1366  << " maxProbDuration= " << maxProbDuration << " sampleStreams= "
1367  << +sampleStreams << " maxTpStreams= " << +maxTpStreams);
1368  if (sampleDuration < maxTp2Duration ||
1369  (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1370  {
1372  station->m_isSampling = true;
1373 
1375  station->m_sampleRate = sampleIdx;
1376 
1377  NS_LOG_DEBUG("FindRate "
1378  << "sampleRate=" << sampleIdx);
1379  station->m_sampleTries--;
1380  return sampleIdx;
1381  }
1382  else
1383  {
1384  station->m_numSamplesSlow++;
1385  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1386  {
1388  station->m_isSampling = true;
1389 
1391  station->m_sampleRate = sampleIdx;
1392 
1393  NS_LOG_DEBUG("FindRate "
1394  << "sampleRate=" << sampleIdx);
1395  station->m_sampleTries--;
1396  return sampleIdx;
1397  }
1398  }
1399  }
1400  }
1401  }
1402  if (station->m_sampleWait > 0)
1403  {
1404  station->m_sampleWait--;
1405  }
1406 
1408 
1409  NS_LOG_DEBUG("FindRate "
1410  << "maxTpRrate=" << station->m_maxTpRate);
1411  return station->m_maxTpRate;
1412 }
1413 
1414 void
1416 {
1417  NS_LOG_FUNCTION(this << station);
1418 
1420 
1421  station->m_numSamplesSlow = 0;
1422  station->m_sampleCount = 0;
1423 
1424  double tempProb;
1425 
1426  if (station->m_ampduPacketCount > 0)
1427  {
1428  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1429  station->m_avgAmpduLen =
1430  (newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel)) / 100;
1431  station->m_ampduLen = 0;
1432  station->m_ampduPacketCount = 0;
1433  }
1434 
1435  /* Initialize global rate indexes */
1436  station->m_maxTpRate = GetLowestIndex(station);
1437  station->m_maxTpRate2 = GetLowestIndex(station);
1438  station->m_maxProbRate = GetLowestIndex(station);
1439 
1441  for (uint8_t j = 0; j < m_numGroups; j++)
1442  {
1443  if (station->m_groupsTable[j].m_supported)
1444  {
1445  station->m_sampleCount++;
1446 
1447  /* (re)Initialize group rate indexes */
1448  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex(station, j);
1449  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex(station, j);
1450  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex(station, j);
1451 
1452  for (uint8_t i = 0; i < m_numRates; i++)
1453  {
1454  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1455  {
1456  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1457 
1458  NS_LOG_DEBUG(
1459  +i << " "
1460  << GetMcsSupported(station,
1461  station->m_groupsTable[j].m_ratesTable[i].mcsIndex)
1462  << "\t attempt="
1463  << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt
1464  << "\t success="
1465  << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1466 
1468  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1469  {
1470  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1475  tempProb =
1476  (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) /
1477  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1478 
1480  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1481 
1482  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1483  {
1484  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1485  }
1486  else
1487  {
1488  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb =
1489  CalculateEwmsd(station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1490  tempProb,
1491  station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1492  m_ewmaLevel);
1494  tempProb =
1495  (tempProb * (100 - m_ewmaLevel) +
1496  station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) /
1497  100;
1498  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1499  }
1500 
1501  station->m_groupsTable[j].m_ratesTable[i].throughput =
1502  CalculateThroughput(station, j, i, tempProb);
1503 
1504  station->m_groupsTable[j].m_ratesTable[i].successHist +=
1505  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1506  station->m_groupsTable[j].m_ratesTable[i].attemptHist +=
1507  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1508  }
1509  else
1510  {
1511  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1512  }
1513 
1515  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess =
1516  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1517  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt =
1518  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1519  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1520  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1521 
1522  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1523  {
1524  SetBestStationThRates(station, GetIndex(j, i));
1525  SetBestProbabilityRate(station, GetIndex(j, i));
1526  }
1527  }
1528  }
1529  }
1530  }
1531 
1532  // Try to sample all available rates during each interval.
1533  station->m_sampleCount *= 8;
1534 
1535  // Recalculate retries for the rates selected.
1536  CalculateRetransmits(station, station->m_maxTpRate);
1537  CalculateRetransmits(station, station->m_maxTpRate2);
1538  CalculateRetransmits(station, station->m_maxProbRate);
1539 
1540  NS_LOG_DEBUG("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2
1541  << "\nmax prob=" << station->m_maxProbRate);
1542  if (m_printStats)
1543  {
1544  PrintTable(station);
1545  }
1546 }
1547 
1548 double
1550  uint8_t groupId,
1551  uint8_t rateId,
1552  double ewmaProb)
1553 {
1559  if (ewmaProb < 10)
1560  {
1561  return 0;
1562  }
1563  else
1564  {
1569  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1570  if (ewmaProb > 90)
1571  {
1572  return 90 / txTime.GetSeconds();
1573  }
1574  else
1575  {
1576  return ewmaProb / txTime.GetSeconds();
1577  }
1578  }
1579 }
1580 
1581 void
1583 {
1584  GroupInfo* group;
1585  MinstrelHtRateInfo rate;
1586  uint8_t tmpGroupId;
1587  uint8_t tmpRateId;
1588  double tmpTh;
1589  double tmpProb;
1590  uint8_t groupId;
1591  uint8_t rateId;
1592  double currentTh;
1593  // maximum group probability (GP) variables
1594  uint8_t maxGPGroupId;
1595  uint8_t maxGPRateId;
1596  double maxGPTh;
1597 
1598  groupId = GetGroupId(index);
1599  rateId = GetRateId(index);
1600  group = &station->m_groupsTable[groupId];
1601  rate = group->m_ratesTable[rateId];
1602 
1603  tmpGroupId = GetGroupId(station->m_maxProbRate);
1604  tmpRateId = GetRateId(station->m_maxProbRate);
1605  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1606  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1607 
1608  if (rate.ewmaProb > 75)
1609  {
1610  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1611  if (currentTh > tmpTh)
1612  {
1613  station->m_maxProbRate = index;
1614  }
1615 
1616  maxGPGroupId = GetGroupId(group->m_maxProbRate);
1617  maxGPRateId = GetRateId(group->m_maxProbRate);
1618  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1619 
1620  if (currentTh > maxGPTh)
1621  {
1622  group->m_maxProbRate = index;
1623  }
1624  }
1625  else
1626  {
1627  if (rate.ewmaProb > tmpProb)
1628  {
1629  station->m_maxProbRate = index;
1630  }
1631  maxGPRateId = GetRateId(group->m_maxProbRate);
1632  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1633  {
1634  group->m_maxProbRate = index;
1635  }
1636  }
1637 }
1638 
1639 /*
1640  * Find & sort topmost throughput rates
1641  *
1642  * If multiple rates provide equal throughput the sorting is based on their
1643  * current success probability. Higher success probability is preferred among
1644  * MCS groups.
1645  */
1646 void
1648 {
1649  uint8_t groupId;
1650  uint8_t rateId;
1651  double th;
1652  double prob;
1653  uint8_t maxTpGroupId;
1654  uint8_t maxTpRateId;
1655  uint8_t maxTp2GroupId;
1656  uint8_t maxTp2RateId;
1657  double maxTpTh;
1658  double maxTpProb;
1659  double maxTp2Th;
1660  double maxTp2Prob;
1661 
1662  groupId = GetGroupId(index);
1663  rateId = GetRateId(index);
1664  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1665  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1666 
1667  maxTpGroupId = GetGroupId(station->m_maxTpRate);
1668  maxTpRateId = GetRateId(station->m_maxTpRate);
1669  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1670  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1671 
1672  maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1673  maxTp2RateId = GetRateId(station->m_maxTpRate2);
1674  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1675  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1676 
1677  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1678  {
1679  station->m_maxTpRate2 = station->m_maxTpRate;
1680  station->m_maxTpRate = index;
1681  }
1682  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1683  {
1684  station->m_maxTpRate2 = index;
1685  }
1686 
1687  // Find best rates per group
1688 
1689  GroupInfo* group = &station->m_groupsTable[groupId];
1690  maxTpGroupId = GetGroupId(group->m_maxTpRate);
1691  maxTpRateId = GetRateId(group->m_maxTpRate);
1692  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1693  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1694 
1695  maxTp2GroupId = GetGroupId(group->m_maxTpRate2);
1696  maxTp2RateId = GetRateId(group->m_maxTpRate2);
1697  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1698  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1699 
1700  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1701  {
1702  group->m_maxTpRate2 = group->m_maxTpRate;
1703  group->m_maxTpRate = index;
1704  }
1705  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1706  {
1707  group->m_maxTpRate2 = index;
1708  }
1709 }
1710 
1711 void
1713 {
1714  NS_LOG_FUNCTION(this << station);
1715 
1717 
1721  NS_LOG_DEBUG("Supported groups by station:");
1722  bool noSupportedGroupFound = true;
1723  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1724  {
1725  if (m_minstrelGroups[groupId].isSupported)
1726  {
1727  station->m_groupsTable[groupId].m_supported = false;
1728 
1729  if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1730  !GetHeSupported(station))
1731  {
1732  // It is a HE group but the receiver does not support HE: skip
1733  continue;
1734  }
1735  if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1736  !GetVhtSupported(station))
1737  {
1738  // It is a VHT group but the receiver does not support VHT: skip
1739  continue;
1740  }
1741  if ((m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_HE) &&
1743  {
1744  // It is not a HE group and the receiver supports HE: skip since
1745  // UseLatestAmendmentOnly attribute is enabled
1746  continue;
1747  }
1748  if (!GetHeSupported(station) &&
1751  {
1752  // It is not a VHT group and the receiver supports VHT (but not HE): skip since
1753  // UseLatestAmendmentOnly attribute is enabled
1754  continue;
1755  }
1756  if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) ||
1758  (m_minstrelGroups[groupId].gi == 400) && !GetShortGuardIntervalSupported(station))
1759  {
1760  // It is a SGI group but the receiver does not support SGI: skip
1761  continue;
1762  }
1763  if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1764  (m_minstrelGroups[groupId].gi < GetGuardInterval(station)))
1765  {
1766  // The receiver does not support the GI: skip
1767  continue;
1768  }
1769  if (GetChannelWidth(station) < m_minstrelGroups[groupId].chWidth)
1770  {
1771  // The receiver does not support the channel width: skip
1772  continue;
1773  }
1774  if (GetNumberOfSupportedStreams(station) < m_minstrelGroups[groupId].streams)
1775  {
1776  // The receiver does not support the number of spatial streams: skip
1777  continue;
1778  }
1779 
1780  NS_LOG_DEBUG("Group: " << +groupId << " type: " << m_minstrelGroups[groupId].type
1781  << " streams: " << +m_minstrelGroups[groupId].streams
1782  << " GI: " << m_minstrelGroups[groupId].gi
1783  << " width: " << m_minstrelGroups[groupId].chWidth);
1784 
1785  noSupportedGroupFound = false;
1786  station->m_groupsTable[groupId].m_supported = true;
1787  station->m_groupsTable[groupId].m_col = 0;
1788  station->m_groupsTable[groupId].m_index = 0;
1789 
1790  station->m_groupsTable[groupId].m_ratesTable =
1792  for (uint8_t i = 0; i < m_numRates; i++)
1793  {
1794  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1795  }
1796 
1797  // Initialize all modes supported by the remote station that belong to the current
1798  // group.
1799  for (uint8_t i = 0; i < station->m_nModes; i++)
1800  {
1801  WifiMode mode = GetMcsSupported(station, i);
1802 
1805  uint8_t rateId = mode.GetMcsValue();
1806  if (mode.GetModulationClass() == WIFI_MOD_CLASS_HT)
1807  {
1808  rateId %= MAX_HT_GROUP_RATES;
1809  }
1810 
1811  if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1812  (mode.GetModulationClass() ==
1814  && IsValidMcs(GetPhy(),
1815  m_minstrelGroups[groupId].streams,
1816  m_minstrelGroups[groupId].chWidth,
1817  mode))
1818  || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1819  (mode.GetModulationClass() ==
1821  && IsValidMcs(GetPhy(),
1822  m_minstrelGroups[groupId].streams,
1823  m_minstrelGroups[groupId].chWidth,
1824  mode))
1825  || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) &&
1826  (mode.GetModulationClass() ==
1828  && (mode.GetMcsValue() <
1829  (m_minstrelGroups[groupId].streams *
1830  8))
1831  && (mode.GetMcsValue() >= ((m_minstrelGroups[groupId].streams - 1) * 8))))
1832  {
1833  NS_LOG_DEBUG("Mode " << +i << ": " << mode);
1834 
1835  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1836  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex =
1837  i;
1838  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1839  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1840  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1841  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1842  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1843  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1844  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1845  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1846  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1847  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1848  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime =
1849  GetFirstMpduTxTime(groupId, GetMcsSupported(station, i));
1850  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1851  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1852  CalculateRetransmits(station, groupId, rateId);
1853  }
1854  }
1855  }
1856  }
1859  if (noSupportedGroupFound)
1860  {
1861  NS_FATAL_ERROR("No supported group has been found");
1862  }
1863  SetNextSample(station);
1864  UpdateStats(station);
1865  station->m_txrate = FindRate(station);
1866 }
1867 
1868 void
1870 {
1871  NS_LOG_FUNCTION(this << station << index);
1872  uint8_t groupId = GetGroupId(index);
1873  uint8_t rateId = GetRateId(index);
1874  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1875  {
1876  CalculateRetransmits(station, groupId, rateId);
1877  }
1878 }
1879 
1880 void
1882  uint8_t groupId,
1883  uint8_t rateId)
1884 {
1885  NS_LOG_FUNCTION(this << station << +groupId << +rateId);
1886 
1887  uint32_t cw = 15; // Is an approximation.
1888  uint32_t cwMax = 1023;
1889  Time cwTime;
1890  Time txTime;
1891  Time dataTxTime;
1892  Time slotTime = GetPhy()->GetSlot();
1893  Time ackTime = GetPhy()->GetSifs() + GetPhy()->GetBlockAckTxTime();
1894 
1895  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1896  {
1897  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1898  }
1899  else
1900  {
1901  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1902  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1903 
1904  dataTxTime =
1906  groupId,
1907  GetMcsSupported(station,
1908  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1909  GetMpduTxTime(
1910  groupId,
1911  GetMcsSupported(station,
1912  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) *
1913  (station->m_avgAmpduLen - 1);
1914 
1915  /* Contention time for first 2 tries */
1916  cwTime = (cw / 2) * slotTime;
1917  cw = Min((cw + 1) * 2, cwMax);
1918  cwTime += (cw / 2) * slotTime;
1919  cw = Min((cw + 1) * 2, cwMax);
1920 
1921  /* Total TX time for data and Contention after first 2 tries */
1922  txTime = cwTime + 2 * (dataTxTime + ackTime);
1923 
1924  /* See how many more tries we can fit inside segment size */
1925  do
1926  {
1927  /* Contention time for this try */
1928  cwTime = (cw / 2) * slotTime;
1929  cw = Min((cw + 1) * 2, cwMax);
1930 
1931  /* Total TX time after this try */
1932  txTime += cwTime + ackTime + dataTxTime;
1933  } while ((txTime < MilliSeconds(6)) &&
1934  (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1935  }
1936 }
1937 
1938 double
1940  double currentProb,
1941  double ewmaProb,
1942  double weight)
1943 {
1944  double diff;
1945  double incr;
1946  double tmp;
1947 
1948  /* calculate exponential weighted moving variance */
1949  diff = currentProb - ewmaProb;
1950  incr = (100 - weight) * diff / 100;
1951  tmp = oldEwmsd * oldEwmsd;
1952  tmp = weight * (tmp + diff * incr) / 100;
1953 
1954  /* return standard deviation */
1955  return sqrt(tmp);
1956 }
1957 
1958 void
1960 {
1961  NS_LOG_FUNCTION(this << station);
1962  station->m_col = station->m_index = 0;
1963 
1964  // for off-setting to make rates fall between 0 and nModes
1965  uint8_t numSampleRates = m_numRates;
1966 
1967  uint16_t newIndex;
1968  for (uint8_t col = 0; col < m_nSampleCol; col++)
1969  {
1970  for (uint8_t i = 0; i < numSampleRates; i++)
1971  {
1976  int uv = m_uniformRandomVariable->GetInteger(0, numSampleRates);
1977  newIndex = (i + uv) % numSampleRates;
1978 
1979  // this loop is used for filling in other uninitialized places
1980  while (station->m_sampleTable[newIndex][col] != 0)
1981  {
1982  newIndex = (newIndex + 1) % m_numRates;
1983  }
1984  station->m_sampleTable[newIndex][col] = i;
1985  }
1986  }
1987 }
1988 
1989 void
1991 {
1992  if (!station->m_statsFile.is_open())
1993  {
1994  std::ostringstream tmp;
1995  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1996  station->m_statsFile.open(tmp.str(), std::ios::out);
1997  }
1998 
1999  station->m_statsFile
2000  << " best ____________rate__________ ________statistics________ "
2001  "________last_______ ______sum-of________\n"
2002  << " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] "
2003  "[prob.|retry|suc|att] [#success | #attempts]\n";
2004  for (uint8_t i = 0; i < m_numGroups; i++)
2005  {
2006  StatsDump(station, i, station->m_statsFile);
2007  }
2008 
2009  station->m_statsFile << "\nTotal packet count:: ideal "
2010  << Max(0, station->m_totalPacketsCount - station->m_samplePacketsCount)
2011  << " lookaround " << station->m_samplePacketsCount << "\n";
2012  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen
2013  << "\n\n";
2014 
2015  station->m_statsFile.flush();
2016 }
2017 
2018 void
2020  uint8_t groupId,
2021  std::ofstream& of)
2022 {
2023  uint8_t numRates = m_numRates;
2024  McsGroup group = m_minstrelGroups[groupId];
2025  Time txTime;
2026  for (uint8_t i = 0; i < numRates; i++)
2027  {
2028  if (station->m_groupsTable[groupId].m_supported &&
2029  station->m_groupsTable[groupId].m_ratesTable[i].supported)
2030  {
2031  of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams
2032  << " ";
2033 
2034  uint16_t maxTpRate = station->m_maxTpRate;
2035  uint16_t maxTpRate2 = station->m_maxTpRate2;
2036  uint16_t maxProbRate = station->m_maxProbRate;
2037 
2038  uint16_t idx = GetIndex(groupId, i);
2039  if (idx == maxTpRate)
2040  {
2041  of << 'A';
2042  }
2043  else
2044  {
2045  of << ' ';
2046  }
2047  if (idx == maxTpRate2)
2048  {
2049  of << 'B';
2050  }
2051  else
2052  {
2053  of << ' ';
2054  }
2055  if (idx == maxProbRate)
2056  {
2057  of << 'P';
2058  }
2059  else
2060  {
2061  of << ' ';
2062  }
2063 
2064  if (group.type == WIFI_MINSTREL_GROUP_HT)
2065  {
2066  of << std::setw(4) << " MCS" << (group.streams - 1) * 8 + i;
2067  }
2068  else
2069  {
2070  of << std::setw(7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
2071  }
2072 
2073  of << " " << std::setw(3) << +idx << " ";
2074 
2075  /* tx_time[rate(i)] in usec */
2076  txTime = GetFirstMpduTxTime(
2077  groupId,
2078  GetMcsSupported(station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
2079  of << std::setw(6) << txTime.GetMicroSeconds() << " ";
2080 
2081  of << std::setw(7) << CalculateThroughput(station, groupId, i, 100) / 100 << " "
2082  << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100
2083  << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb
2084  << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb
2085  << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].prob
2086  << " " << std::setw(2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount
2087  << " " << std::setw(3)
2088  << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " "
2089  << std::setw(3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt
2090  << " " << std::setw(9)
2091  << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " "
2092  << std::setw(9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist
2093  << "\n";
2094  }
2095  }
2096 }
2097 
2098 uint16_t
2099 MinstrelHtWifiManager::GetIndex(uint8_t groupId, uint8_t rateId)
2100 {
2101  NS_LOG_FUNCTION(this << +groupId << +rateId);
2102  uint16_t index;
2103  index = groupId * m_numRates + rateId;
2104  return index;
2105 }
2106 
2107 uint8_t
2109 {
2110  NS_LOG_FUNCTION(this << index);
2111  uint8_t id;
2112  id = index % m_numRates;
2113  return id;
2114 }
2115 
2116 uint8_t
2118 {
2119  NS_LOG_FUNCTION(this << index);
2120  return index / m_numRates;
2121 }
2122 
2123 uint8_t
2124 MinstrelHtWifiManager::GetHtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2125 {
2126  NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2127  uint8_t giIndex = (gi == 400) ? 1 : 0;
2128  uint8_t widthIndex = (chWidth == 40) ? 1 : 0;
2129  return (MAX_HT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_HT_SUPPORTED_STREAMS * giIndex) +
2130  txstreams - 1;
2131 }
2132 
2133 uint8_t
2134 MinstrelHtWifiManager::GetVhtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2135 {
2136  NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2137  uint8_t giIndex = (gi == 400) ? 1 : 0;
2138  uint8_t widthIndex;
2139  if (chWidth == 160)
2140  {
2141  widthIndex = 3;
2142  }
2143  else if (chWidth == 80)
2144  {
2145  widthIndex = 2;
2146  }
2147  else if (chWidth == 40)
2148  {
2149  widthIndex = 1;
2150  }
2151  else // 20 MHz
2152  {
2153  widthIndex = 0;
2154  }
2155  uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2156  groupId += (MAX_VHT_SUPPORTED_STREAMS * 2 * widthIndex) +
2157  (MAX_VHT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
2158  return groupId;
2159 }
2160 
2161 uint8_t
2162 MinstrelHtWifiManager::GetHeGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2163 {
2164  NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2165  uint8_t giIndex;
2166  if (gi == 800)
2167  {
2168  giIndex = 2;
2169  }
2170  else if (gi == 1600)
2171  {
2172  giIndex = 1;
2173  }
2174  else // 3200 ns
2175  {
2176  giIndex = 0;
2177  }
2178  uint8_t widthIndex;
2179  if (chWidth == 160)
2180  {
2181  widthIndex = 3;
2182  }
2183  else if (chWidth == 80)
2184  {
2185  widthIndex = 2;
2186  }
2187  else if (chWidth == 40)
2188  {
2189  widthIndex = 1;
2190  }
2191  else // 20 MHz
2192  {
2193  widthIndex = 0;
2194  }
2195  uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2196  if (GetVhtSupported())
2197  {
2199  }
2200  groupId += (MAX_HE_SUPPORTED_STREAMS * 3 * widthIndex) + (MAX_HE_SUPPORTED_STREAMS * giIndex) +
2201  txstreams - 1;
2202  return groupId;
2203 }
2204 
2205 uint16_t
2207 {
2208  NS_LOG_FUNCTION(this << station);
2209 
2210  uint8_t groupId = 0;
2211  uint8_t rateId = 0;
2212  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
2213  {
2214  groupId++;
2215  }
2216  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2217  {
2218  rateId++;
2219  }
2220  NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2221  station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2222  return GetIndex(groupId, rateId);
2223 }
2224 
2225 uint16_t
2227 {
2228  NS_LOG_FUNCTION(this << station << +groupId);
2229 
2230  uint8_t rateId = 0;
2231  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2232  {
2233  rateId++;
2234  }
2235  NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2236  station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2237  return GetIndex(groupId, rateId);
2238 }
2239 
2242 {
2243  WifiModeList heMcsList;
2244  for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HE))
2245  {
2246  heMcsList.push_back(mode);
2247  }
2248  return heMcsList;
2249 }
2250 
2253 {
2254  WifiModeList vhtMcsList;
2255  for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_VHT))
2256  {
2257  vhtMcsList.push_back(mode);
2258  }
2259  return vhtMcsList;
2260 }
2261 
2264 {
2265  WifiModeList htMcsList;
2266  for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HT))
2267  {
2268  htMcsList.push_back(mode);
2269  }
2270  return htMcsList;
2271 }
2272 
2273 } // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Implementation of Minstrel-HT Rate Control Algorithm.
static TypeId GetTypeId()
Get the type ID.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
uint32_t m_frameLength
Frame length used to calculate modes TxTime in bytes.
void InitSampleTable(MinstrelHtWifiRemoteStation *station)
Initialize Sample Table.
bool m_printStats
If statistics table should be printed.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode) override
This method is a pure virtual method that must be implemented by the sub-class.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally) override
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station, uint16_t allowedWidth) override
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station) override
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
void AddMpduTxTime(uint8_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
void SetNextSample(MinstrelHtWifiRemoteStation *station)
Set the next sample from Sample Table.
uint8_t m_numRates
Number of rates per group Minstrel should consider.
uint8_t m_nSampleCol
Number of sample columns.
void RateInit(MinstrelHtWifiRemoteStation *station)
Initialize Minstrel Table.
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
void PrintTable(MinstrelHtWifiRemoteStation *station)
Printing Minstrel Table.
void StatsDump(MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
Print group statistics.
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss) override
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
double CalculateThroughput(MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
Return the average throughput of the MCS defined by groupId and rateId.
void AddFirstMpduTxTime(uint8_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, double weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
void DoReportDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void SetBestProbabilityRate(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxProbRate if it is better than current value.
WifiModeList GetHeDeviceMcsList() const
Returns a list of only the HE MCS supported by the device.
Time m_updateStats
How frequent do we calculate the stats.
TracedValue< uint64_t > m_currentRate
Trace rate changes.
uint16_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
void DoInitialize() override
Initialize() implementation.
WifiModeList GetVhtDeviceMcsList() const
Returns a list of only the VHT MCS supported by the device.
Time CalculateMpduTxDuration(Ptr< WifiPhy > phy, uint8_t streams, uint16_t gi, uint16_t chWidth, WifiMode mode, MpduType mpduType)
Estimates the TxTime of a frame with a given mode and group (stream, guard interval and channel width...
void CheckInit(MinstrelHtWifiRemoteStation *station)
Check for initializations.
WifiModeList GetHtDeviceMcsList() const
Returns a list of only the HT MCS supported by the device.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
Time GetFirstMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
Time GetMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
uint16_t UpdateRateAfterAllowedWidth(uint16_t txRate, uint16_t allowedWidth)
Given the index of the current TX rate, check whether the channel width is not greater than the given...
uint8_t m_numGroups
Number of groups Minstrel should consider.
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint16_t index)
Calculate the number of retransmissions to set for the index rate.
void SetupPhy(const Ptr< WifiPhy > phy) override
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss) override
This method is a pure virtual method that must be implemented by the sub-class.
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
void UpdateRate(MinstrelHtWifiRemoteStation *station)
Update rate.
uint8_t GetRateId(uint16_t index)
Return the rateId inside a group, from the global index.
Time m_legacyUpdateStats
How frequent do we calculate the stats for legacy MinstrelWifiManager.
uint8_t GetGroupId(uint16_t index)
Return the groupId from the global index.
uint8_t GetVhtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
Returns the groupId of a VHT MCS with the given number of streams, GI and channel width used.
uint8_t GetHtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
Returns the groupId of an HT MCS with the given number of streams, GI and channel width used.
void DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr) override
This method is a pure virtual method that must be implemented by the sub-class.
Ptr< UniformRandomVariable > m_uniformRandomVariable
Provides uniform random variables.
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Update the Minstrel Table.
uint16_t GetIndex(uint8_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
WifiRemoteStation * DoCreateStation() const override
Ptr< MinstrelWifiManager > m_legacyManager
Pointer to an instance of MinstrelWifiManager.
uint8_t GetHeGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
Returns the groupId of an HE MCS with the given number of streams, GI and channel width used.
bool IsValidMcs(Ptr< WifiPhy > phy, uint8_t streams, uint16_t chWidth, WifiMode mode)
Check the validity of a combination of number of streams, chWidth and mode.
void SetupMac(const Ptr< WifiMac > mac) override
Set up MAC associated with this device since it is the object that knows the full set of timing param...
void DoReportFinalDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
Update the number of sample count variables.
void DoReportFinalRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
bool m_useLatestAmendmentOnly
Flag if only the latest supported amendment by both peers should be used.
void DoReportRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
AttributeValue implementation for Time.
Definition: nstime.h:1423
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value drawn from the distribution.
represent a single transmission mode
Definition: wifi-mode.h:50
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:185
uint64_t GetNonHtReferenceRate() const
Definition: wifi-mode.cc:192
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
uint8_t GetMcsValue() const
Definition: wifi-mode.cc:163
Time GetBlockAckTxTime() const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:810
static Time GetPayloadDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, MpduType mpdutype=NORMAL_MPDU, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1433
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:786
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:774
uint16_t GetTxBandwidth(WifiMode mode, uint16_t maxAllowedBandWidth=std::numeric_limits< uint16_t >::max()) const
Get the bandwidth for a transmission occurring on the current operating channel and using the given W...
Definition: wifi-phy.cc:1050
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1473
hold a list of per-remote-station state.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
uint8_t GetNess(const WifiRemoteStation *station) const
uint8_t GetNBasicModes() const
Return the number of basic modes we support.
uint16_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
Ptr< WifiPhy > GetPhy() const
Return the WifiPhy.
uint16_t GetGuardInterval() const
Return the supported HE guard interval duration (in nanoseconds).
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
bool GetHtSupported() const
Return whether the device has HT capability support enabled.
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
bool GetShortGuardIntervalSupported() const
Return whether the device has SGI support enabled.
virtual void SetupPhy(const Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
bool GetVhtSupported() const
Return whether the device has VHT capability support enabled.
bool GetShortPreambleEnabled() const
Return whether the device uses short PHY preambles.
bool GetHeSupported() const
Return whether the device has HE capability support enabled.
virtual void SetupMac(const Ptr< WifiMac > mac)
Set up MAC associated with this device since it is the object that knows the full set of timing param...
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetStbc(bool stbc)
Sets if STBC is being used.
void SetNess(uint8_t ness)
Sets the Ness number.
bool IsValid() const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
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:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
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:1424
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:46
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:229
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
MpduType
The type of an MPDU.
@ WIFI_PREAMBLE_HT_MF
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ FIRST_MPDU_IN_AGGREGATE
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate.
@ MIDDLE_MPDU_IN_AGGREGATE
The MPDU is part of an A-MPDU with multiple MPDUs, but is neither the first nor the last aggregate.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const uint8_t MAX_HT_GROUP_RATES
Number of rates (or MCS) per HT group.
static const uint8_t MAX_VHT_STREAM_GROUPS
Maximal number of groups per stream in VHT (4 possible channel widths and 2 possible GI configuration...
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
static const uint8_t MAX_VHT_GROUP_RATES
Number of rates (or MCS) per VHT group.
static const uint8_t MAX_VHT_SUPPORTED_STREAMS
Maximal number of streams supported by the VHT PHY layer.
static const uint8_t MAX_HT_SUPPORTED_STREAMS
Constants for maximum values.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:535
static const uint8_t MAX_HE_GROUP_RATES
Number of rates (or MCS) per HE group.
static const uint8_t MAX_HT_WIDTH
Maximal channel width in MHz.
static const uint8_t MAX_HT_STREAM_GROUPS
Maximal number of groups per stream in HT (2 possible channel widths and 2 possible GI configurations...
static const uint8_t MAX_HE_STREAM_GROUPS
Maximal number of groups per stream in HE (4 possible channel widths and 3 possible GI configurations...
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
std::vector< MinstrelHtRateInfo > MinstrelHtRate
Data structure for a Minstrel Rate table.
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes.
Definition: wifi-mode.h:261
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
static const uint8_t MAX_HE_WIDTH
Maximal channel width in MHz.
std::vector< struct GroupInfo > McsGroupData
Data structure for a table of groups.
static const uint8_t MAX_VHT_WIDTH
Maximal channel width in MHz.
static const uint8_t MAX_HE_SUPPORTED_STREAMS
Maximal number of streams supported by the HE PHY layer.
mac
Definition: third.py:85
phy
Definition: third.py:82
A struct to contain information of a group.
MinstrelHtRate m_ratesTable
Information about rates of this group.
uint16_t m_maxTpRate2
The second max throughput rate of this group in bps.
uint16_t m_maxProbRate
The highest success probability rate of this group in bps.
uint16_t m_maxTpRate
The max throughput rate of this group in bps.
Data structure to contain the information that defines a group.
uint16_t chWidth
channel width (MHz)
uint16_t gi
guard interval duration (nanoseconds)
McsGroupType type
identifies the group,
bool isSupported
flag whether group is supported
uint8_t streams
number of spatial streams
A struct to contain all statistics information related to a data rate.
Time perfectTxTime
Perfect transmission time calculation, or frame calculation.
double ewmaProb
Exponential weighted moving average of probability.
uint32_t numSamplesSkipped
Number of times this rate statistics were not updated because no attempts have been made.
MinstrelHtWifiRemoteStation structure.
McsGroupData m_groupsTable
Table of groups with stats.
uint32_t m_sampleCount
Max number of samples per update interval.
uint8_t m_sampleGroup
The group that the sample rate belongs to.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
std::ofstream m_statsFile
File where statistics table is written.
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
bool m_isHt
If the station is HT capable.
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
hold per-remote-station state for Minstrel Wifi manager.
uint16_t m_maxTpRate2
second highest throughput rate in bps
Time m_nextStatsUpdate
10 times every second
bool m_initialized
for initializing tables
uint16_t m_sampleRate
current sample rate in bps
uint16_t m_txrate
current transmit rate in bps
int m_totalPacketsCount
total number of packets as of now
bool m_isSampling
a flag to indicate we are currently sampling
MinstrelRate m_minstrelTable
minstrel table
uint32_t m_shortRetry
short retries such as control packets
uint16_t m_maxTpRate
the current throughput rate in bps
bool m_sampleDeferred
a flag to indicate sample rate is on the second stage
uint8_t m_nModes
number of modes supported
SampleRate m_sampleTable
sample table
int m_samplePacketsCount
how many packets we have sample so far
uint8_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
uint32_t m_longRetry
long retries such as data packets
uint16_t m_maxProbRate
rate with highest probability of success in bps
hold per-remote-station state.
WifiRemoteStationState * m_state
Remote station state.
Mac48Address m_address
Mac48Address of the remote station.