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