mirror of
				https://github.com/Telecominfraproject/wlan-cloud-rrm.git
				synced 2025-11-04 04:27:46 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			token_refr
			...
			v2.7.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d09e399d09 | ||
| 
						 | 
					a25b28e7a7 | ||
| 
						 | 
					c3b51aeafd | ||
| 
						 | 
					bb4d3368a0 | ||
| 
						 | 
					7d70bfd650 | ||
| 
						 | 
					4373036d51 | ||
| 
						 | 
					84b896f939 | 
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
				
			|||||||
images:
 | 
					images:
 | 
				
			||||||
  owrrm:
 | 
					  owrrm:
 | 
				
			||||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owrrm
 | 
					    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owrrm
 | 
				
			||||||
    tag: main
 | 
					    tag: v2.7.0
 | 
				
			||||||
    pullPolicy: Always
 | 
					    pullPolicy: Always
 | 
				
			||||||
#    regcred:
 | 
					#    regcred:
 | 
				
			||||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,7 +97,7 @@ public class Modeler implements Runnable {
 | 
				
			|||||||
		public Map<String, State> latestState = new ConcurrentHashMap<>();
 | 
							public Map<String, State> latestState = new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/** List of radio info per device. */
 | 
							/** List of radio info per device. */
 | 
				
			||||||
		public Map<String, JsonArray> latestDeviceStatus =
 | 
							public Map<String, JsonArray> latestDeviceStatusRadios =
 | 
				
			||||||
			new ConcurrentHashMap<>();
 | 
								new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/** List of capabilities per device. */
 | 
							/** List of capabilities per device. */
 | 
				
			||||||
@@ -379,7 +379,7 @@ public class Modeler implements Runnable {
 | 
				
			|||||||
		// Get old vs new radios info and store the new radios info
 | 
							// Get old vs new radios info and store the new radios info
 | 
				
			||||||
		JsonArray newRadioList = config.getRadioConfigList();
 | 
							JsonArray newRadioList = config.getRadioConfigList();
 | 
				
			||||||
		Set<String> newRadioBandsSet = config.getRadioBandsSet(newRadioList);
 | 
							Set<String> newRadioBandsSet = config.getRadioBandsSet(newRadioList);
 | 
				
			||||||
		JsonArray oldRadioList = dataModel.latestDeviceStatus
 | 
							JsonArray oldRadioList = dataModel.latestDeviceStatusRadios
 | 
				
			||||||
			.put(serialNumber, newRadioList);
 | 
								.put(serialNumber, newRadioList);
 | 
				
			||||||
		Set<String> oldRadioBandsSet = config.getRadioBandsSet(oldRadioList);
 | 
							Set<String> oldRadioBandsSet = config.getRadioBandsSet(oldRadioList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -429,7 +429,7 @@ public class Modeler implements Runnable {
 | 
				
			|||||||
			logger.debug("Removed some state entries from data model");
 | 
								logger.debug("Removed some state entries from data model");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (
 | 
							if (
 | 
				
			||||||
			dataModel.latestDeviceStatus.entrySet()
 | 
								dataModel.latestDeviceStatusRadios.entrySet()
 | 
				
			||||||
				.removeIf(e -> !isRRMEnabled(e.getKey()))
 | 
									.removeIf(e -> !isRRMEnabled(e.getKey()))
 | 
				
			||||||
		) {
 | 
							) {
 | 
				
			||||||
			logger.debug("Removed some status entries from data model");
 | 
								logger.debug("Removed some status entries from data model");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -454,9 +454,10 @@ public class DatabaseManager {
 | 
				
			|||||||
			.map(o -> gson.fromJson(o, State.Interface.class))
 | 
								.map(o -> gson.fromJson(o, State.Interface.class))
 | 
				
			||||||
			.collect(Collectors.toList())
 | 
								.collect(Collectors.toList())
 | 
				
			||||||
			.toArray(new State.Interface[0]);
 | 
								.toArray(new State.Interface[0]);
 | 
				
			||||||
		state.radios = new JsonObject[radios.lastKey() + 1];
 | 
							state.radios = new State.Radio[radios.lastKey() + 1];
 | 
				
			||||||
		for (Map.Entry<Integer, JsonObject> entry : radios.entrySet()) {
 | 
							for (Map.Entry<Integer, JsonObject> entry : radios.entrySet()) {
 | 
				
			||||||
			state.radios[entry.getKey()] = entry.getValue();
 | 
								State.Radio radio = new State.Radio();
 | 
				
			||||||
 | 
								state.radios[entry.getKey()] = radio;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return state;
 | 
							return state;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,7 +156,7 @@ public abstract class ChannelOptimizer {
 | 
				
			|||||||
			.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
								.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
				
			||||||
		this.model.latestState.keySet()
 | 
							this.model.latestState.keySet()
 | 
				
			||||||
			.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
								.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
				
			||||||
		this.model.latestDeviceStatus.keySet()
 | 
							this.model.latestDeviceStatusRadios.keySet()
 | 
				
			||||||
			.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
								.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
				
			||||||
		this.model.latestDeviceCapabilities.keySet()
 | 
							this.model.latestDeviceCapabilities.keySet()
 | 
				
			||||||
			.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
								.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
 | 
				
			||||||
@@ -234,8 +234,9 @@ public abstract class ChannelOptimizer {
 | 
				
			|||||||
				// the difference of 8 means it is consecutive
 | 
									// the difference of 8 means it is consecutive
 | 
				
			||||||
				int channelDiff =
 | 
									int channelDiff =
 | 
				
			||||||
					Math.abs(vhtOperObj.channel1 - vhtOperObj.channel2);
 | 
										Math.abs(vhtOperObj.channel1 - vhtOperObj.channel2);
 | 
				
			||||||
				// the "8080" below does not mean 8080 MHz wide, it refers to 80+80 MHz channel
 | 
									// TODO it will currently return just 80 for 80p80 - it should be dealt
 | 
				
			||||||
				return channelDiff == 8 ? 160 : 8080;
 | 
									// with properly.
 | 
				
			||||||
 | 
									return channelDiff == 8 ? 160 : 80;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return MIN_CHANNEL_WIDTH;
 | 
									return MIN_CHANNEL_WIDTH;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -378,16 +379,27 @@ public abstract class ChannelOptimizer {
 | 
				
			|||||||
			radioIndex < state.radios.length;
 | 
								radioIndex < state.radios.length;
 | 
				
			||||||
			radioIndex++
 | 
								radioIndex++
 | 
				
			||||||
		) {
 | 
							) {
 | 
				
			||||||
			int tempChannel = state.radios[radioIndex]
 | 
								int tempChannel = state.radios[radioIndex].channel;
 | 
				
			||||||
				.get("channel")
 | 
					 | 
				
			||||||
				.getAsInt();
 | 
					 | 
				
			||||||
			if (UCentralUtils.isChannelInBand(tempChannel, band)) {
 | 
								if (UCentralUtils.isChannelInBand(tempChannel, band)) {
 | 
				
			||||||
				currentChannel = tempChannel;
 | 
									currentChannel = tempChannel;
 | 
				
			||||||
				currentChannelWidth = state.radios[radioIndex]
 | 
									// treat as two separate 80MHz channel and only assign to one
 | 
				
			||||||
					.get("channel_width")
 | 
									// TODO: support 80p80 properly
 | 
				
			||||||
					.getAsInt();
 | 
									Integer parsedChannelWidth = UCentralUtils
 | 
				
			||||||
 | 
										.parseChannelWidth(
 | 
				
			||||||
 | 
											state.radios[radioIndex].channel_width,
 | 
				
			||||||
 | 
											true
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
									if (parsedChannelWidth != null) {
 | 
				
			||||||
 | 
										currentChannelWidth = parsedChannelWidth;
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									logger.error(
 | 
				
			||||||
 | 
										"Invalid channel width {}",
 | 
				
			||||||
 | 
										state.radios[radioIndex].channel_width
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return new int[] { currentChannel, currentChannelWidth };
 | 
							return new int[] { currentChannel, currentChannelWidth };
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -331,11 +331,11 @@ public class LeastUsedChannelOptimizer extends ChannelOptimizer {
 | 
				
			|||||||
	public Map<String, Map<String, Integer>> computeChannelMap() {
 | 
						public Map<String, Map<String, Integer>> computeChannelMap() {
 | 
				
			||||||
		Map<String, Map<String, Integer>> channelMap = new TreeMap<>();
 | 
							Map<String, Map<String, Integer>> channelMap = new TreeMap<>();
 | 
				
			||||||
		Map<String, List<String>> bandsMap = UCentralUtils
 | 
							Map<String, List<String>> bandsMap = UCentralUtils
 | 
				
			||||||
			.getBandsMap(model.latestDeviceStatus);
 | 
								.getBandsMap(model.latestDeviceStatusRadios);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Map<String, Map<String, List<Integer>>> deviceAvailableChannels =
 | 
							Map<String, Map<String, List<Integer>>> deviceAvailableChannels =
 | 
				
			||||||
			UCentralUtils.getDeviceAvailableChannels(
 | 
								UCentralUtils.getDeviceAvailableChannels(
 | 
				
			||||||
				model.latestDeviceStatus,
 | 
									model.latestDeviceStatusRadios,
 | 
				
			||||||
				model.latestDeviceCapabilities,
 | 
									model.latestDeviceCapabilities,
 | 
				
			||||||
				AVAILABLE_CHANNELS_BAND
 | 
									AVAILABLE_CHANNELS_BAND
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,11 +119,11 @@ public class RandomChannelInitializer extends ChannelOptimizer {
 | 
				
			|||||||
	public Map<String, Map<String, Integer>> computeChannelMap() {
 | 
						public Map<String, Map<String, Integer>> computeChannelMap() {
 | 
				
			||||||
		Map<String, Map<String, Integer>> channelMap = new TreeMap<>();
 | 
							Map<String, Map<String, Integer>> channelMap = new TreeMap<>();
 | 
				
			||||||
		Map<String, List<String>> bandsMap =
 | 
							Map<String, List<String>> bandsMap =
 | 
				
			||||||
			UCentralUtils.getBandsMap(model.latestDeviceStatus);
 | 
								UCentralUtils.getBandsMap(model.latestDeviceStatusRadios);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Map<String, Map<String, List<Integer>>> deviceAvailableChannels =
 | 
							Map<String, Map<String, List<Integer>>> deviceAvailableChannels =
 | 
				
			||||||
			UCentralUtils.getDeviceAvailableChannels(
 | 
								UCentralUtils.getDeviceAvailableChannels(
 | 
				
			||||||
				model.latestDeviceStatus,
 | 
									model.latestDeviceStatusRadios,
 | 
				
			||||||
				model.latestDeviceCapabilities,
 | 
									model.latestDeviceCapabilities,
 | 
				
			||||||
				AVAILABLE_CHANNELS_BAND
 | 
									AVAILABLE_CHANNELS_BAND
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@ import java.util.HashMap;
 | 
				
			|||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Optional;
 | 
					 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
import java.util.TreeMap;
 | 
					import java.util.TreeMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,9 +25,6 @@ import com.facebook.openwifirrm.modules.Modeler.DataModel;
 | 
				
			|||||||
import com.facebook.openwifirrm.ucentral.UCentralUtils;
 | 
					import com.facebook.openwifirrm.ucentral.UCentralUtils;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
 | 
					import com.facebook.openwifirrm.ucentral.WifiScanEntry;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.models.State;
 | 
					import com.facebook.openwifirrm.ucentral.models.State;
 | 
				
			||||||
import com.google.gson.JsonArray;
 | 
					 | 
				
			||||||
import com.google.gson.JsonElement;
 | 
					 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Measurement-based AP-AP TPC algorithm.
 | 
					 * Measurement-based AP-AP TPC algorithm.
 | 
				
			||||||
@@ -178,32 +174,6 @@ public class MeasurementBasedApApTPC extends TPC {
 | 
				
			|||||||
		return managedBSSIDs;
 | 
							return managedBSSIDs;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Get the current band radio tx power (the first one found) for an AP using
 | 
					 | 
				
			||||||
	 * the latest device status.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param latestDeviceStatus JsonArray containing radio config for the AP
 | 
					 | 
				
			||||||
	 * @param band band (e.g., "2G")
 | 
					 | 
				
			||||||
	 * @return an Optional containing the tx power if one exists, or else an
 | 
					 | 
				
			||||||
	 *         empty Optional
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	protected static Optional<Integer> getCurrentTxPower(
 | 
					 | 
				
			||||||
		JsonArray latestDeviceStatus,
 | 
					 | 
				
			||||||
		String band
 | 
					 | 
				
			||||||
	) {
 | 
					 | 
				
			||||||
		for (JsonElement e : latestDeviceStatus) {
 | 
					 | 
				
			||||||
			if (!e.isJsonObject()) {
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			JsonObject radioObject = e.getAsJsonObject();
 | 
					 | 
				
			||||||
			String radioBand = radioObject.get("band").getAsString();
 | 
					 | 
				
			||||||
			if (radioBand.equals(band) && radioObject.has("tx-power")) {
 | 
					 | 
				
			||||||
				return Optional.of(radioObject.get("tx-power").getAsInt());
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return Optional.empty();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Get a map from BSSID to the received signal strength at neighboring APs (RSSI).
 | 
						 * Get a map from BSSID to the received signal strength at neighboring APs (RSSI).
 | 
				
			||||||
	 * List of RSSIs are returned in sorted, ascending order.
 | 
						 * List of RSSIs are returned in sorted, ascending order.
 | 
				
			||||||
@@ -340,7 +310,6 @@ public class MeasurementBasedApApTPC extends TPC {
 | 
				
			|||||||
		Map<String, List<Integer>> bssidToRssiValues =
 | 
							Map<String, List<Integer>> bssidToRssiValues =
 | 
				
			||||||
			buildRssiMap(managedBSSIDs, model.latestWifiScans, band);
 | 
								buildRssiMap(managedBSSIDs, model.latestWifiScans, band);
 | 
				
			||||||
		logger.debug("Starting TPC for the {} band", band);
 | 
							logger.debug("Starting TPC for the {} band", band);
 | 
				
			||||||
		Map<String, JsonArray> allStatuses = model.latestDeviceStatus;
 | 
					 | 
				
			||||||
		for (String serialNumber : serialNumbers) {
 | 
							for (String serialNumber : serialNumbers) {
 | 
				
			||||||
			State state = model.latestState.get(serialNumber);
 | 
								State state = model.latestState.get(serialNumber);
 | 
				
			||||||
			if (
 | 
								if (
 | 
				
			||||||
@@ -370,20 +339,45 @@ public class MeasurementBasedApApTPC extends TPC {
 | 
				
			|||||||
				);
 | 
									);
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			JsonArray radioStatuses =
 | 
					
 | 
				
			||||||
				allStatuses.get(serialNumber).getAsJsonArray();
 | 
								// An AP can have multiple interfaces, optimize for all of them
 | 
				
			||||||
			Optional<Integer> possibleCurrentTxPower = getCurrentTxPower(
 | 
								for (State.Interface iface : state.interfaces) {
 | 
				
			||||||
				radioStatuses,
 | 
									if (iface.ssids == null) {
 | 
				
			||||||
				band
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			if (possibleCurrentTxPower.isEmpty()) {
 | 
					 | 
				
			||||||
				// this AP is not on the band of interest
 | 
					 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			int currentTxPower = possibleCurrentTxPower.get();
 | 
					
 | 
				
			||||||
			String bssid = state.interfaces[0].ssids[0].bssid;
 | 
									for (State.Interface.SSID ssid : iface.ssids) {
 | 
				
			||||||
 | 
										Integer idx = UCentralUtils.parseReferenceIndex(
 | 
				
			||||||
 | 
											ssid.radio.get("$ref").getAsString()
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
										if (idx == null) {
 | 
				
			||||||
 | 
											logger.error(
 | 
				
			||||||
 | 
												"Unable to get radio for {}, invalid radio ref {}",
 | 
				
			||||||
 | 
												serialNumber,
 | 
				
			||||||
 | 
												ssid.radio.get("$ref").getAsString()
 | 
				
			||||||
 | 
											);
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										State.Radio radio = state.radios[idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// this specific SSID is not on the band of interest
 | 
				
			||||||
 | 
										if (
 | 
				
			||||||
 | 
											!UCentralUtils.isChannelInBand(radio.channel, band)
 | 
				
			||||||
 | 
										) {
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										int currentTxPower = radio.tx_power;
 | 
				
			||||||
 | 
										String bssid = ssid.bssid;
 | 
				
			||||||
					List<Integer> rssiValues = bssidToRssiValues.get(bssid);
 | 
										List<Integer> rssiValues = bssidToRssiValues.get(bssid);
 | 
				
			||||||
			logger.debug("Device <{}> : BSSID <{}>", serialNumber, bssid);
 | 
										logger
 | 
				
			||||||
 | 
											.debug(
 | 
				
			||||||
 | 
												"Device <{}> : Interface <{}> : Channel <{}> : BSSID <{}>",
 | 
				
			||||||
 | 
												serialNumber,
 | 
				
			||||||
 | 
												iface.name,
 | 
				
			||||||
 | 
												channel,
 | 
				
			||||||
 | 
												bssid
 | 
				
			||||||
 | 
											);
 | 
				
			||||||
					for (int rssi : rssiValues) {
 | 
										for (int rssi : rssiValues) {
 | 
				
			||||||
						logger.debug("  Neighbor received RSSI: {}", rssi);
 | 
											logger.debug("  Neighbor received RSSI: {}", rssi);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -402,10 +396,13 @@ public class MeasurementBasedApApTPC extends TPC {
 | 
				
			|||||||
					);
 | 
										);
 | 
				
			||||||
					logger.debug("  Old tx_power: {}", currentTxPower);
 | 
										logger.debug("  Old tx_power: {}", currentTxPower);
 | 
				
			||||||
					logger.debug("  New tx_power: {}", newTxPower);
 | 
										logger.debug("  New tx_power: {}", newTxPower);
 | 
				
			||||||
			txPowerMap.computeIfAbsent(serialNumber, k -> new TreeMap<>())
 | 
										txPowerMap
 | 
				
			||||||
 | 
											.computeIfAbsent(serialNumber, k -> new TreeMap<>())
 | 
				
			||||||
						.put(band, newTxPower);
 | 
											.put(band, newTxPower);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public Map<String, Map<String, Integer>> computeTxPowerMap() {
 | 
						public Map<String, Map<String, Integer>> computeTxPowerMap() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,6 @@ import org.slf4j.LoggerFactory;
 | 
				
			|||||||
import com.facebook.openwifirrm.DeviceDataManager;
 | 
					import com.facebook.openwifirrm.DeviceDataManager;
 | 
				
			||||||
import com.facebook.openwifirrm.modules.Modeler.DataModel;
 | 
					import com.facebook.openwifirrm.modules.Modeler.DataModel;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.models.State;
 | 
					import com.facebook.openwifirrm.ucentral.models.State;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Measurement-based AP-client algorithm.
 | 
					 * Measurement-based AP-client algorithm.
 | 
				
			||||||
@@ -42,6 +41,9 @@ public class MeasurementBasedApClientTPC extends TPC {
 | 
				
			|||||||
	/** Default tx power. */
 | 
						/** Default tx power. */
 | 
				
			||||||
	public static final int DEFAULT_TX_POWER = 10;
 | 
						public static final int DEFAULT_TX_POWER = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Default channel width in HMz */
 | 
				
			||||||
 | 
						public static final int DEFAULT_CHANNEL_WIDTH = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Mapping of MCS index to required SNR (dB) in 802.11ac. */
 | 
						/** Mapping of MCS index to required SNR (dB) in 802.11ac. */
 | 
				
			||||||
	private static final List<Double> MCS_TO_SNR = Collections.unmodifiableList(
 | 
						private static final List<Double> MCS_TO_SNR = Collections.unmodifiableList(
 | 
				
			||||||
		Arrays.asList(
 | 
							Arrays.asList(
 | 
				
			||||||
@@ -154,19 +156,16 @@ public class MeasurementBasedApClientTPC extends TPC {
 | 
				
			|||||||
	private int computeTxPowerForRadio(
 | 
						private int computeTxPowerForRadio(
 | 
				
			||||||
		String serialNumber,
 | 
							String serialNumber,
 | 
				
			||||||
		State state,
 | 
							State state,
 | 
				
			||||||
		JsonObject radio,
 | 
							State.Radio radio,
 | 
				
			||||||
		List<Integer> txPowerChoices
 | 
							List<Integer> txPowerChoices
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		// Find current tx power and bandwidth
 | 
							// Find current tx power and bandwidth
 | 
				
			||||||
		int currentTxPower =
 | 
							int currentTxPower = radio.tx_power;
 | 
				
			||||||
			radio.has("tx_power") && !radio.get("tx_power").isJsonNull()
 | 
							// treat as one 160MHz channel vs two 80MHz channels
 | 
				
			||||||
				? radio.get("tx_power").getAsInt()
 | 
							Integer channelWidthMHz =
 | 
				
			||||||
				: 0;
 | 
								UCentralUtils.parseChannelWidth(radio.channel_width, false);
 | 
				
			||||||
		int channelWidth =
 | 
							int channelWidth = (channelWidthMHz != null
 | 
				
			||||||
			1_000_000 /* convert MHz to Hz */ * (radio.has("channel_width") &&
 | 
								? channelWidthMHz : DEFAULT_CHANNEL_WIDTH) * 1_000_000; // convert MHz to HZ
 | 
				
			||||||
				!radio.get("channel_width").isJsonNull()
 | 
					 | 
				
			||||||
					? radio.get("channel_width").getAsInt()
 | 
					 | 
				
			||||||
					: 20);
 | 
					 | 
				
			||||||
		Collections.sort(txPowerChoices);
 | 
							Collections.sort(txPowerChoices);
 | 
				
			||||||
		int minTxPower = txPowerChoices.get(0);
 | 
							int minTxPower = txPowerChoices.get(0);
 | 
				
			||||||
		int maxTxPower = txPowerChoices.get(txPowerChoices.size() - 1);
 | 
							int maxTxPower = txPowerChoices.get(txPowerChoices.size() - 1);
 | 
				
			||||||
@@ -303,17 +302,10 @@ public class MeasurementBasedApClientTPC extends TPC {
 | 
				
			|||||||
				);
 | 
									);
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Map<String, Integer> radioMap = new TreeMap<>();
 | 
								Map<String, Integer> radioMap = new TreeMap<>();
 | 
				
			||||||
 | 
								for (State.Radio radio : state.radios) {
 | 
				
			||||||
			for (JsonObject radio : state.radios) {
 | 
									int currentChannel = radio.channel;
 | 
				
			||||||
				Integer currentChannel =
 | 
					 | 
				
			||||||
					radio.has("channel") && !radio.get("channel").isJsonNull()
 | 
					 | 
				
			||||||
						? radio.get("channel").getAsInt()
 | 
					 | 
				
			||||||
						: null;
 | 
					 | 
				
			||||||
				if (currentChannel == null) {
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				String band = UCentralUtils.getBandFromChannel(currentChannel);
 | 
									String band = UCentralUtils.getBandFromChannel(currentChannel);
 | 
				
			||||||
				if (band == null) {
 | 
									if (band == null) {
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@ import com.facebook.openwifirrm.DeviceDataManager;
 | 
				
			|||||||
import com.facebook.openwifirrm.modules.ConfigManager;
 | 
					import com.facebook.openwifirrm.modules.ConfigManager;
 | 
				
			||||||
import com.facebook.openwifirrm.modules.Modeler.DataModel;
 | 
					import com.facebook.openwifirrm.modules.Modeler.DataModel;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.models.State;
 | 
					import com.facebook.openwifirrm.ucentral.models.State;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,7 +74,7 @@ public abstract class TPC {
 | 
				
			|||||||
		this.model.latestState.keySet()
 | 
							this.model.latestState.keySet()
 | 
				
			||||||
			.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber)
 | 
								.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
		this.model.latestDeviceStatus.keySet()
 | 
							this.model.latestDeviceStatusRadios.keySet()
 | 
				
			||||||
			.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber)
 | 
								.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
		this.model.latestDeviceCapabilities.keySet()
 | 
							this.model.latestDeviceCapabilities.keySet()
 | 
				
			||||||
@@ -203,12 +202,9 @@ public abstract class TPC {
 | 
				
			|||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (JsonObject radio : state.radios) {
 | 
								for (State.Radio radio : state.radios) {
 | 
				
			||||||
				Integer currentChannel =
 | 
									Integer currentChannel = radio.channel;
 | 
				
			||||||
					radio.has("channel") && !radio.get("channel").isJsonNull()
 | 
									if (currentChannel == 0) {
 | 
				
			||||||
						? radio.get("channel").getAsInt()
 | 
					 | 
				
			||||||
						: null;
 | 
					 | 
				
			||||||
				if (currentChannel == null) {
 | 
					 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				apsPerChannel
 | 
									apsPerChannel
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,9 +130,24 @@ public class UCentralUtils {
 | 
				
			|||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Compare vs. existing value
 | 
								// Compare vs. existing value.
 | 
				
			||||||
			int currentValue = radioConfig.get(fieldName).getAsInt();
 | 
								// not all values are int so override those values
 | 
				
			||||||
			if (currentValue == newValue) {
 | 
								Integer currentValue = null;
 | 
				
			||||||
 | 
								JsonElement fieldValue = radioConfig.get(fieldName);
 | 
				
			||||||
 | 
								if (
 | 
				
			||||||
 | 
									fieldValue.isJsonPrimitive() &&
 | 
				
			||||||
 | 
										fieldValue.getAsJsonPrimitive().isNumber()
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
 | 
									currentValue = fieldValue.getAsInt();
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									logger.debug(
 | 
				
			||||||
 | 
										"Unable to get field '{}' as int, value was {}",
 | 
				
			||||||
 | 
										fieldName,
 | 
				
			||||||
 | 
										fieldValue.toString()
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (currentValue != null && currentValue == newValue) {
 | 
				
			||||||
				logger.info(
 | 
									logger.info(
 | 
				
			||||||
					"Device {}: {} {} is already {}",
 | 
										"Device {}: {} {} is already {}",
 | 
				
			||||||
					serialNumber,
 | 
										serialNumber,
 | 
				
			||||||
@@ -150,7 +165,7 @@ public class UCentralUtils {
 | 
				
			|||||||
					operationalBand,
 | 
										operationalBand,
 | 
				
			||||||
					fieldName,
 | 
										fieldName,
 | 
				
			||||||
					newValue,
 | 
										newValue,
 | 
				
			||||||
					currentValue
 | 
										currentValue != null ? currentValue : fieldValue.toString()
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
				wasModified = true;
 | 
									wasModified = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -384,4 +399,52 @@ public class UCentralUtils {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return null;
 | 
							return null;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Tries to parse channel width, if it encounters an error it will return null.
 | 
				
			||||||
 | 
						 * It can handle 80p80 in two ways. First it can just treat it as 160. Second,
 | 
				
			||||||
 | 
						 * it can just apply to the first 80 channel and ignore the second. This is
 | 
				
			||||||
 | 
						 * controlled by treatSeparate.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param channelWidthStr the channel width
 | 
				
			||||||
 | 
						 * @param treatSeparate treats each band separately
 | 
				
			||||||
 | 
						 * @return channel width in MHz
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Integer parseChannelWidth(
 | 
				
			||||||
 | 
							String channelWidthStr,
 | 
				
			||||||
 | 
							boolean treatSeparate
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							// 80p80 is the only case where it can't be parsed into an integer
 | 
				
			||||||
 | 
							if (channelWidthStr.equals("80p80")) {
 | 
				
			||||||
 | 
								return treatSeparate ? 80 : 160;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								return Integer.parseInt(channelWidthStr);
 | 
				
			||||||
 | 
							} catch (NumberFormatException e) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Tries to parse the index from the reference string in the JSON returned from
 | 
				
			||||||
 | 
						 * other services. Note that this only returns the index, the caller is
 | 
				
			||||||
 | 
						 * responsible for making sure that the correct field is passed in and the
 | 
				
			||||||
 | 
						 * index is used in the correct fields. If there's an error parsing, it will
 | 
				
			||||||
 | 
						 * return null.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param reference The reference string, keyed under "$ref"
 | 
				
			||||||
 | 
						 * @return the index of the reference or null if an error occurred.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Integer parseReferenceIndex(String reference) {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								return Integer.parseInt(
 | 
				
			||||||
 | 
									reference,
 | 
				
			||||||
 | 
									reference.lastIndexOf("/") + 1,
 | 
				
			||||||
 | 
									reference.length(),
 | 
				
			||||||
 | 
									10
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							} catch (NumberFormatException e) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -112,8 +112,21 @@ public class State {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public Unit unit;
 | 
						public Unit unit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class Radio {
 | 
				
			||||||
 | 
							public long active_ms;
 | 
				
			||||||
 | 
							public long busy_ms;
 | 
				
			||||||
 | 
							public int channel;
 | 
				
			||||||
 | 
							public String channel_width;
 | 
				
			||||||
 | 
							public long noise;
 | 
				
			||||||
 | 
							public String phy;
 | 
				
			||||||
 | 
							public long receive_ms;
 | 
				
			||||||
 | 
							public long transmit_ms;
 | 
				
			||||||
 | 
							public int tx_power;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Radio[] radios;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO
 | 
						// TODO
 | 
				
			||||||
	public JsonObject[] radios;
 | 
					 | 
				
			||||||
	@SerializedName("link-state") public JsonObject linkState;
 | 
						@SerializedName("link-state") public JsonObject linkState;
 | 
				
			||||||
	public JsonObject gps;
 | 
						public JsonObject gps;
 | 
				
			||||||
	public JsonObject poe;
 | 
						public JsonObject poe;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,15 +30,23 @@ public class VHTOperationElement {
 | 
				
			|||||||
	 * 160 MHz wide channel, this parameter is the channel number of the 80MHz
 | 
						 * 160 MHz wide channel, this parameter is the channel number of the 80MHz
 | 
				
			||||||
	 * channel that contains the primary channel. For a 80+80 MHz wide channel, this
 | 
						 * channel that contains the primary channel. For a 80+80 MHz wide channel, this
 | 
				
			||||||
	 * parameter is the channel number of the primary channel.
 | 
						 * parameter is the channel number of the primary channel.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * This field is an unsigned byte in the specification (i.e., with values
 | 
				
			||||||
 | 
						 * between 0 and 255). But because Java only supports signed bytes, a short
 | 
				
			||||||
 | 
						 * data type is used to store the value.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public final byte channel1;
 | 
						public final short channel1;
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * This should be zero unless the channel is 160MHz or 80+80 MHz wide. If the
 | 
						 * This should be zero unless the channel is 160MHz or 80+80 MHz wide. If the
 | 
				
			||||||
	 * channel is 160 MHz wide, this parameter is the channel number of the 160 MHz
 | 
						 * channel is 160 MHz wide, this parameter is the channel number of the 160 MHz
 | 
				
			||||||
	 * wide channel. If the channel is 80+80 MHz wide, this parameter is the channel
 | 
						 * wide channel. If the channel is 80+80 MHz wide, this parameter is the channel
 | 
				
			||||||
	 * index of the secondary 80 MHz wide channel.
 | 
						 * index of the secondary 80 MHz wide channel.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * This field is an unsigned byte in the specification (i.e., with values
 | 
				
			||||||
 | 
						 * between 0 and 255). But because Java only supports signed bytes, a short
 | 
				
			||||||
 | 
						 * data type is used to store the value.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public final byte channel2;
 | 
						public final short channel2;
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * An 8-element array where each element is between 0 and 4 inclusive. MCS means
 | 
						 * An 8-element array where each element is between 0 and 4 inclusive. MCS means
 | 
				
			||||||
	 * Modulation and Coding Scheme. NSS means Number of Spatial Streams. There can
 | 
						 * Modulation and Coding Scheme. NSS means Number of Spatial Streams. There can
 | 
				
			||||||
@@ -60,8 +68,8 @@ public class VHTOperationElement {
 | 
				
			|||||||
	public VHTOperationElement(String vhtOper) {
 | 
						public VHTOperationElement(String vhtOper) {
 | 
				
			||||||
		byte[] bytes = Base64.decodeBase64(vhtOper);
 | 
							byte[] bytes = Base64.decodeBase64(vhtOper);
 | 
				
			||||||
		this.channelWidth = bytes[0];
 | 
							this.channelWidth = bytes[0];
 | 
				
			||||||
		this.channel1 = bytes[1];
 | 
							this.channel1 = (short) (bytes[1] & 0xff); // read as unsigned value
 | 
				
			||||||
		this.channel2 = bytes[2];
 | 
							this.channel2 = (short) (bytes[2] & 0xff); // read as unsigned value
 | 
				
			||||||
		byte[] vhtMcsForNss = new byte[8];
 | 
							byte[] vhtMcsForNss = new byte[8];
 | 
				
			||||||
		vhtMcsForNss[0] = (byte) (bytes[3] >>> 6);
 | 
							vhtMcsForNss[0] = (byte) (bytes[3] >>> 6);
 | 
				
			||||||
		vhtMcsForNss[1] = (byte) ((bytes[3] & 0b00110000) >>> 4);
 | 
							vhtMcsForNss[1] = (byte) ((bytes[3] & 0b00110000) >>> 4);
 | 
				
			||||||
@@ -83,8 +91,8 @@ public class VHTOperationElement {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public VHTOperationElement(
 | 
						public VHTOperationElement(
 | 
				
			||||||
		byte channelWidth,
 | 
							byte channelWidth,
 | 
				
			||||||
		byte channel1,
 | 
							short channel1,
 | 
				
			||||||
		byte channel2,
 | 
							short channel2,
 | 
				
			||||||
		byte[] vhtMcsForNss
 | 
							byte[] vhtMcsForNss
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -397,23 +397,15 @@ public class TestUtils {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Create an element of {@link State#radios}. */
 | 
						/** Create an element of {@link State#radios}. */
 | 
				
			||||||
	private static JsonObject createStateRadio() {
 | 
						private static State.Radio createStateRadio() {
 | 
				
			||||||
		// @formatter:off
 | 
							State.Radio radio = new State.Radio();
 | 
				
			||||||
		return gson.fromJson(
 | 
							radio.active_ms = 564328;
 | 
				
			||||||
			String.format(
 | 
							radio.busy_ms = 36998;
 | 
				
			||||||
				"    {\n" +
 | 
							radio.noise = 4294967193L;
 | 
				
			||||||
				"      \"active_ms\": 564328,\n" +
 | 
							radio.phy = "platform/soc/c000000.wifi";
 | 
				
			||||||
				"      \"busy_ms\": 36998,\n" +
 | 
							radio.receive_ms = 28;
 | 
				
			||||||
				"      \"noise\": 4294967193,\n" +
 | 
							radio.transmit_ms = 4893;
 | 
				
			||||||
				"      \"phy\": \"platform/soc/c000000.wifi\",\n" +
 | 
							return radio;
 | 
				
			||||||
				"      \"receive_ms\": 28,\n" +
 | 
					 | 
				
			||||||
				"      \"temperature\": 45,\n" +
 | 
					 | 
				
			||||||
				"      \"transmit_ms\": 4893\n" +
 | 
					 | 
				
			||||||
				"    }\n"
 | 
					 | 
				
			||||||
			),
 | 
					 | 
				
			||||||
			JsonObject.class
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
		// @formatter:on
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Create a {@code State.Unit}. */
 | 
						/** Create a {@code State.Unit}. */
 | 
				
			||||||
@@ -477,12 +469,12 @@ public class TestUtils {
 | 
				
			|||||||
			state.interfaces[index] = createUpStateInterface(index);
 | 
								state.interfaces[index] = createUpStateInterface(index);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		state.interfaces[numRadios] = createDownStateInterface(numRadios);
 | 
							state.interfaces[numRadios] = createDownStateInterface(numRadios);
 | 
				
			||||||
		state.radios = new JsonObject[numRadios];
 | 
							state.radios = new State.Radio[numRadios];
 | 
				
			||||||
		for (int i = 0; i < numRadios; i++) {
 | 
							for (int i = 0; i < numRadios; i++) {
 | 
				
			||||||
			state.radios[i] = createStateRadio();
 | 
								state.radios[i] = createStateRadio();
 | 
				
			||||||
			state.radios[i].addProperty("channel", channels[i]);
 | 
								state.radios[i].channel = channels[i];
 | 
				
			||||||
			state.radios[i].addProperty("channel_width", channelWidths[i]);
 | 
								state.radios[i].channel_width = Integer.toString(channelWidths[i]);
 | 
				
			||||||
			state.radios[i].addProperty("tx_power", txPowers[i]);
 | 
								state.radios[i].tx_power = txPowers[i];
 | 
				
			||||||
			state.interfaces[i].ssids[0].bssid = bssids[i];
 | 
								state.interfaces[i].ssids[0].bssid = bssids[i];
 | 
				
			||||||
			state.interfaces[i].ssids[0].associations =
 | 
								state.interfaces[i].ssids[0].associations =
 | 
				
			||||||
				new State.Interface.SSID.Association[clientRssis[i].length];
 | 
									new State.Interface.SSID.Association[clientRssis[i].length];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (48)
 | 
							// A -> No APs on current channel, so stay on it (48)
 | 
				
			||||||
		int aExpectedChannel = 48;
 | 
							int aExpectedChannel = 48;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -73,7 +73,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int bExpectedChannel = channelsB.removeLast();
 | 
							int bExpectedChannel = channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 40)
 | 
								TestUtils.createDeviceStatus(band, 40)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -94,7 +94,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int cExpectedChannel = channelsC.removeFirst();
 | 
							int cExpectedChannel = channelsC.removeFirst();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -138,7 +138,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (1)
 | 
							// A -> No APs on current channel, so stay on it (1)
 | 
				
			||||||
		int aExpectedChannel = 1;
 | 
							int aExpectedChannel = 1;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -160,7 +160,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int bExpectedChannel = channelsB.removeLast();
 | 
							int bExpectedChannel = channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 6)
 | 
								TestUtils.createDeviceStatus(band, 6)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -178,7 +178,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// C -> Assigned to only free prioritized channel (1)
 | 
							// C -> Assigned to only free prioritized channel (1)
 | 
				
			||||||
		int cExpectedChannel = 1;
 | 
							int cExpectedChannel = 1;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 6)
 | 
								TestUtils.createDeviceStatus(band, 6)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -231,7 +231,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A, B, C should just be assigned to the same userChannel
 | 
							// A, B, C should just be assigned to the same userChannel
 | 
				
			||||||
		int aExpectedChannel = 48;
 | 
							int aExpectedChannel = 48;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -252,7 +252,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsB.removeLast();
 | 
							channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 40)
 | 
								TestUtils.createDeviceStatus(band, 40)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -272,7 +272,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.removeFirst();
 | 
							channelsC.removeFirst();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -324,7 +324,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		// A -> No APs on current channel and the current channel is in allowedChannels,
 | 
							// A -> No APs on current channel and the current channel is in allowedChannels,
 | 
				
			||||||
		// so stay on it (48)
 | 
							// so stay on it (48)
 | 
				
			||||||
		int aExpectedChannel = 48;
 | 
							int aExpectedChannel = 48;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -347,7 +347,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsB.removeLast();
 | 
							channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 40)
 | 
								TestUtils.createDeviceStatus(band, 40)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -368,7 +368,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.removeFirst();
 | 
							channelsC.removeFirst();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -414,7 +414,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (48)
 | 
							// A -> No APs on current channel, so stay on it (48)
 | 
				
			||||||
		int aExpectedChannel = 157;
 | 
							int aExpectedChannel = 157;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -438,7 +438,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsB.addAll(Arrays.asList(40, 48, 153, 161));
 | 
							channelsB.addAll(Arrays.asList(40, 48, 153, 161));
 | 
				
			||||||
		channelsB.addAll(Arrays.asList(40, 48, 153, 161));
 | 
							channelsB.addAll(Arrays.asList(40, 48, 153, 161));
 | 
				
			||||||
		int bExpectedChannel = channelsB.removeLast() - 4; // upper extension
 | 
							int bExpectedChannel = channelsB.removeLast() - 4; // upper extension
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 40)
 | 
								TestUtils.createDeviceStatus(band, 40)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -459,7 +459,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int cExpectedChannel = channelsC.removeFirst();
 | 
							int cExpectedChannel = channelsC.removeFirst();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -479,7 +479,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsD = new LinkedList<>();
 | 
							LinkedList<Integer> channelsD = new LinkedList<>();
 | 
				
			||||||
		channelsD.addAll(Arrays.asList(36, 44, 149, 157));
 | 
							channelsD.addAll(Arrays.asList(36, 44, 149, 157));
 | 
				
			||||||
		int dExpectedChannel = channelsD.removeLast();
 | 
							int dExpectedChannel = channelsD.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceD,
 | 
								deviceD,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 40)
 | 
								TestUtils.createDeviceStatus(band, 40)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -532,7 +532,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (36)
 | 
							// A -> No APs on current channel, so stay on it (36)
 | 
				
			||||||
		int aExpectedChannel = 36;
 | 
							int aExpectedChannel = 36;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -554,7 +554,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(Arrays.asList(40, 48, 149));
 | 
							channelsB.addAll(Arrays.asList(40, 48, 149));
 | 
				
			||||||
		int bExpectedChannel = channelsB.removeLast();
 | 
							int bExpectedChannel = channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 36)
 | 
								TestUtils.createDeviceStatus(band, 36)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -575,7 +575,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int cExpectedChannel = channelsC.removeFirst();
 | 
							int cExpectedChannel = channelsC.removeFirst();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -597,7 +597,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsD.addAll(Arrays.asList(40, 48, 153, 161));
 | 
							channelsD.addAll(Arrays.asList(40, 48, 153, 161));
 | 
				
			||||||
		channelsD.addAll(Arrays.asList(40, 48, 153, 161));
 | 
							channelsD.addAll(Arrays.asList(40, 48, 153, 161));
 | 
				
			||||||
		int dExpectedChannel = channelsD.removeLast() - 12;
 | 
							int dExpectedChannel = channelsD.removeLast() - 12;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceD,
 | 
								deviceD,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 36)
 | 
								TestUtils.createDeviceStatus(band, 36)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -622,7 +622,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
			.put(UCentralConstants.BAND_5G, Arrays.asList(48, 165));
 | 
								.put(UCentralConstants.BAND_5G, Arrays.asList(48, 165));
 | 
				
			||||||
		deviceDataManager.setDeviceApConfig(deviceE, apConfig);
 | 
							deviceDataManager.setDeviceApConfig(deviceE, apConfig);
 | 
				
			||||||
		int eExpectedChannel = 36;
 | 
							int eExpectedChannel = 36;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceE,
 | 
								deviceE,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, eExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, eExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -668,7 +668,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (48)
 | 
							// A -> No APs on current channel, so stay on it (48)
 | 
				
			||||||
		int aExpectedChannel = 48;
 | 
							int aExpectedChannel = 48;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -689,7 +689,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		// B -> Same setting as A, but the scan results are bandwidth aware
 | 
							// B -> Same setting as A, but the scan results are bandwidth aware
 | 
				
			||||||
		// Assign to only free channel (165)
 | 
							// Assign to only free channel (165)
 | 
				
			||||||
		int bExpectedChannel = 165;
 | 
							int bExpectedChannel = 165;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 48)
 | 
								TestUtils.createDeviceStatus(band, 48)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -721,7 +721,7 @@ public class LeastUsedChannelOptimizerTest {
 | 
				
			|||||||
		channelsC1.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsC1.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		channelsC2.addAll(Arrays.asList(36, 157, 165));
 | 
							channelsC2.addAll(Arrays.asList(36, 157, 165));
 | 
				
			||||||
		int cExpectedChannel = channelsC1.removeFirst();
 | 
							int cExpectedChannel = channelsC1.removeFirst();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,11 +54,11 @@ public class RandomChannelInitializerTest {
 | 
				
			|||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createState(11, channelWidth, deviceBBssid)
 | 
								TestUtils.createState(11, channelWidth, deviceBBssid)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 7)
 | 
								TestUtils.createDeviceStatus(band, 7)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 8)
 | 
								TestUtils.createDeviceStatus(band, 8)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -99,11 +99,11 @@ public class RandomChannelInitializerTest {
 | 
				
			|||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createState(11, channelWidth, deviceBBssid)
 | 
								TestUtils.createState(11, channelWidth, deviceBBssid)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 7)
 | 
								TestUtils.createDeviceStatus(band, 7)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 8)
 | 
								TestUtils.createDeviceStatus(band, 8)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@ public class UnmanagedApAwareChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (48)
 | 
							// A -> No APs on current channel, so stay on it (48)
 | 
				
			||||||
		int aExpectedChannel = 48;
 | 
							int aExpectedChannel = 48;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -76,7 +76,7 @@ public class UnmanagedApAwareChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int bExpectedChannel = channelsB.removeLast();
 | 
							int bExpectedChannel = channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 40)
 | 
								TestUtils.createDeviceStatus(band, 40)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -110,7 +110,7 @@ public class UnmanagedApAwareChannelOptimizerTest {
 | 
				
			|||||||
			)
 | 
								)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		int cExpectedChannel = 48;
 | 
							int cExpectedChannel = 48;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 149)
 | 
								TestUtils.createDeviceStatus(band, 149)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -156,7 +156,7 @@ public class UnmanagedApAwareChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// A -> No APs on current channel, so stay on it (1)
 | 
							// A -> No APs on current channel, so stay on it (1)
 | 
				
			||||||
		int aExpectedChannel = 1;
 | 
							int aExpectedChannel = 1;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceA,
 | 
								deviceA,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
								TestUtils.createDeviceStatus(band, aExpectedChannel)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -178,7 +178,7 @@ public class UnmanagedApAwareChannelOptimizerTest {
 | 
				
			|||||||
		LinkedList<Integer> channelsB = new LinkedList<>();
 | 
							LinkedList<Integer> channelsB = new LinkedList<>();
 | 
				
			||||||
		channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
							channelsB.addAll(ChannelOptimizer.AVAILABLE_CHANNELS_BAND.get(band));
 | 
				
			||||||
		int bExpectedChannel = channelsB.removeLast();
 | 
							int bExpectedChannel = channelsB.removeLast();
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceB,
 | 
								deviceB,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 6)
 | 
								TestUtils.createDeviceStatus(band, 6)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
@@ -196,7 +196,7 @@ public class UnmanagedApAwareChannelOptimizerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// C -> Assigned to only free prioritized channel (1)
 | 
							// C -> Assigned to only free prioritized channel (1)
 | 
				
			||||||
		int cExpectedChannel = 1;
 | 
							int cExpectedChannel = 1;
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
			deviceC,
 | 
								deviceC,
 | 
				
			||||||
			TestUtils.createDeviceStatus(band, 6)
 | 
								TestUtils.createDeviceStatus(band, 6)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,7 +128,7 @@ public class LocationBasedOptimalTPCTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		DataModel dataModel = new DataModel();
 | 
							DataModel dataModel = new DataModel();
 | 
				
			||||||
		for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
							for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
				
			||||||
			dataModel.latestDeviceStatus.put(
 | 
								dataModel.latestDeviceStatusRadios.put(
 | 
				
			||||||
				device,
 | 
									device,
 | 
				
			||||||
				TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
									TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@@ -195,7 +195,7 @@ public class LocationBasedOptimalTPCTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		DataModel dataModel2 = new DataModel();
 | 
							DataModel dataModel2 = new DataModel();
 | 
				
			||||||
		for (String device : Arrays.asList(deviceA, deviceB)) {
 | 
							for (String device : Arrays.asList(deviceA, deviceB)) {
 | 
				
			||||||
			dataModel2.latestDeviceStatus.put(
 | 
								dataModel2.latestDeviceStatusRadios.put(
 | 
				
			||||||
				device,
 | 
									device,
 | 
				
			||||||
				TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
									TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@@ -213,7 +213,7 @@ public class LocationBasedOptimalTPCTest {
 | 
				
			|||||||
				)
 | 
									)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		dataModel2.latestDeviceStatus
 | 
							dataModel2.latestDeviceStatusRadios
 | 
				
			||||||
			.put(
 | 
								.put(
 | 
				
			||||||
				deviceC,
 | 
									deviceC,
 | 
				
			||||||
				TestUtils.createDeviceStatus(
 | 
									TestUtils.createDeviceStatus(
 | 
				
			||||||
@@ -304,7 +304,7 @@ public class LocationBasedOptimalTPCTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		DataModel dataModel2 = new DataModel();
 | 
							DataModel dataModel2 = new DataModel();
 | 
				
			||||||
		for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
							for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
				
			||||||
			dataModel2.latestDeviceStatus.put(
 | 
								dataModel2.latestDeviceStatusRadios.put(
 | 
				
			||||||
				device,
 | 
									device,
 | 
				
			||||||
				TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
									TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@@ -363,7 +363,7 @@ public class LocationBasedOptimalTPCTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		DataModel dataModel3 = new DataModel();
 | 
							DataModel dataModel3 = new DataModel();
 | 
				
			||||||
		for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
							for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
				
			||||||
			dataModel3.latestDeviceStatus.put(
 | 
								dataModel3.latestDeviceStatusRadios.put(
 | 
				
			||||||
				device,
 | 
									device,
 | 
				
			||||||
				TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
									TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@@ -412,7 +412,7 @@ public class LocationBasedOptimalTPCTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		DataModel dataModel4 = new DataModel();
 | 
							DataModel dataModel4 = new DataModel();
 | 
				
			||||||
		for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
							for (String device : Arrays.asList(deviceA, deviceB, deviceC)) {
 | 
				
			||||||
			dataModel4.latestDeviceStatus.put(
 | 
								dataModel4.latestDeviceStatusRadios.put(
 | 
				
			||||||
				device,
 | 
									device,
 | 
				
			||||||
				TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
									TestUtils.createDeviceStatus(UCentralConstants.BANDS)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,6 @@ import com.facebook.openwifirrm.ucentral.UCentralConstants;
 | 
				
			|||||||
import com.facebook.openwifirrm.ucentral.UCentralUtils;
 | 
					import com.facebook.openwifirrm.ucentral.UCentralUtils;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
 | 
					import com.facebook.openwifirrm.ucentral.WifiScanEntry;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.models.State;
 | 
					import com.facebook.openwifirrm.ucentral.models.State;
 | 
				
			||||||
import com.google.gson.JsonArray;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@TestMethodOrder(OrderAnnotation.class)
 | 
					@TestMethodOrder(OrderAnnotation.class)
 | 
				
			||||||
public class MeasurementBasedApApTPCTest {
 | 
					public class MeasurementBasedApApTPCTest {
 | 
				
			||||||
@@ -122,17 +121,17 @@ public class MeasurementBasedApApTPCTest {
 | 
				
			|||||||
		model.latestState.put(DEVICE_B, stateB);
 | 
							model.latestState.put(DEVICE_B, stateB);
 | 
				
			||||||
		model.latestState.put(DEVICE_C, stateC);
 | 
							model.latestState.put(DEVICE_C, stateC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		model.latestDeviceStatus.put(
 | 
							model.latestDeviceStatusRadios.put(
 | 
				
			||||||
			DEVICE_A,
 | 
								DEVICE_A,
 | 
				
			||||||
			TestUtils
 | 
								TestUtils
 | 
				
			||||||
				.createDeviceStatusDualBand(1, MAX_TX_POWER, 36, MAX_TX_POWER)
 | 
									.createDeviceStatusDualBand(1, MAX_TX_POWER, 36, MAX_TX_POWER)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		model.latestDeviceStatus.put(
 | 
							model.latestDeviceStatusRadios.put(
 | 
				
			||||||
			DEVICE_B,
 | 
								DEVICE_B,
 | 
				
			||||||
			TestUtils
 | 
								TestUtils
 | 
				
			||||||
				.createDeviceStatusDualBand(1, MAX_TX_POWER, 36, MAX_TX_POWER)
 | 
									.createDeviceStatusDualBand(1, MAX_TX_POWER, 36, MAX_TX_POWER)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		model.latestDeviceStatus.put(
 | 
							model.latestDeviceStatusRadios.put(
 | 
				
			||||||
			DEVICE_C,
 | 
								DEVICE_C,
 | 
				
			||||||
			TestUtils
 | 
								TestUtils
 | 
				
			||||||
				.createDeviceStatusDualBand(1, MAX_TX_POWER, 36, MAX_TX_POWER)
 | 
									.createDeviceStatusDualBand(1, MAX_TX_POWER, 36, MAX_TX_POWER)
 | 
				
			||||||
@@ -298,25 +297,6 @@ public class MeasurementBasedApApTPCTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	@Order(2)
 | 
						@Order(2)
 | 
				
			||||||
	void testGetCurrentTxPower() throws Exception {
 | 
					 | 
				
			||||||
		final int expectedTxPower = 29;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		DataModel model = new DataModel();
 | 
					 | 
				
			||||||
		model.latestDeviceStatus.put(
 | 
					 | 
				
			||||||
			DEVICE_A,
 | 
					 | 
				
			||||||
			TestUtils.createDeviceStatusDualBand(1, 5, 36, expectedTxPower)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		JsonArray radioStatuses =
 | 
					 | 
				
			||||||
			model.latestDeviceStatus.get(DEVICE_A).getAsJsonArray();
 | 
					 | 
				
			||||||
		int txPower = MeasurementBasedApApTPC
 | 
					 | 
				
			||||||
			.getCurrentTxPower(radioStatuses, UCentralConstants.BAND_5G)
 | 
					 | 
				
			||||||
			.get();
 | 
					 | 
				
			||||||
		assertEquals(expectedTxPower, txPower);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Test
 | 
					 | 
				
			||||||
	@Order(3)
 | 
					 | 
				
			||||||
	void testBuildRssiMap() throws Exception {
 | 
						void testBuildRssiMap() throws Exception {
 | 
				
			||||||
		// This example includes three APs, and one AP that is unmanaged
 | 
							// This example includes three APs, and one AP that is unmanaged
 | 
				
			||||||
		Set<String> bssidSet = Set.of(BSSID_A, BSSID_B, BSSID_C);
 | 
							Set<String> bssidSet = Set.of(BSSID_A, BSSID_B, BSSID_C);
 | 
				
			||||||
@@ -338,7 +318,7 @@ public class MeasurementBasedApApTPCTest {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	@Order(4)
 | 
						@Order(3)
 | 
				
			||||||
	void testComputeTxPower() throws Exception {
 | 
						void testComputeTxPower() throws Exception {
 | 
				
			||||||
		// Test examples here taken from algorithm design doc from @pohanhf
 | 
							// Test examples here taken from algorithm design doc from @pohanhf
 | 
				
			||||||
		final String serialNumber = "testSerial";
 | 
							final String serialNumber = "testSerial";
 | 
				
			||||||
@@ -513,12 +493,13 @@ public class MeasurementBasedApApTPCTest {
 | 
				
			|||||||
			)
 | 
								)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		// make device C not operate in the 5G band instead of dual band
 | 
							// make device C not operate in the 5G band instead of dual band
 | 
				
			||||||
		dataModel.latestDeviceStatus.put(
 | 
							dataModel.latestState.put(
 | 
				
			||||||
			DEVICE_C,
 | 
								DEVICE_C,
 | 
				
			||||||
			TestUtils.createDeviceStatus(
 | 
								TestUtils.createState(
 | 
				
			||||||
				UCentralConstants.BAND_2G,
 | 
					 | 
				
			||||||
				1,
 | 
									1,
 | 
				
			||||||
				MAX_TX_POWER
 | 
									DEFAULT_CHANNEL_WIDTH,
 | 
				
			||||||
 | 
									MAX_TX_POWER,
 | 
				
			||||||
 | 
									BSSID_C
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		DeviceDataManager deviceDataManager = createDeviceDataManager();
 | 
							DeviceDataManager deviceDataManager = createDeviceDataManager();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifirrm.ucentral;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
					import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
				
			||||||
 | 
					import static org.junit.jupiter.api.Assertions.assertTrue;
 | 
				
			||||||
 | 
					import static org.junit.jupiter.api.Assertions.assertFalse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.junit.jupiter.api.Test;
 | 
					import org.junit.jupiter.api.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,4 +22,60 @@ public class UCentralUtilsTest {
 | 
				
			|||||||
	void test_placeholder() throws Exception {
 | 
						void test_placeholder() throws Exception {
 | 
				
			||||||
		assertEquals(3, 1 + 2);
 | 
							assertEquals(3, 1 + 2);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void test_setRadioConfigFieldChannel() throws Exception {
 | 
				
			||||||
 | 
							final String serialNumber = "aaaaaaaaaaaa";
 | 
				
			||||||
 | 
							final int expectedChannel = 1;
 | 
				
			||||||
 | 
							final Map<String, Integer> newValueList = Collections
 | 
				
			||||||
 | 
								.singletonMap(UCentralConstants.BAND_5G, expectedChannel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// test case where channel value is a string and not an integer
 | 
				
			||||||
 | 
							UCentralApConfiguration config = new UCentralApConfiguration(
 | 
				
			||||||
 | 
								"{\"interfaces\": [], \"radios\": [{\"band\": \"5G\", \"channel\": \"auto\"}]}"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							boolean modified = UCentralUtils
 | 
				
			||||||
 | 
								.setRadioConfigField(serialNumber, config, "channel", newValueList);
 | 
				
			||||||
 | 
							assertTrue(modified);
 | 
				
			||||||
 | 
							assertEquals(
 | 
				
			||||||
 | 
								config.getRadioConfig(0).get("channel").getAsInt(),
 | 
				
			||||||
 | 
								expectedChannel
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// field doesn't exist
 | 
				
			||||||
 | 
							config = new UCentralApConfiguration(
 | 
				
			||||||
 | 
								"{\"interfaces\": [], \"radios\": [{\"band\": \"5G\"}]}"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							modified = UCentralUtils
 | 
				
			||||||
 | 
								.setRadioConfigField(serialNumber, config, "channel", newValueList);
 | 
				
			||||||
 | 
							assertTrue(modified);
 | 
				
			||||||
 | 
							assertEquals(
 | 
				
			||||||
 | 
								config.getRadioConfig(0).get("channel").getAsInt(),
 | 
				
			||||||
 | 
								expectedChannel
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// normal field, not modified
 | 
				
			||||||
 | 
							config = new UCentralApConfiguration(
 | 
				
			||||||
 | 
								"{\"interfaces\": [], \"radios\": [{\"band\": \"5G\", \"channel\": 1}]}"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							modified = UCentralUtils
 | 
				
			||||||
 | 
								.setRadioConfigField(serialNumber, config, "channel", newValueList);
 | 
				
			||||||
 | 
							assertFalse(modified);
 | 
				
			||||||
 | 
							assertEquals(
 | 
				
			||||||
 | 
								config.getRadioConfig(0).get("channel").getAsInt(),
 | 
				
			||||||
 | 
								expectedChannel
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// normal field, modified
 | 
				
			||||||
 | 
							config = new UCentralApConfiguration(
 | 
				
			||||||
 | 
								"{\"interfaces\": [], \"radios\": [{\"band\": \"5G\", \"channel\": 15}]}"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							modified = UCentralUtils
 | 
				
			||||||
 | 
								.setRadioConfigField(serialNumber, config, "channel", newValueList);
 | 
				
			||||||
 | 
							assertTrue(modified);
 | 
				
			||||||
 | 
							assertEquals(
 | 
				
			||||||
 | 
								config.getRadioConfig(0).get("channel").getAsInt(),
 | 
				
			||||||
 | 
								expectedChannel
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,8 +19,8 @@ public class VHTOperationElementTest {
 | 
				
			|||||||
		String vhtOper = "ACQAAAA=";
 | 
							String vhtOper = "ACQAAAA=";
 | 
				
			||||||
		VHTOperationElement vhtOperObj = new VHTOperationElement(vhtOper);
 | 
							VHTOperationElement vhtOperObj = new VHTOperationElement(vhtOper);
 | 
				
			||||||
		byte expectedChannelWidthIndicator = 0; // 20 MHz channel width
 | 
							byte expectedChannelWidthIndicator = 0; // 20 MHz channel width
 | 
				
			||||||
		byte expectedChannel1 = 36;
 | 
							short expectedChannel1 = 36;
 | 
				
			||||||
		byte expectedChannel2 = 0;
 | 
							short expectedChannel2 = 0;
 | 
				
			||||||
		byte[] expectedVhtMcsForNss = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
 | 
							byte[] expectedVhtMcsForNss = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
 | 
				
			||||||
		VHTOperationElement expectedVhtOperObj = new VHTOperationElement(
 | 
							VHTOperationElement expectedVhtOperObj = new VHTOperationElement(
 | 
				
			||||||
			expectedChannelWidthIndicator,
 | 
								expectedChannelWidthIndicator,
 | 
				
			||||||
@@ -57,5 +57,20 @@ public class VHTOperationElementTest {
 | 
				
			|||||||
			expectedVhtMcsForNss
 | 
								expectedVhtMcsForNss
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		assertEquals(expectedVhtOperObj, vhtOperObj);
 | 
							assertEquals(expectedVhtOperObj, vhtOperObj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// test with channel number >= 128 (channel fields should be unsigned)
 | 
				
			||||||
 | 
							vhtOper = "AJUAAAA=";
 | 
				
			||||||
 | 
							vhtOperObj = new VHTOperationElement(vhtOper);
 | 
				
			||||||
 | 
							expectedChannelWidthIndicator = 0;
 | 
				
			||||||
 | 
							expectedChannel1 = 149;
 | 
				
			||||||
 | 
							expectedChannel2 = 0;
 | 
				
			||||||
 | 
							expectedVhtMcsForNss = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
 | 
				
			||||||
 | 
							expectedVhtOperObj = new VHTOperationElement(
 | 
				
			||||||
 | 
								expectedChannelWidthIndicator,
 | 
				
			||||||
 | 
								expectedChannel1,
 | 
				
			||||||
 | 
								expectedChannel2,
 | 
				
			||||||
 | 
								expectedVhtMcsForNss
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							assertEquals(expectedVhtOperObj, vhtOperObj);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user