68 const char *pzLayerName{
"IEEEMACLayer"};
72 const bool ENABLE_TX_RETRY{
false};
75 const bool ENABLE_WMM_OVERHEAD{
false};
77 const std::uint16_t DROP_CODE_SINR = 1;
78 const std::uint16_t DROP_CODE_REGISTRATION_ID = 2;
79 const std::uint16_t DROP_CODE_DST_MAC = 3;
80 const std::uint16_t DROP_CODE_QUEUE_OVERFLOW = 4;
81 const std::uint16_t DROP_CODE_BAD_CONTROL_INFO = 5;
82 const std::uint16_t DROP_CODE_BAD_SPECTRUM_QUERY = 6;
83 const std::uint16_t DROP_CODE_FLOW_CONTROL_ERROR = 7;
84 const std::uint16_t DROP_CODE_DUPLICATE = 8;
85 const std::uint16_t DROP_CODE_RX_DURING_TX = 9;
86 const std::uint16_t DROP_CODE_RX_HIDDEN_BUSY = 10;
109 macConfig_{pPlatformServiceProvider->logService(),
id},
111 downstreamQueue_{
id},
115 neighborMetricManager_{
id},
116 queueMetricManager_{
id},
117 flowControlManager_{*
this},
118 u64SequenceNumber_{},
119 u16EntrySequenceNumber_{},
120 modeTiming_{macConfig_},
121 channelUsageTimedEventId_{},
122 radioMetricTimedEventId_{},
123 downstreamQueueTimedEventId_{},
124 bHasPendingDownstreamQueueEntry_{},
125 RNDZeroToOne_{0.0f, 1.0f},
127 currentEndOfTransmissionTime_{}
129 commonLayerStatistics_[0].reset(
131 STATISTIC_TABLE_LABELS,
"0"});
132 commonLayerStatistics_[1].reset(
134 STATISTIC_TABLE_LABELS,
"1"});
135 commonLayerStatistics_[2].reset(
137 STATISTIC_TABLE_LABELS,
"2"});
138 commonLayerStatistics_[3].reset(
140 STATISTIC_TABLE_LABELS,
"3"});
154 id_, pzLayerName, __func__);
174 for(
auto & iter : commonLayerStatistics_)
176 iter->registerStatistics(statisticRegistrar);
194 id_, pzLayerName, __func__);
213 id_, pzLayerName, __func__);
221 for(std::uint8_t u8Category = 0; u8Category < u8NumCategories; ++u8Category)
223 size_t maxCapacity{macConfig_.
getQueueSize(u8Category)};
249 auto timeNow = Clock::now();
257 "MACI %03hu %s::%s sent a flow control token update," 258 " a handshake response is required to process packets",
264 neighborManager_.
start();
266 channelUsageTimedEventId_ =
277 "MACI %03hu %s::%s: added channel activity timed eventId %zu",
281 channelUsageTimedEventId_);
283 radioMetricTimedEventId_ =
309 "MACI %03hu %s::%s: added radio metric timed eventId %zu",
313 radioMetricTimedEventId_);
323 id_, pzLayerName, __func__);
341 channelUsageTimedEventId_ = 0;
345 radioMetricTimedEventId_ = 0;
349 downstreamQueueTimedEventId_ = 0;
353 flowControlManager_.
stop();
389 for(
const auto & pMessage : msgs)
393 "MACI %03hu %s::%s downstream control message id %hu",
399 switch(pMessage->getId())
403 const auto pFlowControlControlMessage =
411 "MACI %03hu %s::%s received a flow control token request/response",
422 "MACI %03hu %s::%s received a flow control token request but" 423 " flow control is not enabled",
434 const auto pSerializedControlMessage =
437 switch(pSerializedControlMessage->getSerializedId())
441 std::unique_ptr<Controls::FlowControlControlMessage>
443 (pSerializedControlMessage->getSerialization())};
449 "MACI %03hu %s::%s received a flow control token request/response",
460 "MACI %03hu %s::%s received a flow control token request but" 461 " flow control is not enabled",
487 std::uint8_t u8Category{dscpToCategory(pktInfo.getPriority())};
489 commonLayerStatistics_[u8Category]->processInbound(pkt);
494 "MACI %03hu %s::%s: src %hu, dst %hu",
499 pktInfo.getDestination());
505 ERROR_LEVEL,
"MACI %03hu %s::%s: src %hu, dst %hu, " 506 "MAC registration id %hu does not match our id %hu, drop.",
511 pktInfo.getDestination(),
515 commonLayerStatistics_[u8Category]->processOutbound(
517 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
518 DROP_CODE_REGISTRATION_ID);
528 for(
auto & pControlMessage : msgs)
530 switch(pControlMessage->getId())
534 pReceivePropertiesControlMessage =
540 "MACI %03hu %s::%s Receiver Properties Control Message",
549 pFrequencyControlMessage =
555 "MACI %03hu %s::%s Frequency Control Message",
566 if(!pReceivePropertiesControlMessage || !pFrequencyControlMessage ||
567 pFrequencyControlMessage->getFrequencySegments().empty())
571 "MACI %03hu %s::%s: phy control message not" 572 " provided from src %hu, drop",
576 pktInfo.getSource());
578 commonLayerStatistics_[u8Category]->processOutbound(pkt,
579 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
580 DROP_CODE_BAD_CONTROL_INFO);
587 const auto & frequencySegments = pFrequencyControlMessage->getFrequencySegments();
589 TimePoint startOfReception{pReceivePropertiesControlMessage->getTxTime() +
590 pReceivePropertiesControlMessage->getPropagationDelay() +
591 frequencySegments.begin()->getOffset()};
593 Microseconds span{pReceivePropertiesControlMessage->getSpan()};
595 auto callback =std::bind([
this,
600 std::uint64_t u64SequenceNumber,
601 std::uint8_t u8Category)
609 "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, len %zu, freq %ju, offset %ju, duration %ju",
613 pktInfo.getDestination(),
615 frequencySegment.getFrequencyHz(),
616 frequencySegment.getOffset().count(),
617 frequencySegment.getDuration().count());
620 double dNoiseFloordB{};
637 bool bSignalInNoise{};
639 std::tie(dNoiseFloordB,bSignalInNoise) =
646 "MACI %03hu %s upstream EOR processing: spectrum service reporting signal in noise." 647 " This is an unallowable noise mode. Valid PHY noise modes are: none and outofband.",
651 commonLayerStatistics_[u8Category]->processOutbound(pkt,
652 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
653 DROP_CODE_BAD_CONTROL_INFO);
664 "MACI %03hu %s upstream EOR processing: spectrum service request error: %s",
668 commonLayerStatistics_[u8Category]->processOutbound(pkt,
669 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
670 DROP_CODE_BAD_SPECTRUM_QUERY);
675 handleUpstreamPacket(pkt,
676 frequencySegment.getRxPowerdBm(),
687 auto eor = startOfReception + frequencySegments.begin()->getDuration();
704 EMANE::Models::IEEE80211ABG::MACLayer::handleUpstreamPacket(
UpstreamPacket & pkt,
706 double dNoiseFloordBm,
707 std::uint64_t u64SequenceNumber,
709 std::uint8_t u8Category)
715 if(len && pkt.
length() >= len)
730 "MACI %03hu %s::%s: cts pkt from %hu, mac seq %ju entry seq %hu",
734 macHeaderParams.getSrcNEM(),
736 macHeaderParams.getSequenceNumber());
740 macHeaderParams.getDstNEM(),
741 macHeaderParams.getMessageType(),
744 macHeaderParams.getDurationMicroseconds(),
763 if(macHeaderParams.getDstNEM() == id_)
776 entry.durationMicroseconds_ = macHeaderParams.getDurationMicroseconds();
788 Microseconds::zero()};
792 macHeaderParams.getMessageType(),
795 macHeaderParams.getDurationMicroseconds() +
796 overheadMicroseconds,
803 if(!checkUpstremReception(pkt,
809 macHeaderParams.getNumRetries(),
814 "MACI %03hu %s::%s: src %hu, dst %hu, reception failed, drop",
818 macHeaderParams.getSrcNEM(),
819 macHeaderParams.getDstNEM());
828 if(
isDuplicate(macHeaderParams.getSrcNEM(), macHeaderParams.getSequenceNumber()))
832 "MACI %03hu %s::%s: duplicate pkt from %hu, entry seq %hu, drop",
836 macHeaderParams.getSrcNEM(),
837 macHeaderParams.getSequenceNumber());
839 commonLayerStatistics_[u8Category]->processOutbound(pkt,
840 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
841 DROP_CODE_DUPLICATE);
848 std::pair <bool, std::uint16_t> result{};
853 for(tryNum = 0; (tryNum <= macHeaderParams.getNumRetries()) && !result.first; ++tryNum)
856 result = checkUpstremReception(pkt,
867 DEBUG_LEVEL,
"MACI %03hu %s::%s: src %hu, dst %hu, reception passed, retires %d",
871 macHeaderParams.getSrcNEM(),
872 macHeaderParams.getDstNEM(),
880 DEBUG_LEVEL,
"MACI %03hu %s::%s: src %hu, dst %hu, reception failed in %d tries",
884 macHeaderParams.getSrcNEM(),
885 macHeaderParams.getDstNEM(),
888 commonLayerStatistics_[u8Category]->processOutbound(pkt,
889 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
900 if(macHeaderParams.getDstNEM() != id_ && !isBroadcast(macHeaderParams.getDstNEM()))
906 "MACI %03hu %s::%s: nexthop %hu, not this nem, promiscous mode disabled, drop",
910 macHeaderParams.getDstNEM());
912 commonLayerStatistics_[u8Category]->processOutbound(
914 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
923 processOutbound(pkt,std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow));
930 "MACI %03hu %s::%s: send upsream packet tx state %s",
941 "MACI %03hu %s::%s, malformed pkt, len %zd, prefix len %zd",
952 std::pair<bool, std::uint16_t>
953 EMANE::Models::IEEE80211ABG::MACLayer::checkUpstremReception(
UpstreamPacket & pkt,
955 std::uint64_t u64SequenceNumber,
957 double dNoiseFloordBm,
960 std::uint8_t u8Category)
965 double dNoiseFloorAdjustmentMilliWatts{};
979 "MACI %03hu %s::%s: clobber rx during tx, drop",
985 isBroadcast(rMACHeaderParams.
getDstNEM()) ?
990 return std::pair<bool, std::uint16_t>(
false, DROP_CODE_RX_DURING_TX);
998 "MACI %03hu %s::%s: clobber rx hidden busy, drop",
1004 isBroadcast(rMACHeaderParams.
getDstNEM()) ?
1009 return std::pair<bool, std::uint16_t>(
false, DROP_CODE_RX_HIDDEN_BUSY);
1020 "MACI %03hu %s::%s: common rx noise, avg %3.2f, random %3.2f dBm of " 1021 "noise to noise floor %3.2f dBm",
1030 dNoiseFloorAdjustmentMilliWatts += dRandomNoiseMilliWatts;
1033 isBroadcast(rMACHeaderParams.
getDstNEM()) ?
1046 "MACI %03hu %s::%s: hidden rx noise, avg %3.2f, random %3.2f, dBm of " 1047 "noise to noise floor %3.2f dBm",
1055 dNoiseFloorAdjustmentMilliWatts += dRandomNoiseMilliWatts;
1058 isBroadcast(rMACHeaderParams.
getDstNEM()) ?
1063 double dNoiseFloorAdjusteddBm{
Utils::MILLIWATT_TO_DB(dNoiseFloorMilliWatts + dNoiseFloorAdjustmentMilliWatts)};
1070 "MACI %03hu %s::%s: rxpwr %3.2f dBm, adjusted noise floor %3.2f dBm, datarate %hu, drop",
1075 dNoiseFloorAdjusteddBm,
1079 isBroadcast(rMACHeaderParams.
getDstNEM()) ?
1084 return std::pair<bool, std::uint16_t>(
false, DROP_CODE_SINR);
1088 double dSINR{dRxPowerdBm - dNoiseFloorAdjusteddBm};
1092 "MACI %03hu %s::%s: rxpwr %3.2f dBm, adjusted noise floor %3.2f dBm, sinr %3.2f, datarate %hu, pass",
1097 dNoiseFloorAdjusteddBm,
1102 pktInfo.getSource(),
1106 dNoiseFloorAdjusteddBm,
1114 return std::pair<bool, std::uint16_t>(
true, {});
1128 std::uint8_t u8Category{dscpToCategory(pktInfo.getPriority())};
1130 commonLayerStatistics_[u8Category]->processInbound(pkt);
1134 commonLayerStatistics_[u8Category]->processOutbound(
1136 std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
1137 DROP_CODE_FLOW_CONTROL_ERROR);
1143 std::uint8_t u8Retries{isBroadcast(pktInfo.getDestination()) ?
1157 entry.bRtsCtsEnable_ =
true;
1160 if(bHasPendingDownstreamQueueEntry_)
1162 std::vector<DownstreamQueueEntry> result{downstreamQueue_.
enqueue(entry)};
1165 for(
auto & iter : result)
1167 commonLayerStatistics_[u8Category]->
1168 processOutbound(iter.pkt_,
1169 std::chrono::duration_cast<Microseconds>(Clock::now() - iter.acquireTime_),
1170 DROP_CODE_QUEUE_OVERFLOW);
1177 if(currentEndOfTransmissionTime_ <= Clock::now())
1179 handleDownstreamQueueEntry(u64SequenceNumber_);
1184 bHasPendingDownstreamQueueEntry_ =
true;
1186 pendingDownstreamQueueEntry_ = std::move(entry);
1188 auto optionalWait = pTxState_->
getWaitTime(pendingDownstreamQueueEntry_);
1190 if(optionalWait.second)
1192 downstreamQueueTimedEventId_ =
1194 schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1196 u64SequenceNumber_),
1197 optionalWait.first);
1201 handleDownstreamQueueEntry(u64SequenceNumber_);
1215 "MACI %03hu %s::%s: event id %hu",
1239 setEntrySequenceNumber(entry);
1242 std::uint8_t numRetries{ENABLE_TX_RETRY ? entry.
numRetries_ : std::uint8_t{}};
1264 setEntrySequenceNumber(entry);
1290 setEntrySequenceNumber(entry);
1311 "MACI %03hu %s::%s",
1329 Microseconds overheadMicroseconds{ENABLE_WMM_OVERHEAD ?
1331 Microseconds::zero()};
1369 entry.
pkt_.
prepend(serialization.c_str(), serialization.size());
1375 processOutbound(entry.
pkt_,
1376 std::chrono::duration_cast<Microseconds>(Clock::now() - entry.
acquireTime_),
1401 EMANE::Models::IEEE80211ABG::MACLayer::changeDownstreamState(
TransmissionTxState * pState)
1405 "MACI %03hu %s::%s: %s => %s",
1441 float fNumEstimatedOneAndTwoHopNeighbors{fNumEstimatedOneHopNeighbors + fNumEstimatedTwoHopNeighbors};
1457 float X2{RNDZeroToOne_()};
1469 if(fNumEstimatedOneAndTwoHopNeighbors > 1)
1473 static_cast<Microseconds::rep
>((fNumEstimatedOneAndTwoHopNeighbors - 2.0f) *
1477 float X1{RNDZeroToOne_()};
1479 float fDelayTimeFactor{
getRatio(totalOneAndTwoHopUtilizationMicroseconds, deltaT)};
1481 if(fDelayTimeFactor > 1)
1483 fDelayTimeFactor = 1;
1486 if(X1 <= fDelayTimeFactor)
1489 auto nodeDelayMicroseconds =
1490 Microseconds{
static_cast<Microseconds::rep
>(floorf(X2 * fNumEstimatedOneAndTwoHopNeighbors))};
1493 preDelayMicroseconds +=
1494 Microseconds{nodeDelayMicroseconds.count() * averageMessageDurationMicroseconds.count()};
1496 if(preDelayMicroseconds > messageDurationOverheadExtraMicroseconds)
1499 preDelayMicroseconds -= messageDurationOverheadExtraMicroseconds;
1504 postDelayMicroseconds =
1505 Microseconds{
static_cast<Microseconds::rep
>(powf(fDelayTimeFactor, 2.0f) *
1506 (fNumEstimatedOneAndTwoHopNeighbors - 1.0f) *
1507 averageMessageDurationMicroseconds.count())};
1509 if(postDelayMicroseconds > preDelayMicroseconds)
1511 postDelayMicroseconds -= preDelayMicroseconds;
1515 postDelayMicroseconds = Microseconds::zero();
1518 postDelayMicroseconds += averageMessageDurationMicroseconds;
1528 if(!ENABLE_TX_RETRY)
1531 float X3{RNDZeroToOne_()};
1544 float fUtilizationFactorAdjusted{
getRatio((totalOneHopUtilizationMicroseconds -
1545 localUtilizationMicroseconds -
1546 remoteUtilizationMicroseconds), deltaT)};
1549 if(fUtilizationFactorAdjusted > 1.0f)
1551 fUtilizationFactorAdjusted = 1.0f;
1554 float fPreTran = (fUtilizationFactorAdjusted * fUtilizationFactorAdjusted) *
1555 (1.0 - A) * (fNumEstimatedOneHopNeighbors / iCW);
1566 float X4{RNDZeroToOne_()};
1571 float H{fHiddenChannelActivity - C2};
1579 else if(H >(1.0f - C2))
1601 "MACI %03hu %s::%s: est nbrs 1 hop %3.2f, " 1602 "2 hop %3.2f, bw %lf, avg duration %lf," 1603 " pre delay %lf, post delay %lf, tx collision %s",
1607 fNumEstimatedOneHopNeighbors,
1608 fNumEstimatedTwoHopNeighbors,
1609 std::chrono::duration_cast<
DoubleSeconds>(totalOneAndTwoHopUtilizationMicroseconds).count(),
1610 std::chrono::duration_cast<
DoubleSeconds>(averageMessageDurationMicroseconds).count(),
1611 std::chrono::duration_cast<
DoubleSeconds>(preDelayMicroseconds).count(),
1612 std::chrono::duration_cast<
DoubleSeconds>(postDelayMicroseconds).count(),
1642 float fUtilizationFactorAdjusted{
getRatio((totalOneHopUtilizationMicroseconds -
1643 localUtilizationMicroseconds -
1644 remoteUtilizationMicroseconds), deltaT)};
1646 float fUtilizationFactorActual{
getRatio(totalOneHopUtilizationMicroseconds, deltaT)};
1650 float X1{RNDZeroToOne_()};
1652 float X2{RNDZeroToOne_()};
1654 float X3{RNDZeroToOne_()};
1660 float P1{}, P2{}, P3{}, P4{}, PP1{}, PP2{};
1663 if(fUtilizationFactorAdjusted > 1.0f)
1665 fUtilizationFactorAdjusted = 1.0f;
1669 if(fUtilizationFactorActual > 1.0f)
1671 fUtilizationFactorActual = 1.0f;
1675 if(fNumEstimatedOneHopNeighbors > 0.0f)
1677 P1 = fUtilizationFactorAdjusted * fUtilizationFactorAdjusted * A *(fNumEstimatedOneHopNeighbors / iCW);
1687 if(fNumEstimatedOneHopNeighbors > 0.0f)
1692 PP1 += utilizationRatioVector[u8Category].second * cwMinVector[u8Category] / macConfig_.
getCWMin(u8Category);
1696 "MACI %03hu %s::%s: idx %zu, PP1 %4.3f, LBWU %4.3f, CWMINR %3.2f, CWMIN %hhu",
1702 utilizationRatioVector[u8Category].second,
1703 cwMinVector[u8Category],
1707 P1 = fUtilizationFactorActual * fUtilizationFactorActual * PP1;
1718 if(fHiddenChannelActivity > 0.0f)
1720 fUtilizationFactorActual = 1.0f + log10f(fUtilizationFactorActual);
1722 float fBWDelta{fUtilizationFactorActual - (2.0f * fHiddenChannelActivity)};
1729 P3 = 1.0f - fUtilizationFactorActual + fBWDelta + C1;
1750 if(fNumEstimatedCommonNeighbors > 2.0f)
1752 if(iCW > fNumEstimatedCommonNeighbors)
1757 PP2 += utilizationRatioVector[u8Category].first * cwMinVector[u8Category] / macConfig_.
getCWMin(u8Category);
1761 "MACI %03hu %s::%s: idx %zu, PP2 %4.3f, TBWU %4.3f, CWMINR %3.2f, CWMIN %hhu",
1767 utilizationRatioVector[u8Category].first,
1768 cwMinVector[u8Category],
1772 P2 = fUtilizationFactorAdjusted * fUtilizationFactorAdjusted * (fNumEstimatedCommonNeighbors - 2) * PP2;
1788 DEBUG_LEVEL,
"MACI %03hu %s::%s: src %hu, nbrs [active %zd, est %5.3f, common %5.3f, hidden %5.3f]" 1789 " hidden activity %5.3f, utilization factor [actual %5.3f, adjusted %5.3f " 1790 "utilization [one hop %lf, local %lf, remote %lf] " 1791 "CW %d, X1 %5.3f, X2 %5.3f, X3 %5.3f, C1 %5.3f, P1 %5.3f, P2 %5.3f, P3 %5.3f P4 %5.3f, " 1792 "PP1 %5.3f, PP2 %5.3f, 0x%02X",
1793 id_, pzLayerName, __func__,
1796 fNumEstimatedOneHopNeighbors,
1797 fNumEstimatedCommonNeighbors,
1799 fHiddenChannelActivity,
1800 fUtilizationFactorActual,
1801 fUtilizationFactorAdjusted,
1802 std::chrono::duration_cast<
DoubleSeconds>(totalOneHopUtilizationMicroseconds).count(),
1803 std::chrono::duration_cast<
DoubleSeconds>(localUtilizationMicroseconds).count(),
1804 std::chrono::duration_cast<
DoubleSeconds>(remoteUtilizationMicroseconds).count(),
1805 iCW, X1, X2, X3, C1, P1, P2, P3, P4, PP1, PP2, collisionStatus);
1811 bool EMANE::Models::IEEE80211ABG::MACLayer::handleDownstreamQueueEntry(std::uint64_t u64SequenceNumber)
1813 if(u64SequenceNumber == u64SequenceNumber_)
1818 while(bHasPendingDownstreamQueueEntry_)
1823 if(!pTxState_->
process(
this,pendingDownstreamQueueEntry_))
1825 pTxState_->
update(
this,pendingDownstreamQueueEntry_);
1827 std::tie(pendingDownstreamQueueEntry_,bHasPendingDownstreamQueueEntry_) =
1835 if(bHasPendingDownstreamQueueEntry_)
1837 auto optionalWait = pTxState_->
getWaitTime(pendingDownstreamQueueEntry_);
1839 if(optionalWait.second && optionalWait.first > Clock::now())
1841 downstreamQueueTimedEventId_ =
1843 schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1845 u64SequenceNumber_),
1846 optionalWait.first);
1865 size_t historySize{16};
1868 Microseconds vaildIntervalMicroseconds{std::chrono::seconds{5}};
1870 auto dupIter = duplicateMap_.find(src);
1872 if(dupIter == duplicateMap_.end())
1876 v.reserve(historySize);
1880 duplicateMap_.insert(std::make_pair(src, v));
1888 size_t oldestIndex{};
1893 for(
size_t idx = 0; idx < dupIter->second.size(); ++idx)
1895 if(dupIter->second.at(idx).seq_ == seq)
1898 if((dupIter->second.at(idx).tp_ + vaildIntervalMicroseconds) >= timeNow)
1916 if(dupIter->second.at(idx).tp_ < oldestTime)
1919 oldestTime = dupIter->second.at(idx).tp_;
1927 if(dupIter->second.size() < historySize)
1935 dupIter->second.at(oldestIndex) =
SequenceEntry(seq, timeNow);
1950 auto status = flowControlManager_.
addToken();
1956 "MACI %03hu %s::%s: failed to add token (tokens:%hu)",
1984 "MACI %03hu %s::%s: failed to remove token (tokens:%hu)",
2003 EMANE::Models::IEEE80211ABG::MACLayer::checkPOR(
float fSINR,
size_t packetSize, std::uint16_t u16DataRateIndex)
2006 float fPCR{pcrManager_.
getPCR(fSINR, packetSize, u16DataRateIndex)};
2009 float fRandom{RNDZeroToOne_()};
2012 bool bResult{fPCR >= fRandom};
2016 "MACI %03hu %s::%s: sinr %3.2f, pcr %3.2f %s rand %3.3f",
2022 bResult ?
">=" :
"<",
2032 EMANE::Models::IEEE80211ABG::MACLayer::dscpToCategory(std::uint8_t dscp)
const 2035 std::uint8_t u8Category{};
2040 if(dscp >= 8 && dscp <= 23)
2044 else if(dscp >= 32 && dscp <= 47)
2048 else if(dscp >= 48 && dscp <= 63)
2056 "MACI %03hu %s::%s: wmm %s, dscp %hhu, category %hhu",
2072 return macStatistics_;
2089 entry.
u16Seq_ = u16EntrySequenceNumber_++;
bool configure(const ConfigurationUpdate &update)
void sendDownstreamUnicastData(DownstreamQueueEntry &entry)
void incrementUpstreamUnicastDataDiscardDueToSinr()
increment unicast data discard due to sinr
double MILLIWATT_TO_DB(double dMillWatt)
float getLocalNodeTx() const
std::uint8_t getQueueSize(std::uint8_t) const
get the queue size for a given queue index
size_t getTotalActiveOneHopNeighbors() const
std::string Serialization
const std::uint8_t MSG_TYPE_UNICAST_CTS_CTRL
A Packet class that allows upstream processing to strip layer headers as the packet travels up the st...
const PacketInfo & getPacketInfo() const
void updateNeighborStatus()
void processConfiguration(const ConfigurationUpdate &update) override
void incrementUpstreamBroadcastDataDiscardDueToSinr()
increment braodcast data discard due to sinr
The Registrar interface provides access to all of the emulator registrars.
A Serialized Control Message is used to encapsulate Serializable control messages as they traverse pr...
std::uint16_t getRtsThreshold() const
float getAverageRxPowerPerMessageMilliWatts() const
EMANE::DownstreamPacket pkt_
std::uint32_t getBroadcastDataRateKbps() const
get the broadcast datarate
void handleOneHopNeighborsEvent(const Serialization &serialization)
Microseconds getNeighborTimeoutMicroseconds() const
virtual ConfigurationRegistrar & configurationRegistrar()=0
void updateNeighborRxMetric(NEMId src, std::uint64_t u64SeqNum, const uuid_t &uuid, const TimePoint &rxTime)
void sendDownstreamBroadcastData(DownstreamQueueEntry &)
class used to define timing parameters
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
Controls::R2RIQueueMetrics getQueueMetrics()
Controls::R2RINeighborMetrics getNeighborMetrics()
std::uint8_t getNumAccessCategories() const
get the number of access categories (queues)
ModeTimingParameters & getModeTiming()
virtual StatisticRegistrar & statisticRegistrar()=0
Recieve Properties Control Message is sent from the emulator physical layer with every upstream packe...
Holds the frequency, offset and duration of a frequency segment.
void setNeighborTimeoutMicroseconds(const Microseconds &timeOutMicroseconds)
void postStart() override
std::list< const ControlMessage * > ControlMessages
int getContentionWindow(std::uint8_t, std::uint8_t) const
get the contention window
std::pair< std::uint16_t, bool > addToken(std::uint16_t u16Tokens=1)
void incrementUpstreamUnicastDataDiscardDueToClobberRxDuringTx()
increment unicast data discard due to collision rx during tx
std::uint8_t getBroadcastDataRateIndex() const
get the broadcast datarate index
float getNumberOfEstimatedTwoHopNeighbors() const
static TimeStampControlMessage * create(const TimePoint ×tamp)
std::vector< UtilizationRatioPair > UtilizationRatioVector
Microseconds getAllUtilizationMicroseconds(NEMId src) const
void setDelayTime(IEEE80211ABG::DownstreamQueueEntry &entry)
std::vector< SequenceEntry > SequenceVector
void incrementUpstreamBroadcastNoiseHiddenRx()
increment braodcastcast data collision due to hidden rx
NEMId getDestination() const
structure defines the mac downstream packet queue entry
Microseconds getTxOpMicroseconds(std::uint8_t) const
get the txop for a given queue index
std::uint16_t stripLengthPrefixFraming()
constexpr NEMId NEM_BROADCAST_MAC_ADDRESS
Common NEM layer statistics and drop reason tables.
const std::uint8_t MAX_ACCESS_CATEGORIES
float getHiddenChannelActivity(NEMId src) const
size_t strip(size_t size)
SpectrumServiceException is thrown when an exception occurs during spectrum service processing...
void prepend(const void *buf, size_t size)
void sendDownstreamUnicastCts(DownstreamQueueEntry &entry, NEMId origin)
void start(std::uint16_t u16TotalTokensAvailable)
size_t getDepth()
get the number of entries for all active queues
RadioServiceProvider * pRadioService_
virtual EventRegistrar & eventRegistrar()=0
static FlowControlControlMessage * create(const Serialization &serialization)
void updateNeighborTxMetric(NEMId dst, std::uint64_t u64DataRatebps, const TimePoint &txTime)
Store source, destination, creation time and priority information for a packet.
static FrequencyControlMessage * create(std::uint64_t u64BandwidthHz, const FrequencySegments &frequencySegments)
void processUpstreamControl(const ControlMessages &msgs) override
std::pair< DownstreamQueueEntry, bool > dequeue()
blocking dequeue, returns highest priority item first
float getNumberOfEstimatedCommonNeighbors(NEMId src) const
DECLARE_MAC_LAYER(EMANE::Models::IEEE80211ABG::MACLayer)
base class used to define the transitions for the mac tx states
void setMaxEntrySize(size_t)
set the max entry size for all queues
void updateCtrlChannelActivity(NEMId src, NEMId origin, std::uint8_t type, float fRxPowerMilliWatts, const TimePoint &tvTime, const Microseconds &duration, std::uint8_t u8Category)
const char * what() const
std::uint16_t getCWMin(std::uint8_t) const
get the min contention window size for a given queue index
The Frequency Control Message is sent to the emulator physical layer to specify the frequency segment...
std::pair< std::string, bool > configurationValidator(const ConfigurationUpdate &updates) noexcept
std::uint64_t u64DataRatebps_
Microseconds getOverheadMicroseconds(std::uint8_t u8Category) const
get the overhead time
void processFlowControlMessage(const Controls::FlowControlControlMessage *pMsg)
#define LOGGER_VERBOSE_LOGGING_FN_VARGS(logger, level, fn, fmt, args...)
std::vector< std::string > StatisticTableLabels
const PacketInfo & getPacketInfo() const
void incrementUpstreamBroadcastNoiseRxCommon()
increment unicastcast data collision due to rx common
Specialized packet the allows downstream processing to add layer specific headers as the packet trave...
virtual const char * statename()=0
void processDownstreamPacket(DownstreamPacket &pkt, const ControlMessages &msgs) override
Microseconds durationMicroseconds_
void load(const std::string &uri)
Microseconds getChannelActivityIntervalMicroseconds() const
virtual bool process(MACLayer *, DownstreamQueueEntry &)=0
#define EMANE_EVENT_IEEE80211ABG_ONEHOP_NEIGHBORS
const std::uint8_t MSG_TYPE_BROADCAST_DATA
float getRandomRxPowerCommonNodesMilliWatts(NEMId src)
void setCategories(std::uint8_t u8NumCategories)
COLLISION_TYPE checkForRxCollision(NEMId src, std::uint8_t u8Category, std::uint8_t retries)
std::uint32_t getUnicastDataRateKbps() const
get the unicast datarate
std::uint16_t getFlowControlTokens() const
get the number of flow control tokens
std::chrono::microseconds Microseconds
virtual void update(MACLayer *, DownstreamQueueEntry &)
class used to define the mac layer statistic items
void incrementUpstreamUnicastNoiseRxCommon()
increment braodcastcast data collision due to rx common
std::chrono::duration< double > DoubleSeconds
std::string getPcrUri() const
get the pcr uri
Microseconds getTotalOneHopUtilizationMicroseconds() const
bool processConfiguration(const ConfigurationUpdate &update)
static R2RISelfMetricControlMessage * create(const Serialization &serialization)
float getRatio(const EMANE::Microseconds &d1, const EMANE::Microseconds d2)
float getNumberOfEstimatedHiddenNeighbors(NEMId src) const
Flow Control Control Messages are sent between a MAC layer and a transport in order to communicate da...
void updateQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize, std::uint32_t u32QueueDepth, std::uint32_t u32NumDiscards, const Microseconds &queueDelay)
The RadioServiceProvider interface provides access to radio (RF) model specific services.
std::pair< double, bool > maxBinNoiseFloor(const SpectrumWindow &window, double dRxPowerdBm, const TimePoint &startTime=TimePoint::min())
Microseconds getNeighborMetricDeleteTimeMicroseconds() const
void sendDownstreamPacket(const CommonMACHeader &hdr, DownstreamPacket &pkt, const ControlMessages &msgs=DownstreamTransport::empty)
void incrementUpstreamUnicastDataDiscardDueToClobberRxHiddenBusy()
increment unicast data discard due to collision rx busy hidden
const std::uint8_t MSG_TYPE_UNICAST_DATA
TimerEventId schedule(Function fn, const TimePoint &timePoint, const Duration &interval=Duration::zero())
void sendUpstreamControl(const ControlMessages &msgs)
std::uint8_t getRetryLimit(std::uint8_t) const
get the retry limit for a given queue index
void registerStatistics(StatisticRegistrar &statisticRegistrar)
bool getPromiscuosEnable() const
get the promiscuous mode
void setNeighborDeleteTimeMicroseconds(const Microseconds &ageMicroseconds)
Priority getPriority() const
void initialize(Registrar ®istrar) override
structure used to define parameters to detect duplicate frames
float getNumberOfEstimatedOneHopNeighbors() const
void incrementUpstreamUnicastNoiseHiddenRx()
increment unicastcast data collision due to hidden rx
Microseconds getTotalTwoHopUtilizationMicroseconds() const
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
static R2RINeighborMetricControlMessage * create(const Serialization &serialization)
void registerConfiguration(ConfigurationRegistrar &configRegistrar)
bool getRadioMetricEnable() const
virtual std::pair< TimePoint, bool > getWaitTime(DownstreamQueueEntry &)=0
Microseconds getSlotSizeMicroseconds() const
get the slot duration for a given mode and distance
void sendDownstreamMessage(DownstreamQueueEntry &entry, MACHeaderParams &macHeaderParams)
double DB_TO_MILLIWATT(double ddB)
float getRandomRxPowerHiddenNodesMilliWatts(NEMId src)
Microseconds getRadioMetricReportIntervalMicroseconds() const
std::uint8_t getUnicastDataRateIndex() const
get the unicast datarate index
MACLayer(NEMId id, PlatformServiceProvider *pPlatformServiceProvider, RadioServiceProvider *pRadioServiceProvider)
void processEvent(const EventId &, const Serialization &)
bool getWmmEnable() const
get the wmm mode
std::pair< std::uint16_t, bool > removeToken()
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void incrementUpstreamBroadcastDataDiscardDueToClobberRxHiddenBusy()
increment braodcast data discard due to collision rx busy hidden
virtual void registerEvent(EventId eventId)=0
std::vector< DownstreamQueueEntry > enqueue(DownstreamQueueEntry &entry)
enqueue, inserts items by priority, signals on success.
bool isDuplicate(NEMId src, std::uint16_t seq)
Microseconds getAverageMessageDurationMicroseconds() const
std::uint32_t getMaxDataRateKbps() const
std::vector< float > CWRatioVector
Clock::time_point TimePoint
TimePoint preTxDelayTime_
virtual bool cancelTimedEvent(TimerEventId eventId)=0
void incrementUpstreamUnicastCtsRxFromPhy()
increment unicast cts recv from phy
void updateDataChannelActivity(NEMId src, std::uint8_t type, float fRxPowerMilliWatts, const TimePoint &timePoint, const Microseconds &duration, std::uint8_t u8Category)
void sendUpstreamPacket(UpstreamPacket &pkt, const ControlMessages &msgs=empty)
Microseconds postTxDelayMicroseconds_
void setMaxCapacity(size_t)
set the max number of entries for all queues
void processUpstreamPacket(const CommonMACHeader &hdr, UpstreamPacket &pkt, const ControlMessages &msgs) override
void prependLengthPrefixFraming(std::uint16_t u16Length)
MACStatistics & getStatistics()
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
void processDownstreamControl(const ControlMessages &msgs) override
static IdleTxState * instance()
size_t getMaxCapacity()
get the max number of entries for all queues
Microseconds getDeferIntervalMicroseconds(std::uint8_t) const
get the defer time
virtual SpectrumServiceProvider & spectrumService()=0
virtual SpectrumWindow request(std::uint64_t u64FrequencyHz, const Microseconds &duration=Microseconds::zero(), const TimePoint &startTime=TimePoint::min()) const =0
void setCategories(std::uint8_t u8Category)
set the number of categories (queues)
float getPCR(float fSinr, size_t size, std::uint16_t DataRateIndex)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void incrementUpstreamBroadcastDataDiscardDueToClobberRxDuringTx()
increment braodcast data discard due to collision rx during tx
std::uint16_t getQueueEntrySize(std::uint8_t) const
get the queue entry size for a given queue index
CWRatioVector getCWMinRatioVector(std::uint8_t) const
static R2RIQueueMetricControlMessage * create(const Serialization &serialization)
bool getFlowControlEnable() const
get the flow control enable status
size_t getNumOverFlow(bool bClear)
bool addQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize)
float getAverageRxPowerPerMessageHiddenNodesMilliWatts() const
const std::uint8_t MSG_TYPE_UNICAST_RTS_CTS_DATA
void configure(const ConfigurationUpdate &update) override
void incrementUpstreamUnicastRtsCtsDataRxFromPhy()
increment unicast rts/ctsdata recv from phy
IEEE 80211 ABG MAC implementation.
Interface used to create a MAC layer plugin implementation.
WMMManager::UtilizationRatioVector getUtilizationRatios()