blob: e678e652d6972171bd1dcd75e0b4c16dc310b260 [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.
#ifndef GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_ENERGY_H_
#define GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_ENERGY_H_
#include <cstdint>
#include <string>
#include <fbl/algorithm.h>
// Energy units defined here are to represent those defined in
// IEEE standards and International System of Units.
// The upper/lower cases in units are of significant meaning.
// Do not alter cases to meet a particular coding style.
// Presentation factors in following considerations:
// 1. Valid range as in defined in the standards.
// 2. Imperative precision of values (integral, 0.5 step, 0.25 step, etc.).
// 3. Practical precision of values (up to the hardware).
// 4. Storage size
// 5. Cross-language compatibility
// 6. Encoding schemes defined in the standards.
// Consider float (32 bits) or fixed-point type (8 or 16 bits)
// when integral type does not meet needs.
namespace wlan {
namespace common {
template <typename Storage, typename Unit> struct EnergyType {
Storage val;
protected:
constexpr explicit EnergyType(Storage v) : val(v) {}
};
// Below operators are defined only for the operands with matching template types.
template <typename Storage, typename Unit>
constexpr bool operator==(const EnergyType<Storage, Unit>& lhs,
const EnergyType<Storage, Unit>& rhs) {
return lhs.val == rhs.val;
}
template <typename Storage, typename Unit>
constexpr bool operator!=(const EnergyType<Storage, Unit>& lhs,
const EnergyType<Storage, Unit>& rhs) {
return lhs.val != rhs.val;
}
template <typename Storage, typename Unit>
constexpr bool operator>(const EnergyType<Storage, Unit>& lhs,
const EnergyType<Storage, Unit>& rhs) {
return lhs.val > rhs.val;
}
template <typename Storage, typename Unit>
constexpr bool operator<(const EnergyType<Storage, Unit>& lhs,
const EnergyType<Storage, Unit>& rhs) {
return lhs.val < rhs.val;
}
template <typename Storage, typename Unit>
constexpr bool operator>=(const EnergyType<Storage, Unit>& lhs,
const EnergyType<Storage, Unit>& rhs) {
return lhs.val >= rhs.val;
}
template <typename Storage, typename Unit>
constexpr bool operator<=(const EnergyType<Storage, Unit>& lhs,
const EnergyType<Storage, Unit>& rhs) {
return lhs.val <= rhs.val;
}
// milliwatt. 10^(-3) Watt.
struct mWatt : EnergyType<uint16_t, mWatt> {
explicit mWatt(uint16_t v = 0);
};
// 10^-15 Watt = 10^-12 milliWatt
struct FemtoWatt : EnergyType<uint64_t, FemtoWatt> {
explicit constexpr FemtoWatt(uint64_t v = 0) : EnergyType<uint64_t, FemtoWatt>(v) {}
};
constexpr FemtoWatt& operator+=(FemtoWatt& lhs, FemtoWatt rhs) {
lhs.val += rhs.val;
return lhs;
}
constexpr FemtoWatt& operator-=(FemtoWatt& lhs, FemtoWatt rhs) {
lhs.val -= rhs.val;
return lhs;
}
// LINT.IfChange
// IEEE Std 802.11-2016, Table 9-60, 9-71
// For the use for SNR or relative comparison.
// For precision of 1 dB step, See IEEE 802.11-2016, Table 6-7, 9-18, etc.
struct dB : EnergyType<int8_t, dB> {
explicit dB(int8_t v = 0);
};
// For precision of 0.5 dB step, See IEEE 802.11-2016, 9.4.2.41, 9.4.2.162,
struct dBh : EnergyType<int16_t, dBh> {
explicit dBh(int16_t v = 0);
};
// TODO(porce): Implement dBq unit
// For precision of 0.25 dB step, See IEEE 802.11-2016, 9.4.1.28-30, 9.4.1.49, Table 20-1
// TODO(porce): Implement dBr unit
// IEEE 802.11-2016, 20.3.2
// For ANPI, IEEE Std 802.11-2016, 11.11.9.4,
// DataFrameRSSI, IEEE Std 802.11-2016, Table 6-7
// Beacon RSSI IEEE Std 802.11-2016, 11.45, Table 6-7
// Note, RXVECTOR's RSSI is unitless uint8_t.
// For Transmit Power
// See dot11MaximumTransmitPowerLevel, defined as int32_t
struct dBm : EnergyType<int8_t, dBm> {
explicit constexpr dBm(int8_t v = 0) : EnergyType<int8_t, dBm>(v) {}
};
// IEEE Std 802.11-2016, 9.4.2.21.7, 9.4.2.38, 9.6.8.30, etc.
struct dBmh : EnergyType<int16_t, dBmh> {
explicit dBmh(int16_t v = 0);
};
// LINT.ThenChange(//garnet/lib/wlan/protocol/include/wlan/protocol/mac.h)
dB to_dB(dBh u);
dBh to_dBh(dB u);
dBm to_dBm(dBmh u);
dBmh to_dBmh(dBm u);
// IEEE Std 802.11-2016, 9.5.1.19-20, Figure 9-391 Tx Power field
// TODO(porce): Implement int8_t dBmTwosComplement(dBm val);
typedef uint8_t Rcpi; // IEEE Std 802.11-2016, Table 9-154
Rcpi to_Rcpi(dBmh u, bool measured);
mWatt operator+(const mWatt& lhs, const mWatt& rhs);
mWatt operator-(const mWatt& lhs, const mWatt& rhs);
mWatt operator-(const mWatt& rhs);
dB operator+(const dB& lhs, const dB& rhs);
dB operator-(const dB& lhs, const dB& rhs);
dB operator-(const dB& rhs);
dBh operator+(const dBh& lhs, const dBh& rhs);
dBh operator-(const dBh& lhs, const dBh& rhs);
dBh operator-(const dBh& rhs);
dBm operator+(const dBm& lhs, const dB& rhs);
dBm operator-(const dBm& lhs, const dB& rhs);
dBm operator+(const dBm& lhs, const dBm& rhs);
dBmh operator+(const dBmh& lhs, const dBh& rhs);
dBmh operator-(const dBmh& lhs, const dBh& rhs);
// Convert dBm to femtowatts: femtowatts = 10^(12 + dBm/10)
//
// For input in the [-100, 48] dBm range, inclusive, results will be accurate within 3%.
// This range corresponds to [100 femtoWatts, ~63 Watts], which covers most
// practical applications such as representing rx/tx power.
//
// Inputs above 48 dBm will be clipped to 48 dBm.
// For inputs below -100 dBm, the result will be below 100 femtowatts.
//
// The output will be always less than 2^56. This allows the user to safely sum up to 256
// values without overflowing.
constexpr FemtoWatt to_femtoWatt_approx(dBm dbm) {
dbm = fbl::clamp(dbm, dBm(-120), dBm(48));
// femtowatts = 10^12 * milliwatts = 10^12 * 10^(0.1 * dbm)
// = 10^(0.1 * (dbm + 120))
// = 2^(C * t)
// where C = 0.1 * log(10) / log(2),
// t = dbm + 120
// C in 24:8 fixed point format, i.e. round(0.1 * log(10)/log(2) * (2^8))
constexpr uint32_t base_conv = 85;
// C * t in 24:8 fixed point format
uint32_t bin_exp = base_conv * (dbm.val + 120);
// Now, the idea is to handle the integer part and the fractional part
// of the exponent (C * t) separately:
// 2^(C * t) = a * b
// where a = 2^(floor(C * t)),
// b = 2^(fract(C * t))
uint64_t a = (1ull << (bin_exp >> 8));
// Approximate 2^x on [0, 1] with y(x) = x + K,
// and use that to compute 2^(fract(C * t)) in 24:8 format.
// K is chosen as 246/256 to minimize the maximum relative error
// for inputs in the range [-100, 48].
uint32_t b = (bin_exp & 0xff) + 246;
return FemtoWatt((a * b) >> 8);
}
dBm to_dBm(FemtoWatt fw);
} // namespace common
} // namespace wlan
#endif // GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_ENERGY_H_