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