wifi: Add a WifiChannelConfig struct to replace ChannelTuple

This commit is contained in:
Stefano Avallone
2025-06-17 15:54:43 +02:00
parent c18e8e3c83
commit f68a641f51
6 changed files with 189 additions and 45 deletions

View File

@@ -189,7 +189,7 @@ MeshWifiInterfaceMac::SwitchFrequencyChannel(uint16_t new_id)
* Now we use dirty channel switch -- just change frequency
*/
GetWifiPhy()->SetOperatingChannel(
WifiPhy::ChannelTuple{new_id, 0, GetWifiPhy()->GetPhyBand(), 0});
WifiPhy::ChannelTuple{static_cast<uint8_t>(new_id), 0, GetWifiPhy()->GetPhyBand(), 0});
// Don't know NAV on new channel
GetLink(SINGLE_LINK_OP_ID).channelAccessManager->NotifyNavResetNow(Seconds(0));
}

View File

@@ -172,6 +172,7 @@ set(source_files
model/wifi-tx-parameters.cc
model/wifi-tx-timer.cc
model/wifi-tx-vector.cc
model/wifi-types.cc
model/wifi-utils.cc
model/yans-error-rate-model.cc
model/yans-wifi-channel.cc

View File

@@ -1012,7 +1012,7 @@ WifiPhy::ConfigureStandard(WifiStandard standard)
if (!m_operatingChannel.IsSet())
{
NS_LOG_DEBUG("Setting the operating channel first");
SetOperatingChannel(m_channelSettings);
SetOperatingChannel(m_channelCfg);
// return because we are called back by SetOperatingChannel
return;
}
@@ -1124,36 +1124,39 @@ void
WifiPhy::SetOperatingChannel(const WifiPhyOperatingChannel& channel)
{
NS_LOG_FUNCTION(this << channel);
ChannelSegments segments{};
WifiChannelConfig cfg;
for (std::size_t segmentId = 0; segmentId < channel.GetNSegments(); ++segmentId)
{
segments.emplace_back(channel.GetNumber(segmentId),
channel.GetWidth(segmentId),
channel.GetPhyBand(),
channel.GetPrimaryChannelIndex(MHz_u{20}));
cfg.segments.emplace_back(channel.GetNumber(segmentId),
channel.GetWidth(segmentId),
channel.GetPhyBand(),
channel.GetPrimaryChannelIndex(MHz_u{20}));
}
SetOperatingChannel(segments);
}
void
WifiPhy::SetOperatingChannel(const ChannelTuple& tuple)
{
SetOperatingChannel(ChannelSegments{tuple});
SetOperatingChannel(cfg);
}
void
WifiPhy::SetOperatingChannel(const ChannelSegments& channelSegments)
{
NS_LOG_FUNCTION(this << +std::get<0>(channelSegments.front())
<< std::get<1>(channelSegments.front())
<< static_cast<WifiPhyBand>(std::get<2>(channelSegments.front()))
<< +std::get<3>(channelSegments.front()));
SetOperatingChannel(WifiChannelConfig(channelSegments));
}
m_channelSettings = channelSegments;
void
WifiPhy::SetOperatingChannel(const WifiChannelConfig& channelCfg)
{
NS_LOG_FUNCTION(this << +channelCfg.front().number << channelCfg.front().width
<< channelCfg.front().band << +channelCfg.front().p20Index);
if (IsInitialized() && m_operatingChannel.IsSet() && (m_channelCfg == channelCfg))
{
NS_LOG_DEBUG("Already operating on requested channel");
return;
}
if (m_standard == WIFI_STANDARD_UNSPECIFIED)
{
NS_LOG_DEBUG("Channel information will be applied when a standard is configured");
m_channelCfg = channelCfg;
return;
}
@@ -1168,12 +1171,13 @@ WifiPhy::SetOperatingChannel(const ChannelSegments& channelSegments)
if (delay.value().IsStrictlyPositive())
{
// switching channel has been postponed
void (WifiPhy::*fp)(const ChannelSegments&) = &WifiPhy::SetOperatingChannel;
Simulator::Schedule(delay.value(), fp, this, channelSegments);
Simulator::Schedule(delay.value(), [=, this] { SetOperatingChannel(channelCfg); });
return;
}
}
m_channelCfg = channelCfg;
// channel can be switched now.
DoChannelSwitch();
}
@@ -1229,7 +1233,7 @@ WifiPhy::DoChannelSwitch()
// Update unspecified parameters with default values
std::optional<uint8_t> prevChannelNumber{};
for (auto& [number, width, band, primary20] : m_channelSettings)
for (auto& [number, width, band, primary20] : m_channelCfg.segments)
{
if (band == WIFI_PHY_BAND_UNSPECIFIED)
{
@@ -1253,27 +1257,23 @@ WifiPhy::DoChannelSwitch()
// We need to call SetStandard if this is the first time we set a channel or we
// are changing PHY band. Checking if the new PHY band is different than the
// previous one covers both cases because initially the PHY band is unspecified
bool changingPhyBand =
(static_cast<WifiPhyBand>(std::get<2>(m_channelSettings.front())) != m_band);
const auto changingPhyBand = (m_channelCfg.front().band != m_band);
NS_ABORT_MSG_IF(IsInitialized() && m_fixedPhyBand && changingPhyBand,
"Trying to change PHY band while prohibited.");
m_band = static_cast<WifiPhyBand>(std::get<2>(m_channelSettings.front()));
m_band = m_channelCfg.front().band;
NS_LOG_DEBUG("switching channel");
std::vector<FrequencyChannelInfo> segments{};
std::transform(m_channelSettings.cbegin(),
m_channelSettings.cend(),
std::transform(m_channelCfg.segments.cbegin(),
m_channelCfg.segments.cend(),
std::back_inserter(segments),
[this](const auto& channelTuple) {
return FrequencyChannelInfo{std::get<0>(channelTuple),
MHz_u{0},
std::get<1>(channelTuple),
m_band};
[this](const auto& segment) {
return FrequencyChannelInfo{segment.number, MHz_u{0}, segment.width, m_band};
});
m_operatingChannel.Set(segments, m_standard);
m_operatingChannel.SetPrimary20Index(std::get<3>(m_channelSettings.front()));
m_operatingChannel.SetPrimary20Index(m_channelCfg.front().p20Index);
// check that the channel width is supported
if (const auto chWidth = GetChannelWidth();

View File

@@ -941,14 +941,11 @@ class WIFI_EXPORT WifiPhy : public Object
*/
Ptr<MobilityModel> GetMobility() const;
using ChannelTuple = std::tuple<uint8_t /* channel number */,
MHz_u /* channel width */,
WifiPhyBand /* WifiPhyBand */,
uint8_t /* primary20 index*/>; //!< Tuple identifying a segment
//!< of an operating channel
/// kept for backward compatibility, can be deprecated when using strong types
using ChannelTuple = WifiChannelConfig::SegmentWithoutUnits;
using ChannelSegments =
std::vector<ChannelTuple>; //!< segments identifying an operating channel
/// segments identifying an operating channel
using ChannelSegments = std::list<WifiChannelConfig::TupleWithoutUnits>;
/**
* If the standard for this object has not been set yet, store the channel settings
@@ -974,12 +971,12 @@ class WIFI_EXPORT WifiPhy : public Object
void SetOperatingChannel(const ChannelSegments& channelSegments);
/**
* This overloaded function is used when the operating channel
* consists of a single segment, identified by a tuple.
* This overloaded function is used to pass a WifiChannelConfig object from which
* the operating channel can be deduced.
*
* @param tuple the segment identifying the operating channel
* @param channelCfg the channel config object
*/
void SetOperatingChannel(const ChannelTuple& tuple);
void SetOperatingChannel(const WifiChannelConfig& channelCfg);
/**
* Configure whether it is prohibited to change PHY band after initialization.
@@ -1613,7 +1610,7 @@ class WIFI_EXPORT WifiPhy : public Object
WifiStandard m_standard; //!< WifiStandard
WifiModulationClass m_maxModClassSupported; //!< max modulation class supported
WifiPhyBand m_band; //!< WifiPhyBand
ChannelSegments m_channelSettings; //!< Store operating channel settings until initialization
WifiChannelConfig m_channelCfg; //!< Store operating channel config until initialization
WifiPhyOperatingChannel m_operatingChannel; //!< Operating channel
bool m_fixedPhyBand; //!< True to prohibit changing PHY band after initialization

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Universita' degli Studi di Napoli Federico II
*
* SPDX-License-Identifier: GPL-2.0-only
*
* Author: Stefano Avallone <stavallo@unina.it>
*/
#include "wifi-types.h"
namespace ns3
{
WifiChannelConfig::WifiChannelConfig(const std::list<TupleWithoutUnits>& tuples)
{
std::for_each(tuples.cbegin(), tuples.cend(), [this](auto&& t) {
segments.emplace_back(std::make_from_tuple<SegmentWithoutUnits>(t));
});
}
} // namespace ns3

View File

@@ -9,13 +9,17 @@
#ifndef WIFI_TYPES_H
#define WIFI_TYPES_H
#include "wifi-phy-band.h"
#include "wifi-units.h"
#include "ns3/fatal-error.h"
#include <compare>
#include <list>
#include <map>
#include <ostream>
#include <tuple>
#include <vector>
namespace ns3
{
@@ -92,6 +96,127 @@ enum class FrequencyChannelType : uint8_t
CH_80211P
};
/**
* Struct defining the configuration of a wifi channel, which can be made of one or multiple
* channel segments.
*/
struct WifiChannelConfig
{
/// a channel segment, as a struct without units for channel width (to be deprecated when using
/// strong types)
struct SegmentWithoutUnits
{
uint8_t number{}; ///< channel number
double width{}; ///< channel width in MHz
WifiPhyBand band{WIFI_PHY_BAND_UNSPECIFIED}; ///< PHY band
uint8_t p20Index{}; ///< primary20 index
};
/// a channel segment, as a struct with units for channel width
struct Segment
{
uint8_t number{}; ///< channel number
MHz_u width{}; ///< channel width
WifiPhyBand band{WIFI_PHY_BAND_UNSPECIFIED}; ///< PHY band
uint8_t p20Index{}; ///< primary20 index
/**
* Constructor.
*
* @param n the channel number
* @param w the channel width
* @param b the PHY band
* @param i the primary20 index
*/
Segment(uint8_t n, MHz_u w, WifiPhyBand b, uint8_t i)
: number(n),
width(w),
band(b),
p20Index(i)
{
}
/**
* Converting constructor (to be deprecated when using strong types)
*
* @param s a channel segment as a struct without units for channel width
*/
Segment(const SegmentWithoutUnits& s)
: number(s.number),
width(MHz_u{s.width}),
band(s.band),
p20Index(s.p20Index)
{
}
/**
* Three-way comparison operator
*
* @param rhs right hand side
* @return deduced comparison type
*/
auto operator<=>(const Segment& rhs) const = default;
};
std::vector<Segment> segments; ///< channel config
WifiChannelConfig() = default;
/**
* Construct a channel config from a channel segment
*
* @param segment the channel segment
*/
WifiChannelConfig(const Segment& segment)
: segments(std::vector<Segment>{segment})
{
}
/**
* Construct a channel config from a segment without units for channel width
*
* @param s the segment without units for channel width
*/
WifiChannelConfig(const SegmentWithoutUnits& s)
: WifiChannelConfig(Segment(s))
{
}
/// a channel segment, as a tuple without units for channel width (to be deprecated when using
/// strong types)
using TupleWithoutUnits = std::tuple<uint64_t /* channel number */,
uint64_t /* channel width in MHz */,
WifiPhyBand /* PHY band */,
uint64_t /* primary20 index*/>;
/**
* Construct a channel config from a list of tuples without units for channel width
*
* @param tuples the list of tuples without units for channel width
*/
WifiChannelConfig(const std::list<TupleWithoutUnits>& tuples);
/// @return a const reference to the first channel segment
const Segment& front() const
{
return segments.front();
}
/// @return a reference to the first channel segment
Segment& front()
{
return segments.front();
}
/**
* Three-way comparison operator
*
* @param rhs right hand side
* @return deduced comparison type
*/
auto operator<=>(const WifiChannelConfig& rhs) const = default;
};
/**
* The different Resource Unit (RU) types.
*/