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