blob: 156e1be6cea0dc757285dc7fd2dfedddd849b158 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <math.h>
#include <wlan/common/energy.h>
#include <limits>
namespace wlan {
namespace common {
mWatt::mWatt(uint16_t v) : EnergyType<uint16_t, mWatt>(v) {}
mWatt operator+(const mWatt& lhs, const mWatt& rhs) {
return mWatt(lhs.val + rhs.val);
}
mWatt operator-(const mWatt& lhs, const mWatt& rhs) {
return mWatt(lhs.val - rhs.val);
}
mWatt operator-(const mWatt& rhs) {
return mWatt(-rhs.val);
}
dB::dB(int8_t v) : EnergyType<int8_t, dB>(v) {}
dB operator+(const dB& lhs, const dB& rhs) {
return dB(lhs.val + rhs.val);
}
dB operator-(const dB& lhs, const dB& rhs) {
return dB(lhs.val - rhs.val);
}
dB operator-(const dB& rhs) {
return dB(-rhs.val);
}
dBh::dBh(int16_t v) : EnergyType<int16_t, dBh>(v) {}
dBh operator+(const dBh& lhs, const dBh& rhs) {
return dBh(lhs.val + rhs.val);
}
dBh operator-(const dBh& lhs, const dBh& rhs) {
return dBh(lhs.val - rhs.val);
}
dBh operator-(const dBh& rhs) {
return dBh(-rhs.val);
}
dBm operator+(const dBm& lhs, const dB& rhs) {
return dBm(lhs.val + rhs.val);
}
dBm operator-(const dBm& lhs, const dB& rhs) {
return dBm(lhs.val - rhs.val);
}
static dBm add_dBm(const dBm& lhs, const dBm& rhs) {
auto max = std::max(lhs.val, rhs.val);
auto min = std::min(lhs.val, rhs.val);
auto diff = max - min;
// Math formula for the answer. Note the answer is a function of diff.
// alpha := pow(10.0f, -diff / 10.0f);
// beta := 10.0f * log10(1 + alpha);
// answer := max + beta;
// Since dBm is an integral type, it can be quantized to the integer precision.
int8_t beta = 0;
switch (diff) {
case 0:
case 1:
beta = 3;
break;
case 2:
case 3:
beta = 2;
break;
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
beta = 1;
break;
default:
beta = 0;
break;
}
return dBm(max + beta);
}
dBm operator+(const dBm& lhs, const dBm& rhs) {
return add_dBm(lhs, rhs);
}
dBmh::dBmh(int16_t v) : EnergyType<int16_t, dBmh>(v) {}
dBmh operator+(const dBmh& lhs, const dBh& rhs) {
return dBmh(lhs.val + rhs.val);
}
dBmh operator-(const dBmh& lhs, const dBh& rhs) {
return dBmh(lhs.val - rhs.val);
}
dB to_dB(dBh u) {
return dB(u.val / 2);
}
dBh to_dBh(dB u) {
return dBh(u.val * 2);
}
dBm to_dBm(dBmh u) {
return dBm(u.val / 2);
}
dBmh to_dBmh(dBm u) {
return dBmh(u.val * 2);
}
// TODO(porce): Implement int8_t dBmTwosComplement(dBm val);
// IEEE Std 802.11-2016, Table 9-154
Rcpi to_Rcpi(dBmh u, bool measured) {
if (!measured) { return 255; }
if (u < dBmh(-219)) { return 0; } // -219 = 2 * (-109.5)
if (u.val >= 0) { return 220; }
return static_cast<uint8_t>(u.val + 220); // 2 * (dBm + 100)
}
dBm to_dBm(FemtoWatt fw) {
if (fw.val == 0) { return dBm(std::numeric_limits<int8_t>::min()); }
// This shouldn't be called too often, so we use log10() to make it simple.
double dbm = 10.0 * (log10(static_cast<double>(fw.val)) - 12.0);
// Casting to int8_t is safe since the resulting value will always be between
// -120 and 73 for all possible uint64_t inputs
return dBm(static_cast<int8_t>(round(dbm)));
}
} // namespace common
} // namespace wlan