mirror of
				https://github.com/Telecominfraproject/wlan-cloud-rrm.git
				synced 2025-10-30 18:17:58 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			release/v2
			...
			v2.7.0-RC3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 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-RC3 | ||||||
|     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,15 +379,26 @@ 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 | ||||||
| 				break; | 					.parseChannelWidth( | ||||||
|  | 						state.radios[radioIndex].channel_width, | ||||||
|  | 						true | ||||||
|  | 					); | ||||||
|  | 				if (parsedChannelWidth != null) { | ||||||
|  | 					currentChannelWidth = parsedChannelWidth; | ||||||
|  | 					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,40 +339,68 @@ 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 | 					continue; | ||||||
| 			); | 				} | ||||||
| 			if (possibleCurrentTxPower.isEmpty()) { |  | ||||||
| 				// this AP is not on the band of interest | 				for (State.Interface.SSID ssid : iface.ssids) { | ||||||
| 				continue; | 					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); | ||||||
|  | 					logger | ||||||
|  | 						.debug( | ||||||
|  | 							"Device <{}> : Interface <{}> : Channel <{}> : BSSID <{}>", | ||||||
|  | 							serialNumber, | ||||||
|  | 							iface.name, | ||||||
|  | 							channel, | ||||||
|  | 							bssid | ||||||
|  | 						); | ||||||
|  | 					for (int rssi : rssiValues) { | ||||||
|  | 						logger.debug("  Neighbor received RSSI: {}", rssi); | ||||||
|  | 					} | ||||||
|  | 					List<Integer> txPowerChoices = updateTxPowerChoices( | ||||||
|  | 						band, | ||||||
|  | 						serialNumber, | ||||||
|  | 						DEFAULT_TX_POWER_CHOICES | ||||||
|  | 					); | ||||||
|  | 					int newTxPower = computeTxPower( | ||||||
|  | 						serialNumber, | ||||||
|  | 						currentTxPower, | ||||||
|  | 						rssiValues, | ||||||
|  | 						coverageThreshold, | ||||||
|  | 						nthSmallestRssi, | ||||||
|  | 						txPowerChoices | ||||||
|  | 					); | ||||||
|  | 					logger.debug("  Old tx_power: {}", currentTxPower); | ||||||
|  | 					logger.debug("  New tx_power: {}", newTxPower); | ||||||
|  | 					txPowerMap | ||||||
|  | 						.computeIfAbsent(serialNumber, k -> new TreeMap<>()) | ||||||
|  | 						.put(band, newTxPower); | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			int currentTxPower = possibleCurrentTxPower.get(); |  | ||||||
| 			String bssid = state.interfaces[0].ssids[0].bssid; |  | ||||||
| 			List<Integer> rssiValues = bssidToRssiValues.get(bssid); |  | ||||||
| 			logger.debug("Device <{}> : BSSID <{}>", serialNumber, bssid); |  | ||||||
| 			for (int rssi : rssiValues) { |  | ||||||
| 				logger.debug("  Neighbor received RSSI: {}", rssi); |  | ||||||
| 			} |  | ||||||
| 			List<Integer> txPowerChoices = updateTxPowerChoices( |  | ||||||
| 				band, |  | ||||||
| 				serialNumber, |  | ||||||
| 				DEFAULT_TX_POWER_CHOICES |  | ||||||
| 			); |  | ||||||
| 			int newTxPower = computeTxPower( |  | ||||||
| 				serialNumber, |  | ||||||
| 				currentTxPower, |  | ||||||
| 				rssiValues, |  | ||||||
| 				coverageThreshold, |  | ||||||
| 				nthSmallestRssi, |  | ||||||
| 				txPowerChoices |  | ||||||
| 			); |  | ||||||
| 			logger.debug("  Old tx_power: {}", currentTxPower); |  | ||||||
| 			logger.debug("  New tx_power: {}", newTxPower); |  | ||||||
| 			txPowerMap.computeIfAbsent(serialNumber, k -> new TreeMap<>()) |  | ||||||
| 				.put(band, newTxPower); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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