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
20 namespace wifi_offload {
21 namespace {
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) */
25 constexpr 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 };
32 static_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 */
GetChannelNumber(uint32_t frequency)45 uint8_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 */
GetChannelIndex(uint8_t channel_number)63 size_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
ChannelHistogram()76 ChannelHistogram::ChannelHistogram() {
77 std::memset(scan_count_internal_high_res_, 0,
78 sizeof(scan_count_internal_high_res_));
79 }
80
IsSupportedFrequency(uint32_t frequency)81 bool ChannelHistogram::IsSupportedFrequency(uint32_t frequency) {
82 return GetChannelNumber(frequency) != 0;
83 }
84
GetChannelScanCount(uint8_t channel_number) const85 uint8_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
IncrementScanCountForFrequency(uint32_t frequency)109 bool 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
IncrementScanCountForFrequencyForTest(uint32_t frequency,uint32_t increase_count)119 bool ChannelHistogram::IncrementScanCountForFrequencyForTest(
120 uint32_t frequency, uint32_t increase_count) {
121 return IncrementScanCountForChannelForTest(GetChannelNumber(frequency),
122 increase_count);
123 }
124
IncrementScanCountForChannelForTest(uint8_t channel,uint32_t increase_count)125 bool 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
operator ==(const ChannelHistogram & other) const136 bool 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
Serialize(flatbuffers::FlatBufferBuilder * builder) const150 flatbuffers::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
Deserialize(const flatbuffers::Vector<uint8_t> & fbs_scan_count)159 bool 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