1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "chre/apps/wifi_offload/channel_histogram.h" 18#include "chre/apps/wifi_offload/utility.h" 19 20namespace wifi_offload { 21namespace { 22 23/* Strictly increasing sequence of supported channel numbers in 24 * 2.4GHz (802.11b/g/n) and 5GHz (802.11a/h/j/n/ac) */ 25constexpr uint8_t kAllChannels[] = { 26 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 27 16, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 28 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 29 122, 124, 126, 128, 132, 134, 136, 138, 140, 142, 144, 149, 151, 153, 30 155, 157, 159, 161, 165, 183, 184, 185, 187, 188, 189, 192, 196, 31}; 32static_assert(sizeof(kAllChannels) / sizeof(kAllChannels[0]) == 33 ChannelHistogram::kNumChannels, 34 "some elements unspecified"); 35 36/** 37 * Returns the channel number of a given frequency based on 802.11. 38 * 39 * @param frequency Frequncy of the channel in MHz 40 * 41 * @return Channel number of the given frequency. Zero if unsupported 42 * frequency or channel number. Returned value will be in the range of 43 * [0, 255] 44 */ 45uint8_t GetChannelNumber(uint32_t frequency) { 46 int channel_number = 47 utility::Ieee80211FrequencyToChannel(static_cast<int>(frequency)); 48 if (channel_number <= 0 || channel_number > 255) { 49 LOGE("Unknown channel frequency %" PRIu32 " MHz.", frequency); 50 channel_number = 0; 51 } 52 return static_cast<uint8_t>(channel_number); 53} 54 55/** 56 * Returns the index of a given channel number in kAllChannels. 57 * 58 * @param channel_number Channel number we want to map to an index 59 * 60 * @return Index of the given channel number in kAllChannels. kNumChannels if 61 * not found. Returned value will be in the range of [0, kNumChannels] 62 */ 63size_t GetChannelIndex(uint8_t channel_number) { 64 for (size_t i = 0; i < ChannelHistogram::kNumChannels; i++) { 65 if (channel_number == kAllChannels[i]) { 66 return i; 67 } 68 } 69 70 LOGE("Unsupported channel number: %" PRIu8, channel_number); 71 return ChannelHistogram::kNumChannels; 72} 73 74} // namespace 75 76ChannelHistogram::ChannelHistogram() { 77 std::memset(scan_count_internal_high_res_, 0, 78 sizeof(scan_count_internal_high_res_)); 79} 80 81bool ChannelHistogram::IsSupportedFrequency(uint32_t frequency) { 82 return GetChannelNumber(frequency) != 0; 83} 84 85uint8_t ChannelHistogram::GetChannelScanCount(uint8_t channel_number) const { 86 size_t index = GetChannelIndex(channel_number); 87 if (index == kNumChannels) { 88 return 0; 89 } 90 91 if (scan_count_internal_high_res_[index] == 0) { 92 return 0; 93 } 94 95 uint32_t max_count = 0; 96 // since there is at least one non-zero value, max_count won't be 0 97 for (const auto count : scan_count_internal_high_res_) { 98 if (max_count < count) { 99 max_count = count; 100 } 101 } 102 103 // linearly map from [1,max_count] to [1,255] 104 uint64_t scaled_value = scan_count_internal_high_res_[index]; 105 scaled_value = scaled_value * 254 / max_count + 1; 106 return static_cast<uint8_t>(scaled_value); 107} 108 109bool ChannelHistogram::IncrementScanCountForFrequency(uint32_t frequency) { 110 size_t index = GetChannelIndex(GetChannelNumber(frequency)); 111 if (index == kNumChannels) { 112 return false; 113 } 114 115 scan_count_internal_high_res_[index]++; 116 return true; 117} 118 119bool ChannelHistogram::IncrementScanCountForFrequencyForTest( 120 uint32_t frequency, uint32_t increase_count) { 121 return IncrementScanCountForChannelForTest(GetChannelNumber(frequency), 122 increase_count); 123} 124 125bool ChannelHistogram::IncrementScanCountForChannelForTest( 126 uint8_t channel, uint32_t increase_count) { 127 size_t index = GetChannelIndex(channel); 128 if (index == kNumChannels) { 129 return false; 130 } 131 132 scan_count_internal_high_res_[index] += increase_count; 133 return true; 134} 135 136bool ChannelHistogram::operator==(const ChannelHistogram &other) const { 137 if (this == &other) { 138 return true; 139 } 140 141 for (const auto channel : kAllChannels) { 142 // Compare scaled values, rather than raw values 143 if (GetChannelScanCount(channel) != other.GetChannelScanCount(channel)) { 144 return false; 145 } 146 } 147 return true; 148} 149 150flatbuffers::Offset<flatbuffers::Vector<uint8_t>> ChannelHistogram::Serialize( 151 flatbuffers::FlatBufferBuilder *builder) const { 152 uint8_t lowResScanCount[kNumChannels]; 153 for (size_t i = 0; i < kNumChannels; i++) { 154 lowResScanCount[i] = GetChannelScanCount(kAllChannels[i]); 155 } 156 return builder->CreateVector(lowResScanCount, kNumChannels); 157} 158 159bool ChannelHistogram::Deserialize( 160 const flatbuffers::Vector<uint8_t> &fbs_scan_count) { 161 if (fbs_scan_count.size() != kNumChannels) { 162 LOGE("Failed to deserialize ChannelHistogram. Null or incomplete members."); 163 return false; 164 } 165 166 for (uint8_t i = 0; i < kNumChannels; i++) { 167 scan_count_internal_high_res_[i] = fbs_scan_count.Get(i); 168 } 169 return true; 170} 171 172} // namespace wifi_offload 173