普通文本  |  173行  |  5.39 KB

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "chre/apps/wifi_offload/channel_histogram.h"
#include "chre/apps/wifi_offload/utility.h"

namespace wifi_offload {
namespace {

/* Strictly increasing sequence of supported channel numbers in
 * 2.4GHz (802.11b/g/n) and 5GHz (802.11a/h/j/n/ac) */
constexpr uint8_t kAllChannels[] = {
    1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,
    16,  34,  36,  38,  40,  42,  44,  46,  48,  50,  52,  54,  56,  58,
    60,  62,  64,  100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120,
    122, 124, 126, 128, 132, 134, 136, 138, 140, 142, 144, 149, 151, 153,
    155, 157, 159, 161, 165, 183, 184, 185, 187, 188, 189, 192, 196,
};
static_assert(sizeof(kAllChannels) / sizeof(kAllChannels[0]) ==
                  ChannelHistogram::kNumChannels,
              "some elements unspecified");

/**
 * Returns the channel number of a given frequency based on 802.11.
 *
 * @param frequency Frequncy of the channel in MHz
 *
 * @return Channel number of the given frequency. Zero if unsupported
 *         frequency or channel number. Returned value will be in the range of
 *         [0, 255]
 */
uint8_t GetChannelNumber(uint32_t frequency) {
  int channel_number =
      utility::Ieee80211FrequencyToChannel(static_cast<int>(frequency));
  if (channel_number <= 0 || channel_number > 255) {
    LOGE("Unknown channel frequency %" PRIu32 " MHz.", frequency);
    channel_number = 0;
  }
  return static_cast<uint8_t>(channel_number);
}

/**
 * Returns the index of a given channel number in kAllChannels.
 *
 * @param channel_number Channel number we want to map to an index
 *
 * @return Index of the given channel number in kAllChannels. kNumChannels if
 *         not found. Returned value will be in the range of [0, kNumChannels]
 */
size_t GetChannelIndex(uint8_t channel_number) {
  for (size_t i = 0; i < ChannelHistogram::kNumChannels; i++) {
    if (channel_number == kAllChannels[i]) {
      return i;
    }
  }

  LOGE("Unsupported channel number: %" PRIu8, channel_number);
  return ChannelHistogram::kNumChannels;
}

}  // namespace

ChannelHistogram::ChannelHistogram() {
  std::memset(scan_count_internal_high_res_, 0,
              sizeof(scan_count_internal_high_res_));
}

bool ChannelHistogram::IsSupportedFrequency(uint32_t frequency) {
  return GetChannelNumber(frequency) != 0;
}

uint8_t ChannelHistogram::GetChannelScanCount(uint8_t channel_number) const {
  size_t index = GetChannelIndex(channel_number);
  if (index == kNumChannels) {
    return 0;
  }

  if (scan_count_internal_high_res_[index] == 0) {
    return 0;
  }

  uint32_t max_count = 0;
  // since there is at least one non-zero value, max_count won't be 0
  for (const auto count : scan_count_internal_high_res_) {
    if (max_count < count) {
      max_count = count;
    }
  }

  // linearly map from [1,max_count] to [1,255]
  uint64_t scaled_value = scan_count_internal_high_res_[index];
  scaled_value = scaled_value * 254 / max_count + 1;
  return static_cast<uint8_t>(scaled_value);
}

bool ChannelHistogram::IncrementScanCountForFrequency(uint32_t frequency) {
  size_t index = GetChannelIndex(GetChannelNumber(frequency));
  if (index == kNumChannels) {
    return false;
  }

  scan_count_internal_high_res_[index]++;
  return true;
}

bool ChannelHistogram::IncrementScanCountForFrequencyForTest(
    uint32_t frequency, uint32_t increase_count) {
  return IncrementScanCountForChannelForTest(GetChannelNumber(frequency),
                                             increase_count);
}

bool ChannelHistogram::IncrementScanCountForChannelForTest(
    uint8_t channel, uint32_t increase_count) {
  size_t index = GetChannelIndex(channel);
  if (index == kNumChannels) {
    return false;
  }

  scan_count_internal_high_res_[index] += increase_count;
  return true;
}

bool ChannelHistogram::operator==(const ChannelHistogram &other) const {
  if (this == &other) {
    return true;
  }

  for (const auto channel : kAllChannels) {
    // Compare scaled values, rather than raw values
    if (GetChannelScanCount(channel) != other.GetChannelScanCount(channel)) {
      return false;
    }
  }
  return true;
}

flatbuffers::Offset<flatbuffers::Vector<uint8_t>> ChannelHistogram::Serialize(
    flatbuffers::FlatBufferBuilder *builder) const {
  uint8_t lowResScanCount[kNumChannels];
  for (size_t i = 0; i < kNumChannels; i++) {
    lowResScanCount[i] = GetChannelScanCount(kAllChannels[i]);
  }
  return builder->CreateVector(lowResScanCount, kNumChannels);
}

bool ChannelHistogram::Deserialize(
    const flatbuffers::Vector<uint8_t> &fbs_scan_count) {
  if (fbs_scan_count.size() != kNumChannels) {
    LOGE("Failed to deserialize ChannelHistogram. Null or incomplete members.");
    return false;
  }

  for (uint8_t i = 0; i < kNumChannels; i++) {
    scan_count_internal_high_res_[i] = fbs_scan_count.Get(i);
  }
  return true;
}

}  // namespace wifi_offload