From f68a641f51344344fbff5e875d36788655e9ae72 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Tue, 17 Jun 2025 15:54:43 +0200 Subject: [PATCH] wifi: Add a WifiChannelConfig struct to replace ChannelTuple --- src/mesh/model/mesh-wifi-interface-mac.cc | 2 +- src/wifi/CMakeLists.txt | 1 + src/wifi/model/wifi-phy.cc | 64 +++++------ src/wifi/model/wifi-phy.h | 21 ++-- src/wifi/model/wifi-types.cc | 21 ++++ src/wifi/model/wifi-types.h | 125 ++++++++++++++++++++++ 6 files changed, 189 insertions(+), 45 deletions(-) create mode 100644 src/wifi/model/wifi-types.cc diff --git a/src/mesh/model/mesh-wifi-interface-mac.cc b/src/mesh/model/mesh-wifi-interface-mac.cc index 24a0b5834..df8550361 100644 --- a/src/mesh/model/mesh-wifi-interface-mac.cc +++ b/src/mesh/model/mesh-wifi-interface-mac.cc @@ -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(new_id), 0, GetWifiPhy()->GetPhyBand(), 0}); // Don't know NAV on new channel GetLink(SINGLE_LINK_OP_ID).channelAccessManager->NotifyNavResetNow(Seconds(0)); } diff --git a/src/wifi/CMakeLists.txt b/src/wifi/CMakeLists.txt index b7702f1b1..a5f0fa250 100644 --- a/src/wifi/CMakeLists.txt +++ b/src/wifi/CMakeLists.txt @@ -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 diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index 3a201e71e..a34558fbf 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -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(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 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(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(std::get<2>(m_channelSettings.front())); + m_band = m_channelCfg.front().band; NS_LOG_DEBUG("switching channel"); std::vector 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(); diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index b20426542..66e6e51c7 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -941,14 +941,11 @@ class WIFI_EXPORT WifiPhy : public Object */ Ptr GetMobility() const; - using ChannelTuple = std::tuple; //!< 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; //!< segments identifying an operating channel + /// segments identifying an operating channel + using ChannelSegments = std::list; /** * 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 diff --git a/src/wifi/model/wifi-types.cc b/src/wifi/model/wifi-types.cc new file mode 100644 index 000000000..fb0fa47df --- /dev/null +++ b/src/wifi/model/wifi-types.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Universita' degli Studi di Napoli Federico II + * + * SPDX-License-Identifier: GPL-2.0-only + * + * Author: Stefano Avallone + */ + +#include "wifi-types.h" + +namespace ns3 +{ + +WifiChannelConfig::WifiChannelConfig(const std::list& tuples) +{ + std::for_each(tuples.cbegin(), tuples.cend(), [this](auto&& t) { + segments.emplace_back(std::make_from_tuple(t)); + }); +} + +} // namespace ns3 diff --git a/src/wifi/model/wifi-types.h b/src/wifi/model/wifi-types.h index 91df11873..f41e78195 100644 --- a/src/wifi/model/wifi-types.h +++ b/src/wifi/model/wifi-types.h @@ -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 +#include #include #include +#include +#include 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 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}) + { + } + + /** + * 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; + + /** + * 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& 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. */