diff --git a/examples/wireless/wifi-backward-compatibility.cc b/examples/wireless/wifi-backward-compatibility.cc index e90e55cea..4668af903 100644 --- a/examples/wireless/wifi-backward-compatibility.cc +++ b/examples/wireless/wifi-backward-compatibility.cc @@ -17,6 +17,7 @@ * Author: Sebastien Deronne */ +#include "ns3/attribute-container.h" #include "ns3/boolean.h" #include "ns3/command-line.h" #include "ns3/config.h" @@ -150,7 +151,10 @@ main(int argc, char* argv[]) WifiMacHelper mac; WifiHelper wifi; Ssid ssid = Ssid("ns3"); - TupleValue, UintegerValue> channelValue; + AttributeContainerValue< + TupleValue, UintegerValue>, + ';'> + channelValue; const auto& [staStandard, staBand] = ConvertStringToStandardAndBand(staVersion); wifi.SetStandard(staStandard); @@ -160,7 +164,7 @@ main(int argc, char* argv[]) // Workaround needed as long as we do not fully support channel bonding uint16_t width = (staVersion == "80211ac" ? 20 : 0); - channelValue.Set(WifiPhy::ChannelTuple{0, width, staBand, 0}); + channelValue.Set(WifiPhy::ChannelSegments{{0, width, staBand, 0}}); phy.Set("ChannelSettings", channelValue); NetDeviceContainer staDevice; @@ -174,7 +178,7 @@ main(int argc, char* argv[]) // Workaround needed as long as we do not fully support channel bonding width = (apVersion == "80211ac" ? 20 : 0); - channelValue.Set(WifiPhy::ChannelTuple{0, width, apBand, 0}); + channelValue.Set(WifiPhy::ChannelSegments{{0, width, apBand, 0}}); phy.Set("ChannelSettings", channelValue); NetDeviceContainer apDevice; diff --git a/examples/wireless/wifi-ht-network.cc b/examples/wireless/wifi-ht-network.cc index 153bafbca..aaf27ae23 100644 --- a/examples/wireless/wifi-ht-network.cc +++ b/examples/wireless/wifi-ht-network.cc @@ -18,6 +18,7 @@ * Sebastien Deronne */ +#include "ns3/attribute-container.h" #include "ns3/boolean.h" #include "ns3/command-line.h" #include "ns3/config.h" @@ -176,10 +177,12 @@ main(int argc, char* argv[]) wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(sgi)); Ssid ssid = Ssid("ns3-80211n"); - TupleValue, UintegerValue> + AttributeContainerValue< + TupleValue, UintegerValue>, + ';'> channelValue; WifiPhyBand band = (frequency == 5.0 ? WIFI_PHY_BAND_5GHZ : WIFI_PHY_BAND_2_4GHZ); - channelValue.Set(WifiPhy::ChannelTuple{0, channelWidth, band, 0}); + channelValue.Set(WifiPhy::ChannelSegments{{0, channelWidth, band, 0}}); mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid)); phy.Set("ChannelSettings", channelValue); diff --git a/src/wifi/examples/wifi-manager-example.cc b/src/wifi/examples/wifi-manager-example.cc index d005c0be8..11b5db1aa 100644 --- a/src/wifi/examples/wifi-manager-example.cc +++ b/src/wifi/examples/wifi-manager-example.cc @@ -46,6 +46,7 @@ // --broadcast instead of unicast (default is unicast) // --rtsThreshold (by default, value of 99999 disables it) +#include "ns3/attribute-container.h" #include "ns3/boolean.h" #include "ns3/command-line.h" #include "ns3/config.h" @@ -639,41 +640,38 @@ main(int argc, char* argv[]) NetDeviceContainer serverDevice; NetDeviceContainer clientDevice; - TupleValue, UintegerValue> channelValue; + AttributeContainerValue< + TupleValue, UintegerValue>, + ';'> + channelValue; WifiMacHelper wifiMac; if (infrastructure) { Ssid ssid = Ssid("ns-3-ssid"); wifiMac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid)); - channelValue.Set(WifiPhy::ChannelTuple{0, - serverSelectedStandard.m_width, - serverSelectedStandard.m_band, - 0}); + channelValue.Set(WifiPhy::ChannelSegments{ + {0, serverSelectedStandard.m_width, serverSelectedStandard.m_band, 0}}); wifiPhy.Set("ChannelSettings", channelValue); serverDevice = wifi.Install(wifiPhy, wifiMac, serverNode); wifiMac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid)); - channelValue.Set(WifiPhy::ChannelTuple{0, - clientSelectedStandard.m_width, - clientSelectedStandard.m_band, - 0}); + channelValue.Set(WifiPhy::ChannelSegments{ + {0, clientSelectedStandard.m_width, clientSelectedStandard.m_band, 0}}); + wifiPhy.Set("ChannelSettings", channelValue); clientDevice = wifi.Install(wifiPhy, wifiMac, clientNode); } else { wifiMac.SetType("ns3::AdhocWifiMac"); - channelValue.Set(WifiPhy::ChannelTuple{0, - serverSelectedStandard.m_width, - serverSelectedStandard.m_band, - 0}); + channelValue.Set(WifiPhy::ChannelSegments{ + {0, serverSelectedStandard.m_width, serverSelectedStandard.m_band, 0}}); wifiPhy.Set("ChannelSettings", channelValue); serverDevice = wifi.Install(wifiPhy, wifiMac, serverNode); - channelValue.Set(WifiPhy::ChannelTuple{0, - clientSelectedStandard.m_width, - clientSelectedStandard.m_band, - 0}); + channelValue.Set(WifiPhy::ChannelSegments{ + {0, clientSelectedStandard.m_width, clientSelectedStandard.m_band, 0}}); + wifiPhy.Set("ChannelSettings", channelValue); clientDevice = wifi.Install(wifiPhy, wifiMac, clientNode); } diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index a0e531ffd..edaa75411 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -30,6 +30,7 @@ #include "wifi-radio-energy-model.h" #include "wifi-utils.h" +#include "ns3/attribute-container.h" #include "ns3/channel.h" #include "ns3/dsss-phy.h" #include "ns3/eht-phy.h" //also includes OFDM, HT, VHT and HE @@ -80,9 +81,11 @@ WifiPhy::GetTypeId() MakePointerChecker()) .AddAttribute( "ChannelSettings", - "Tuple {channel number, channel width (MHz), PHY band, primary20 index} " - "describing the settings of the operating channel. The primary20 index is " - "the index of the primary 20 MHz channel within the operating channel " + "A vector of tuple {channel number, channel width (MHz), PHY band, primary20 " + "index} " + "describing the settings of the operating channel for each segment. " + "The primary20 index (only the value set for the first segment is used) " + "is the index of the primary 20 MHz channel within the operating channel " "(0 indicates the 20 MHz subchannel with the lowest center frequency) and " "is only valid if the width of the operating channel is a multiple of 20 MHz. " "If the standard for this object has not been set yet, the value of this " @@ -91,19 +94,19 @@ WifiPhy::GetTypeId() "band for the configured standard is used. If the channel width and the " "channel number are both 0, the default channel width for the configured " "standard and band are used. If the channel number is 0, the default " - "channel number for the configured standard, band and channel width is used." + "channel number for the configured standard, band and channel width is used. " "Note that the channel width can be left unspecified (0) if the channel " "number uniquely identify a frequency channel for the given standard and band.", StringValue("{0, 0, BAND_UNSPECIFIED, 0}"), - MakeTupleAccessor, - UintegerValue>((void(WifiPhy::*)(const ChannelTuple&)) & - WifiPhy::SetOperatingChannel), - MakeTupleChecker, - UintegerValue>( + MakeAttributeContainerAccessor< + TupleValue, UintegerValue>, + ';'>((void(WifiPhy::*)(const ChannelSegments&)) & WifiPhy::SetOperatingChannel), + MakeAttributeContainerChecker< + TupleValue, UintegerValue>, + ';'>(MakeTupleChecker, + UintegerValue>( MakeUintegerChecker(0, 233), MakeUintegerChecker(0, 160), MakeEnumChecker(WifiPhyBand::WIFI_PHY_BAND_2_4GHZ, @@ -114,7 +117,7 @@ WifiPhy::GetTypeId() "BAND_6GHZ", WifiPhyBand::WIFI_PHY_BAND_UNSPECIFIED, "BAND_UNSPECIFIED"), - MakeUintegerChecker(0, 7))) + MakeUintegerChecker(0, 7)))) .AddAttribute("Frequency", "The center frequency (MHz) of the current operating channel.", TypeId::ATTR_GET, @@ -1128,14 +1131,22 @@ WifiPhy::SetOperatingChannel(const WifiPhyOperatingChannel& channel) } void -WifiPhy::SetOperatingChannel(const ChannelTuple& channelTuple) +WifiPhy::SetOperatingChannel(const ChannelTuple& tuple) { - // the generic operator<< for tuples does not give a pretty result - NS_LOG_FUNCTION(this << +std::get<0>(channelTuple) << std::get<1>(channelTuple) - << static_cast(std::get<2>(channelTuple)) - << +std::get<3>(channelTuple)); + SetOperatingChannel(ChannelSegments{tuple}); +} - m_channelSettings = channelTuple; +void +WifiPhy::SetOperatingChannel(const ChannelSegments& channelSegments) +{ + NS_ASSERT_MSG(channelSegments.size() == 1, + "Non-contiguous operating channel is not supported yet"); + 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())); + + m_channelSettings = channelSegments; if (m_standard == WIFI_STANDARD_UNSPECIFIED) { @@ -1154,8 +1165,8 @@ WifiPhy::SetOperatingChannel(const ChannelTuple& channelTuple) if (delay.value().IsStrictlyPositive()) { // switching channel has been postponed - void (WifiPhy::*fp)(const ChannelTuple&) = &WifiPhy::SetOperatingChannel; - Simulator::Schedule(delay.value(), fp, this, channelTuple); + void (WifiPhy::*fp)(const ChannelSegments&) = &WifiPhy::SetOperatingChannel; + Simulator::Schedule(delay.value(), fp, this, channelSegments); return; } } @@ -1213,7 +1224,7 @@ WifiPhy::DoChannelSwitch() // Update unspecified parameters with default values { - auto& [number, width, band, primary20] = m_channelSettings; + auto& [number, width, band, primary20] = m_channelSettings.front(); if (band == WIFI_PHY_BAND_UNSPECIFIED) { band = GetDefaultPhyBand(m_standard); @@ -1234,15 +1245,16 @@ 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)) != m_band); + bool changingPhyBand = + (static_cast(std::get<2>(m_channelSettings.front())) != 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)); + m_band = static_cast(std::get<2>(m_channelSettings.front())); // check that the channel width is supported - ChannelWidthMhz chWidth = std::get<1>(m_channelSettings); + const auto chWidth = std::get<1>(m_channelSettings.front()); if (m_device) { @@ -1264,8 +1276,8 @@ WifiPhy::DoChannelSwitch() } NS_LOG_DEBUG("switching channel"); - m_operatingChannel.Set(std::get<0>(m_channelSettings), 0, chWidth, m_standard, m_band); - m_operatingChannel.SetPrimary20Index(std::get<3>(m_channelSettings)); + m_operatingChannel.Set(std::get<0>(m_channelSettings.front()), 0, chWidth, m_standard, m_band); + m_operatingChannel.SetPrimary20Index(std::get<3>(m_channelSettings.front())); if (changingPhyBand) { diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index cb9e1eeb0..435b8635f 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -919,26 +919,15 @@ class WifiPhy : public Object */ Ptr GetMobility() const; - using ChannelTuple = - std::tuple; //!< Tuple identifying an operating channel + using ChannelTuple = std::tuple; //!< Tuple identifying a segment + //!< of an operating channel + + using ChannelSegments = + std::vector; //!< segments identifying an operating channel - /** - * If the standard for this object has not been set yet, store the given channel - * settings. Otherwise, check if a channel switch can be performed now. If not, - * schedule another call to this method when channel switch can be performed. - * Otherwise, set the operating channel based on the given channel settings and - * call ConfigureStandard if the PHY band has changed. - * - * Note that, in case a Spectrum PHY is used, a spectrum channel covering the - * operating channel bandwidth must have been already added when actually setting - * the operating channel. - * - * \param channelTuple the given channel settings - */ - void SetOperatingChannel(const ChannelTuple& channelTuple); /** * If the standard for this object has not been set yet, store the channel settings * corresponding to the given operating channel. Otherwise, check if a channel switch @@ -953,6 +942,23 @@ class WifiPhy : public Object * \param channel the given operating channel */ void SetOperatingChannel(const WifiPhyOperatingChannel& channel); + + /** + * This overloaded function is used to pass a list of segments + * from which the operating channel can be deduced. + * + * \param channelSegments the segments identifying the operating channel + */ + void SetOperatingChannel(const ChannelSegments& channelSegments); + + /** + * This overloaded function is used when the operating channel + * consists of a single segment, identified by a tuple. + * + * \param tuple the segment identifying the operating channel + */ + void SetOperatingChannel(const ChannelTuple& tuple); + /** * Configure whether it is prohibited to change PHY band after initialization. * @@ -1564,7 +1570,7 @@ class WifiPhy : public Object WifiStandard m_standard; //!< WifiStandard WifiModulationClass m_maxModClassSupported; //!< max modulation class supported WifiPhyBand m_band; //!< WifiPhyBand - ChannelTuple m_channelSettings; //!< Store operating channel settings until initialization + ChannelSegments m_channelSettings; //!< Store operating channel settings until initialization WifiPhyOperatingChannel m_operatingChannel; //!< Operating channel bool m_fixedPhyBand; //!< True to prohibit changing PHY band after initialization diff --git a/src/wifi/test/wifi-fils-frame-test.cc b/src/wifi/test/wifi-fils-frame-test.cc index 369086998..3966dd751 100644 --- a/src/wifi/test/wifi-fils-frame-test.cc +++ b/src/wifi/test/wifi-fils-frame-test.cc @@ -186,9 +186,12 @@ WifiFilsFrameTest::SetupDevice(Ptr& channel, bool isAp) MobilityHelper mobility; node.Create(1); phy.SetChannel(channel); - TupleValue, UintegerValue> channelValue; - channelValue.Set( - WifiPhy::ChannelTuple{INVALID_CHAN_NUM, m_params.bw, DEFAULT_BAND, DEFAULT_PRIMARY_INDEX}); + AttributeContainerValue< + TupleValue, UintegerValue>, + ';'> + channelValue; + channelValue.Set(WifiPhy::ChannelSegments{ + {INVALID_CHAN_NUM, m_params.bw, DEFAULT_BAND, DEFAULT_PRIMARY_INDEX}}); phy.Set("ChannelSettings", channelValue); phy.Set("Antennas", UintegerValue(m_params.nss)); phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(m_params.nss)); diff --git a/src/wifi/test/wifi-primary-channels-test.cc b/src/wifi/test/wifi-primary-channels-test.cc index 6c3d97aa2..76dbd5121 100644 --- a/src/wifi/test/wifi-primary-channels-test.cc +++ b/src/wifi/test/wifi-primary-channels-test.cc @@ -18,6 +18,7 @@ */ #include "ns3/ap-wifi-mac.h" +#include "ns3/attribute-container.h" #include "ns3/boolean.h" #include "ns3/config.h" #include "ns3/ctrl-headers.h" @@ -397,13 +398,16 @@ WifiPrimaryChannelsTest::DoSetup() "WaitBeaconTimeout", TimeValue(MicroSeconds(102400))); // same as BeaconInterval - TupleValue, UintegerValue> channelValue; + AttributeContainerValue< + TupleValue, UintegerValue>, + ';'> + channelValue; // Each BSS uses a distinct primary20 channel for (uint8_t bss = 0; bss < m_nBss; bss++) { channelValue.Set( - WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss}); + WifiPhy::ChannelSegments{{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss}}); phy.Set("ChannelSettings", channelValue); m_staDevices.push_back(wifi.Install(phy, mac, wifiStaNodes[bss])); @@ -412,7 +416,7 @@ WifiPrimaryChannelsTest::DoSetup() for (uint8_t bss = 0; bss < m_nBss; bss++) { channelValue.Set( - WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss}); + WifiPhy::ChannelSegments{{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss}}); phy.Set("ChannelSettings", channelValue); mac.SetType("ns3::ApWifiMac",