Update to esphome 2025.12, use its cc1101

This commit is contained in:
2026-01-05 20:53:51 +00:00
parent b4659499e9
commit d4855e2f1c
25 changed files with 23 additions and 4869 deletions
+2 -3
View File
@@ -31,8 +31,7 @@ spi:
cc1101: cc1101:
id: transceiver id: transceiver
cs_pin: 13 cs_pin: 13
tuner: frequency: 433.34MHz
frequency: 433340
remote_transmitter: remote_transmitter:
pin: 4 pin: 4
@@ -43,7 +42,7 @@ remote_transmitter:
- cc1101.begin_tx: transceiver - cc1101.begin_tx: transceiver
on_complete: on_complete:
then: then:
- cc1101.end_tx: transceiver - cc1101.set_idle: transceiver
cover: cover:
- name: "Office window" - name: "Office window"
-2
View File
@@ -1,2 +0,0 @@
This is a snapshot of https://github.com/esphome/esphome/pull/6300 that is
confirmed to work with our hardware.
-406
View File
@@ -1,406 +0,0 @@
from esphome import automation, pins
from esphome.automation import maybe_simple_id
import esphome.codegen as cg
from esphome.components import (
binary_sensor,
remote_base,
sensor,
spi,
text_sensor,
voltage_sampler,
)
import esphome.config_validation as cv
from esphome.const import (
CONF_CHANNEL,
CONF_CODE,
CONF_FREQUENCY,
CONF_ID,
CONF_PROTOCOL,
CONF_SENSOR,
CONF_TEMPERATURE,
CONF_WAIT_TIME,
# DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
ENTITY_CATEGORY_DIAGNOSTIC,
ICON_CHIP,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_DECIBEL_MILLIWATT,
UNIT_EMPTY,
)
CODEOWNERS = ["@gabest11"]
DEPENDENCIES = ["spi"]
AUTO_LOAD = [
"remote_base",
"voltage_sampler",
"sensor",
"binary_sensor",
"text_sensor",
"number",
"switch",
"select",
"text",
]
MULTI_CONF = True
UNIT_MEGA_HERTZ = "MHz"
UNIT_KILO_HERTZ = "kHz"
UNIT_MILLI_VOLT = "mV"
UNIT_MICRO_AMPERE = "mA"
UNIT_DECIBEL_MICRO_VOLT = "dBuV"
ns = cg.esphome_ns.namespace("cc1101")
CC1101Component = ns.class_("CC1101Component", cg.PollingComponent, spi.SPIDevice)
CONF_CC1101_ID = "cc1101_id"
CONF_GDO0_PIN = "gdo0_pin"
CONF_GDO0_ADC_ID = "gdo0_adc_id"
CONF_OUTPUT_POWER = "output_power"
CONF_RX_ATTENUATION = "rx_attenuation"
CONF_DC_BLOCKING_FILTER = "dc_blocking_filter"
# tuner
CONF_TUNER = "tuner"
# CONF_FREQUENCY = "frequency"
CONF_IF_FREQUENCY = "if_frequency"
CONF_BANDWIDTH = "bandwidth"
# CONF_CHANNEL = "channel"
CONF_CHANNEL_SPACING = "channel_spacing"
CONF_FSK_DEVIATION = "fsk_deviation"
CONF_MSK_DEVIATION = "msk_deviation"
CONF_SYMBOL_RATE = "symbol_rate"
CONF_SYNC_MODE = "sync_mode"
CONF_CARRIER_SENSE_ABOVE_THRESHOLD = "carrier_sense_above_threshold"
CONF_MODULATION = "modulation"
# agc
CONF_AGC = "agc"
CONF_MAGN_TARGET = "magn_target"
CONF_MAX_LNA_GAIN = "max_lna_gain"
CONF_MAX_DVGA_GAIN = "max_dvga_gain"
CONF_CARRIER_SENSE_ABS_THR = "carrier_sense_abs_thr"
CONF_CARRIER_SENSE_REL_THR = "carrier_sense_rel_thr"
CONF_LNA_PRIORITY = "lna_priority"
CONF_FILTER_LENGTH_FSK_MSK = "filter_length_fsk_msk"
CONF_FILTER_LENGTH_ASK_OOK = "filter_length_ask_ook"
CONF_FREEZE = "freeze"
CONF_HYST_LEVEL = "hyst_level"
# sensor
CONF_CHIP_ID = "chip_id"
CONF_RSSI = "rssi"
CONF_LQI = "lqi"
# CONF_TEMPERATURE = "temperature"
SyncMode = ns.enum("SyncMode", True)
SYNC_MODE = {
"None": SyncMode.SYNC_MODE_NONE,
"15/16": SyncMode.SYNC_MODE_15_16,
"16/16": SyncMode.SYNC_MODE_16_16,
"30/32": SyncMode.SYNC_MODE_30_32,
}
Modulation = ns.enum("Modulation", True)
MODULATION = {
"2-FSK": Modulation.MODULATION_2_FSK,
"GFSK": Modulation.MODULATION_GFSK,
"UNUSED 2": Modulation.MODULATION_UNUSED_2,
"ASK/OOK": Modulation.MODULATION_ASK_OOK,
"4-FSK": Modulation.MODULATION_4_FSK,
"UNUSED 5": Modulation.MODULATION_UNUSED_5,
"UNUSED 6": Modulation.MODULATION_UNUSED_6,
"MSK": Modulation.MODULATION_MSK,
}
RxAttenuation = ns.enum("RxAttenuation", True)
RX_ATTENUATION = {
"0dB": RxAttenuation.RX_ATTENUATION_0DB,
"6dB": RxAttenuation.RX_ATTENUATION_6DB,
"12dB": RxAttenuation.RX_ATTENUATION_12DB,
"18dB": RxAttenuation.RX_ATTENUATION_18DB,
}
MagnTarget = ns.enum("MagnTarget", True)
MAGN_TARGET = {
"24dB": MagnTarget.MAGN_TARGET_24DB,
"27dB": MagnTarget.MAGN_TARGET_27DB,
"30dB": MagnTarget.MAGN_TARGET_30DB,
"33dB": MagnTarget.MAGN_TARGET_33DB,
"36dB": MagnTarget.MAGN_TARGET_36DB,
"38dB": MagnTarget.MAGN_TARGET_38DB,
"40dB": MagnTarget.MAGN_TARGET_40DB,
"42dB": MagnTarget.MAGN_TARGET_42DB,
}
MaxLnaGain = ns.enum("MaxLnaGain", True)
MAX_LNA_GAIN = {
"Default": MaxLnaGain.MAX_LNA_GAIN_DEFAULT,
"2.6dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_2P6DB,
"6.1dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_6P1DB,
"7.4dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_7P4DB,
"9.2dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_9P2DB,
"11.5dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_11P5DB,
"14.6dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_14P6DB,
"17.1dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_17P1DB,
}
MaxDvgaGain = ns.enum("MaxDvgaGain", True)
MAX_DVGA_GAIN = {
"Default": MaxDvgaGain.MAX_DVGA_GAIN_DEFAULT,
"-1": MaxDvgaGain.MAX_DVGA_GAIN_MINUS_1,
"-2": MaxDvgaGain.MAX_DVGA_GAIN_MINUS_2,
"-3": MaxDvgaGain.MAX_DVGA_GAIN_MINUS_3,
}
CarrierSenseRelThr = ns.enum("CarrierSenseRelThr", True)
CARRIER_SENSE_REL_THR = {
"Default": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_DEFAULT,
"+6dB": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_PLUS_6DB,
"+10dB": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_PLUS_10DB,
"+14dB": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_PLUS_14DB,
}
FilterLengthFskMsk = ns.enum("FilterLengthFskMsk", True)
FILTER_LENGTH_FSK_MSK = {
"8": FilterLengthFskMsk.FILTER_LENGTH_8,
"16": FilterLengthFskMsk.FILTER_LENGTH_16,
"32": FilterLengthFskMsk.FILTER_LENGTH_32,
"64": FilterLengthFskMsk.FILTER_LENGTH_64,
}
FilterLengthAskOok = ns.enum("FilterLengthAskOok", True)
FILTER_LENGTH_ASK_OOK = {
"4dB": FilterLengthAskOok.FILTER_LENGTH_4DB,
"8dB": FilterLengthAskOok.FILTER_LENGTH_8DB,
"12dB": FilterLengthAskOok.FILTER_LENGTH_12DB,
"16dB": FilterLengthAskOok.FILTER_LENGTH_16DB,
}
Freeze = ns.enum("Freeze", True)
FREEZE = {
"Default": Freeze.AGC_FREEZE_DEFAULT,
"On Sync": Freeze.AGC_FREEZE_ON_SYNC,
"Analog Only": Freeze.AGC_FREEZE_ANALOG_ONLY,
"Analog And Digital": Freeze.AGC_FREEZE_ANALOG_AND_DIGITAL,
}
WaitTime = ns.enum("WaitTime", True)
WAIT_TIME = {
"8": WaitTime.WAIT_TIME_8_SAMPLES,
"16": WaitTime.WAIT_TIME_16_SAMPLES,
"24": WaitTime.WAIT_TIME_24_SAMPLES,
"32": WaitTime.WAIT_TIME_32_SAMPLES,
}
HystLevel = ns.enum("HystLevel", True)
HYST_LEVEL = {
"None": HystLevel.HYST_LEVEL_NONE,
"Low": HystLevel.HYST_LEVEL_LOW,
"Medium": HystLevel.HYST_LEVEL_MEDIUM,
"High": HystLevel.HYST_LEVEL_HIGH,
}
TYPES = {
None: {
CONF_OUTPUT_POWER: [cv.float_range(-70, 11)],
CONF_RX_ATTENUATION: [cv.enum(RX_ATTENUATION)],
CONF_DC_BLOCKING_FILTER: [cv.boolean],
},
CONF_TUNER: {
CONF_FREQUENCY: [cv.float_range(300000, 928000)],
CONF_IF_FREQUENCY: [cv.float_range(25, 788)],
CONF_BANDWIDTH: [cv.float_range(58, 812)],
CONF_CHANNEL: [cv.uint8_t],
CONF_CHANNEL_SPACING: [cv.float_range(25, 405)],
CONF_FSK_DEVIATION: [cv.float_range(1.5, 381)],
CONF_MSK_DEVIATION: [cv.int_range(1, 8)],
CONF_SYMBOL_RATE: [cv.float_range(600, 500000)],
CONF_SYNC_MODE: [cv.enum(SYNC_MODE)],
CONF_CARRIER_SENSE_ABOVE_THRESHOLD: [cv.boolean],
CONF_MODULATION: [cv.enum(MODULATION)],
},
CONF_AGC: {
CONF_MAGN_TARGET: [cv.enum(MAGN_TARGET)],
CONF_MAX_LNA_GAIN: [cv.enum(MAX_LNA_GAIN)],
CONF_MAX_DVGA_GAIN: [cv.enum(MAX_DVGA_GAIN)],
CONF_CARRIER_SENSE_ABS_THR: [cv.int_range(-8, 7)],
CONF_CARRIER_SENSE_REL_THR: [cv.enum(CARRIER_SENSE_REL_THR)],
CONF_LNA_PRIORITY: [cv.boolean],
CONF_FILTER_LENGTH_FSK_MSK: [cv.enum(FILTER_LENGTH_FSK_MSK)],
CONF_FILTER_LENGTH_ASK_OOK: [cv.enum(FILTER_LENGTH_ASK_OOK)],
CONF_FREEZE: [cv.enum(FREEZE)],
CONF_WAIT_TIME: [cv.enum(WAIT_TIME)],
CONF_HYST_LEVEL: [cv.enum(HYST_LEVEL)],
},
CONF_SENSOR: {
CONF_CHIP_ID: [
text_sensor.text_sensor_schema(
# unit_of_measurement=UNIT_,
# accuracy_decimals=3,
# device_class=DEVICE_CLASS_,
# state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_CHIP,
),
"text_sensor",
],
CONF_RSSI: [
sensor.sensor_schema(
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
# icon=ICON_CHIP,
),
"sensor",
],
CONF_LQI: [
sensor.sensor_schema(
unit_of_measurement=UNIT_EMPTY,
accuracy_decimals=0,
# device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
# icon=ICON_CHIP,
),
"sensor",
],
CONF_TEMPERATURE: [
sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
# icon=ICON_CHIP,
),
"sensor",
],
},
}
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(CC1101Component),
cv.Optional(CONF_GDO0_PIN): cv.All(pins.internal_gpio_output_pin_schema),
cv.Optional(CONF_GDO0_ADC_ID): cv.use_id(voltage_sampler.VoltageSampler),
}
)
.extend(
{cv.Optional(k): v[0] for k, v in TYPES[None].items()},
{
cv.Optional(CONF_TUNER): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_TUNER].items()}
),
cv.Optional(CONF_AGC): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_AGC].items()}
),
cv.Optional(CONF_SENSOR): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_SENSOR].items()}
),
},
)
.extend(cv.polling_component_schema("60s"))
.extend(spi.spi_device_schema(cs_pin_required=True))
)
CC1101_COMPONENT_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_CC1101_ID): cv.use_id(CC1101Component),
}
)
async def for_each_conf(config, types, callback):
for section in types:
if section is not None and section not in config:
continue
c = config[section] if section is not None else config
for type, args in types[section].items():
if type not in c:
continue
setter = "set_"
if section is not None and section != CONF_SENSOR:
setter += section + "_"
setter += type
# print(setter + "(" + repr(c[type]) + ")")
await callback(c[type], args[1:], setter)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await spi.register_spi_device(var, config)
if CONF_GDO0_PIN in config:
gdo0_pin = await cg.gpio_pin_expression(config[CONF_GDO0_PIN])
cg.add(var.set_config_gdo0_pin(gdo0_pin))
if CONF_GDO0_ADC_ID in config:
gdo0_adc_id = await cg.get_variable(config[CONF_GDO0_ADC_ID])
cg.add(var.set_config_gdo0_adc_pin(gdo0_adc_id))
async def set_var(c, args, setter):
if len(args) > 0:
s = None
if args[0] == "sensor":
s = await sensor.new_sensor(c)
elif args[0] == "binary_sensor":
s = await binary_sensor.new_binary_sensor(c)
elif args[0] == "text_sensor":
s = await text_sensor.new_text_sensor(c)
if s is not None:
cg.add(getattr(var, setter + "_" + args[0])(s))
else:
cg.add(getattr(var, setter)(c))
await for_each_conf(config, TYPES, set_var)
BeginTxAction = ns.class_("BeginTxAction", automation.Action)
EndTxAction = ns.class_("EndTxAction", automation.Action)
CC1101_ACTION_SCHEMA = maybe_simple_id(
{
cv.GenerateID(CONF_ID): cv.use_id(CC1101Component),
}
)
@automation.register_action("cc1101.begin_tx", BeginTxAction, CC1101_ACTION_SCHEMA)
@automation.register_action("cc1101.end_tx", EndTxAction, CC1101_ACTION_SCHEMA)
async def cc1101_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
CC1101RawAction = ns.class_("CC1101RawAction", remote_base.RCSwitchRawAction)
CC1101_TRANSMIT_SCHEMA = (
cv.Schema(
{
cv.GenerateID(CONF_CC1101_ID): cv.use_id(CC1101Component),
}
)
.extend(remote_base.REMOTE_TRANSMITTABLE_SCHEMA)
.extend(remote_base.RC_SWITCH_RAW_SCHEMA)
.extend(remote_base.RC_SWITCH_TRANSMITTER)
)
@remote_base.register_action(
"rc_switch_raw_cc1101", CC1101RawAction, CC1101_TRANSMIT_SCHEMA
)
async def rc_switch_raw_cc1101_action(var, config, args):
proto = await cg.templatable(
config[CONF_PROTOCOL],
args,
remote_base.RCSwitchBase,
to_exp=remote_base.build_rc_switch_protocol,
)
cg.add(var.set_protocol(proto))
cg.add(var.set_code(await cg.templatable(config[CONF_CODE], args, cg.std_string)))
await cg.register_parented(var, config[CONF_CC1101_ID])
File diff suppressed because it is too large Load Diff
-125
View File
@@ -1,125 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/spi/spi.h"
#include "esphome/components/remote_base/rc_switch_protocol.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/text_sensor/text_sensor.h"
#include "esphome/components/number/number.h"
#include "esphome/components/switch/switch.h"
#include "esphome/components/select/select.h"
#include "esphome/components/text/text.h"
#include <string>
#include "cc1101defs.h"
#include "cc1101sub.h"
namespace esphome {
namespace cc1101 {
class CC1101Component : public PollingComponent,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1KHZ> {
public:
CC1101Component();
void set_config_gdo0_pin(InternalGPIOPin *pin) { gdo0_ = pin; }
void set_config_gdo0_adc_pin(voltage_sampler::VoltageSampler *pin) { gdo0_adc_ = pin; }
void setup() override;
void dump_config() override;
void update() override;
void loop() override;
void begin_tx();
void end_tx();
CC1101_SUB_NUMBER(output_power, float)
CC1101_SUB_SELECT(rx_attenuation, RxAttenuation)
CC1101_SUB_SWITCH(dc_blocking_filter)
// TODO: CC1101_SUB_SWITCH(manchester)
CC1101_SUB_NUMBER(tuner_frequency, float)
CC1101_SUB_NUMBER(tuner_if_frequency, float)
CC1101_SUB_NUMBER(tuner_bandwidth, float)
CC1101_SUB_NUMBER(tuner_channel, uint8_t)
CC1101_SUB_NUMBER(tuner_channel_spacing, float)
CC1101_SUB_NUMBER(tuner_fsk_deviation, float)
CC1101_SUB_NUMBER(tuner_msk_deviation, uint8_t)
CC1101_SUB_NUMBER(tuner_symbol_rate, float)
CC1101_SUB_SELECT(tuner_sync_mode, SyncMode)
CC1101_SUB_SWITCH(tuner_carrier_sense_above_threshold)
CC1101_SUB_SELECT(tuner_modulation, Modulation)
CC1101_SUB_SELECT(agc_magn_target, MagnTarget)
CC1101_SUB_SELECT(agc_max_lna_gain, MaxLnaGain)
CC1101_SUB_SELECT(agc_max_dvga_gain, MaxDvgaGain)
CC1101_SUB_NUMBER(agc_carrier_sense_abs_thr, int8_t)
CC1101_SUB_SELECT(agc_carrier_sense_rel_thr, CarrierSenseRelThr)
CC1101_SUB_SWITCH(agc_lna_priority)
CC1101_SUB_SELECT(agc_filter_length_fsk_msk, FilterLengthFskMsk)
CC1101_SUB_SELECT(agc_filter_length_ask_ook, FilterLengthAskOok)
CC1101_SUB_SELECT(agc_freeze, Freeze)
CC1101_SUB_SELECT(agc_wait_time, WaitTime)
CC1101_SUB_SELECT(agc_hyst_level, HystLevel)
CC1101_SUB_TEXT_SENSOR(chip_id)
// TODO: PARTNUM
// TODO: VERSION
CC1101_SUB_SENSOR(rssi)
CC1101_SUB_SENSOR(lqi)
// TODO: CRC OK
CC1101_SUB_SENSOR(temperature)
protected:
InternalGPIOPin *gdo0_;
voltage_sampler::VoltageSampler *gdo0_adc_;
std::string chip_id_;
bool reset_;
float output_power_requested_;
float output_power_effective_;
uint8_t pa_table_[8];
union {
struct CC1101State state_;
uint8_t regs_[sizeof(struct CC1101State) / sizeof(uint8_t)];
};
void strobe_(Command cmd);
void write_(Register reg);
void write_(Register reg, uint8_t value);
void write_(Register reg, uint8_t *buffer, size_t length);
bool read_(Register reg);
bool read_(Register reg, uint8_t *buffer, size_t length);
// bool send_data_(const uint8_t* data, size_t length);
void send_(Command cmd);
bool wait_(Command cmd);
template<class S, class T> void publish_(S *s, T state);
// template specialization here in the header is not supported by the compiler
void publish_switch_(switch_::Switch *s, bool state);
void publish_select_(select::Select *s, size_t index);
};
template<typename... Ts> class BeginTxAction : public Action<Ts...>, public Parented<CC1101Component> {
public:
void play(Ts... x) override { this->parent_->begin_tx(); }
};
template<typename... Ts> class EndTxAction : public Action<Ts...>, public Parented<CC1101Component> {
public:
void play(Ts... x) override { this->parent_->end_tx(); }
};
template<typename... Ts>
class CC1101RawAction : public remote_base::RCSwitchRawAction<Ts...>, public Parented<CC1101Component> {
protected:
void play(Ts... x) override {
this->parent_->begin_tx();
remote_base::RCSwitchRawAction<Ts...>::play(x...);
this->parent_->end_tx();
}
public:
};
} // namespace cc1101
} // namespace esphome
-693
View File
@@ -1,693 +0,0 @@
#pragma once
#include <cinttypes>
namespace esphome {
namespace cc1101 {
static constexpr float XTAL_FREQUENCY = 26000;
static constexpr float OUTPUT_POWER_MIN = -30;
static constexpr float OUTPUT_POWER_MAX = 11;
static constexpr float FREQUENCY_MIN = 300000;
static constexpr float FREQUENCY_MAX = 928000;
static constexpr float IF_FREQUENCY_MIN = 25;
static constexpr float IF_FREQUENCY_MAX = 788;
static constexpr float BANDWIDTH_MIN = 58;
static constexpr float BANDWIDTH_MAX = 812;
static constexpr uint8_t CHANNEL_MIN = 0;
static constexpr uint8_t CHANNEL_MAX = 255;
static constexpr float CHANNEL_SPACING_MIN = 25;
static constexpr float CHANNEL_SPACING_MAX = 405;
static constexpr float FSK_DEVIATION_MIN = 1.5f;
static constexpr float FSK_DEVIATION_MAX = 381;
static constexpr uint8_t MSK_DEVIATION_MIN = 1;
static constexpr uint8_t MSK_DEVIATION_MAX = 8;
static constexpr float SYMBOL_RATE_MIN = 600;
static constexpr float SYMBOL_RATE_MAX = 500000;
static constexpr int8_t CARRIER_SENSE_ABS_THR_MIN = -8;
static constexpr int8_t CARRIER_SENSE_ABS_THR_MAX = 7;
static constexpr uint8_t BUS_BURST = 0x40;
static constexpr uint8_t BUS_READ = 0x80;
static constexpr uint8_t BUS_WRITE = 0x00;
static constexpr uint8_t BYTES_IN_RXFIFO = 0x7F; // byte number in RXfifo
enum class Register : uint8_t {
IOCFG2, // GDO2 output pin configuration
IOCFG1, // GDO1 output pin configuration
IOCFG0, // GDO0 output pin configuration
FIFOTHR, // RX FIFO and TX FIFO thresholds
SYNC1, // Sync word, high INT8U
SYNC0, // Sync word, low INT8U
PKTLEN, // Packet length
PKTCTRL1, // Packet automation control
PKTCTRL0, // Packet automation control
ADDR, // Device address
CHANNR, // Channel number
FSCTRL1, // Frequency synthesizer control
FSCTRL0, // Frequency synthesizer control
FREQ2, // Frequency control word, high INT8U
FREQ1, // Frequency control word, middle INT8U
FREQ0, // Frequency control word, low INT8U
MDMCFG4, // Modem configuration
MDMCFG3, // Modem configuration
MDMCFG2, // Modem configuration
MDMCFG1, // Modem configuration
MDMCFG0, // Modem configuration
DEVIATN, // Modem deviation setting
MCSM2, // Main Radio Control State Machine configuration
MCSM1, // Main Radio Control State Machine configuration
MCSM0, // Main Radio Control State Machine configuration
FOCCFG, // Frequency Offset Compensation configuration
BSCFG, // Bit Synchronization configuration
AGCCTRL2, // AGC control
AGCCTRL1, // AGC control
AGCCTRL0, // AGC control
WOREVT1, // High INT8U Event 0 timeout
WOREVT0, // Low INT8U Event 0 timeout
WORCTRL, // Wake On Radio control
FREND1, // Front end RX configuration
FREND0, // Front end TX configuration
FSCAL3, // Frequency synthesizer calibration
FSCAL2, // Frequency synthesizer calibration
FSCAL1, // Frequency synthesizer calibration
FSCAL0, // Frequency synthesizer calibration
RCCTRL1, // RC oscillator configuration
RCCTRL0, // RC oscillator configuration
FSTEST, // Frequency synthesizer calibration control
PTEST, // Production test
AGCTEST, // AGC test
TEST2, // Various test settings
TEST1, // Various test settings
TEST0, // Various test settings
UNUSED,
PARTNUM,
VERSION,
FREQEST,
LQI,
RSSI,
MARCSTATE,
WORTIME1,
WORTIME0,
PKTSTATUS,
VCO_VC_DAC,
TXBYTES,
RXBYTES,
RCCTRL1_STATUS,
RCCTRL0_STATUS,
PATABLE,
FIFO,
};
enum class Command : uint8_t {
RES = 0x30, // Reset chip.
FSTXON, // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
// If in RX/TX: Go to a wait state where only the synthesizer is
// running (for quick RX / TX turnaround).
XOFF, // Turn off crystal oscillator.
CAL, // Calibrate frequency synthesizer and turn it off
// (enables quick start).
RX, // Enable RX. Perform calibration first if coming from IDLE and
// MCSM0.FS_AUTOCAL=1.
TX, // In IDLE state: Enable TX. Perform calibration first if
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
// Only go to TX if channel is clear.
IDLE, // Exit RX / TX, turn off frequency synthesizer and exit
// Wake-On-Radio mode if applicable.
AFC, // Perform AFC adjustment of the frequency synthesizer
WOR, // Start automatic RX polling sequence (Wake-on-Radio)
PWD, // Enter power down mode when CSn goes high.
FRX, // Flush the RX FIFO buffer.
FTX, // Flush the TX FIFO buffer.
WORRST, // Reset real time clock.
NOP, // No operation. May be used to pad strobe commands to two
// INT8Us for simpler software.
};
enum class State : uint8_t {
SLEEP,
IDLE,
XOFF,
VCOON_MC,
REGON_MC,
MANCAL,
VCOON,
REGON,
STARTCAL,
BWBOOST,
FS_LOCK,
IFADCON,
ENDCAL,
RX,
RX_END,
RX_RST,
TXRX_SWITCH,
RXFIFO_OVERFLOW,
FSTXON,
TX,
TX_END,
RXTX_SWITCH,
TXFIFO_UNDERFLOW,
};
enum class RxAttenuation : uint8_t {
RX_ATTENUATION_0DB,
RX_ATTENUATION_6DB,
RX_ATTENUATION_12DB,
RX_ATTENUATION_18DB,
LAST,
};
// MDMCFG2
enum class SyncMode : uint8_t {
SYNC_MODE_NONE,
SYNC_MODE_15_16,
SYNC_MODE_16_16,
SYNC_MODE_30_32,
LAST,
};
enum class Modulation : uint8_t {
MODULATION_2_FSK,
MODULATION_GFSK,
MODULATION_UNUSED_2,
MODULATION_ASK_OOK,
MODULATION_4_FSK,
MODULATION_UNUSED_5,
MODULATION_UNUSED_6,
MODULATION_MSK,
LAST,
};
// AGCCTRL2
enum class MagnTarget : uint8_t {
MAGN_TARGET_24DB,
MAGN_TARGET_27DB,
MAGN_TARGET_30DB,
MAGN_TARGET_33DB,
MAGN_TARGET_36DB,
MAGN_TARGET_38DB,
MAGN_TARGET_40DB,
MAGN_TARGET_42DB,
LAST,
};
enum class MaxLnaGain : uint8_t {
MAX_LNA_GAIN_DEFAULT,
MAX_LNA_GAIN_MINUS_2P6DB,
MAX_LNA_GAIN_MINUS_6P1DB,
MAX_LNA_GAIN_MINUS_7P4DB,
MAX_LNA_GAIN_MINUS_9P2DB,
MAX_LNA_GAIN_MINUS_11P5DB,
MAX_LNA_GAIN_MINUS_14P6DB,
MAX_LNA_GAIN_MINUS_17P1DB,
LAST,
};
enum class MaxDvgaGain : uint8_t {
MAX_DVGA_GAIN_DEFAULT,
MAX_DVGA_GAIN_MINUS_1,
MAX_DVGA_GAIN_MINUS_2,
MAX_DVGA_GAIN_MINUS_3,
LAST,
};
// AGCCTRL1
// CARRIER_SENSE_ABS_THR => number -7..+7, -8 is disabled
enum class CarrierSenseRelThr : uint8_t {
CARRIER_SENSE_REL_THR_DEFAULT,
CARRIER_SENSE_REL_THR_PLUS_6DB,
CARRIER_SENSE_REL_THR_PLUS_10DB,
CARRIER_SENSE_REL_THR_PLUS_14DB,
LAST,
};
// AGC_LNA_PRIORITY => switch
// AGCCTRL0
enum class FilterLengthFskMsk : uint8_t {
FILTER_LENGTH_8DB,
FILTER_LENGTH_16DB,
FILTER_LENGTH_32DB,
FILTER_LENGTH_64DB,
LAST,
};
enum class FilterLengthAskOok : uint8_t {
FILTER_LENGTH_4DB,
FILTER_LENGTH_8DB,
FILTER_LENGTH_12DB,
FILTER_LENGTH_16DB,
LAST,
};
enum class Freeze : uint8_t {
FREEZE_DEFAULT,
FREEZE_ON_SYNC,
FREEZE_ANALOG_ONLY,
FREEZE_ANALOG_AND_DIGITAL,
LAST,
};
enum class WaitTime : uint8_t {
WAIT_TIME_8_SAMPLES,
WAIT_TIME_16_SAMPLES,
WAIT_TIME_24_SAMPLES,
WAIT_TIME_32_SAMPLES,
LAST,
};
enum class HystLevel : uint8_t {
HYST_LEVEL_NONE,
HYST_LEVEL_LOW,
HYST_LEVEL_MEDIUM,
HYST_LEVEL_HIGH,
LAST,
};
//
struct CC1101State {
// 0x00
union {
uint8_t IOCFG2;
struct {
uint8_t GDO2_CFG : 6;
uint8_t GDO2_INV : 1;
uint8_t : 1;
};
};
// 0x01
union {
uint8_t IOCFG1;
struct {
uint8_t GDO1_CFG : 6;
uint8_t GDO1_INV : 1;
uint8_t GDO_DS : 1; // GDO, not GD0
};
};
// 0x02
union {
uint8_t IOCFG0;
struct {
uint8_t GDO0_CFG : 6;
uint8_t GDO0_INV : 1;
uint8_t TEMP_SENSOR_ENABLE : 1;
};
};
// 0x03
union {
uint8_t FIFOTHR;
struct {
uint8_t FIFO_THR : 4;
uint8_t CLOSE_IN_RX : 2; // RxAttenuation
uint8_t ADC_RETENTION : 1;
uint8_t : 1;
};
};
// 0x04
uint8_t SYNC1;
// 0x05
uint8_t SYNC0;
// 0x06
uint8_t PKTLEN;
// 0x07
union {
uint8_t PKTCTRL1;
struct {
uint8_t ADR_CHK : 2;
uint8_t APPEND_STATUS : 1;
uint8_t CRC_AUTOFLUSH : 1;
uint8_t : 1;
uint8_t PQT : 3;
};
};
// 0x08
union {
uint8_t PKTCTRL0;
struct {
uint8_t LENGTH_CONFIG : 2;
uint8_t CRC_EN : 1;
uint8_t : 1;
uint8_t PKT_FORMAT : 2;
uint8_t WHITE_DATA : 1;
uint8_t : 1;
};
};
// 0x09
uint8_t ADDR;
// 0x0A
uint8_t CHANNR;
// 0x0B
union {
uint8_t FSCTRL1;
struct {
uint8_t FREQ_IF : 5;
uint8_t RESERVED : 1; // hm?
uint8_t : 2;
};
};
// 0x0C
uint8_t FSCTRL0;
// 0x0D
uint8_t FREQ2; // [7:6] always zero
// 0x0E
uint8_t FREQ1;
// 0x0F
uint8_t FREQ0;
// 0x10
union {
uint8_t MDMCFG4;
struct {
uint8_t DRATE_E : 4;
uint8_t CHANBW_M : 2;
uint8_t CHANBW_E : 2;
};
};
// 0x11
union {
uint8_t MDMCFG3;
struct {
uint8_t DRATE_M : 8;
};
};
// 0x12
union {
uint8_t MDMCFG2;
struct {
uint8_t SYNC_MODE : 2;
uint8_t CARRIER_SENSE_ABOVE_THRESHOLD : 1;
uint8_t MANCHESTER_EN : 1;
uint8_t MOD_FORMAT : 3; // Modulation
uint8_t DEM_DCFILT_OFF : 1;
};
};
// 0x13
union {
uint8_t MDMCFG1;
struct {
uint8_t CHANSPC_E : 2;
uint8_t : 2;
uint8_t NUM_PREAMBLE : 3;
uint8_t FEC_EN : 1;
};
};
// 0x14
union {
uint8_t MDMCFG0;
struct {
uint8_t CHANSPC_M : 8;
};
};
// 0x15
union {
uint8_t DEVIATN;
struct {
uint8_t DEVIATION_M : 3;
uint8_t : 1;
uint8_t DEVIATION_E : 3;
uint8_t : 1;
};
};
// 0x16
union {
uint8_t MCSM2;
struct {
uint8_t RX_TIME : 3;
uint8_t RX_TIME_QUAL : 1;
uint8_t RX_TIME_RSSI : 1;
uint8_t : 3;
};
};
// 0x17
union {
uint8_t MCSM1;
struct {
uint8_t TXOFF_MODE : 2;
uint8_t RXOFF_MODE : 2;
uint8_t CCA_MODE : 2;
uint8_t : 2;
};
};
// 0x18
union {
uint8_t MCSM0;
struct {
uint8_t XOSC_FORCE_ON : 1;
uint8_t PIN_CTRL_EN : 1;
uint8_t PO_TIMEOUT : 2;
uint8_t FS_AUTOCAL : 2;
uint8_t : 2;
};
};
// 0x19
union {
uint8_t FOCCFG;
struct {
uint8_t FOC_LIMIT : 2;
uint8_t FOC_POST_K : 1;
uint8_t FOC_PRE_K : 2;
uint8_t FOC_BS_CS_GATE : 1;
uint8_t : 2;
};
};
// 0x1A
union {
uint8_t BSCFG;
struct {
uint8_t BS_LIMIT : 2;
uint8_t BS_POST_KP : 1;
uint8_t BS_POST_KI : 1;
uint8_t BS_PRE_KP : 2;
uint8_t BS_PRE_KI : 2;
};
};
// 0x1B
union {
uint8_t AGCCTRL2;
struct {
uint8_t MAGN_TARGET : 3; // MagnTarget
uint8_t MAX_LNA_GAIN : 3; // MaxLnaGain
uint8_t MAX_DVGA_GAIN : 2; // MaxDvgaGain
};
};
// 0x1C
union {
uint8_t AGCCTRL1;
struct {
uint8_t CARRIER_SENSE_ABS_THR : 4;
uint8_t CARRIER_SENSE_REL_THR : 2; // CarrierSenseRelThr
uint8_t AGC_LNA_PRIORITY : 1;
uint8_t : 1;
};
};
// 0x1D
union {
uint8_t AGCCTRL0;
struct {
uint8_t FILTER_LENGTH : 2; // FilterLengthFskMsk or FilterLengthAskOok
uint8_t AGC_FREEZE : 2; // Freeze
uint8_t WAIT_TIME : 2; // WaitTime
uint8_t HYST_LEVEL : 2; // HystLevel
};
};
// 0x1E
uint8_t WOREVT1;
// 0x1F
uint8_t WOREVT0;
// 0x20
union {
uint8_t WORCTRL;
struct {
uint8_t WOR_RES : 2;
uint8_t : 1;
uint8_t RC_CAL : 1;
uint8_t EVENT1 : 3;
uint8_t RC_PD : 1;
};
};
// 0x21
union {
uint8_t FREND1;
struct {
uint8_t MIX_CURRENT : 2;
uint8_t LODIV_BUF_CURRENT_RX : 2;
uint8_t LNA2MIX_CURRENT : 2;
uint8_t LNA_CURRENT : 2;
};
};
// 0x22
union {
uint8_t FREND0;
struct {
uint8_t PA_POWER : 3;
uint8_t : 1;
uint8_t LODIV_BUF_CURRENT_TX : 2;
uint8_t : 2;
};
};
// 0x23
union {
uint8_t FSCAL3;
struct {
uint8_t FSCAL3_LO : 4;
uint8_t CHP_CURR_CAL_EN : 2; // Disable charge pump calibration stage when 0.
uint8_t FSCAL3_HI : 2;
};
};
// 0x24
union {
// uint8_t FSCAL2;
struct {
uint8_t FSCAL2 : 5;
uint8_t VCO_CORE_H_EN : 1;
uint8_t : 2;
};
};
// 0x25
union {
// uint8_t FSCAL1;
struct {
uint8_t FSCAL1 : 6;
uint8_t : 2;
};
};
// 0x26
union {
// uint8_t FSCAL0;
struct {
uint8_t FSCAL0 : 7;
uint8_t : 1;
};
};
// 0x27
union {
// uint8_t RCCTRL1;
struct {
uint8_t RCCTRL1 : 7;
uint8_t : 1;
};
};
// 0x28
union {
// uint8_t RCCTRL0;
struct {
uint8_t RCCTRL0 : 7;
uint8_t : 1;
};
};
// 0x29
uint8_t FSTEST;
// 0x2A
uint8_t PTEST;
// 0x2B
uint8_t AGCTEST;
// 0x2C
uint8_t TEST2;
// 0x2D
uint8_t TEST1;
// 0x2E
union {
uint8_t TEST0;
struct {
uint8_t TEST0_LO : 1;
uint8_t VCO_SEL_CAL_EN : 1; // Enable VCO selection calibration stage when 1
uint8_t TEST0_HI : 6;
};
};
// 0x2F
uint8_t REG_2F;
// 0x30
uint8_t PARTNUM;
// 0x31
uint8_t VERSION;
// 0x32
union {
uint8_t FREQEST;
struct {
int8_t FREQOFF_EST : 8;
};
};
// 0x33
union {
uint8_t LQI;
struct {
uint8_t LQI_EST : 7;
uint8_t LQI_CRC_OK : 1;
};
};
// 0x34
int8_t RSSI;
// 0x35
union {
// uint8_t MARCSTATE;
struct {
uint8_t MARC_STATE : 5; // State
uint8_t : 3;
};
};
// 0x36
uint8_t WORTIME1;
// 0x37
uint8_t WORTIME0;
// 0x38
union {
uint8_t PKTSTATUS;
struct {
uint8_t GDO0 : 1;
uint8_t : 1;
uint8_t GDO2 : 1;
uint8_t SFD : 1;
uint8_t CCA : 1;
uint8_t PQT_REACHED : 1;
uint8_t CS : 1;
uint8_t CRC_OK : 1; // same as LQI_CRC_OK?
};
};
// 0x39
uint8_t VCO_VC_DAC;
// 0x3A
union {
uint8_t TXBYTES;
struct {
uint8_t NUM_TXBYTES : 7;
uint8_t TXFIFO_UNDERFLOW : 1;
};
};
// 0x3B
union {
uint8_t RXBYTES;
struct {
uint8_t NUM_RXBYTES : 7;
uint8_t RXFIFO_OVERFLOW : 1;
};
};
// 0x3C
union {
// uint8_t RCCTRL1_STATUS;
struct {
uint8_t RCCTRL1_STATUS : 7;
uint8_t : 1;
};
};
// 0x3D
union {
// uint8_t RCCTRL0_STATUS;
struct {
uint8_t RCCTRL0_STATUS : 7;
uint8_t : 1;
};
};
// 0x3E
uint8_t REG_3E;
// 0x3F
uint8_t REG_3F;
};
} // namespace cc1101
} // namespace esphome
-684
View File
@@ -1,684 +0,0 @@
#pragma once
#include <cinttypes>
#include <cmath>
#include <cstdio>
namespace esphome {
namespace cc1101 {
// CC1101 Design Note DN013
// The typical CC1101 output power levels and current consumption for the different PATABLE
// register settings are given in Table 1for 315 MHz, in Table 2 for 433 MHz, in Table 3 for 868
// MHz, and in Table 4 for 915 MHz. It is however not recommended to use the PATABLE
// register settings from 0x61 to 0x6F for CC1101.
struct PowerTableItem {
uint8_t value;
uint8_t dbm_diff; // starts from 12.0, diff to previous entry, scaled by 10
};
struct PowerTable {
public:
static float find(const PowerTableItem *items, size_t count, float &dbm_target) {
int dbmi = 120;
int dbmi_target = (int) std::lround(dbm_target * 10);
for (size_t i = 0; i < count; i++) {
dbmi -= items[i].dbm_diff;
if (dbmi_target >= dbmi) {
if (items[i].value >= 0x61 && items[i].value <= 0x6F)
continue; // see note in the commend above
dbm_target = (float) dbmi / 10;
return items[i].value;
}
}
dbm_target = -30;
return 0x03;
}
};
// filtered tables to save memory
// - at least 1dBm difference
// - 0x61 - 0x6F removed
// - no values below -30dBm
static const PowerTableItem PA_TABLE_315[] = {
{0xC0, 14}, // C0 10.6 -35.3 -44.4 -57.8 -53.8 -58.3 -57.2 -57.8 -56.7 28.5
{0xC3, 10}, // C3 9.6 -39.2 -45.3 -59.0 -54.2 -59.0 -57.5 -58.3 -57.2 26.2
{0xC6, 11}, // C6 8.5 -43.2 -46.3 -59.2 -54.7 -59.1 -57.7 -58.3 -57.4 24.4
{0xC9, 10}, // C9 7.5 -47.0 -47.3 -58.9 -55.0 -59.0 -57.9 -58.4 -57.5 23.0
{0x81, 12}, // 81 6.3 -49.2 -45.7 -57.3 -53.6 -59.0 -56.0 -56.5 -57.5 19.5
{0x85, 13}, // 85 5.0 -51.0 -47.2 -59.8 -54.2 -59.0 -56.9 -57.9 -58.0 18.3
{0x88, 11}, // 88 3.9 -46.6 -48.1 -60.0 -55.0 -58.9 -57.5 -58.2 -58.2 17.4
{0xCF, 11}, // CF 2.8 -49.8 -51.3 -57.6 -56.8 -59.1 -58.4 -58.1 -58.3 18.0
{0x8D, 11}, // 8D 1.7 -43.8 -49.5 -58.9 -56.3 -58.8 -58.2 -58.4 -58.5 15.8
{0x50, 10}, // 50 0.7 -59.2 -51.2 -59.0 -56.5 -59.0 -58.3 -58.3 -58.2 15.3
{0x40, 10}, // 40 -0.3 -58.2 -52.1 -59.4 -56.9 -59.0 -58.4 -58.4 -58.3 14.7
{0x3D, 10}, // 3D -1.3 -54.4 -48.4 -59.8 -57.5 -58.9 -58.3 -58.5 -58.5 19.3
{0x55, 10}, // 55 -2.3 -56.7 -53.6 -59.7 -57.5 -59.1 -58.7 -58.4 -58.4 13.7
{0x39, 11}, // 39 -3.4 -50.9 -49.5 -59.8 -58.0 -59.0 -58.5 -58.4 -58.4 16.8
{0x2B, 15}, // 2B -4.9 -51.2 -50.4 -59.9 -58.0 -58.9 -58.7 -58.3 -58.4 15.6
{0x29, 16}, // 29 -6.5 -51.8 -51.6 -59.9 -58.4 -59.0 -58.8 -58.3 -58.3 14.7
{0x28, 10}, // 28 -7.5 -52.2 -52.5 -60.0 -58.6 -59.0 -58.8 -58.2 -58.4 14.3
{0x27, 11}, // 27 -8.6 -52.9 -53.1 -60.0 -58.8 -59.1 -58.8 -58.3 -58.5 13.9
{0x26, 12}, // 26 -9.8 -53.6 -54.3 -60.1 -58.7 -59.0 -58.7 -58.4 -58.4 13.4
{0x25, 13}, // 25 -11.1 -54.3 -55.5 -60.1 -58.8 -59.1 -58.8 -58.4 -58.4 13.0
{0x33, 11}, // 33 -12.2 -55.0 -56.3 -60.0 -58.7 -59.0 -58.9 -58.4 -58.4 12.8
{0x1F, 11}, // 1F -13.3 -55.6 -57.2 -60.0 -58.8 -58.9 -58.9 -58.3 -58.4 12.4
{0x1D, 12}, // 1D -14.5 -56.0 -58.0 -60.0 -58.8 -59.1 -58.7 -58.4 -58.5 12.1
{0x32, 11}, // 32 -15.6 -56.9 -58.8 -59.9 -58.8 -59.0 -58.8 -58.3 -58.5 12.2
{0x1A, 10}, // 1A -16.6 -57.3 -59.5 -59.9 -58.8 -59.1 -58.8 -58.4 -58.4 11.8
{0x18, 19}, // 18 -18.5 -57.8 -60.3 -60.0 -58.8 -59.0 -58.9 -58.2 -58.5 11.6
{0x17, 11}, // 17 -19.6 -58.7 -60.9 -60.0 -58.7 -58.9 -58.9 -58.5 -58.4 11.4
{0x0C, 11}, // C -20.7 -59.4 -61.1 -60.0 -58.8 -59.1 -58.9 -58.4 -58.3 11.3
{0x0A, 15}, // A -22.2 -59.9 -61.9 -60.0 -58.9 -59.0 -58.9 -58.4 -58.5 11.2
{0x08, 18}, // 8 -24.0 -60.5 -62.5 -60.0 -58.7 -59.1 -58.8 -58.3 -58.5 11.1
{0x07, 11}, // 7 -25.1 -61.3 -62.9 -60.1 -58.8 -59.1 -58.8 -58.4 -58.4 11.0
{0x06, 13}, // 6 -26.4 -61.6 -63.2 -60.1 -58.7 -59.0 -58.9 -58.5 -58.5 11.0
{0x05, 13}, // 5 -27.7 -62.3 -63.4 -60.1 -58.7 -59.2 -58.8 -58.4 -58.5 10.9
{0x04, 19}, // 4 -29.6 -62.7 -63.6 -59.9 -58.7 -59.0 -58.9 -58.4 -58.4 10.8
};
static const PowerTableItem PA_TABLE_433[] = {
{0xC0, 21}, // C0 9.9 -43.4 -45.0 -53.9 -55.2 -55.8 -52.3 -55.6 29.1
{0xC3, 11}, // C3 8.8 -49.3 -45.9 -55.9 -55.4 -57.2 -52.6 -57.5 26.9
{0xC6, 10}, // C6 7.8 -56.2 -46.9 -56.9 -55.6 -58.2 -53.2 -57.9 25.2
{0xC9, 10}, // C9 6.8 -56.1 -47.9 -57.3 -55.9 -58.5 -54.0 -56.9 23.8
{0xCC, 10}, // CC 5.8 -52.8 -48.9 -57.0 -56.1 -58.4 -54.6 -56.2 22.6
{0x85, 10}, // 85 4.8 -54.2 -53.0 -58.3 -55.0 -57.8 -56.8 -58.0 19.1
{0x88, 12}, // 88 3.6 -56.2 -53.8 -58.3 -55.7 -58.1 -57.2 -58.2 18.2
{0x8B, 13}, // 8B 2.3 -57.7 -54.5 -58.0 -56.3 -58.1 -57.5 -58.2 17.3
{0x8E, 19}, // 8E 0.4 -58.0 -55.5 -57.8 -57.4 -58.2 -58.1 -58.4 16.2
{0x40, 12}, // 40 -0.8 -59.7 -56.1 -58.2 -57.7 -58.4 -58.3 -58.2 15.4
{0x3C, 13}, // 3C -2.1 -60.6 -57.3 -58.2 -58.0 -58.5 -58.4 -58.5 19.3
{0x3A, 10}, // 3A -3.1 -59.5 -57.5 -58.3 -58.3 -58.6 -58.1 -58.6 18.1
{0x8F, 15}, // 8F -4.6 -52.2 -57.7 -58.1 -58.8 -58.4 -58.7 -58.3 14.4
{0x37, 10}, // 37 -5.6 -56.8 -58.3 -58.3 -58.8 -58.4 -58.5 -58.4 16.2
{0x36, 12}, // 36 -6.8 -56.8 -58.9 -58.3 -58.8 -58.3 -58.5 -58.5 15.6
{0x28, 10}, // 28 -7.8 -56.6 -59.0 -58.2 -59.0 -58.4 -58.5 -58.4 15.1
{0x26, 21}, // 26 -9.9 -57.0 -59.4 -58.3 -59.0 -58.4 -58.7 -58.4 14.3
{0x25, 15}, // 25 -11.4 -57.3 -59.7 -58.4 -59.0 -58.3 -58.7 -58.5 13.9
{0x24, 19}, // 24 -13.3 -57.9 -59.9 -58.2 -59.0 -58.6 -58.7 -58.5 13.5
{0x1E, 10}, // 1E -14.3 -58.4 -59.8 -58.2 -59.0 -58.4 -58.6 -58.6 13.2
{0x1C, 12}, // 1C -15.5 -58.6 -59.9 -58.4 -58.8 -58.6 -58.8 -58.5 12.9
{0x1A, 15}, // 1A -17.0 -59.4 -59.9 -58.3 -59.1 -58.5 -58.7 -58.4 12.7
{0x18, 18}, // 18 -18.8 -60.2 -59.9 -58.2 -59.0 -58.5 -58.7 -58.6 12.5
{0x17, 10}, // 17 -19.8 -60.6 -59.9 -58.2 -58.9 -58.4 -58.7 -58.4 12.4
{0x0C, 12}, // C -21.0 -61.1 -59.9 -58.4 -59.0 -58.5 -58.7 -58.6 12.3
{0x15, 15}, // 15 -22.5 -61.7 -60.0 -58.2 -59.1 -58.3 -58.6 -58.7 12.2
{0x08, 18}, // 8 -24.3 -62.3 -59.9 -58.3 -59.0 -58.4 -58.8 -58.5 12.1
{0x07, 10}, // 7 -25.3 -62.6 -59.9 -58.2 -59.0 -58.6 -58.7 -58.5 12.0
{0x06, 12}, // 6 -26.5 -63.2 -59.9 -58.3 -58.9 -58.5 -58.6 -58.6 12.0
{0x05, 14}, // 5 -27.9 -63.5 -59.8 -58.3 -59.1 -58.5 -58.7 -58.4 11.9
{0x04, 16}, // 4 -29.5 -63.7 -59.9 -58.3 -58.9 -58.5 -58.5 -58.5 11.9
};
static const PowerTableItem PA_TABLE_868[] = {
{0xC0, 13}, // C0 10.7 -35.1 -58.6 -58.6 -57.5 -50.0 34.2
{0xC3, 11}, // C3 9.6 -41.5 -58.5 -58.3 -57.4 -54.4 31.6
{0xC6, 11}, // C6 8.5 -47.7 -58.5 -58.3 -57.6 -55.0 29.5
{0xC9, 10}, // C9 7.5 -44.4 -58.5 -58.5 -57.7 -53.6 27.8
{0xCC, 10}, // CC 6.5 -40.6 -58.6 -58.4 -57.6 -52.5 26.3
{0xCE, 10}, // CE 5.5 -38.5 -58.5 -58.4 -57.8 -52.2 25.0
{0x84, 11}, // 84 4.4 -35.3 -58.7 -58.5 -57.8 -55.8 20.3
{0x87, 10}, // 87 3.4 -39.4 -58.6 -58.6 -57.8 -55.7 19.5
{0xCF, 10}, // CF 2.4 -36.6 -58.6 -58.4 -57.7 -53.6 22.0
{0x8C, 13}, // 8C 1.1 -50.2 -58.6 -58.5 -57.7 -55.9 17.9
{0x50, 14}, // 50 -0.3 -42.1 -58.5 -58.5 -57.6 -57.1 16.9
{0x40, 12}, // 40 -1.5 -43.2 -58.5 -58.7 -57.7 -57.2 16.1
{0x3F, 11}, // 3F -2.6 -53.7 -58.6 -58.5 -57.8 -57.5 21.4
{0x55, 10}, // 55 -3.6 -44.9 -58.6 -58.4 -57.8 -57.5 15.0
{0x57, 12}, // 57 -4.8 -46.0 -58.6 -58.5 -57.6 -57.4 14.5
{0x8F, 12}, // 8F -6.0 -51.6 -58.5 -58.6 -57.7 -57.1 15.0
{0x2A, 14}, // 2A -7.4 -49.3 -58.5 -58.6 -57.7 -57.4 16.2
{0x28, 16}, // 28 -9.0 -49.0 -58.5 -58.6 -57.7 -57.4 15.4
{0x26, 20}, // 26 -11.0 -49.2 -58.5 -58.5 -57.7 -57.4 14.6
{0x25, 15}, // 25 -12.5 -49.5 -58.6 -58.6 -57.8 -57.3 14.1
{0x24, 18}, // 24 -14.3 -50.2 -58.5 -58.4 -57.8 -57.4 13.7
{0x1D, 14}, // 1D -15.7 -50.7 -58.6 -58.6 -57.8 -57.5 13.3
{0x1B, 13}, // 1B -17.0 -51.3 -58.5 -58.4 -57.7 -57.5 13.1
{0x19, 16}, // 19 -18.6 -52.0 -58.6 -58.5 -57.8 -57.5 12.9
{0x22, 10}, // 22 -19.6 -52.5 -58.5 -58.6 -57.7 -57.4 12.9
{0x0D, 15}, // D -21.1 -53.3 -58.6 -58.6 -57.8 -57.4 12.6
{0x0B, 12}, // B -22.3 -53.9 -58.6 -58.5 -57.8 -57.4 12.5
{0x09, 15}, // 9 -23.8 -54.7 -58.5 -58.5 -57.8 -57.5 12.4
{0x21, 10}, // 21 -24.8 -55.1 -58.5 -58.5 -57.7 -57.5 12.5
{0x13, 17}, // 13 -26.5 -55.9 -58.6 -58.5 -57.6 -57.6 12.3
{0x05, 12}, // 5 -27.7 -56.4 -58.4 -58.4 -57.7 -57.5 12.2
{0x12, 12}, // 12 -28.9 -57.1 -58.4 -58.5 -57.7 -57.3 12.2
};
static const PowerTableItem PA_TABLE_915[] = {
{0xC0, 26}, // C0 9.4 -33.5 -58.5 -58.4 -55.8 -32.6 31.8
{0xC3, 11}, // C3 8.3 -41.5 -58.6 -58.4 -56.3 -38.0 29.3
{0xC6, 11}, // C6 7.2 -42.5 -58.5 -58.4 -56.7 -40.5 27.4
{0xC9, 10}, // C9 6.2 -37.6 -58.6 -58.4 -57.2 -38.8 25.9
{0xCD, 12}, // CD 5.0 -34.2 -58.6 -58.5 -57.5 -37.3 24.3
{0x84, 11}, // 84 3.9 -32.0 -58.6 -58.4 -57.7 -40.1 19.7
{0x87, 10}, // 87 2.9 -36.5 -58.4 -58.5 -57.7 -39.6 18.9
{0x8A, 11}, // 8A 1.8 -42.2 -58.5 -58.4 -57.7 -39.6 18.1
{0x8D, 13}, // 8D 0.5 -46.8 -58.5 -58.5 -57.7 -40.4 17.3
{0x8E, 11}, // 8E -0.6 -46.6 -58.5 -58.5 -57.8 -41.1 16.7
{0x51, 10}, // 51 -1.6 -38.7 -58.4 -58.5 -57.7 -46.9 16.0
{0x3E, 11}, // 3E -2.7 -50.0 -58.5 -58.4 -57.6 -55.3 20.7
{0x3B, 11}, // 3B -3.8 -50.7 -58.6 -58.4 -57.6 -55.2 18.9
{0x39, 13}, // 39 -5.1 -50.0 -58.5 -58.5 -57.6 -54.0 17.7
{0x2B, 13}, // 2B -6.4 -47.6 -58.4 -58.4 -57.8 -52.1 16.5
{0x36, 15}, // 36 -7.9 -46.9 -58.5 -58.4 -57.7 -51.2 15.8
{0x35, 14}, // 35 -9.3 -46.7 -58.6 -58.4 -57.7 -50.7 15.2
{0x26, 16}, // 26 -10.9 -47.0 -58.6 -58.4 -57.8 -50.9 14.5
{0x25, 14}, // 25 -12.3 -47.2 -58.6 -58.3 -57.7 -51.0 14.1
{0x24, 18}, // 24 -14.1 -48.1 -58.4 -58.4 -57.8 -51.4 13.7
{0x1D, 14}, // 1D -15.5 -48.7 -58.4 -58.5 -57.7 -51.9 13.2
{0x1B, 13}, // 1B -16.8 -49.3 -58.6 -58.4 -57.8 -52.3 13.0
{0x19, 15}, // 19 -18.3 -50.2 -58.5 -58.5 -57.6 -52.8 12.8
{0x18, 10}, // 18 -19.3 -50.6 -58.5 -58.5 -57.7 -53.1 12.7
{0x17, 10}, // 17 -20.3 -51.2 -58.6 -58.5 -57.8 -53.1 12.6
{0x0C, 11}, // C -21.4 -51.8 -58.4 -58.5 -57.7 -53.4 12.5
{0x0A, 13}, // A -22.7 -52.6 -58.5 -58.4 -57.7 -53.6 12.4
{0x08, 16}, // 8 -24.3 -53.6 -58.4 -58.4 -57.6 -54.1 12.3
{0x13, 19}, // 13 -26.2 -54.6 -58.4 -58.5 -57.7 -54.3 12.2
{0x05, 11}, // 5 -27.3 -55.3 -58.4 -58.4 -57.8 -54.5 12.1
{0x12, 13}, // 12 -28.6 -55.9 -58.6 -58.5 -57.7 -54.7 12.1
{0x03, 12}, // 3 -29.8 -56.9 -58.5 -58.4 -57.7 -54.7 12.0
};
/*
static const PowerTableItem PA_TABLE_315_FULL[] = {
{0xC0, 4}, // C0 10.6 -35.3 -44.4 -57.8 -53.8 -58.3 -57.2 -57.8 -56.7 28.5
{0xC1, 2}, // C1 10.3 -36.6 -44.7 -58.4 -54.0 -58.5 -57.4 -58.0 -56.8 27.6
{0xC2, 4}, // C2 9.9 -37.8 -45.0 -58.8 -54.1 -59.0 -57.3 -58.3 -56.9 26.9
{0xC3, 3}, // C3 9.6 -39.2 -45.3 -59.0 -54.2 -59.0 -57.5 -58.3 -57.2 26.2
{0xC4, 4}, // C4 9.2 -40.5 -45.7 -59.1 -54.5 -58.9 -57.5 -58.4 -57.2 25.6
{0xC5, 3}, // C5 8.8 -41.9 -46.0 -59.2 -54.6 -58.9 -57.6 -58.4 -57.3 25.0
{0xC6, 3}, // C6 8.5 -43.2 -46.3 -59.2 -54.7 -59.1 -57.7 -58.3 -57.4 24.4
{0xC7, 3}, // C7 8.2 -44.5 -46.6 -59.2 -55.0 -59.1 -57.9 -58.3 -57.3 23.9
{0xC8, 2}, // C8 7.9 -45.7 -47.0 -59.1 -55.0 -59.1 -57.9 -58.4 -57.3 23.4
{0xC9, 4}, // C9 7.5 -47.0 -47.3 -58.9 -55.0 -59.0 -57.9 -58.4 -57.5 23.0
{0xCA, 2}, // CA 7.2 -48.0 -47.7 -58.8 -55.0 -59.0 -57.8 -58.4 -57.7 22.5
{0xCB, 2}, // CB 6.9 -49.1 -47.9 -58.7 -55.4 -58.9 -58.1 -58.3 -57.6 22.1
{0xCC, 3}, // CC 6.6 -50.0 -48.3 -58.7 -55.3 -59.0 -58.1 -58.4 -57.8 21.7
{0x80, 0}, // 80 6.6 -46.9 -45.4 -56.3 -53.7 -59.0 -55.8 -56.3 -57.5 19.8
{0x81, 2}, // 81 6.3 -49.2 -45.7 -57.3 -53.6 -59.0 -56.0 -56.5 -57.5 19.5
{0xCD, 0}, // CD 6.3 -50.9 -48.6 -58.4 -55.5 -58.9 -58.0 -58.1 -57.8 21.3
{0x82, 2}, // 82 6.0 -52.0 -46.2 -58.1 -53.8 -58.9 -56.4 -57.1 -57.7 19.2
{0x83, 2}, // 83 5.8 -53.7 -46.5 -58.7 -53.8 -59.0 -56.6 -57.3 -57.8 18.9
{0xCE, 2}, // CE 5.6 -51.9 -49.2 -58.2 -55.5 -58.9 -58.1 -58.3 -57.9 20.6
{0x84, 1}, // 84 5.4 -53.0 -46.8 -59.5 -54.0 -59.0 -56.9 -57.5 -57.8 18.6
{0x85, 4}, // 85 5.0 -51.0 -47.2 -59.8 -54.2 -59.0 -56.9 -57.9 -58.0 18.3
{0x86, 2}, // 86 4.7 -49.3 -47.5 -60.0 -54.4 -59.0 -57.1 -58.0 -58.1 18.0
{0x87, 4}, // 87 4.3 -47.8 -47.8 -60.0 -54.6 -59.0 -57.2 -58.2 -58.1 17.7
{0x88, 3}, // 88 3.9 -46.6 -48.1 -60.0 -55.0 -58.9 -57.5 -58.2 -58.2 17.4
{0x89, 3}, // 89 3.5 -45.8 -48.4 -59.9 -55.2 -58.9 -57.7 -58.3 -58.3 17.0
{0x8A, 3}, // 8A 3.1 -45.0 -48.7 -59.9 -55.3 -59.0 -57.8 -58.2 -58.3 16.7
{0xCF, 3}, // CF 2.8 -49.8 -51.3 -57.6 -56.8 -59.1 -58.4 -58.1 -58.3 18.0
{0x8B, 0}, // 8B 2.7 -44.5 -48.9 -59.6 -55.8 -58.9 -57.7 -58.5 -58.3 16.4
{0x8C, 5}, // 8C 2.2 -44.1 -49.2 -59.0 -56.1 -58.9 -57.9 -58.3 -58.4 16.1
{0x8D, 5}, // 8D 1.7 -43.8 -49.5 -58.9 -56.3 -58.8 -58.2 -58.4 -58.5 15.8
{0x50, 10}, // 50 0.7 -59.2 -51.2 -59.0 -56.5 -59.0 -58.3 -58.3 -58.2 15.3
{0x8E, 0}, // 8E 0.6 -43.7 -50.0 -58.7 -56.7 -58.9 -58.3 -58.3 -58.5 15.2
{0x60, 0}, // 60 0.5 -59.9 -51.3 -59.0 -56.6 -59.1 -58.2 -58.4 -58.4 15.2
{0x51, 4}, // 51 0.1 -58.9 -51.6 -59.2 -56.8 -59.0 -58.4 -58.5 -58.4 15.0
{0x61, 2}, // 61 -0.1 -59.3 -51.7 -59.2 -56.7 -59.0 -58.5 -58.4 -58.4 14.8
{0x40, 1}, // 40 -0.3 -58.2 -52.1 -59.4 -56.9 -59.0 -58.4 -58.4 -58.3 14.7
{0x52, 2}, // 52 -0.5 -58.2 -52.1 -59.3 -56.7 -58.8 -58.4 -58.4 -58.5 14.6
{0x62, 1}, // 62 -0.7 -58.8 -52.3 -59.3 -57.0 -59.0 -58.4 -58.4 -58.3 14.5
{0x3F, 1}, // 3F -0.8 -57.0 -48.3 -59.9 -57.3 -59.1 -58.3 -58.4 -58.5 20.5
{0x3E, 1}, // 3E -1.0 -55.9 -48.4 -59.8 -57.4 -59.1 -58.4 -58.5 -58.3 19.9
{0x53, 1}, // 53 -1.1 -57.6 -52.7 -59.3 -57.1 -59.1 -58.6 -58.4 -58.4 14.3
{0x3D, 1}, // 3D -1.3 -54.4 -48.4 -59.8 -57.5 -58.9 -58.3 -58.5 -58.5 19.3
{0x63, 0}, // 63 -1.3 -58.0 -52.8 -59.5 -57.3 -59.1 -58.5 -58.3 -58.4 14.2
{0x3C, 3}, // 3C -1.7 -53.2 -48.6 -59.9 -57.6 -59.0 -58.4 -58.4 -58.5 18.6
{0x54, 0}, // 54 -1.7 -57.2 -53.2 -59.3 -57.3 -59.0 -58.5 -58.3 -58.4 14.0
{0x64, 1}, // 64 -1.9 -57.4 -53.3 -59.5 -57.4 -59.0 -58.5 -58.2 -58.3 13.9
{0x3B, 2}, // 3B -2.1 -52.2 -48.7 -59.8 -57.7 -59.2 -58.5 -58.4 -58.5 18.0
{0x55, 1}, // 55 -2.3 -56.7 -53.6 -59.7 -57.5 -59.1 -58.7 -58.4 -58.4 13.7
{0x65, 2}, // 65 -2.5 -57.1 -53.7 -59.7 -57.7 -59.0 -58.7 -58.4 -58.4 13.7
{0x2F, 1}, // 2F -2.6 -51.5 -48.7 -60.0 -57.9 -59.0 -58.4 -58.3 -58.3 17.3
{0x3A, 1}, // 3A -2.7 -51.4 -49.1 -59.8 -57.8 -59.1 -58.5 -58.4 -58.4 17.4
{0x56, 2}, // 56 -3.0 -56.6 -54.1 -59.7 -57.7 -58.9 -58.8 -58.4 -58.5 13.5
{0x2E, 1}, // 2E -3.1 -51.3 -49.1 -60.0 -57.9 -59.0 -58.6 -58.3 -58.4 16.9
{0x66, 0}, // 66 -3.1 -56.9 -54.3 -59.7 -57.8 -58.9 -58.8 -58.4 -58.4 13.4
{0x39, 2}, // 39 -3.4 -50.9 -49.5 -59.8 -58.0 -59.0 -58.5 -58.4 -58.4 16.8
{0x57, 1}, // 57 -3.5 -56.6 -54.4 -59.8 -57.9 -59.0 -58.7 -58.3 -58.4 13.3
{0x2D, 1}, // 2D -3.6 -51.1 -49.4 -60.0 -58.1 -59.1 -58.6 -58.5 -58.4 16.4
{0x67, 1}, // 67 -3.7 -56.8 -54.7 -59.9 -58.0 -59.0 -58.8 -58.4 -58.3 13.2
{0x8F, 5}, // 8F -4.2 -45.9 -52.6 -58.4 -58.5 -59.0 -58.8 -58.3 -58.6 13.3
{0x2C, 0}, // 2C -4.2 -51.0 -49.8 -60.0 -58.0 -59.0 -58.6 -58.4 -58.4 16.0
{0x38, 0}, // 38 -4.3 -50.7 -50.2 -59.8 -58.0 -59.0 -58.6 -58.3 -58.5 16.1
{0x68, 0}, // 68 -4.3 -56.9 -55.1 -59.7 -58.0 -59.0 -58.9 -58.5 -58.5 13.0
{0x2B, 6}, // 2B -4.9 -51.2 -50.4 -59.9 -58.0 -58.9 -58.7 -58.3 -58.4 15.6
{0x69, 0}, // 69 -4.9 -56.9 -55.5 -59.9 -58.3 -59.1 -58.9 -58.3 -58.5 12.8
{0x37, 5}, // 37 -5.4 -51.3 -50.5 -60.0 -58.3 -59.1 -58.7 -58.4 -58.4 15.4
{0x6A, 0}, // 6A -5.5 -56.9 -56.1 -59.8 -58.3 -59.0 -58.8 -58.4 -58.5 12.6
{0x2A, 2}, // 2A -5.7 -51.5 -51.1 -60.0 -58.4 -59.1 -58.7 -58.3 -58.6 15.2
{0x6B, 3}, // 6B -6.1 -57.0 -56.5 -59.9 -58.5 -59.0 -58.9 -58.3 -58.6 12.5
{0x29, 4}, // 29 -6.5 -51.8 -51.6 -59.9 -58.4 -59.0 -58.8 -58.3 -58.3 14.7
{0x6C, 2}, // 6C -6.7 -57.0 -57.0 -59.9 -58.5 -59.1 -58.9 -58.5 -58.4 12.3
{0x36, 0}, // 36 -6.7 -51.9 -51.5 -60.0 -58.2 -59.0 -58.8 -58.4 -58.4 14.7
{0x6D, 5}, // 6D -7.2 -57.3 -57.1 -60.0 -58.6 -58.9 -58.8 -58.4 -58.3 12.2
{0x28, 2}, // 28 -7.5 -52.2 -52.5 -60.0 -58.6 -59.0 -58.8 -58.2 -58.4 14.3
{0x35, 5}, // 35 -8.1 -52.7 -52.7 -60.0 -58.7 -59.0 -58.9 -58.3 -58.5 14.1
{0x6E, 3}, // 6E -8.4 -58.0 -57.9 -60.0 -58.6 -59.1 -58.9 -58.3 -58.5 11.9
{0x27, 1}, // 27 -8.6 -52.9 -53.1 -60.0 -58.8 -59.1 -58.8 -58.3 -58.5 13.9
{0x26, 12}, // 26 -9.8 -53.6 -54.3 -60.1 -58.7 -59.0 -58.7 -58.4 -58.4 13.4
{0x34, 0}, // 34 -9.9 -53.7 -54.4 -59.9 -58.8 -59.0 -58.7 -58.3 -58.4 13.5
{0x25, 11}, // 25 -11.1 -54.3 -55.5 -60.1 -58.8 -59.1 -58.8 -58.4 -58.4 13.0
{0x33, 10}, // 33 -12.2 -55.0 -56.3 -60.0 -58.7 -59.0 -58.9 -58.4 -58.4 12.8
{0x24, 8}, // 24 -13.0 -55.4 -56.9 -60.1 -58.7 -59.1 -59.0 -58.3 -58.5 12.6
{0x6F, 1}, // 6F -13.2 -58.3 -60.7 -59.8 -58.7 -59.1 -58.9 -58.3 -58.5 11.2
{0x1F, 1}, // 1F -13.3 -55.6 -57.2 -60.0 -58.8 -58.9 -58.9 -58.3 -58.4 12.4
{0x1E, 5}, // 1E -13.9 -55.8 -57.4 -60.0 -58.6 -59.1 -58.9 -58.4 -58.5 12.2
{0x1D, 5}, // 1D -14.5 -56.0 -58.0 -60.0 -58.8 -59.1 -58.7 -58.4 -58.5 12.1
{0x1C, 6}, // 1C -15.2 -56.3 -58.3 -60.1 -58.9 -58.9 -58.8 -58.3 -58.4 12.0
{0x23, 2}, // 23 -15.4 -56.8 -58.3 -60.1 -58.7 -59.0 -58.8 -58.3 -58.5 12.1
{0x32, 1}, // 32 -15.6 -56.9 -58.8 -59.9 -58.8 -59.0 -58.8 -58.3 -58.5 12.2
{0x1B, 3}, // 1B -15.9 -56.8 -58.9 -60.0 -58.8 -59.1 -58.7 -58.5 -58.5 11.9
{0x1A, 7}, // 1A -16.6 -57.3 -59.5 -59.9 -58.8 -59.1 -58.8 -58.4 -58.4 11.8
{0x19, 8}, // 19 -17.5 -57.5 -59.6 -60.0 -58.7 -59.0 -58.9 -58.3 -58.5 11.7
{0x18, 10}, // 18 -18.5 -57.8 -60.3 -60.0 -58.8 -59.0 -58.9 -58.2 -58.5 11.6
{0x22, 3}, // 22 -18.8 -58.4 -60.6 -59.9 -58.7 -59.1 -58.9 -58.5 -58.5 11.7
{0x0F, 0}, // F -18.8 -58.3 -60.5 -59.8 -58.7 -59.1 -58.9 -58.2 -58.4 11.5
{0x0E, 5}, // E -19.4 -58.6 -60.9 -59.9 -58.6 -58.9 -58.9 -58.3 -58.5 11.4
{0x17, 2}, // 17 -19.6 -58.7 -60.9 -60.0 -58.7 -58.9 -58.9 -58.5 -58.4 11.4
{0x0D, 3}, // D -20.0 -58.8 -61.0 -60.0 -58.8 -59.0 -58.8 -58.5 -58.4 11.4
{0x0C, 6}, // C -20.7 -59.4 -61.1 -60.0 -58.8 -59.1 -58.9 -58.4 -58.3 11.3
{0x16, 1}, // 16 -20.9 -59.4 -61.4 -59.9 -58.8 -59.1 -58.9 -58.4 -58.3 11.3
{0x31, 4}, // 31 -21.3 -59.2 -61.5 -60.0 -58.6 -59.1 -58.9 -58.3 -58.5 11.5
{0x0B, 0}, // B -21.4 -59.3 -61.8 -60.0 -58.8 -58.9 -58.9 -58.4 -58.5 11.3
{0x0A, 8}, // A -22.2 -59.9 -61.9 -60.0 -58.9 -59.0 -58.9 -58.4 -58.5 11.2
{0x15, 1}, // 15 -22.4 -59.9 -62.3 -60.1 -58.6 -59.1 -59.1 -58.3 -58.4 11.2
{0x09, 6}, // 9 -23.0 -60.3 -62.0 -59.9 -58.7 -59.0 -58.8 -58.4 -58.5 11.1
{0x08, 10}, // 8 -24.0 -60.5 -62.5 -60.0 -58.7 -59.1 -58.8 -58.3 -58.5 11.1
{0x14, 3}, // 14 -24.3 -60.6 -62.7 -60.0 -58.9 -59.2 -58.9 -58.2 -58.4 11.1
{0x21, 1}, // 21 -24.5 -60.7 -62.4 -59.9 -58.9 -58.9 -58.8 -58.3 -58.5 11.2
{0x07, 6}, // 7 -25.1 -61.3 -62.9 -60.1 -58.8 -59.1 -58.8 -58.4 -58.4 11.0
{0x06, 12}, // 6 -26.4 -61.6 -63.2 -60.1 -58.7 -59.0 -58.9 -58.5 -58.5 11.0
{0x13, 2}, // 13 -26.6 -61.8 -63.1 -59.9 -58.7 -59.1 -58.8 -58.4 -58.6 11.0
{0x05, 10}, // 5 -27.7 -62.3 -63.4 -60.1 -58.7 -59.2 -58.8 -58.4 -58.5 10.9
{0x04, 19}, // 4 -29.6 -62.7 -63.6 -59.9 -58.7 -59.0 -58.9 -58.4 -58.4 10.8
{0x12, 1}, // 12 -29.8 -62.8 -63.5 -60.0 -58.7 -59.1 -58.8 -58.3 -58.6 10.9
{0x03, 18}, // 3 -31.7 -63.4 -63.9 -60.1 -58.8 -59.1 -58.7 -58.3 -58.5 10.8
{0x02, 29}, // 2 -34.6 -64.0 -64.0 -59.9 -58.7 -58.9 -58.8 -58.4 -58.6 10.7
{0x11, 0}, // 11 -34.6 -64.0 -64.0 -59.9 -58.7 -59.0 -58.9 -58.3 -58.4 10.8
{0x01, 36}, // 1 -38.3 -64.9 -63.9 -60.0 -58.9 -58.9 -58.9 -58.4 -58.5 10.7
{0x10, 29}, // 10 -41.2 -65.3 -64.0 -59.9 -58.6 -59.0 -58.9 -58.4 -58.5 10.6
{0x30, 0}, // 30 -41.3 -65.5 -63.9 -60.0 -58.7 -59.1 -58.8 -58.4 -58.6 10.9
{0x20, 0}, // 20 -41.3 -65.3 -64.0 -60.1 -58.8 -59.1 -58.9 -58.4 -58.3 10.8
{0x00, 225}, // 0 -63.8 -65.4 -64.0 -59.9 -58.9 -58.9 -58.8 -58.3 -58.5 10.3
};
static const PowerTableItem PA_TABLE_433_FULL[] = {
{0xC0, 10}, // C0 9.9 -43.4 -45.0 -53.9 -55.2 -55.8 -52.3 -55.6 29.1
{0xC1, 4}, // C1 9.5 -45.2 -45.3 -54.6 -55.2 -56.5 -52.5 -56.5 28.3
{0xC2, 3}, // C2 9.2 -47.1 -45.5 -55.2 -55.1 -56.9 -52.4 -57.1 27.6
{0xC3, 3}, // C3 8.8 -49.3 -45.9 -55.9 -55.4 -57.2 -52.6 -57.5 26.9
{0xC4, 3}, // C4 8.5 -51.8 -46.2 -56.3 -55.3 -57.7 -52.9 -57.9 26.3
{0xC5, 4}, // C5 8.1 -54.6 -46.5 -56.6 -55.4 -58.1 -53.2 -57.9 25.7
{0xC6, 2}, // C6 7.8 -56.2 -46.9 -56.9 -55.6 -58.2 -53.2 -57.9 25.2
{0xC7, 3}, // C7 7.4 -57.0 -47.2 -57.0 -55.7 -58.3 -53.5 -57.6 24.7
{0xC8, 3}, // C8 7.1 -57.4 -47.6 -57.2 -55.9 -58.4 -53.5 -57.2 24.2
{0xC9, 2}, // C9 6.8 -56.1 -47.9 -57.3 -55.9 -58.5 -54.0 -56.9 23.8
{0xCA, 3}, // CA 6.4 -54.9 -48.3 -57.2 -56.1 -58.6 -54.2 -56.7 23.4
{0x80, 1}, // 80 6.3 -50.3 -51.7 -57.7 -53.8 -56.4 -56.3 -57.1 20.6
{0xCB, 2}, // CB 6.1 -53.8 -48.6 -57.0 -56.1 -58.5 -54.3 -56.7 23.0
{0x81, 0}, // 81 6.0 -51.4 -52.0 -58.0 -54.0 -56.6 -56.1 -57.4 20.3
{0xCC, 2}, // CC 5.8 -52.8 -48.9 -57.0 -56.1 -58.4 -54.6 -56.2 22.6
{0x82, 0}, // 82 5.8 -52.3 -52.1 -58.2 -54.2 -57.0 -56.3 -57.5 20.0
{0xCD, 2}, // CD 5.5 -52.1 -49.2 -56.9 -56.2 -58.2 -54.8 -56.2 22.3
{0x83, 0}, // 83 5.5 -53.0 -52.5 -58.3 -54.4 -57.4 -56.4 -57.8 19.7
{0x84, 4}, // 84 5.1 -53.7 -52.9 -58.1 -54.6 -57.5 -56.6 -57.9 19.4
{0xCE, 1}, // CE 4.9 -50.6 -49.9 -56.6 -56.3 -58.4 -55.4 -55.8 21.6
{0x85, 1}, // 85 4.8 -54.2 -53.0 -58.3 -55.0 -57.8 -56.8 -58.0 19.1
{0x86, 3}, // 86 4.4 -54.9 -53.1 -58.2 -55.1 -57.8 -56.9 -58.1 18.8
{0x87, 4}, // 87 4.0 -55.6 -53.5 -58.2 -55.3 -58.1 -56.9 -58.2 18.5
{0x88, 3}, // 88 3.6 -56.2 -53.8 -58.3 -55.7 -58.1 -57.2 -58.2 18.2
{0x89, 3}, // 89 3.2 -56.8 -53.9 -58.2 -55.8 -58.1 -57.3 -58.0 17.9
{0x8A, 4}, // 8A 2.8 -57.4 -54.1 -58.2 -56.0 -58.3 -57.7 -58.1 17.6
{0x8B, 5}, // 8B 2.3 -57.7 -54.5 -58.0 -56.3 -58.1 -57.5 -58.2 17.3
{0xCF, 2}, // CF 2.0 -48.3 -52.4 -56.0 -57.0 -57.7 -57.3 -56.4 19.3
{0x8C, 1}, // 8C 1.9 -58.2 -54.7 -58.1 -56.7 -58.3 -58.0 -58.2 17.1
{0x8D, 5}, // 8D 1.4 -58.4 -54.9 -58.0 -56.8 -58.2 -58.2 -58.1 16.8
{0x8E, 9}, // 8E 0.4 -58.0 -55.5 -57.8 -57.4 -58.2 -58.1 -58.4 16.2
{0x50, 0}, // 50 0.4 -59.0 -55.2 -58.2 -57.4 -58.4 -57.8 -58.4 16.0
{0x60, 3}, // 60 0.1 -59.1 -55.4 -58.1 -57.4 -58.4 -57.7 -58.3 15.9
{0x51, 4}, // 51 -0.3 -59.2 -55.8 -58.2 -57.5 -58.4 -57.9 -58.3 15.7
{0x61, 2}, // 61 -0.5 -59.3 -55.8 -58.2 -57.8 -58.3 -58.1 -58.3 15.6
{0x40, 3}, // 40 -0.8 -59.7 -56.1 -58.2 -57.7 -58.4 -58.3 -58.2 15.4
{0x52, 0}, // 52 -0.9 -59.6 -56.1 -58.3 -57.7 -58.3 -58.3 -58.3 15.3
{0x3F, 2}, // 3F -1.1 -61.3 -56.9 -58.2 -57.9 -58.5 -58.2 -58.6 21.1
{0x62, 0}, // 62 -1.1 -59.6 -56.2 -58.2 -57.8 -58.4 -58.2 -58.3 15.3
{0x3E, 2}, // 3E -1.4 -61.4 -57.0 -58.3 -57.9 -58.5 -58.2 -58.5 20.5
{0x53, 1}, // 53 -1.5 -59.7 -56.5 -58.3 -57.9 -58.4 -58.1 -58.3 15.0
{0x3D, 1}, // 3D -1.7 -61.1 -57.2 -58.3 -57.9 -58.6 -58.3 -58.5 19.9
{0x63, 0}, // 63 -1.7 -59.8 -56.7 -58.3 -57.9 -58.4 -58.4 -58.3 15.0
{0x3C, 4}, // 3C -2.1 -60.6 -57.3 -58.2 -58.0 -58.5 -58.4 -58.5 19.3
{0x54, 1}, // 54 -2.2 -60.0 -56.8 -58.3 -58.1 -58.5 -58.4 -58.5 14.8
{0x64, 0}, // 64 -2.3 -60.1 -57.0 -58.2 -58.2 -58.5 -58.6 -58.5 14.7
{0x3B, 2}, // 3B -2.5 -60.4 -57.5 -58.3 -58.1 -58.5 -58.2 -58.5 18.7
{0x55, 2}, // 55 -2.8 -60.3 -57.2 -58.3 -58.2 -58.3 -58.4 -58.6 14.5
{0x65, 1}, // 65 -2.9 -60.2 -57.2 -58.3 -58.3 -58.4 -58.4 -58.4 14.5
{0x2F, 1}, // 2F -3.0 -58.4 -57.6 -58.3 -58.1 -58.6 -58.4 -58.5 17.9
{0x3A, 1}, // 3A -3.1 -59.5 -57.5 -58.3 -58.3 -58.6 -58.1 -58.6 18.1
{0x56, 1}, // 56 -3.3 -60.2 -57.5 -58.4 -58.6 -58.5 -58.4 -58.3 14.3
{0x2E, 2}, // 2E -3.5 -58.0 -57.8 -58.3 -58.4 -58.3 -58.3 -58.5 17.5
{0x66, 0}, // 66 -3.5 -60.3 -57.6 -58.2 -58.4 -58.3 -58.5 -58.5 14.2
{0x39, 2}, // 39 -3.8 -58.7 -57.8 -58.3 -58.3 -58.4 -58.4 -58.5 17.5
{0x57, 2}, // 57 -4.0 -60.3 -57.7 -58.4 -58.4 -58.4 -58.7 -58.4 14.1
{0x2D, 0}, // 2D -4.0 -57.6 -58.0 -58.2 -58.5 -58.4 -58.6 -58.5 17.1
{0x67, 0}, // 67 -4.1 -60.1 -57.8 -58.1 -58.6 -58.4 -58.7 -58.6 14.0
{0x8F, 5}, // 8F -4.6 -52.2 -57.7 -58.1 -58.8 -58.4 -58.7 -58.3 14.4
{0x2C, 1}, // 2C -4.7 -57.4 -58.3 -58.3 -58.7 -58.5 -58.5 -58.5 16.7
{0x38, 0}, // 38 -4.7 -58.2 -58.0 -58.3 -58.6 -58.4 -58.5 -58.5 16.9
{0x68, 0}, // 68 -4.7 -60.4 -57.8 -58.4 -58.7 -58.4 -58.7 -58.5 13.8
{0x2B, 5}, // 2B -5.3 -57.0 -58.7 -58.4 -58.6 -58.4 -58.5 -58.5 16.3
{0x69, 0}, // 69 -5.3 -60.6 -58.4 -58.3 -58.8 -58.4 -58.7 -58.5 13.6
{0x37, 2}, // 37 -5.6 -56.8 -58.3 -58.3 -58.8 -58.4 -58.5 -58.4 16.2
{0x6A, 3}, // 6A -5.9 -60.8 -58.6 -58.3 -58.7 -58.5 -58.6 -58.5 13.5
{0x2A, 0}, // 2A -6.0 -56.8 -58.6 -58.4 -58.8 -58.4 -58.6 -58.3 15.9
{0x6B, 5}, // 6B -6.5 -60.5 -58.9 -58.3 -58.6 -58.5 -58.7 -58.3 13.3
{0x36, 2}, // 36 -6.8 -56.8 -58.9 -58.3 -58.8 -58.3 -58.5 -58.5 15.6
{0x29, 1}, // 29 -6.9 -56.7 -58.9 -58.1 -58.6 -58.5 -58.6 -58.5 15.5
{0x6C, 1}, // 6C -7.1 -60.5 -58.9 -58.2 -58.9 -58.5 -58.6 -58.6 13.2
{0x6D, 6}, // 6D -7.7 -60.4 -59.2 -58.4 -59.0 -58.5 -58.6 -58.5 13.0
{0x28, 0}, // 28 -7.8 -56.6 -59.0 -58.2 -59.0 -58.4 -58.5 -58.4 15.1
{0x35, 5}, // 35 -8.3 -56.8 -59.1 -58.4 -58.9 -58.5 -58.6 -58.5 15.0
{0x27, 3}, // 27 -8.7 -56.8 -59.2 -58.2 -58.9 -58.5 -58.6 -58.4 14.7
{0x6E, 2}, // 6E -8.9 -60.2 -59.3 -58.3 -58.8 -58.5 -58.7 -58.5 12.8
{0x26, 10}, // 26 -9.9 -57.0 -59.4 -58.3 -59.0 -58.4 -58.7 -58.4 14.3
{0x34, 1}, // 34 -10.1 -57.0 -59.4 -58.4 -58.9 -58.3 -58.7 -58.5 14.4
{0x25, 13}, // 25 -11.4 -57.3 -59.7 -58.4 -59.0 -58.3 -58.7 -58.5 13.9
{0x33, 9}, // 33 -12.3 -57.8 -59.8 -58.4 -58.9 -58.3 -58.7 -58.6 13.8
{0x24, 10}, // 24 -13.3 -57.9 -59.9 -58.2 -59.0 -58.6 -58.7 -58.5 13.5
{0x1F, 3}, // 1F -13.7 -57.9 -59.9 -58.4 -59.0 -58.5 -58.7 -58.5 13.3
{0x1E, 6}, // 1E -14.3 -58.4 -59.8 -58.2 -59.0 -58.4 -58.6 -58.6 13.2
{0x1D, 5}, // 1D -14.9 -58.6 -59.8 -58.3 -59.0 -58.5 -58.7 -58.5 13.1
{0x6F, 5}, // 6F -15.5 -59.1 -59.9 -58.3 -59.1 -58.5 -58.7 -58.6 12.4
{0x1C, 0}, // 1C -15.5 -58.6 -59.9 -58.4 -58.8 -58.6 -58.8 -58.5 12.9
{0x23, 0}, // 23 -15.6 -59.0 -59.9 -58.1 -59.0 -58.4 -58.6 -58.5 13.1
{0x32, 0}, // 32 -15.7 -59.0 -59.8 -58.2 -58.8 -58.5 -58.6 -58.5 13.1
{0x1B, 5}, // 1B -16.2 -59.1 -59.9 -58.3 -59.0 -58.5 -58.6 -58.4 12.8
{0x1A, 8}, // 1A -17.0 -59.4 -59.9 -58.3 -59.1 -58.5 -58.7 -58.4 12.7
{0x19, 8}, // 19 -17.8 -59.7 -59.9 -58.3 -59.0 -58.4 -58.6 -58.5 12.6
{0x18, 10}, // 18 -18.8 -60.2 -59.9 -58.2 -59.0 -58.5 -58.7 -58.6 12.5
{0x22, 1}, // 22 -19.0 -60.4 -59.9 -58.3 -59.0 -58.5 -58.6 -58.5 12.6
{0x0F, 3}, // F -19.3 -60.4 -59.8 -58.4 -59.0 -58.6 -58.6 -58.5 12.4
{0x17, 5}, // 17 -19.8 -60.6 -59.9 -58.2 -58.9 -58.4 -58.7 -58.4 12.4
{0x0E, 0}, // E -19.8 -60.5 -59.9 -58.3 -59.1 -58.5 -58.8 -58.6 12.4
{0x0D, 5}, // D -20.4 -60.7 -60.0 -58.4 -59.0 -58.5 -58.5 -58.5 12.3
{0x0C, 6}, // C -21.0 -61.1 -59.9 -58.4 -59.0 -58.5 -58.7 -58.6 12.3
{0x16, 0}, // 16 -21.0 -61.2 -59.9 -58.3 -59.1 -58.5 -58.7 -58.4 12.3
{0x31, 3}, // 31 -21.3 -61.3 -60.0 -58.3 -59.0 -58.5 -58.7 -58.5 12.5
{0x0B, 3}, // B -21.7 -61.3 -59.9 -58.2 -58.9 -58.5 -58.8 -58.4 12.2
{0x15, 8}, // 15 -22.5 -61.7 -60.0 -58.2 -59.1 -58.3 -58.6 -58.7 12.2
{0x0A, 0}, // A -22.5 -61.8 -60.0 -58.2 -58.9 -58.6 -58.6 -58.6 12.2
{0x09, 8}, // 9 -23.3 -61.8 -60.0 -58.2 -59.0 -58.6 -58.6 -58.4 12.1
{0x08, 10}, // 8 -24.3 -62.3 -59.9 -58.3 -59.0 -58.4 -58.8 -58.5 12.1
{0x14, 0}, // 14 -24.3 -62.1 -59.9 -58.4 -59.1 -58.5 -58.7 -58.5 12.1
{0x21, 1}, // 21 -24.5 -62.4 -59.9 -58.3 -59.1 -58.4 -58.6 -58.4 12.2
{0x07, 8}, // 7 -25.3 -62.6 -59.9 -58.2 -59.0 -58.6 -58.7 -58.5 12.0
{0x06, 11}, // 6 -26.5 -63.2 -59.9 -58.3 -58.9 -58.5 -58.6 -58.6 12.0
{0x13, 0}, // 13 -26.5 -63.0 -59.8 -58.3 -59.0 -58.4 -58.7 -58.4 12.0
{0x05, 13}, // 5 -27.9 -63.5 -59.8 -58.3 -59.1 -58.5 -58.7 -58.4 11.9
{0x04, 16}, // 4 -29.5 -63.7 -59.9 -58.3 -58.9 -58.5 -58.5 -58.5 11.9
{0x12, 1}, // 12 -29.6 -63.6 -59.7 -58.3 -59.1 -58.6 -58.6 -58.5 11.9
{0x03, 17}, // 3 -31.4 -64.2 -60.1 -58.4 -59.0 -58.6 -58.8 -58.6 11.8
{0x11, 23}, // 11 -33.8 -64.3 -59.9 -58.3 -58.9 -58.6 -58.6 -58.5 11.8
{0x02, 0}, // 2 -33.8 -64.4 -59.9 -58.3 -59.1 -58.4 -58.8 -58.6 11.7
{0x01, 27}, // 1 -36.5 -64.2 -59.9 -58.4 -59.0 -58.6 -58.6 -58.5 11.7
{0x10, 17}, // 10 -38.3 -64.4 -59.9 -58.4 -59.0 -58.5 -58.8 -58.5 11.7
{0x20, 0}, // 20 -38.3 -64.6 -59.9 -58.3 -59.0 -58.6 -58.7 -58.5 11.8
{0x30, 1}, // 30 -38.4 -64.4 -59.9 -58.3 -59.1 -58.5 -58.7 -58.6 11.9
{0x00, 243}, // 0 -62.7 -64.5 -59.8 -58.2 -58.9 -58.5 -58.7 -58.6 11.3
};
static const PowerTableItem PA_TABLE_868_FULL[] = {
{0xC0, 3}, // C0 10.7 -35.1 -58.6 -58.6 -57.5 -50.0 34.2
{0xC1, 3}, // C1 10.3 -37.0 -58.5 -58.6 -57.5 -51.4 33.3
{0xC2, 3}, // C2 10.0 -39.2 -58.3 -58.5 -57.4 -53.2 32.4
{0xC3, 4}, // C3 9.6 -41.5 -58.5 -58.3 -57.4 -54.4 31.6
{0xC4, 4}, // C4 9.2 -44.0 -58.6 -58.5 -57.4 -55.2 30.9
{0xC5, 2}, // C5 8.9 -46.2 -58.5 -58.6 -57.6 -55.4 30.2
{0xC6, 4}, // C6 8.5 -47.7 -58.5 -58.3 -57.6 -55.0 29.5
{0xC7, 3}, // C7 8.2 -47.3 -58.5 -58.5 -57.7 -54.5 28.9
{0xC8, 3}, // C8 7.8 -45.9 -58.5 -58.4 -57.7 -54.1 28.3
{0xC9, 2}, // C9 7.5 -44.4 -58.5 -58.5 -57.7 -53.6 27.8
{0xCA, 2}, // CA 7.2 -42.9 -58.6 -58.4 -57.6 -53.2 27.3
{0xCB, 4}, // CB 6.8 -41.7 -58.5 -58.4 -57.8 -52.8 26.8
{0xCC, 2}, // CC 6.5 -40.6 -58.6 -58.4 -57.6 -52.5 26.3
{0xCD, 2}, // CD 6.2 -39.8 -58.4 -58.6 -57.6 -52.3 25.9
{0xCE, 7}, // CE 5.5 -38.5 -58.5 -58.4 -57.8 -52.2 25.0
{0x80, 2}, // 80 5.2 -31.9 -58.5 -58.4 -57.8 -56.2 21.2
{0x81, 2}, // 81 5.0 -32.6 -58.5 -58.6 -57.8 -56.2 21.0
{0x82, 2}, // 82 4.8 -33.4 -58.4 -58.4 -57.7 -56.2 20.8
{0x83, 2}, // 83 4.6 -34.3 -58.4 -58.5 -57.7 -56.1 20.5
{0x84, 1}, // 84 4.4 -35.3 -58.7 -58.5 -57.8 -55.8 20.3
{0x85, 3}, // 85 4.1 -36.5 -58.7 -58.6 -57.7 -55.8 20.0
{0x86, 3}, // 86 3.7 -37.8 -58.6 -58.5 -57.8 -55.8 19.7
{0x87, 3}, // 87 3.4 -39.4 -58.6 -58.6 -57.8 -55.7 19.5
{0x88, 3}, // 88 3.0 -41.0 -58.5 -58.5 -57.7 -55.7 19.1
{0x89, 3}, // 89 2.6 -43.0 -58.5 -58.6 -57.6 -55.8 18.8
{0xCF, 2}, // CF 2.4 -36.6 -58.6 -58.4 -57.7 -53.6 22.0
{0x8A, 2}, // 8A 2.1 -45.1 -58.5 -58.5 -57.6 -55.8 18.5
{0x8B, 4}, // 8B 1.7 -47.5 -58.5 -58.4 -57.8 -55.8 18.2
{0x8C, 5}, // 8C 1.1 -50.2 -58.6 -58.5 -57.7 -55.9 17.9
{0x8D, 5}, // 8D 0.6 -52.6 -58.5 -58.5 -57.8 -55.8 17.6
{0x50, 9}, // 50 -0.3 -42.1 -58.5 -58.5 -57.6 -57.1 16.9
{0x60, 2}, // 60 -0.5 -42.3 -58.6 -58.5 -57.6 -57.2 16.8
{0x8E, 0}, // 8E -0.5 -55.5 -58.5 -58.6 -57.7 -56.2 17.0
{0x51, 4}, // 51 -0.9 -42.6 -58.6 -58.6 -57.6 -57.1 16.5
{0x61, 2}, // 61 -1.1 -42.8 -58.3 -58.5 -57.6 -57.1 16.4
{0x40, 3}, // 40 -1.5 -43.2 -58.5 -58.7 -57.7 -57.2 16.1
{0x52, 1}, // 52 -1.6 -43.2 -58.5 -58.5 -57.7 -57.2 16.1
{0x62, 1}, // 62 -1.8 -43.2 -58.4 -58.6 -57.7 -57.0 16.0
{0x53, 4}, // 53 -2.3 -43.7 -58.6 -58.6 -57.7 -57.2 15.7
{0x63, 1}, // 63 -2.4 -43.8 -58.6 -58.4 -57.6 -57.1 15.6
{0x3F, 2}, // 3F -2.6 -53.7 -58.6 -58.5 -57.8 -57.5 21.4
{0x3E, 1}, // 3E -2.8 -54.2 -58.6 -58.5 -57.7 -57.5 20.8
{0x54, 1}, // 54 -2.9 -44.4 -58.5 -58.6 -57.8 -57.4 15.3
{0x64, 2}, // 64 -3.1 -44.3 -58.6 -58.6 -57.7 -57.4 15.3
{0x3D, 1}, // 3D -3.2 -54.7 -58.6 -58.5 -57.7 -57.5 20.2
{0x3C, 2}, // 3C -3.5 -55.0 -58.6 -58.5 -57.7 -57.5 19.6
{0x55, 1}, // 55 -3.6 -44.9 -58.6 -58.4 -57.8 -57.5 15.0
{0x65, 1}, // 65 -3.7 -44.9 -58.6 -58.5 -57.7 -57.5 15.0
{0x3B, 2}, // 3B -4.0 -55.0 -58.5 -58.5 -57.7 -57.3 19.0
{0x56, 2}, // 56 -4.2 -45.4 -58.5 -58.5 -57.7 -57.5 14.7
{0x66, 2}, // 66 -4.4 -45.4 -58.5 -58.5 -57.7 -57.4 14.7
{0x2F, 0}, // 2F -4.5 -52.6 -58.6 -58.6 -57.6 -57.4 18.2
{0x3A, 0}, // 3A -4.5 -54.1 -58.6 -58.5 -57.8 -57.5 18.4
{0x57, 2}, // 57 -4.8 -46.0 -58.6 -58.5 -57.6 -57.4 14.5
{0x2E, 1}, // 2E -4.9 -51.8 -58.6 -58.4 -57.7 -57.4 17.8
{0x67, 0}, // 67 -5.0 -46.0 -58.5 -58.5 -57.8 -57.5 14.4
{0x39, 2}, // 39 -5.2 -52.9 -58.6 -58.6 -57.7 -57.5 17.8
{0x2D, 2}, // 2D -5.5 -50.9 -58.6 -58.5 -57.7 -57.4 17.4
{0x68, 2}, // 68 -5.7 -46.6 -58.5 -58.5 -57.7 -57.5 14.2
{0x8F, 2}, // 8F -6.0 -51.6 -58.5 -58.6 -57.7 -57.1 15.0
{0x2C, 0}, // 2C -6.0 -50.3 -58.6 -58.5 -57.7 -57.3 17.0
{0x38, 0}, // 38 -6.1 -51.8 -58.6 -58.5 -57.7 -57.3 17.1
{0x69, 2}, // 69 -6.3 -47.3 -58.4 -58.6 -57.6 -57.5 14.0
{0x2B, 4}, // 2B -6.7 -49.8 -58.5 -58.5 -57.7 -57.5 16.6
{0x6A, 2}, // 6A -6.9 -48.1 -58.6 -58.5 -57.7 -57.5 13.8
{0x37, 0}, // 37 -6.9 -49.5 -58.5 -58.5 -57.6 -57.3 16.4
{0x2A, 5}, // 2A -7.4 -49.3 -58.5 -58.6 -57.7 -57.4 16.2
{0x6B, 0}, // 6B -7.5 -49.5 -58.5 -58.6 -57.7 -57.4 13.8
{0x36, 5}, // 36 -8.1 -49.0 -58.5 -58.5 -57.7 -57.3 15.8
{0x29, 0}, // 29 -8.2 -49.1 -58.6 -58.5 -57.8 -57.4 15.8
{0x6C, 5}, // 6C -8.7 -52.2 -58.6 -58.5 -57.6 -57.4 14.0
{0x28, 3}, // 28 -9.0 -49.0 -58.5 -58.6 -57.7 -57.4 15.4
{0x35, 4}, // 35 -9.4 -48.9 -58.5 -58.5 -57.8 -57.3 15.2
{0x27, 4}, // 27 -9.8 -49.0 -58.5 -58.5 -57.7 -57.3 15.0
{0x26, 11}, // 26 -11.0 -49.2 -58.5 -58.5 -57.7 -57.4 14.6
{0x34, 0}, // 34 -11.1 -49.2 -58.6 -58.6 -57.7 -57.3 14.6
{0x25, 14}, // 25 -12.5 -49.5 -58.6 -58.6 -57.8 -57.3 14.1
{0x33, 8}, // 33 -13.3 -49.7 -58.6 -58.5 -57.8 -57.5 14.0
{0x24, 10}, // 24 -14.3 -50.2 -58.5 -58.4 -57.8 -57.4 13.7
{0x6D, 1}, // 6D -14.5 -55.3 -58.6 -58.5 -57.7 -57.5 14.7
{0x1F, 0}, // 1F -14.6 -50.3 -58.6 -58.6 -57.7 -57.5 13.5
{0x1E, 5}, // 1E -15.1 -50.6 -58.6 -58.5 -57.6 -57.4 13.4
{0x1D, 5}, // 1D -15.7 -50.7 -58.6 -58.6 -57.8 -57.5 13.3
{0x1C, 6}, // 1C -16.4 -51.1 -58.6 -58.4 -57.6 -57.3 13.2
{0x23, 1}, // 23 -16.5 -51.0 -58.6 -58.6 -57.8 -57.4 13.3
{0x32, 0}, // 32 -16.5 -51.0 -58.6 -58.5 -57.7 -57.4 13.4
{0x1B, 5}, // 1B -17.0 -51.3 -58.5 -58.4 -57.7 -57.5 13.1
{0x1A, 8}, // 1A -17.8 -51.6 -58.6 -58.5 -57.7 -57.3 13.0
{0x19, 8}, // 19 -18.6 -52.0 -58.6 -58.5 -57.8 -57.5 12.9
{0x18, 8}, // 18 -19.5 -52.6 -58.5 -58.5 -57.8 -57.4 12.8
{0x22, 1}, // 22 -19.6 -52.5 -58.5 -58.6 -57.7 -57.4 12.9
{0x0F, 3}, // F -20.0 -52.8 -58.5 -58.5 -57.7 -57.6 12.7
{0x0E, 5}, // E -20.5 -53.0 -58.5 -58.6 -57.7 -57.6 12.7
{0x17, 0}, // 17 -20.5 -52.9 -58.6 -58.6 -57.7 -57.5 12.7
{0x0D, 6}, // D -21.1 -53.3 -58.6 -58.6 -57.8 -57.4 12.6
{0x0C, 5}, // C -21.7 -53.6 -58.6 -58.5 -57.7 -57.5 12.6
{0x16, 0}, // 16 -21.7 -53.6 -58.5 -58.6 -57.6 -57.5 12.6
{0x31, 1}, // 31 -21.9 -53.7 -58.5 -58.4 -57.8 -57.3 12.8
{0x0B, 4}, // B -22.3 -53.9 -58.6 -58.5 -57.8 -57.4 12.5
{0x0A, 6}, // A -23.0 -54.3 -58.6 -58.5 -57.8 -57.4 12.5
{0x15, 0}, // 15 -23.0 -54.3 -58.5 -58.5 -57.8 -57.4 12.5
{0x09, 8}, // 9 -23.8 -54.7 -58.5 -58.5 -57.8 -57.5 12.4
{0x08, 8}, // 8 -24.6 -55.0 -58.6 -58.6 -57.7 -57.6 12.3
{0x14, 0}, // 14 -24.7 -55.0 -58.5 -58.5 -57.7 -57.5 12.4
{0x21, 1}, // 21 -24.8 -55.1 -58.5 -58.5 -57.7 -57.5 12.5
{0x07, 6}, // 7 -25.5 -55.4 -58.6 -58.5 -57.7 -57.5 12.3
{0x13, 10}, // 13 -26.5 -55.9 -58.6 -58.5 -57.6 -57.6 12.3
{0x06, 0}, // 6 -26.5 -55.9 -58.5 -58.5 -57.6 -57.5 12.2
{0x05, 11}, // 5 -27.7 -56.4 -58.4 -58.4 -57.7 -57.5 12.2
{0x12, 11}, // 12 -28.9 -57.1 -58.4 -58.5 -57.7 -57.3 12.2
{0x04, 0}, // 4 -28.9 -57.0 -58.6 -58.4 -57.7 -57.5 12.1
{0x03, 13}, // 3 -30.2 -57.3 -58.5 -58.5 -57.7 -57.5 12.1
{0x02, 15}, // 2 -31.7 -57.9 -58.5 -58.5 -57.7 -57.3 12.0
{0x11, 0}, // 11 -31.7 -58.0 -58.5 -58.5 -57.8 -57.3 12.1
{0x01, 14}, // 1 -33.1 -58.4 -58.6 -58.5 -57.8 -57.5 12.0
{0x10, 10}, // 10 -34.1 -58.2 -58.7 -58.3 -57.7 -57.5 11.9
{0x20, 0}, // 20 -34.1 -58.2 -58.5 -58.5 -57.7 -57.5 12.1
{0x30, 1}, // 30 -34.2 -58.4 -58.6 -58.5 -57.8 -57.5 12.2
{0x6E, 115}, // 6E -45.8 -57.9 -58.6 -58.5 -57.7 -57.5 16.1
{0x00, 135}, // 0 -59.3 -58.3 -58.4 -58.5 -57.8 -57.4 11.3
{0x6F, 99}, // 6F -69.2 -58.2 -58.5 -58.4 -57.6 -57.4 10.8
};
static const PowerTableItem PA_TABLE_915_FULL[] = {
{0xC0, 15}, // C0 9.4 -33.5 -58.5 -58.4 -55.8 -32.6 31.8
{0xC1, 4}, // C1 9.0 -35.9 -58.3 -58.5 -56.1 -34.4 30.9
{0xC2, 4}, // C2 8.6 -38.6 -58.5 -58.4 -56.1 -36.2 30.0
{0xC3, 2}, // C3 8.3 -41.5 -58.6 -58.4 -56.3 -38.0 29.3
{0xC4, 4}, // C4 7.9 -43.6 -58.5 -58.4 -56.5 -39.6 28.6
{0xC5, 3}, // C5 7.6 -43.9 -58.5 -58.5 -56.7 -40.5 28.0
{0xC6, 3}, // C6 7.2 -42.5 -58.5 -58.4 -56.7 -40.5 27.4
{0xC7, 2}, // C7 6.9 -40.7 -58.5 -58.5 -56.8 -40.0 26.9
{0xC8, 3}, // C8 6.6 -39.0 -58.5 -58.4 -56.9 -39.4 26.4
{0xC9, 3}, // C9 6.2 -37.6 -58.6 -58.4 -57.2 -38.8 25.9
{0xCA, 2}, // CA 5.9 -36.5 -58.6 -58.4 -57.3 -38.2 25.5
{0xCB, 3}, // CB 5.6 -35.6 -58.4 -58.4 -57.3 -37.8 25.1
{0xCC, 2}, // CC 5.3 -34.8 -58.6 -58.3 -57.3 -37.5 24.7
{0xCD, 2}, // CD 5.0 -34.2 -58.6 -58.5 -57.5 -37.3 24.3
{0x80, 0}, // 80 4.9 -27.8 -58.5 -58.4 -57.7 -40.6 20.7
{0x81, 2}, // 81 4.7 -28.7 -58.4 -58.5 -57.7 -40.6 20.5
{0x82, 2}, // 82 4.5 -29.6 -58.5 -58.4 -57.7 -40.5 20.2
{0xCE, 2}, // CE 4.3 -33.2 -58.5 -58.3 -57.5 -37.2 23.7
{0x83, 0}, // 83 4.2 -30.7 -58.5 -58.4 -57.7 -40.4 20.0
{0x84, 3}, // 84 3.9 -32.0 -58.6 -58.4 -57.7 -40.1 19.7
{0x85, 2}, // 85 3.6 -33.3 -58.5 -58.5 -57.8 -39.9 19.4
{0x86, 3}, // 86 3.3 -34.8 -58.5 -58.5 -57.6 -39.8 19.2
{0x87, 3}, // 87 2.9 -36.5 -58.4 -58.5 -57.7 -39.6 18.9
{0x88, 3}, // 88 2.5 -38.3 -58.6 -58.4 -57.8 -39.5 18.6
{0x89, 2}, // 89 2.2 -40.2 -58.6 -58.5 -57.6 -39.6 18.3
{0x8A, 4}, // 8A 1.8 -42.2 -58.5 -58.4 -57.7 -39.6 18.1
{0xCF, 1}, // CF 1.6 -31.3 -58.7 -58.3 -57.6 -40.0 21.4
{0x8B, 3}, // 8B 1.3 -44.0 -58.5 -58.4 -57.7 -39.8 17.8
{0x8C, 4}, // 8C 0.9 -45.8 -58.4 -58.4 -57.6 -40.0 17.5
{0x8D, 4}, // 8D 0.5 -46.8 -58.5 -58.5 -57.7 -40.4 17.3
{0x8E, 11}, // 8E -0.6 -46.6 -58.5 -58.5 -57.8 -41.1 16.7
{0x50, 3}, // 50 -0.9 -37.9 -58.5 -58.5 -57.8 -45.9 16.5
{0x60, 2}, // 60 -1.1 -38.0 -58.4 -58.4 -57.7 -46.1 16.4
{0x51, 5}, // 51 -1.6 -38.7 -58.4 -58.5 -57.7 -46.9 16.0
{0x61, 1}, // 61 -1.8 -38.7 -58.5 -58.4 -57.7 -47.0 15.9
{0x40, 3}, // 40 -2.1 -39.4 -58.6 -58.5 -57.7 -47.5 15.7
{0x52, 1}, // 52 -2.2 -39.3 -58.5 -58.4 -57.7 -47.4 15.6
{0x62, 1}, // 62 -2.4 -39.4 -58.5 -58.5 -57.8 -47.6 15.6
{0x3F, 1}, // 3F -2.5 -49.6 -58.4 -58.4 -57.6 -55.1 21.3
{0x3E, 2}, // 3E -2.7 -50.0 -58.5 -58.4 -57.6 -55.3 20.7
{0x53, 1}, // 53 -2.9 -40.1 -58.5 -58.4 -57.8 -47.7 15.3
{0x3D, 1}, // 3D -3.0 -50.3 -58.4 -58.5 -57.7 -55.2 20.1
{0x63, 0}, // 63 -3.0 -40.1 -58.4 -58.4 -57.8 -47.7 15.2
{0x3C, 3}, // 3C -3.4 -50.7 -58.4 -58.5 -57.7 -55.3 19.5
{0x54, 1}, // 54 -3.5 -40.8 -58.5 -58.5 -57.7 -48.0 15.0
{0x64, 2}, // 64 -3.7 -40.8 -58.5 -58.5 -57.6 -48.1 14.9
{0x3B, 0}, // 3B -3.8 -50.7 -58.6 -58.4 -57.6 -55.2 18.9
{0x55, 2}, // 55 -4.1 -41.6 -58.5 -58.4 -57.7 -49.2 14.7
{0x2F, 1}, // 2F -4.2 -50.3 -58.5 -58.4 -57.7 -54.1 18.1
{0x65, 0}, // 65 -4.3 -41.6 -58.6 -58.4 -57.6 -49.2 14.6
{0x3A, 1}, // 3A -4.4 -50.5 -58.6 -58.4 -57.7 -54.8 18.3
{0x2E, 2}, // 2E -4.7 -49.4 -58.5 -58.4 -57.7 -53.6 17.7
{0x56, 0}, // 56 -4.7 -42.3 -58.5 -58.5 -57.8 -50.5 14.4
{0x66, 2}, // 66 -4.9 -42.3 -58.5 -58.4 -57.7 -50.6 14.4
{0x39, 1}, // 39 -5.1 -50.0 -58.5 -58.5 -57.6 -54.0 17.7
{0x2D, 1}, // 2D -5.2 -48.8 -58.5 -58.4 -57.7 -53.0 17.3
{0x57, 2}, // 57 -5.4 -43.1 -58.6 -58.4 -57.8 -51.9 14.2
{0x67, 1}, // 67 -5.6 -43.1 -58.5 -58.4 -57.8 -52.1 14.1
{0x8F, 1}, // 8F -5.7 -46.0 -58.6 -58.4 -57.6 -45.5 14.9
{0x2C, 0}, // 2C -5.8 -48.1 -58.5 -58.4 -57.7 -52.4 16.9
{0x38, 1}, // 38 -5.9 -49.2 -58.6 -58.4 -57.7 -53.3 17.1
{0x68, 2}, // 68 -6.2 -43.9 -58.5 -58.5 -57.6 -51.6 13.9
{0x2B, 2}, // 2B -6.4 -47.6 -58.4 -58.4 -57.8 -52.1 16.5
{0x37, 2}, // 37 -6.7 -47.4 -58.6 -58.4 -57.7 -51.7 16.4
{0x69, 0}, // 69 -6.8 -44.9 -58.5 -58.4 -57.7 -51.8 13.8
{0x2A, 4}, // 2A -7.2 -47.2 -58.6 -58.4 -57.8 -51.6 16.1
{0x6A, 2}, // 6A -7.4 -46.2 -58.5 -58.4 -57.9 -53.1 13.7
{0x36, 5}, // 36 -7.9 -46.9 -58.5 -58.4 -57.7 -51.2 15.8
{0x29, 0}, // 29 -8.0 -47.0 -58.6 -58.4 -57.8 -51.2 15.7
{0x6B, 4}, // 6B -8.4 -49.0 -58.5 -58.4 -57.8 -55.4 13.9
{0x28, 4}, // 28 -8.8 -46.8 -58.4 -58.5 -57.6 -50.9 15.3
{0x35, 5}, // 35 -9.3 -46.7 -58.6 -58.4 -57.7 -50.7 15.2
{0x27, 3}, // 27 -9.7 -46.7 -58.5 -58.4 -57.6 -50.7 14.9
{0x26, 12}, // 26 -10.9 -47.0 -58.6 -58.4 -57.8 -50.9 14.5
{0x34, 0}, // 34 -10.9 -47.0 -58.5 -58.4 -57.8 -50.8 14.5
{0x25, 14}, // 25 -12.3 -47.2 -58.6 -58.3 -57.7 -51.0 14.1
{0x6C, 0}, // 6C -12.4 -54.4 -58.6 -58.4 -57.8 -55.3 14.6
{0x33, 6}, // 33 -13.1 -47.6 -58.5 -58.4 -57.8 -51.2 14.0
{0x24, 10}, // 24 -14.1 -48.1 -58.4 -58.4 -57.8 -51.4 13.7
{0x1F, 3}, // 1F -14.4 -48.2 -58.5 -58.4 -57.7 -51.5 13.5
{0x1E, 5}, // 1E -14.9 -48.4 -58.5 -58.4 -57.8 -51.7 13.4
{0x1D, 5}, // 1D -15.5 -48.7 -58.4 -58.5 -57.7 -51.9 13.2
{0x1C, 6}, // 1C -16.1 -49.0 -58.4 -58.4 -57.7 -52.2 13.1
{0x23, 1}, // 23 -16.3 -49.1 -58.4 -58.5 -57.8 -51.9 13.3
{0x32, 0}, // 32 -16.4 -49.0 -58.5 -58.5 -57.7 -52.0 13.3
{0x1B, 4}, // 1B -16.8 -49.3 -58.6 -58.4 -57.8 -52.3 13.0
{0x1A, 6}, // 1A -17.5 -49.7 -58.5 -58.4 -57.8 -52.6 12.9
{0x19, 8}, // 19 -18.3 -50.2 -58.5 -58.5 -57.6 -52.8 12.8
{0x18, 10}, // 18 -19.3 -50.6 -58.5 -58.5 -57.7 -53.1 12.7
{0x22, 0}, // 22 -19.4 -50.7 -58.5 -58.5 -57.8 -53.1 12.8
{0x0F, 3}, // F -19.7 -50.9 -58.5 -58.5 -57.7 -52.9 12.6
{0x0E, 5}, // E -20.2 -51.2 -58.6 -58.5 -57.8 -53.3 12.6
{0x17, 1}, // 17 -20.3 -51.2 -58.6 -58.5 -57.8 -53.1 12.6
{0x0D, 5}, // D -20.8 -51.4 -58.5 -58.5 -57.8 -53.2 12.5
{0x0C, 5}, // C -21.4 -51.8 -58.4 -58.5 -57.7 -53.4 12.5
{0x16, 0}, // 16 -21.4 -51.9 -58.5 -58.5 -57.7 -53.4 12.5
{0x31, 3}, // 31 -21.7 -52.0 -58.5 -58.4 -57.8 -53.4 12.7
{0x0B, 3}, // B -22.0 -52.2 -58.5 -58.4 -57.9 -53.6 12.4
{0x0A, 6}, // A -22.7 -52.6 -58.5 -58.4 -57.7 -53.6 12.4
{0x15, 1}, // 15 -22.8 -52.7 -58.5 -58.4 -57.8 -53.6 12.4
{0x09, 6}, // 9 -23.5 -53.1 -58.5 -58.5 -57.7 -54.0 12.3
{0x6D, 3}, // 6D -23.8 -50.2 -58.5 -58.4 -57.6 -55.3 15.5
{0x08, 5}, // 8 -24.3 -53.6 -58.4 -58.4 -57.6 -54.1 12.3
{0x14, 0}, // 14 -24.4 -53.7 -58.6 -58.4 -57.8 -53.9 12.3
{0x21, 2}, // 21 -24.6 -53.6 -58.6 -58.4 -57.8 -53.9 12.4
{0x07, 5}, // 7 -25.2 -54.1 -58.6 -58.4 -57.7 -54.0 12.2
{0x13, 10}, // 13 -26.2 -54.6 -58.4 -58.5 -57.7 -54.3 12.2
{0x06, 0}, // 6 -26.2 -54.6 -58.5 -58.3 -57.7 -54.3 12.2
{0x05, 11}, // 5 -27.3 -55.3 -58.4 -58.4 -57.8 -54.5 12.1
{0x12, 13}, // 12 -28.6 -55.9 -58.6 -58.5 -57.7 -54.7 12.1
{0x04, 0}, // 4 -28.6 -56.1 -58.5 -58.4 -57.8 -54.5 12.0
{0x03, 11}, // 3 -29.8 -56.9 -58.5 -58.4 -57.7 -54.7 12.0
{0x02, 13}, // 2 -31.2 -57.5 -58.4 -58.4 -57.9 -54.7 11.9
{0x11, 1}, // 11 -31.3 -57.6 -58.6 -58.3 -57.8 -54.7 12.0
{0x01, 14}, // 1 -32.7 -58.4 -58.4 -58.4 -57.7 -54.7 11.9
{0x10, 8}, // 10 -33.6 -58.6 -58.5 -58.3 -57.8 -54.8 11.9
{0x20, 1}, // 20 -33.7 -58.6 -58.5 -58.3 -57.9 -54.6 12.0
{0x30, 0}, // 30 -33.7 -58.5 -58.5 -58.4 -57.7 -54.9 12.1
{0x00, 245}, // 0 -58.2 -58.5 -58.6 -58.3 -57.6 -54.1 11.2
{0x6E, 62}, // 6E -64.5 -58.8 -58.5 -58.4 -57.7 -55.5 16.0
{0x6F, 52}, // 6F -69.7 -58.6 -58.6 -58.4 -57.7 -55.3 10.7
};
*/
} // namespace cc1101
} // namespace esphome
-57
View File
@@ -1,57 +0,0 @@
#pragma once
namespace esphome {
namespace cc1101 {
#ifndef SUB_TEXT
#define SUB_TEXT(name) \
protected: \
text::Text *name##_text_{nullptr}; \
\
public: \
void set_##name##_text(text::Text *text) { this->name##_text_ = text; }
#endif
#define CC1101_SUB_NUMBER(name, type) \
SUB_NUMBER(name) \
void publish_##name() { this->publish_(this->name##_number_, (float) this->get_##name()); } \
void set_##name(type value); \
type get_##name();
#define CC1101_SUB_SWITCH(name) \
SUB_SWITCH(name) \
void publish_##name() { this->publish_switch_(this->name##_switch_, this->get_##name()); } \
void set_##name(bool value); \
bool get_##name();
#define CC1101_SUB_SELECT(name, type) \
SUB_SELECT(name) \
void publish_##name() { this->publish_select_(this->name##_select_, (size_t) this->get_##name()); } \
void set_##name(type value); \
type get_##name();
#define CC1101_SUB_TEXT(name) \
SUB_TEXT(name) \
void publish_##name() { this->publish_(this->name##_text_, this->get_##name()); } \
void set_##name(const std::string &value); \
std::string get_##name();
#define CC1101_SUB_SENSOR(name) \
SUB_SENSOR(name) \
void publish_##name##_sensor() { this->publish_(this->name##_sensor_, (float) this->get_##name##_sensor()); } \
float get_##name##_sensor();
#define CC1101_SUB_BINARY_SENSOR(name) \
SUB_BINARY_SENSOR(name) \
void publish_##name##_binary_sensor() { \
this->publish_(this->name##_binary_sensor_, this->get_##name##_binary_sensor()); \
} \
bool get_##name##_binary_sensor();
#define CC1101_SUB_TEXT_SENSOR(name) \
SUB_TEXT_SENSOR(name) \
void publish_##name##_text_sensor() { this->publish_(this->name##_text_sensor_, this->get_##name##_text_sensor()); } \
std::string get_##name##_text_sensor();
} // namespace cc1101
} // namespace esphome
-204
View File
@@ -1,204 +0,0 @@
import esphome.codegen as cg
from esphome.components import number
import esphome.config_validation as cv
from esphome.const import (
CONF_CHANNEL,
CONF_FREQUENCY,
CONF_MODE,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_SIGNAL_STRENGTH,
ENTITY_CATEGORY_CONFIG,
UNIT_DECIBEL,
UNIT_DECIBEL_MILLIWATT,
)
from .. import (
CC1101_COMPONENT_SCHEMA,
CONF_AGC,
CONF_BANDWIDTH,
CONF_CARRIER_SENSE_ABS_THR,
CONF_CC1101_ID,
CONF_CHANNEL_SPACING,
CONF_FSK_DEVIATION,
CONF_IF_FREQUENCY,
CONF_MSK_DEVIATION,
CONF_OUTPUT_POWER,
CONF_SYMBOL_RATE,
CONF_TUNER,
UNIT_KILO_HERTZ,
for_each_conf,
ns,
)
NumberMode = number.NumberMode
OutputPowerNumber = ns.class_("OutputPowerNumber", number.Number)
TunerFrequencyNumber = ns.class_("TunerFrequencyNumber", number.Number)
TunerIfFrequencyNumber = ns.class_("TunerIfFrequencyNumber", number.Number)
TunerBandwidthNumber = ns.class_("TunerBandwidthNumber", number.Number)
TunerChannelNumber = ns.class_("TunerChannelNumber", number.Number)
TunerChannelSpacingNumber = ns.class_("TunerChannelSpacingNumber", number.Number)
TunerFskDeviationNumber = ns.class_("TunerFskDeviationNumber", number.Number)
TunerMskDeviationNumber = ns.class_("TunerMskDeviationNumber", number.Number)
TunerSymbolRateNumber = ns.class_("TunerSymbolRateNumber", number.Number)
AgcCarrierSenseAbsThrNumber = ns.class_("AgcCarrierSenseAbsThrNumber", number.Number)
TYPES = {
None: {
CONF_OUTPUT_POWER: [
number.number_schema(
OutputPowerNumber,
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.OUTPUT_POWER_MIN,
ns.OUTPUT_POWER_MAX,
0.1,
NumberMode.NUMBER_MODE_SLIDER,
],
},
CONF_TUNER: {
CONF_FREQUENCY: [
number.number_schema(
TunerFrequencyNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.FREQUENCY_MIN,
ns.FREQUENCY_MAX,
1,
],
CONF_IF_FREQUENCY: [
number.number_schema(
TunerIfFrequencyNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.IF_FREQUENCY_MIN,
ns.IF_FREQUENCY_MAX,
0.001,
],
CONF_BANDWIDTH: [
number.number_schema(
TunerBandwidthNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.BANDWIDTH_MIN,
ns.BANDWIDTH_MAX,
0.001,
],
CONF_CHANNEL: [
number.number_schema(
TunerChannelNumber,
# unit_of_measurement=,
# device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.CHANNEL_MIN,
ns.CHANNEL_MAX,
1,
# NumberMode.NUMBER_MODE_BOX,
],
CONF_CHANNEL_SPACING: [
number.number_schema(
TunerChannelSpacingNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.CHANNEL_SPACING_MIN,
ns.CHANNEL_SPACING_MAX,
0.001,
],
CONF_FSK_DEVIATION: [
number.number_schema(
TunerFskDeviationNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.FSK_DEVIATION_MIN,
ns.FSK_DEVIATION_MAX,
0.001,
],
CONF_MSK_DEVIATION: [
number.number_schema(
TunerMskDeviationNumber,
# unit_of_measurement=,
# device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.MSK_DEVIATION_MIN,
ns.MSK_DEVIATION_MAX,
1,
],
CONF_SYMBOL_RATE: [
number.number_schema(
TunerSymbolRateNumber,
# unit_of_measurement=,
# device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.SYMBOL_RATE_MIN,
ns.SYMBOL_RATE_MAX,
1,
],
},
CONF_AGC: {
CONF_CARRIER_SENSE_ABS_THR: [
number.number_schema(
AgcCarrierSenseAbsThrNumber,
unit_of_measurement=UNIT_DECIBEL,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
ns.CARRIER_SENSE_ABS_THR_MIN,
ns.CARRIER_SENSE_ABS_THR_MAX,
1,
],
},
}
CONFIG_SCHEMA = CC1101_COMPONENT_SCHEMA.extend(
{cv.Optional(k): v[0] for k, v in TYPES[None].items()},
{
cv.Optional(CONF_TUNER): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_TUNER].items()}
),
cv.Optional(CONF_AGC): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_AGC].items()}
),
},
)
async def to_code(config):
parent = await cg.get_variable(config[CONF_CC1101_ID])
async def new_number(c, args, setter):
# only override mode when it's set to auto in user config
if CONF_MODE not in c or c[CONF_MODE] == NumberMode.NUMBER_MODE_AUTO:
if len(args) > 3 and args[3] is not None:
c[CONF_MODE] = args[3]
n = await number.new_number(
c, min_value=args[0], max_value=args[1], step=args[2]
)
await cg.register_parented(n, parent)
cg.add(getattr(parent, setter + "_number")(n))
await for_each_conf(config, TYPES, new_number)
-51
View File
@@ -1,51 +0,0 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../cc1101.h"
#include <cmath>
namespace esphome {
namespace cc1101 {
// maybe there is a way to specialize type dependent member pointers
template<void (CC1101Component::*F)(float)>
class NumberFloat : public number::Number, public Parented<CC1101Component> {
protected:
void control(float value) override {
this->publish_state(value);
(this->parent_->*F)(value);
}
};
template<void (CC1101Component::*F)(uint8_t)>
class NumberUInt8 : public number::Number, public Parented<CC1101Component> {
protected:
void control(float value) override {
this->publish_state(value);
(this->parent_->*F)((uint8_t) lround(value));
}
};
template<void (CC1101Component::*F)(int8_t)>
class NumberInt8 : public number::Number, public Parented<CC1101Component> {
protected:
void control(float value) override {
this->publish_state(value);
(this->parent_->*F)((int8_t) lround(value));
}
};
using OutputPowerNumber = NumberFloat<&CC1101Component::set_output_power>;
using TunerFrequencyNumber = NumberFloat<&CC1101Component::set_tuner_frequency>;
using TunerIfFrequencyNumber = NumberFloat<&CC1101Component::set_tuner_if_frequency>;
using TunerBandwidthNumber = NumberFloat<&CC1101Component::set_tuner_bandwidth>;
using TunerChannelNumber = NumberUInt8<&CC1101Component::set_tuner_channel>;
using TunerChannelSpacingNumber = NumberFloat<&CC1101Component::set_tuner_channel_spacing>;
using TunerFskDeviationNumber = NumberFloat<&CC1101Component::set_tuner_fsk_deviation>;
using TunerMskDeviationNumber = NumberUInt8<&CC1101Component::set_tuner_msk_deviation>;
using TunerSymbolRateNumber = NumberFloat<&CC1101Component::set_tuner_symbol_rate>;
using AgcCarrierSenseAbsThrNumber = NumberInt8<&CC1101Component::set_agc_carrier_sense_abs_thr>;
} // namespace cc1101
} // namespace esphome
-178
View File
@@ -1,178 +0,0 @@
import esphome.codegen as cg
from esphome.components import select
import esphome.config_validation as cv
from esphome.const import CONF_WAIT_TIME, ENTITY_CATEGORY_CONFIG
from .. import (
CARRIER_SENSE_REL_THR,
CC1101_COMPONENT_SCHEMA,
CONF_AGC,
CONF_CARRIER_SENSE_REL_THR,
CONF_CC1101_ID,
CONF_FILTER_LENGTH_ASK_OOK,
CONF_FILTER_LENGTH_FSK_MSK,
CONF_FREEZE,
CONF_HYST_LEVEL,
CONF_MAGN_TARGET,
CONF_MAX_DVGA_GAIN,
CONF_MAX_LNA_GAIN,
CONF_MODULATION,
CONF_RX_ATTENUATION,
CONF_SYNC_MODE,
CONF_TUNER,
FILTER_LENGTH_ASK_OOK,
FILTER_LENGTH_FSK_MSK,
FREEZE,
HYST_LEVEL,
MAGN_TARGET,
MAX_DVGA_GAIN,
MAX_LNA_GAIN,
MODULATION,
RX_ATTENUATION,
SYNC_MODE,
WAIT_TIME,
for_each_conf,
ns,
)
RxAttenuationSelect = ns.class_("RxAttenuationSelect", select.Select)
TunerSyncModeSelect = ns.class_("TunerSyncModeSelect", select.Select)
TunerModulationSelect = ns.class_("TunerModulationSelect", select.Select)
AgcMagnTargetSelect = ns.class_("AgcMagnTargetSelect", select.Select)
AgcMaxLnaGainSelect = ns.class_("AgcMaxLnaGainSelect", select.Select)
AgcMaxDvgaGainSelect = ns.class_("AgcMaxDvgaGainSelect", select.Select)
AgcCarrierSenseRelThrSelect = ns.class_("AgcCarrierSenseRelThrSelect", select.Select)
AgcFilterLengthFskMskSelect = ns.class_("AgcFilterLengthFskMskSelect", select.Select)
AgcFilterLengthAskOokSelect = ns.class_("AgcFilterLengthAskOokSelect", select.Select)
AgcFreezeSelect = ns.class_("AgcFreezeSelect", select.Select)
AgcWaitTimeSelect = ns.class_("AgcWaitTimeSelect", select.Select)
AgcHystLevelSelect = ns.class_("AgcHystLevelSelect", select.Select)
TYPES = {
None: {
CONF_RX_ATTENUATION: [
select.select_schema(
RxAttenuationSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
RX_ATTENUATION,
],
},
CONF_TUNER: {
CONF_SYNC_MODE: [
select.select_schema(
TunerSyncModeSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
SYNC_MODE,
],
CONF_MODULATION: [
select.select_schema(
TunerModulationSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
MODULATION,
],
},
CONF_AGC: {
CONF_MAGN_TARGET: [
select.select_schema(
AgcMagnTargetSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
MAGN_TARGET,
],
CONF_MAX_LNA_GAIN: [
select.select_schema(
AgcMaxLnaGainSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
MAX_LNA_GAIN,
],
CONF_MAX_DVGA_GAIN: [
select.select_schema(
AgcMaxDvgaGainSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
MAX_DVGA_GAIN,
],
CONF_CARRIER_SENSE_REL_THR: [
select.select_schema(
AgcCarrierSenseRelThrSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
CARRIER_SENSE_REL_THR,
],
CONF_FILTER_LENGTH_FSK_MSK: [
select.select_schema(
AgcFilterLengthFskMskSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
FILTER_LENGTH_FSK_MSK,
],
CONF_FILTER_LENGTH_ASK_OOK: [
select.select_schema(
AgcFilterLengthAskOokSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
FILTER_LENGTH_ASK_OOK,
],
CONF_FREEZE: [
select.select_schema(
AgcFreezeSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
FREEZE,
],
CONF_WAIT_TIME: [
select.select_schema(
AgcWaitTimeSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
WAIT_TIME,
],
CONF_HYST_LEVEL: [
select.select_schema(
AgcHystLevelSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
HYST_LEVEL,
],
},
}
CONFIG_SCHEMA = CC1101_COMPONENT_SCHEMA.extend(
{cv.Optional(k): v[0] for k, v in TYPES[None].items()},
{
cv.Optional(CONF_TUNER): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_TUNER].items()}
),
cv.Optional(CONF_AGC): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_AGC].items()}
),
},
)
async def to_code(config):
parent = await cg.get_variable(config[CONF_CC1101_ID])
async def new_select(c, args, setter):
s = await select.new_select(c, options=list(args[0].keys()))
await cg.register_parented(s, parent)
cg.add(getattr(parent, setter + "_select")(s))
await for_each_conf(config, TYPES, new_select)
-34
View File
@@ -1,34 +0,0 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../cc1101.h"
namespace esphome {
namespace cc1101 {
template<class T, void (CC1101Component::*F)(T)>
class Select : public select::Select, public Parented<CC1101Component> {
protected:
void control(const std::string &value) override {
this->publish_state(value);
if (auto index = this->active_index()) {
(this->parent_->*F)((T) *index);
}
}
};
using RxAttenuationSelect = Select<RxAttenuation, &CC1101Component::set_rx_attenuation>;
using TunerSyncModeSelect = Select<SyncMode, &CC1101Component::set_tuner_sync_mode>;
using TunerModulationSelect = Select<Modulation, &CC1101Component::set_tuner_modulation>;
using AgcMagnTargetSelect = Select<MagnTarget, &CC1101Component::set_agc_magn_target>;
using AgcMaxLnaGainSelect = Select<MaxLnaGain, &CC1101Component::set_agc_max_lna_gain>;
using AgcMaxDvgaGainSelect = Select<MaxDvgaGain, &CC1101Component::set_agc_max_dvga_gain>;
using AgcCarrierSenseRelThrSelect = Select<CarrierSenseRelThr, &CC1101Component::set_agc_carrier_sense_rel_thr>;
using AgcFilterLengthFskMskSelect = Select<FilterLengthFskMsk, &CC1101Component::set_agc_filter_length_fsk_msk>;
using AgcFilterLengthAskOokSelect = Select<FilterLengthAskOok, &CC1101Component::set_agc_filter_length_ask_ook>;
using AgcFreezeSelect = Select<Freeze, &CC1101Component::set_agc_freeze>;
using AgcWaitTimeSelect = Select<WaitTime, &CC1101Component::set_agc_wait_time>;
using AgcHystLevelSelect = Select<HystLevel, &CC1101Component::set_agc_hyst_level>;
} // namespace cc1101
} // namespace esphome
-78
View File
@@ -1,78 +0,0 @@
import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
from .. import (
CC1101_COMPONENT_SCHEMA,
CONF_AGC,
CONF_CARRIER_SENSE_ABOVE_THRESHOLD,
CONF_CC1101_ID,
CONF_DC_BLOCKING_FILTER,
CONF_LNA_PRIORITY,
CONF_TUNER,
for_each_conf,
ns,
)
DcBlockingFilterSwitch = ns.class_("DcBlockingFilterSwitch", switch.Switch)
CarrierSenseAboveThresholdSwitch = ns.class_(
"CarrierSenseAboveThresholdSwitch", switch.Switch
)
AgcLnaPrioritySwitch = ns.class_("AgcLnaPrioritySwitch", switch.Switch)
TYPES = {
None: {
CONF_DC_BLOCKING_FILTER: [
switch.switch_schema(
DcBlockingFilterSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
],
},
CONF_TUNER: {
CONF_CARRIER_SENSE_ABOVE_THRESHOLD: [
switch.switch_schema(
CarrierSenseAboveThresholdSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
],
},
CONF_AGC: {
CONF_LNA_PRIORITY: [
switch.switch_schema(
AgcLnaPrioritySwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
],
},
}
CONFIG_SCHEMA = CC1101_COMPONENT_SCHEMA.extend(
{cv.Optional(k): v[0] for k, v in TYPES[None].items()},
{
cv.Optional(CONF_TUNER): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_TUNER].items()}
),
cv.Optional(CONF_AGC): cv.Schema(
{cv.Optional(k): v[0] for k, v in TYPES[CONF_AGC].items()}
),
},
)
async def to_code(config):
parent = await cg.get_variable(config[CONF_CC1101_ID])
async def new_switch(c, args, setter):
s = await switch.new_switch(c)
await cg.register_parented(s, parent)
cg.add(getattr(parent, setter + "_switch")(s))
await for_each_conf(config, TYPES, new_switch)
-22
View File
@@ -1,22 +0,0 @@
#pragma once
#include "esphome/components/switch/switch.h"
#include "../cc1101.h"
namespace esphome {
namespace cc1101 {
template<void (CC1101Component::*F)(bool)> class Switch : public switch_::Switch, public Parented<CC1101Component> {
protected:
void write_state(bool value) override {
this->publish_state(value);
(this->parent_->*F)(value);
}
};
using DcBlockingFilterSwitch = Switch<&CC1101Component::set_dc_blocking_filter>;
using CarrierSenseAboveThresholdSwitch = Switch<&CC1101Component::set_tuner_carrier_sense_above_threshold>;
using AgcLnaPrioritySwitch = Switch<&CC1101Component::set_agc_lna_priority>;
} // namespace cc1101
} // namespace esphome
-133
View File
@@ -1,133 +0,0 @@
from typing import Optional
import esphome.codegen as cg
from esphome.components import mqtt, text, web_server
import esphome.config_validation as cv
from esphome.const import (
CONF_ENTITY_CATEGORY,
CONF_ICON,
CONF_ID,
CONF_MQTT_ID,
CONF_WEB_SERVER,
ENTITY_CATEGORY_CONFIG,
)
from esphome.core import CORE
from esphome.cpp_generator import MockObjClass
from esphome.cpp_helpers import setup_entity
from .. import CC1101_COMPONENT_SCHEMA, CONF_CC1101_ID, for_each_conf, ns
CONF_DUMMY_TEXT = "dummy_text"
ICON_FORMAT_TEXT = "mdi:format-text"
DummyText = ns.class_("DummyText", text.Text)
# The text component isn't implemented the same way as switch, select, number.
# It is not possible to create our own text platform as it is now, so I adopted
# the necessary code from those.
_TEXT_SCHEMA = (
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
.extend(
{
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextComponent),
}
)
)
_UNDEF = object()
def text_schema(
class_: MockObjClass = _UNDEF,
*,
entity_category: str = _UNDEF,
device_class: str = _UNDEF,
icon: str = _UNDEF,
):
schema = _TEXT_SCHEMA
if class_ is not _UNDEF:
schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
if entity_category is not _UNDEF:
schema = schema.extend(
{
cv.Optional(
CONF_ENTITY_CATEGORY, default=entity_category
): cv.entity_category
}
)
if icon is not _UNDEF:
schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
return schema
TEXT_SCHEMA = text_schema() # for compatibility
async def setup_text_core_(
var,
config,
*,
min_length: Optional[int],
max_length: Optional[int],
pattern: Optional[str],
):
await setup_entity(var, config)
cg.add(var.traits.set_min_length(min_length))
cg.add(var.traits.set_max_length(max_length))
if pattern is not None:
cg.add(var.traits.set_pattern(pattern))
if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
mqtt_ = cg.new_Pvariable(mqtt_id, var)
await mqtt.register_mqtt_component(mqtt_, config)
if web_server_config := config.get(CONF_WEB_SERVER):
await web_server.add_entity_config(var, web_server_config)
async def register_text(
var,
config,
min_length: Optional[int] = 0,
max_length: Optional[int] = 255,
pattern: Optional[str] = None,
):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_text(var))
await setup_text_core_(
var, config, min_length=min_length, max_length=max_length, pattern=pattern
)
TYPES = {
None: {
CONF_DUMMY_TEXT: [
text_schema(
DummyText,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_FORMAT_TEXT,
),
0,
64,
]
},
}
CONFIG_SCHEMA = CC1101_COMPONENT_SCHEMA.extend(
{cv.Optional(k): v[0] for k, v in TYPES[None].items()},
)
async def to_code(config):
parent = await cg.get_variable(config[CONF_CC1101_ID])
async def new_text(c, args, setter):
var = cg.new_Pvariable(c[CONF_ID])
await register_text(var, c, min_length=args[0], max_length=args[1])
await cg.register_parented(var, parent)
cg.add(getattr(parent, setter + "_text")(var))
await for_each_conf(config, TYPES, new_text)
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include "esphome/components/text/text.h"
#include "../cc1101.h"
namespace esphome {
namespace cc1101 {
class DummyText : public text::Text, public Parented<CC1101Component> {
protected:
void control(const std::string &value) override {
this->publish_state(value);
// this->parent_->set_dummy_text(value);
}
};
} // namespace cc1101
} // namespace esphome
View File
-282
View File
@@ -1,282 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.const as c
from esphome.components import lock, binary_sensor, text_sensor, sensor, button, time
AUTO_LOAD = ["binary_sensor", "text_sensor", "sensor", "button"]
CONF_PAIRED = "paired"
CONF_ERROR = "error"
CONF_BATTERY_CRITICAL = "battery_critical"
CONF_DOOR_CONTACT = "door_contact"
CONF_DOOR_CONTACT_SENSOR = "door_contact_sensor"
CONF_BEACON_RSSI = "beacon_rssi"
CONF_BEACON_LATENCY = "beacon_latency"
CONF_HEARTBEAT_LATENCY = "heartbeat_latency"
CONF_BEACON_BLE_ADDRESS = "beacon_ble_address"
CONF_LOCK_CURRENT_DATETIME = "lock_current_datetime"
CONF_TRIGGER = "trigger"
CONF_CONFIG_UPDATE_COUNT = "config_update_count"
CONF_LAST_ACTION = "last_action"
CONF_LAST_ACTION_TRIGGER = "last_action_trigger"
CONF_LAST_ACTION_COMPLETION_STATUS = "last_action_completion_status"
CONF_NIGHT_MODE_ACTIVE = "night_mode_active"
CONF_BATTERY_RESISTANCE = "battery_resistance"
CONF_LAST_ACTION_LOWEST_VOLTAGE = "last_action_lowest_voltage"
CONF_LAST_ACTION_START_VOLTAGE = "last_action_start_voltage"
CONF_LAST_ACTION_LOCK_DISTANCE = "last_action_lock_distance"
CONF_LAST_ACTION_START_TEMPERATURE = "last_action_start_temperature"
CONF_LAST_ACTION_BATTERY_DRAIN = "last_action_battery_drain"
CONF_LAST_ACTION_MAX_TURN_CURRENT = "last_action_max_turn_current"
CONF_REQUEST_BATTERY_REPORTS = "request_battery_reports"
CONF_RESTART_AFTER_BEACON_LATENCY = "restart_after_beacon_latency"
CONF_REQUEST_STATE = "request_state"
CONF_UNPAIR = "unpair"
CONF_TIME_SOURCE = "time_source"
nuki_lock_ns = cg.esphome_ns.namespace("nuki_lock")
NukiLockComponent = nuki_lock_ns.class_("NukiLockComponent", lock.Lock, cg.PollingComponent)
RequestStateButton = nuki_lock_ns.class_("RequestStateButton", button.Button)
UnpairButton = nuki_lock_ns.class_("UnpairButton", button.Button)
CONFIG_SCHEMA = lock.LOCK_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(NukiLockComponent),
# Required sensors (if unconfigured, defaults are used).
cv.Optional(CONF_PAIRED, default={
c.CONF_NAME: "Paired",
}): binary_sensor.binary_sensor_schema(
device_class=c.DEVICE_CLASS_CONNECTIVITY,
),
cv.Optional(CONF_ERROR, default={
c.CONF_NAME: "Error",
}): text_sensor.text_sensor_schema(
icon="mdi:alert",
),
cv.Optional(CONF_BATTERY_CRITICAL, default={
c.CONF_NAME: "Battery critical",
}): binary_sensor.binary_sensor_schema(
device_class=c.DEVICE_CLASS_BATTERY,
),
cv.Optional(c.CONF_BATTERY_LEVEL, default={
c.CONF_NAME: "Battery",
}): sensor.sensor_schema(
device_class=c.DEVICE_CLASS_BATTERY,
unit_of_measurement=c.UNIT_PERCENT,
),
cv.Optional(CONF_DOOR_CONTACT, default={
c.CONF_NAME: "Door contact",
}): binary_sensor.binary_sensor_schema(
device_class=c.DEVICE_CLASS_DOOR,
),
cv.Optional(CONF_DOOR_CONTACT_SENSOR, default={
c.CONF_NAME: "Door contact sensor",
}): text_sensor.text_sensor_schema(),
cv.Optional(CONF_TRIGGER, default={
c.CONF_NAME: "Trigger",
}): text_sensor.text_sensor_schema(),
cv.Optional(CONF_NIGHT_MODE_ACTIVE, default={
c.CONF_NAME: "Night mode active",
}): binary_sensor.binary_sensor_schema(
icon="mdi:weather-night",
),
# Optional sensors.
cv.Optional(CONF_BEACON_RSSI): sensor.sensor_schema(
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
state_class=c.STATE_CLASS_MEASUREMENT,
device_class=c.DEVICE_CLASS_SIGNAL_STRENGTH,
unit_of_measurement=c.UNIT_DECIBEL_MILLIWATT,
),
cv.Optional(CONF_BEACON_LATENCY): sensor.sensor_schema(
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
state_class=c.STATE_CLASS_MEASUREMENT,
unit_of_measurement=c.UNIT_MILLISECOND,
),
cv.Optional(CONF_HEARTBEAT_LATENCY): sensor.sensor_schema(
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
state_class=c.STATE_CLASS_MEASUREMENT,
unit_of_measurement=c.UNIT_MILLISECOND,
),
cv.Optional(CONF_BEACON_BLE_ADDRESS): text_sensor.text_sensor_schema(
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
icon="mdi:bluetooth",
),
cv.Optional(CONF_LOCK_CURRENT_DATETIME): text_sensor.text_sensor_schema(
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
device_class=c.DEVICE_CLASS_TIMESTAMP,
),
cv.Optional(CONF_CONFIG_UPDATE_COUNT): sensor.sensor_schema(
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
state_class=c.STATE_CLASS_TOTAL,
),
cv.Optional(CONF_LAST_ACTION): text_sensor.text_sensor_schema(),
cv.Optional(CONF_LAST_ACTION_TRIGGER): text_sensor.text_sensor_schema(),
cv.Optional(CONF_LAST_ACTION_COMPLETION_STATUS): text_sensor.text_sensor_schema(),
# Optional sensors - battery report.
cv.Optional(CONF_REQUEST_BATTERY_REPORTS, default=False): cv.boolean,
cv.Optional(c.CONF_BATTERY_VOLTAGE, default={
c.CONF_NAME: "Battery voltage",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
device_class=c.DEVICE_CLASS_VOLTAGE,
unit_of_measurement=c.UNIT_VOLT,
accuracy_decimals=3,
),
cv.Optional(CONF_BATTERY_RESISTANCE, default={
c.CONF_NAME: "Battery resistance",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
unit_of_measurement=c.UNIT_OHM,
accuracy_decimals=3,
icon="mdi:resistor",
),
cv.Optional(CONF_LAST_ACTION_LOWEST_VOLTAGE, default={
c.CONF_NAME: "Last action lowest voltage",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
device_class=c.DEVICE_CLASS_VOLTAGE,
unit_of_measurement=c.UNIT_VOLT,
accuracy_decimals=3,
),
cv.Optional(CONF_LAST_ACTION_START_VOLTAGE, default={
c.CONF_NAME: "Last action start voltage",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
device_class=c.DEVICE_CLASS_VOLTAGE,
unit_of_measurement=c.UNIT_VOLT,
accuracy_decimals=3,
),
cv.Optional(CONF_LAST_ACTION_LOCK_DISTANCE, default={
c.CONF_NAME: "Last action lock distance",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
unit_of_measurement=c.UNIT_DEGREES,
icon="mdi:rotate-360",
),
cv.Optional(CONF_LAST_ACTION_START_TEMPERATURE, default={
c.CONF_NAME: "Last action start temperature",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
unit_of_measurement=c.UNIT_CELSIUS,
device_class=c.DEVICE_CLASS_TEMPERATURE,
),
cv.Optional(CONF_LAST_ACTION_BATTERY_DRAIN, default={
c.CONF_NAME: "Last action battery drain",
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
unit_of_measurement=c.UNIT_WATT_HOURS,
device_class=c.DEVICE_CLASS_ENERGY,
accuracy_decimals=5,
),
cv.Optional(CONF_LAST_ACTION_MAX_TURN_CURRENT, default={
c.CONF_NAME: "Last action max turn current",
c.CONF_DISABLED_BY_DEFAULT: True, # A few others, too.
}): sensor.sensor_schema(
state_class=c.STATE_CLASS_MEASUREMENT,
entity_category=c.ENTITY_CATEGORY_DIAGNOSTIC,
unit_of_measurement=c.UNIT_AMPERE,
device_class=c.DEVICE_CLASS_CURRENT,
accuracy_decimals=3,
),
# Configuration.
cv.Optional(CONF_RESTART_AFTER_BEACON_LATENCY, default="10min"): cv.positive_time_period_milliseconds,
# Actions.
cv.Optional(CONF_REQUEST_STATE, default={
c.CONF_NAME: "Request state",
}): button.button_schema(RequestStateButton,
entity_category=c.ENTITY_CATEGORY_CONFIG,
icon="mdi:refresh",
),
cv.Optional(CONF_UNPAIR, default={
c.CONF_NAME: "Unpair",
}): button.button_schema(
UnpairButton,
entity_category=c.ENTITY_CATEGORY_CONFIG,
icon="mdi:close",
),
# Time autoupdate.
cv.Optional(c.CONF_PIN): cv.positive_int,
cv.Optional(CONF_TIME_SOURCE): cv.use_id(time.RealTimeClock),
}).extend(cv.polling_component_schema("30min"))
async def to_code(config):
var = cg.new_Pvariable(config[c.CONF_ID])
await cg.register_component(var, config)
await lock.register_lock(var, config)
request_state_button = await button.new_button(config[CONF_REQUEST_STATE])
await cg.register_parented(request_state_button, config[c.CONF_ID])
cg.add(var.set_request_state_button(request_state_button))
unpair_button = await button.new_button(config[CONF_UNPAIR])
await cg.register_parented(unpair_button, config[c.CONF_ID])
cg.add(var.set_request_state_button(unpair_button))
cg.add(var.set_paired_binary_sensor(await binary_sensor.new_binary_sensor(config[CONF_PAIRED])))
cg.add(var.set_error_text_sensor(await text_sensor.new_text_sensor(config[CONF_ERROR])))
cg.add(var.set_battery_critical_binary_sensor(await binary_sensor.new_binary_sensor(config[CONF_BATTERY_CRITICAL])))
cg.add(var.set_battery_level_sensor(await sensor.new_sensor(config[c.CONF_BATTERY_LEVEL])))
cg.add(var.set_door_contact_binary_sensor(await binary_sensor.new_binary_sensor(config[CONF_DOOR_CONTACT])))
cg.add(var.set_door_contact_sensor_text_sensor(await text_sensor.new_text_sensor(config[CONF_DOOR_CONTACT_SENSOR])))
cg.add(var.set_trigger_text_sensor(await text_sensor.new_text_sensor(config[CONF_TRIGGER])))
cg.add(var.set_night_mode_active_binary_sensor(await binary_sensor.new_binary_sensor(config[CONF_NIGHT_MODE_ACTIVE])))
if CONF_BEACON_RSSI in config:
cg.add(var.set_beacon_rssi_sensor( await sensor.new_sensor(config[CONF_BEACON_RSSI])))
if CONF_BEACON_LATENCY in config:
cg.add(var.set_beacon_latency_sensor(await sensor.new_sensor(config[CONF_BEACON_LATENCY])))
if CONF_HEARTBEAT_LATENCY in config:
cg.add(var.set_heartbeat_latency_sensor(await sensor.new_sensor(config[CONF_HEARTBEAT_LATENCY])))
if CONF_BEACON_BLE_ADDRESS in config:
cg.add(var.set_beacon_ble_address_text_sensor(await text_sensor.new_text_sensor(config[CONF_BEACON_BLE_ADDRESS])))
if CONF_LOCK_CURRENT_DATETIME in config:
sens = await text_sensor.new_text_sensor(config[CONF_LOCK_CURRENT_DATETIME])
cg.add(var.set_lock_current_datetime_text_sensor(sens))
if CONF_CONFIG_UPDATE_COUNT in config:
cg.add(var.set_config_update_count_sensor(await sensor.new_sensor(config[CONF_CONFIG_UPDATE_COUNT])))
if CONF_LAST_ACTION in config:
cg.add(var.set_last_action_text_sensor(await text_sensor.new_text_sensor(config[CONF_LAST_ACTION])))
if CONF_LAST_ACTION_TRIGGER in config:
cg.add(var.set_last_action_trigger_text_sensor(await text_sensor.new_text_sensor(config[CONF_LAST_ACTION_TRIGGER])))
if CONF_LAST_ACTION_COMPLETION_STATUS in config:
cg.add(var.set_last_action_completion_status_text_sensor(await text_sensor.new_text_sensor(config[CONF_LAST_ACTION_COMPLETION_STATUS])))
if config.get(CONF_REQUEST_BATTERY_REPORTS):
cg.add(var.set_request_battery_reports(True))
cg.add(var.set_battery_voltage_sensor(await sensor.new_sensor(config[c.CONF_BATTERY_VOLTAGE])))
cg.add(var.set_battery_resistance_sensor(await sensor.new_sensor(config[CONF_BATTERY_RESISTANCE])))
cg.add(var.set_last_action_lowest_voltage_sensor(await sensor.new_sensor(config[CONF_LAST_ACTION_LOWEST_VOLTAGE])))
cg.add(var.set_last_action_start_voltage_sensor(await sensor.new_sensor(config[CONF_LAST_ACTION_START_VOLTAGE])))
cg.add(var.set_last_action_lock_distance_sensor(await sensor.new_sensor(config[CONF_LAST_ACTION_LOCK_DISTANCE])))
cg.add(var.set_last_action_start_temperature_sensor(await sensor.new_sensor(config[CONF_LAST_ACTION_START_TEMPERATURE])))
cg.add(var.set_last_action_battery_drain_sensor(await sensor.new_sensor(config[CONF_LAST_ACTION_BATTERY_DRAIN])))
cg.add(var.set_last_action_max_turn_current_sensor(await sensor.new_sensor(config[CONF_LAST_ACTION_MAX_TURN_CURRENT])))
if CONF_RESTART_AFTER_BEACON_LATENCY in config:
cg.add(var.set_restart_after_beacon_latency(config[CONF_RESTART_AFTER_BEACON_LATENCY]))
if c.CONF_PIN in config:
cg.add(var.set_pin(config[c.CONF_PIN]))
if CONF_TIME_SOURCE in config:
cg.add(var.set_time_source(await cg.get_variable(config[CONF_TIME_SOURCE])))
-543
View File
@@ -1,543 +0,0 @@
#include "nuki_lock.h"
#include "esphome/core/application.h"
#include "esphome/core/log.h"
namespace {
using namespace esphome;
const char *TAG = "nuki_lock";
class Adapt {
public:
static esphome::lock::LockState lock_state_to_esphome(
NukiLock::LockState state) {
switch (state) {
case NukiLock::LockState::Locked:
return esphome::lock::LOCK_STATE_LOCKED;
case NukiLock::LockState::Unlocked:
return esphome::lock::LOCK_STATE_UNLOCKED;
case NukiLock::LockState::MotorBlocked:
return esphome::lock::LOCK_STATE_JAMMED;
case NukiLock::LockState::Locking:
return esphome::lock::LOCK_STATE_LOCKING;
case NukiLock::LockState::Unlocking:
return esphome::lock::LOCK_STATE_UNLOCKING;
default:
return esphome::lock::LOCK_STATE_NONE;
}
}
static std::string lock_action_to_string(NukiLock::LockAction action) {
char result[256];
NukiLock::lockactionToString(action, result);
return result;
}
static bool door_sensor_state_to_is_door_open(Nuki::DoorSensorState state) {
switch (state) {
case Nuki::DoorSensorState::DoorClosed:
return false;
default:
return true;
}
}
static std::string door_sensor_state_to_string(Nuki::DoorSensorState state) {
char result[256];
NukiLock::doorSensorStateToString(state, result);
return result;
}
static std::string key_turner_datetime_iso(
const NukiLock::KeyTurnerState &state) {
uint8_t tzOffsetHours = abs(state.timeZoneOffset / 60);
uint8_t tzOffsetMinutes = abs(state.timeZoneOffset % 60);
char ts[256];
sprintf(ts, "%d-%.2d-%.2dT%.2d:%.2d:%.2d%c%.2d:%.2d", state.currentTimeYear,
state.currentTimeMonth, state.currentTimeDay, state.currentTimeHour,
state.currentTimeMinute, state.currentTimeSecond,
state.timeZoneOffset >= 0 ? '+' : '-', tzOffsetHours,
tzOffsetMinutes);
return ts;
}
static std::string trigger_to_string(NukiLock::Trigger trigger) {
char result[256];
NukiLock::triggerToString(trigger, result);
return result;
}
static std::string completion_status_to_string(
NukiLock::CompletionStatus status) {
char result[256];
NukiLock::completionStatusToString(status, result);
return result;
}
static std::string cmd_result_to_string(Nuki::CmdResult result) {
char resultStr[256];
NukiLock::cmdResultToString(result, resultStr);
return resultStr;
}
static std::string error_to_string(NukiLock::ErrorCode error) {
switch (error) {
case NukiLock::ErrorCode::ERROR_BAD_CRC:
return "ERROR_BAD_CRC";
case NukiLock::ErrorCode::ERROR_BAD_LENGTH:
return "ERROR_BAD_LENGTH";
case NukiLock::ErrorCode::ERROR_UNKNOWN:
return "ERROR_UNKNOWN";
case NukiLock::ErrorCode::P_ERROR_NOT_PAIRING:
return "P_ERROR_NOT_PAIRING";
case NukiLock::ErrorCode::P_ERROR_BAD_AUTHENTICATOR:
return "P_ERROR_BAD_AUTHENTICATOR";
case NukiLock::ErrorCode::P_ERROR_BAD_PARAMETER:
return "P_ERROR_BAD_PARAMETER";
case NukiLock::ErrorCode::P_ERROR_MAX_USER:
return "P_ERROR_MAX_USER";
case NukiLock::ErrorCode::K_ERROR_NOT_AUTHORIZED:
return "K_ERROR_NOT_AUTHORIZED";
case NukiLock::ErrorCode::K_ERROR_BAD_PIN:
return "K_ERROR_BAD_PIN";
case NukiLock::ErrorCode::K_ERROR_BAD_NONCE:
return "K_ERROR_BAD_NONCE";
case NukiLock::ErrorCode::K_ERROR_BAD_PARAMETER:
return "K_ERROR_BAD_PARAMETER";
case NukiLock::ErrorCode::K_ERROR_INVALID_AUTH_ID:
return "K_ERROR_INVALID_AUTH_ID";
case NukiLock::ErrorCode::K_ERROR_DISABLED:
return "K_ERROR_DISABLED";
case NukiLock::ErrorCode::K_ERROR_REMOTE_NOT_ALLOWED:
return "K_ERROR_REMOTE_NOT_ALLOWED";
case NukiLock::ErrorCode::K_ERROR_TIME_NOT_ALLOWED:
return "K_ERROR_TIME_NOT_ALLOWED";
case NukiLock::ErrorCode::K_ERROR_TOO_MANY_PIN_ATTEMPTS:
return "K_ERROR_TOO_MANY_PIN_ATTEMPTS";
case NukiLock::ErrorCode::K_ERROR_TOO_MANY_ENTRIES:
return "K_ERROR_TOO_MANY_ENTRIES";
case NukiLock::ErrorCode::K_ERROR_CODE_ALREADY_EXISTS:
return "K_ERROR_CODE_ALREADY_EXISTS";
case NukiLock::ErrorCode::K_ERROR_CODE_INVALID:
return "K_ERROR_CODE_INVALID";
case NukiLock::ErrorCode::K_ERROR_CODE_INVALID_TIMEOUT_1:
return "K_ERROR_CODE_INVALID_TIMEOUT_1";
case NukiLock::ErrorCode::K_ERROR_CODE_INVALID_TIMEOUT_2:
return "K_ERROR_CODE_INVALID_TIMEOUT_2";
case NukiLock::ErrorCode::K_ERROR_CODE_INVALID_TIMEOUT_3:
return "K_ERROR_CODE_INVALID_TIMEOUT_3";
case NukiLock::ErrorCode::K_ERROR_AUTO_UNLOCK_TOO_RECENT:
return "K_ERROR_AUTO_UNLOCK_TOO_RECENT";
case NukiLock::ErrorCode::K_ERROR_POSITION_UNKNOWN:
return "K_ERROR_POSITION_UNKNOWN";
case NukiLock::ErrorCode::K_ERROR_MOTOR_BLOCKED:
return "K_ERROR_MOTOR_BLOCKED";
case NukiLock::ErrorCode::K_ERROR_CLUTCH_FAILURE:
return "K_ERROR_CLUTCH_FAILURE";
case NukiLock::ErrorCode::K_ERROR_MOTOR_TIMEOUT:
return "K_ERROR_MOTOR_TIMEOUT";
case NukiLock::ErrorCode::K_ERROR_BUSY:
return "K_ERROR_BUSY";
case NukiLock::ErrorCode::K_ERROR_CANCELED:
return "K_ERROR_CANCELED";
case NukiLock::ErrorCode::K_ERROR_NOT_CALIBRATED:
return "K_ERROR_NOT_CALIBRATED";
case NukiLock::ErrorCode::K_ERROR_MOTOR_POSITION_LIMIT:
return "K_ERROR_MOTOR_POSITION_LIMIT";
case NukiLock::ErrorCode::K_ERROR_MOTOR_LOW_VOLTAGE:
return "K_ERROR_MOTOR_LOW_VOLTAGE";
case NukiLock::ErrorCode::K_ERROR_MOTOR_POWER_FAILURE:
return "K_ERROR_MOTOR_POWER_FAILURE";
case NukiLock::ErrorCode::K_ERROR_CLUTCH_POWER_FAILURE:
return "K_ERROR_CLUTCH_POWER_FAILURE";
case NukiLock::ErrorCode::K_ERROR_VOLTAGE_TOO_LOW:
return "K_ERROR_VOLTAGE_TOO_LOW";
case NukiLock::ErrorCode::K_ERROR_FIRMWARE_UPDATE_NEEDED:
return "K_ERROR_FIRMWARE_UPDATE_NEEDED";
default:
return std::string("Unknown #") +
std::to_string(static_cast<uint8_t>(error));
}
}
};
} // namespace
namespace esphome {
namespace nuki_lock {
bool NukiLockComponent::update_key_turner_state_() {
NukiLock::KeyTurnerState retrievedKeyTurnerState;
Nuki::CmdResult result =
nuki_lock_->requestKeyTurnerState(&retrievedKeyTurnerState);
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "request for key turner state failed: %s",
Adapt::cmd_result_to_string(result).c_str());
publish_state(lock::LOCK_STATE_NONE);
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
// TODO(https://github.com/esphome/feature-requests/issues/1568): publish
// unavailable for all related sensors.
schedule_update();
return false;
}
publish_state(
Adapt::lock_state_to_esphome(retrievedKeyTurnerState.lockState));
door_contact_binary_sensor_->publish_state(
Adapt::door_sensor_state_to_is_door_open(
retrievedKeyTurnerState.doorSensorState));
door_contact_sensor_text_sensor_->publish_state(
Adapt::door_sensor_state_to_string(
retrievedKeyTurnerState.doorSensorState));
battery_level_sensor_->publish_state(nuki_lock_->getBatteryPerc());
battery_critical_binary_sensor_->publish_state(
nuki_lock_->isBatteryCritical());
trigger_text_sensor_->publish_state(
Adapt::trigger_to_string(retrievedKeyTurnerState.trigger));
night_mode_active_binary_sensor_->publish_state(
retrievedKeyTurnerState.nightModeActive > 0);
if (lock_current_datetime_text_sensor_ != nullptr) {
lock_current_datetime_text_sensor_->publish_state(
Adapt::key_turner_datetime_iso(retrievedKeyTurnerState));
}
if (config_update_count_sensor_ != nullptr) {
config_update_count_sensor_->publish_state(
retrievedKeyTurnerState.configUpdateCount);
}
if (last_action_text_sensor_ != nullptr) {
last_action_text_sensor_->publish_state(
Adapt::lock_action_to_string(retrievedKeyTurnerState.lastLockAction));
}
if (last_action_trigger_text_sensor_ != nullptr) {
last_action_trigger_text_sensor_->publish_state(Adapt::trigger_to_string(
retrievedKeyTurnerState.lastLockActionTrigger));
}
if (last_action_completion_status_text_sensor_ != nullptr) {
last_action_completion_status_text_sensor_->publish_state(
Adapt::completion_status_to_string(
retrievedKeyTurnerState.lastLockActionCompletionStatus));
}
return true;
}
bool NukiLockComponent::update_lock_time_() {
if (time_source_ == nullptr) {
ESP_LOGE(TAG, "updating lock time failed: time source not set");
return false;
}
Nuki::CmdResult result = nuki_lock_->verifySecurityPin();
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "verifying security pin for lock time update failed: %s",
Adapt::cmd_result_to_string(result).c_str());
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
return false;
}
ESPTime now = time_source_->utcnow();
if (!now.is_valid()) {
ESP_LOGE(TAG, "updating lock time failed: time source is invalid");
return false;
}
Nuki::TimeValue tv = {
.year = now.year,
.month = now.month,
.day = now.day_of_month,
.hour = now.hour,
.minute = now.minute,
.second = now.second,
};
ESP_LOGI(TAG, "Setting lock time: %.4d-%.2d-%.2d %.2d:%.2d:%.2d", tv.year,
tv.month, tv.day, tv.hour, tv.minute, tv.second);
result = nuki_lock_->updateTime(tv);
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "updating lock time failed: %s",
Adapt::cmd_result_to_string(result).c_str());
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
return false;
}
return true;
}
bool NukiLockComponent::update_battery_report_() {
NukiLock::BatteryReport batteryReport;
Nuki::CmdResult result =
this->nuki_lock_->requestBatteryReport(&batteryReport);
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "request for battery report failed: %s",
Adapt::cmd_result_to_string(result).c_str());
// TODO(https://github.com/esphome/feature-requests/issues/1568): publish
// unavailable for all related sensors.
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
return false;
}
battery_voltage_sensor_->publish_state(batteryReport.batteryVoltage /
1000.0f);
battery_resistance_sensor_->publish_state(batteryReport.batteryResistance /
1000.0f);
last_action_lowest_voltage_sensor_->publish_state(
batteryReport.lowestVoltage / 1000.0f);
last_action_start_voltage_sensor_->publish_state(batteryReport.startVoltage /
1000.0f);
last_action_lock_distance_sensor_->publish_state(batteryReport.lockDistance);
last_action_start_temperature_sensor_->publish_state(
batteryReport.startTemperature);
// Milliwattseconds (mWs) to Wh.
last_action_battery_drain_sensor_->publish_state(batteryReport.batteryDrain /
1000.0f / 3600.0f);
last_action_max_turn_current_sensor_->publish_state(
batteryReport.maxTurnCurrent / 1000.0f);
return true;
}
void NukiLockComponent::notify(Nuki::EventType event) {
ESP_LOGI(TAG, "received Nuki event - updating state");
// Have to execute later as this runs in BLE scanner context and we can't do
// any BLE in this context.
schedule_update();
}
void NukiLockComponent::schedule_update() {
if (!update_scheduled_) {
update_scheduled_ = true;
defer([this]() {
update();
update_scheduled_ = false;
});
}
}
void NukiLockComponent::setup() {
traits.set_supports_open(true);
traits.set_supported_states(std::set<lock::LockState>{
lock::LOCK_STATE_NONE, lock::LOCK_STATE_LOCKED, lock::LOCK_STATE_UNLOCKED,
lock::LOCK_STATE_JAMMED, lock::LOCK_STATE_LOCKING,
lock::LOCK_STATE_UNLOCKING});
publish_state(lock::LOCK_STATE_NONE);
uint8_t mac[6];
get_mac_address_raw(mac);
our_device_id_ = mac[0] + (mac[1] << 8) + (mac[2] << 16) + (mac[3] << 24);
// name will be used as part of the Preferences key to save credentials.
// There's a limit of 15 characters on key length, keep it predictable.
our_device_name_ = "nuki" + std::to_string(get_object_id_hash());
nuki_lock_ = new NukiLock::NukiLock(our_device_name_, our_device_id_);
scanner_.initialize();
nuki_lock_->registerBleScanner(&scanner_);
nuki_lock_->initialize();
nuki_lock_->setEventHandler(this);
if (pin_set_) {
nuki_lock_->saveSecurityPincode(pin_);
}
bool paired = nuki_lock_->isPairedWithLock();
paired_binary_sensor_->publish_initial_state(paired);
error_text_sensor_->publish_state("No error");
set_interval("ble_loop", 320 /* ms*/, [this]() { ble_loop_(); });
schedule_update();
}
void NukiLockComponent::unpair() {
ESP_LOGI(TAG, "unpairing Nuki lock");
nuki_lock_->unPairNuki();
// Force BLE update on the next loop.
last_passive_update_millis_ = 0;
// And a regular fetch.
schedule_update();
}
void NukiLockComponent::ble_loop_() {
scanner_.update();
unsigned long ts = millis();
bool should_publish_update = last_passive_update_millis_ == 0 ||
last_passive_update_millis_ + 60000 < ts;
bool paired = nuki_lock_->isPairedWithLock();
if (should_publish_update) {
last_passive_update_millis_ = ts;
paired_binary_sensor_->publish_state(paired);
}
if (!paired) {
if (nuki_lock_->pairNuki() == Nuki::PairingResult::Success) {
ESP_LOGI(TAG, "Nuki lock successfully paired!");
// Force BLE update on the next loop.
last_passive_update_millis_ = 0;
// And a regular fetch.
schedule_update();
} else if (should_publish_update) {
ESP_LOGW(TAG,
"Nuki lock is not yet paired. Make sure Bluetooth pairing "
"is enabled in lock settings, then press and hold the button "
"on the lock for a few seconds until LED glows constantly");
}
return;
}
nuki_lock_->updateConnectionState();
// Update timestamp as we might have gotten a refresh packet on BLE.
ts = millis();
unsigned long beaconLatency = ts - nuki_lock_->getLastReceivedBeaconTs(),
heartbeatLatency = ts - nuki_lock_->getLastHeartbeat();
if (should_publish_update) {
if (beacon_rssi_sensor_ != nullptr) {
int rssi = nuki_lock_->getRssi();
if (rssi != 0) {
beacon_rssi_sensor_->publish_state(rssi);
}
}
if (beacon_latency_sensor_ != nullptr) {
beacon_latency_sensor_->publish_state(beaconLatency);
}
if (heartbeat_latency_sensor_ != nullptr) {
heartbeat_latency_sensor_->publish_state(heartbeatLatency);
}
if (beacon_ble_address_text_sensor_ != nullptr) {
beacon_ble_address_text_sensor_->publish_state(
nuki_lock_->getBleAddress().toString());
}
}
if (restart_after_beacon_latency_ != 0 &&
beaconLatency > restart_after_beacon_latency_) {
ESP_LOGE(TAG,
"Beacon latency %d higher than configured maximum %d. Restarting "
"the device");
App.safe_reboot();
}
}
void NukiLockComponent::update() {
bool paired = nuki_lock_->isPairedWithLock();
if (paired) {
if (time_source_ != nullptr) {
// Update time first, then request the state so we get updated time.
update_lock_time_();
}
update_key_turner_state_();
if (request_battery_reports_) {
update_battery_report_();
}
}
}
void NukiLockComponent::send_action_(NukiLock::LockAction action) {
if (!this->nuki_lock_->isPairedWithLock()) {
ESP_LOGE(TAG, "lock or unlock action %d called before a lock is paired",
action);
return;
}
Nuki::CmdResult result = this->nuki_lock_->lockAction(action);
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "setting state %d failed: %s", action,
Adapt::cmd_result_to_string(result).c_str());
publish_state(lock::LOCK_STATE_NONE);
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
schedule_update();
}
}
void NukiLockComponent::control(const lock::LockCall &call) {
auto action = *call.get_state();
switch (action) {
case lock::LOCK_STATE_LOCKED:
publish_state(lock::LOCK_STATE_LOCKING);
send_action_(NukiLock::LockAction::Lock);
break;
case lock::LOCK_STATE_UNLOCKED:
publish_state(lock::LOCK_STATE_UNLOCKING);
send_action_(NukiLock::LockAction::Unlock);
break;
default:
ESP_LOGE(TAG, "unsupported lock state requested: %d", action);
return;
}
// Final lock state will be published once Nuki informs us of an update.
}
void NukiLockComponent::open_latch() {
publish_state(lock::LOCK_STATE_UNLOCKING);
send_action_(NukiLock::LockAction::Unlatch);
}
void NukiLockComponent::dump_config() {
char device_id[256];
sprintf(device_id, "%s (0x%.8x)", our_device_name_.c_str(), our_device_id_);
LOG_LOCK("", device_id, this);
// Required.
LOG_BINARY_SENSOR(" ", "", paired_binary_sensor_);
LOG_TEXT_SENSOR(" ", "", error_text_sensor_);
LOG_BINARY_SENSOR(" ", "", battery_critical_binary_sensor_);
LOG_SENSOR(" ", "", battery_level_sensor_);
LOG_BINARY_SENSOR(" ", "", door_contact_binary_sensor_);
LOG_TEXT_SENSOR(" ", "", door_contact_sensor_text_sensor_);
LOG_TEXT_SENSOR(" ", "", trigger_text_sensor_);
LOG_BINARY_SENSOR(" ", "", night_mode_active_binary_sensor_);
// Optional.
LOG_SENSOR(" ", "", beacon_rssi_sensor_);
LOG_SENSOR(" ", "", beacon_latency_sensor_);
LOG_SENSOR(" ", "", heartbeat_latency_sensor_);
LOG_TEXT_SENSOR(" ", "", beacon_ble_address_text_sensor_);
LOG_TEXT_SENSOR(" ", "", lock_current_datetime_text_sensor_);
LOG_SENSOR(" ", "", config_update_count_sensor_);
LOG_TEXT_SENSOR(" ", "", last_action_text_sensor_);
LOG_TEXT_SENSOR(" ", "", last_action_trigger_text_sensor_);
LOG_TEXT_SENSOR(" ", "", last_action_completion_status_text_sensor_);
if (request_battery_reports_) {
// Optional sensors - battery report.
LOG_SENSOR(" ", "", battery_voltage_sensor_);
LOG_SENSOR(" ", "", battery_resistance_sensor_);
LOG_SENSOR(" ", "", last_action_lowest_voltage_sensor_);
LOG_SENSOR(" ", "", last_action_start_voltage_sensor_);
LOG_SENSOR(" ", "", last_action_lock_distance_sensor_);
LOG_SENSOR(" ", "", last_action_start_temperature_sensor_);
LOG_SENSOR(" ", "", last_action_battery_drain_sensor_);
LOG_SENSOR(" ", "", last_action_max_turn_current_sensor_);
}
ESP_LOGCONFIG(TAG, " Restart after beacon latency: %dms",
restart_after_beacon_latency_);
if (time_source_ != nullptr) {
ESP_LOGCONFIG(TAG, " Time source: set");
}
if (pin_set_) {
ESP_LOGCONFIG(
TAG, " Pin: " ESPHOME_LOG_SECRET_BEGIN "%d" ESPHOME_LOG_SECRET_END,
pin_);
}
}
} // namespace nuki_lock
} // namespace esphome
-145
View File
@@ -1,145 +0,0 @@
#pragma once
#include "BleScanner.h"
#include "NukiConstants.h"
#include "NukiLock.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/button/button.h"
#include "esphome/components/lock/lock.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/text_sensor/text_sensor.h"
#include "esphome/components/time/real_time_clock.h"
#include "esphome/core/component.h"
#include "esphome/core/time.h"
namespace esphome {
namespace nuki_lock {
class NukiLockComponent : public lock::Lock,
public PollingComponent,
public Nuki::SmartlockEventHandler {
public:
explicit NukiLockComponent()
: Lock(),
last_passive_update_millis_(0),
restart_after_beacon_latency_(0),
update_scheduled_(false),
request_battery_reports_(false),
pin_set_(false) {};
// Component.
void setup() override;
float get_setup_priority() const override {
return setup_priority::HARDWARE - 1.0f;
}
void dump_config() override;
// PollingComponent.
void update() override;
// Nuki::SmartlockEventHandler.
void notify(Nuki::EventType event);
// Passive updates (predefined update frequency).
SUB_BINARY_SENSOR(paired)
SUB_SENSOR(beacon_rssi)
SUB_SENSOR(beacon_latency)
SUB_SENSOR(heartbeat_latency)
SUB_TEXT_SENSOR(beacon_ble_address)
// Active updates (configured update_interval frequency).
// Key turner state.
SUB_BINARY_SENSOR(battery_critical)
SUB_SENSOR(battery_level)
SUB_BINARY_SENSOR(door_contact)
SUB_TEXT_SENSOR(door_contact_sensor)
SUB_TEXT_SENSOR(lock_current_datetime)
SUB_TEXT_SENSOR(error)
SUB_TEXT_SENSOR(trigger)
SUB_SENSOR(config_update_count)
SUB_TEXT_SENSOR(last_action)
SUB_TEXT_SENSOR(last_action_trigger)
SUB_TEXT_SENSOR(last_action_completion_status)
SUB_BINARY_SENSOR(night_mode_active)
// Battery report.
SUB_SENSOR(battery_voltage)
SUB_SENSOR(battery_resistance)
SUB_SENSOR(last_action_lowest_voltage)
SUB_SENSOR(last_action_start_voltage)
SUB_SENSOR(last_action_lock_distance)
SUB_SENSOR(last_action_start_temperature)
SUB_SENSOR(last_action_battery_drain)
SUB_SENSOR(last_action_max_turn_current)
// Actions.
SUB_BUTTON(lock_n_go)
SUB_BUTTON(unpair)
SUB_BUTTON(request_state)
void set_request_battery_reports(bool value) {
request_battery_reports_ = value;
}
void set_restart_after_beacon_latency(unsigned long value) {
restart_after_beacon_latency_ = value;
}
void set_pin(unsigned long value) {
pin_ = value;
pin_set_ = true;
}
void set_time_source(time::RealTimeClock *value) { time_source_ = value; }
// RequestStateButton.
void schedule_update();
// UnpairButton.
void unpair();
protected:
// lock::Lock.
void control(const lock::LockCall &call) override;
void open_latch() override;
private:
bool update_key_turner_state_();
bool update_battery_report_();
bool update_lock_time_();
void ble_loop_();
void send_action_(NukiLock::LockAction action);
NukiLock::NukiLock *nuki_lock_;
BleScanner::Scanner scanner_;
time::RealTimeClock *time_source_{nullptr};
uint16_t pin_;
bool pin_set_;
unsigned long last_passive_update_millis_;
unsigned long restart_after_beacon_latency_;
bool update_scheduled_;
bool request_battery_reports_;
uint32_t our_device_id_;
std::string our_device_name_;
};
class RequestStateButton : public button::Button,
public Parented<NukiLockComponent> {
public:
RequestStateButton() = default;
protected:
void press_action() override { get_parent()->schedule_update(); }
};
class UnpairButton : public button::Button, public Parented<NukiLockComponent> {
public:
UnpairButton() = default;
protected:
void press_action() override { get_parent()->unpair(); }
};
} // namespace nuki_lock
} // namespace esphome
+1 -1
View File
@@ -166,7 +166,7 @@ void SomfyRTSCover::setup() {
/*qos=*/1 /* (at least once) */); /*qos=*/1 /* (at least once) */);
} else { } else {
this->rolling_code_ = 0; this->rolling_code_ = 0;
this->mark_failed("Missing rolling_code"); this->mark_failed(LOG_STR("Missing rolling_code"));
ESP_LOGE(TAG, "No rolling code in flash, and MQTT client unavailable"); ESP_LOGE(TAG, "No rolling code in flash, and MQTT client unavailable");
} }
} }
+7 -6
View File
@@ -63,11 +63,7 @@ Syslog::Syslog() {
this->errors_encountered_ = 0; this->errors_encountered_ = 0;
} }
void Syslog::setup() { void Syslog::on_log(uint8_t level, const char *tag, const char *raw_message, size_t raw_message_len) {
#ifdef USE_LOGGER
if (logger::global_logger != nullptr && this->forward_logger_) {
logger::global_logger->add_on_log_callback(
[this](int level, const char *tag, const char *raw_message, size_t raw_message_len) {
if (level > this->min_log_level_) return; if (level > this->min_log_level_) return;
std::string message = std::string(raw_message, raw_message_len); std::string message = std::string(raw_message, raw_message_len);
@@ -77,7 +73,12 @@ void Syslog::setup() {
} else { } else {
this->log(level, tag, message); this->log(level, tag, message);
} }
}); }
void Syslog::setup() {
#ifdef USE_LOGGER
if (logger::global_logger != nullptr && this->forward_logger_) {
logger::global_logger->add_log_listener(this);
} }
#endif #endif
+3 -1
View File
@@ -16,6 +16,7 @@
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/components/logger/logger.h"
#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || \ #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || \
defined(USE_SOCKET_IMPL_LWIP_SOCKETS) defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
@@ -28,7 +29,7 @@ namespace esphome {
namespace syslog { namespace syslog {
class Syslog : public Component { class Syslog : public Component, public logger::LogListener {
public: public:
explicit Syslog(); explicit Syslog();
@@ -49,6 +50,7 @@ class Syslog : public Component {
void set_forward_logger(bool forward) { this->forward_logger_ = forward; } void set_forward_logger(bool forward) { this->forward_logger_ = forward; }
void set_strip_color_codes(bool strip) { this->strip_color_codes_ = strip; } void set_strip_color_codes(bool strip) { this->strip_color_codes_ = strip; }
void on_log(uint8_t, const char *, const char *, size_t) override;
void log(int level, const std::string &tag, const std::string &msg); void log(int level, const std::string &tag, const std::string &msg);
protected: protected:
Generated
+3 -3
View File
@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1765472234, "lastModified": 1767379071,
"narHash": "sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0=", "narHash": "sha256-EgE0pxsrW9jp9YFMkHL9JMXxcqi/OoumPJYwf+Okucw=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2fbfb1d73d239d2402a8fe03963e37aab15abe8b", "rev": "fb7944c166a3b630f177938e478f0378e64ce108",
"type": "github" "type": "github"
}, },
"original": { "original": {
+1
View File
@@ -2,6 +2,7 @@ external_components:
# Path is relative to the main YAML file, not this device_base template! # Path is relative to the main YAML file, not this device_base template!
- source: components - source: components
# https://github.com/esphome/esphome/issues/12591
syslog: syslog:
ip_address: !secret syslog_server ip_address: !secret syslog_server