Home | History | Annotate | Download | only in wifi_offload
      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  */
     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  */
     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 
     76 ChannelHistogram::ChannelHistogram() {
     77   std::memset(scan_count_internal_high_res_, 0,
     78               sizeof(scan_count_internal_high_res_));
     79 }
     80 
     81 bool ChannelHistogram::IsSupportedFrequency(uint32_t frequency) {
     82   return GetChannelNumber(frequency) != 0;
     83 }
     84 
     85 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 
    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 
    119 bool ChannelHistogram::IncrementScanCountForFrequencyForTest(
    120     uint32_t frequency, uint32_t increase_count) {
    121   return IncrementScanCountForChannelForTest(GetChannelNumber(frequency),
    122                                              increase_count);
    123 }
    124 
    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 
    136 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 
    150 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 
    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