[cc1101] Add new cc1101 component (#11849)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
@@ -97,6 +97,7 @@ esphome/components/camera_encoder/* @DT-art1
|
||||
esphome/components/canbus/* @danielschramm @mvturnho
|
||||
esphome/components/cap1188/* @mreditor97
|
||||
esphome/components/captive_portal/* @esphome/core
|
||||
esphome/components/cc1101/* @gabest11 @lygris
|
||||
esphome/components/ccs811/* @habbie
|
||||
esphome/components/cd74hc4067/* @asoehlke
|
||||
esphome/components/ch422g/* @clydebarrow @jesterret
|
||||
|
||||
220
esphome/components/cc1101/__init__.py
Normal file
220
esphome/components/cc1101/__init__.py
Normal file
@@ -0,0 +1,220 @@
|
||||
from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import spi
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_CHANNEL, CONF_FREQUENCY, CONF_ID, CONF_WAIT_TIME
|
||||
|
||||
CODEOWNERS = ["@lygris", "@gabest11"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
MULTI_CONF = True
|
||||
|
||||
ns = cg.esphome_ns.namespace("cc1101")
|
||||
CC1101Component = ns.class_("CC1101Component", cg.Component, spi.SPIDevice)
|
||||
|
||||
# Config keys
|
||||
CONF_OUTPUT_POWER = "output_power"
|
||||
CONF_RX_ATTENUATION = "rx_attenuation"
|
||||
CONF_DC_BLOCKING_FILTER = "dc_blocking_filter"
|
||||
CONF_IF_FREQUENCY = "if_frequency"
|
||||
CONF_FILTER_BANDWIDTH = "filter_bandwidth"
|
||||
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_TYPE = "modulation_type"
|
||||
CONF_MANCHESTER = "manchester"
|
||||
CONF_NUM_PREAMBLE = "num_preamble"
|
||||
CONF_SYNC1 = "sync1"
|
||||
CONF_SYNC0 = "sync0"
|
||||
CONF_PKTLEN = "pktlen"
|
||||
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"
|
||||
|
||||
# Enums
|
||||
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,
|
||||
"ASK/OOK": Modulation.MODULATION_ASK_OOK,
|
||||
"4-FSK": Modulation.MODULATION_4_FSK,
|
||||
"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_8DB,
|
||||
"16": FilterLengthFskMsk.FILTER_LENGTH_16DB,
|
||||
"32": FilterLengthFskMsk.FILTER_LENGTH_32DB,
|
||||
"64": FilterLengthFskMsk.FILTER_LENGTH_64DB,
|
||||
}
|
||||
|
||||
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.FREEZE_DEFAULT,
|
||||
"On Sync": Freeze.FREEZE_ON_SYNC,
|
||||
"Analog Only": Freeze.FREEZE_ANALOG_ONLY,
|
||||
"Analog And Digital": Freeze.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,
|
||||
}
|
||||
|
||||
# Config key -> Validator mapping
|
||||
CONFIG_MAP = {
|
||||
CONF_OUTPUT_POWER: cv.float_range(min=-30.0, max=11.0),
|
||||
CONF_RX_ATTENUATION: cv.enum(RX_ATTENUATION, upper=False),
|
||||
CONF_DC_BLOCKING_FILTER: cv.boolean,
|
||||
CONF_FREQUENCY: cv.float_range(min=300000.0, max=928000.0),
|
||||
CONF_IF_FREQUENCY: cv.float_range(min=25, max=788),
|
||||
CONF_FILTER_BANDWIDTH: cv.float_range(min=58.0, max=812.0),
|
||||
CONF_CHANNEL: cv.uint8_t,
|
||||
CONF_CHANNEL_SPACING: cv.float_range(min=25, max=405),
|
||||
CONF_FSK_DEVIATION: cv.float_range(min=1.5, max=381),
|
||||
CONF_MSK_DEVIATION: cv.int_range(min=1, max=8),
|
||||
CONF_SYMBOL_RATE: cv.float_range(min=600, max=500000),
|
||||
CONF_SYNC_MODE: cv.enum(SYNC_MODE, upper=False),
|
||||
CONF_CARRIER_SENSE_ABOVE_THRESHOLD: cv.boolean,
|
||||
CONF_MODULATION_TYPE: cv.enum(MODULATION, upper=False),
|
||||
CONF_MANCHESTER: cv.boolean,
|
||||
CONF_NUM_PREAMBLE: cv.int_range(min=0, max=7),
|
||||
CONF_SYNC1: cv.hex_uint8_t,
|
||||
CONF_SYNC0: cv.hex_uint8_t,
|
||||
CONF_PKTLEN: cv.uint8_t,
|
||||
CONF_MAGN_TARGET: cv.enum(MAGN_TARGET, upper=False),
|
||||
CONF_MAX_LNA_GAIN: cv.enum(MAX_LNA_GAIN, upper=False),
|
||||
CONF_MAX_DVGA_GAIN: cv.enum(MAX_DVGA_GAIN, upper=False),
|
||||
CONF_CARRIER_SENSE_ABS_THR: cv.int_range(min=-8, max=7),
|
||||
CONF_CARRIER_SENSE_REL_THR: cv.enum(CARRIER_SENSE_REL_THR, upper=False),
|
||||
CONF_LNA_PRIORITY: cv.boolean,
|
||||
CONF_FILTER_LENGTH_FSK_MSK: cv.enum(FILTER_LENGTH_FSK_MSK, upper=False),
|
||||
CONF_FILTER_LENGTH_ASK_OOK: cv.enum(FILTER_LENGTH_ASK_OOK, upper=False),
|
||||
CONF_FREEZE: cv.enum(FREEZE, upper=False),
|
||||
CONF_WAIT_TIME: cv.enum(WAIT_TIME, upper=False),
|
||||
CONF_HYST_LEVEL: cv.enum(HYST_LEVEL, upper=False),
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema({cv.GenerateID(): cv.declare_id(CC1101Component)})
|
||||
.extend({cv.Optional(key): validator for key, validator in CONFIG_MAP.items()})
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(spi.spi_device_schema(cs_pin_required=True))
|
||||
)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
for key in CONFIG_MAP:
|
||||
if key in config:
|
||||
cg.add(getattr(var, f"set_{key}")(config[key]))
|
||||
|
||||
|
||||
# Actions
|
||||
BeginTxAction = ns.class_("BeginTxAction", automation.Action)
|
||||
BeginRxAction = ns.class_("BeginRxAction", automation.Action)
|
||||
ResetAction = ns.class_("ResetAction", automation.Action)
|
||||
SetIdleAction = ns.class_("SetIdleAction", automation.Action)
|
||||
|
||||
CC1101_ACTION_SCHEMA = cv.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.begin_rx", BeginRxAction, CC1101_ACTION_SCHEMA)
|
||||
@automation.register_action("cc1101.reset", ResetAction, CC1101_ACTION_SCHEMA)
|
||||
@automation.register_action("cc1101.set_idle", SetIdleAction, 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
|
||||
550
esphome/components/cc1101/cc1101.cpp
Normal file
550
esphome/components/cc1101/cc1101.cpp
Normal file
@@ -0,0 +1,550 @@
|
||||
#include "cc1101.h"
|
||||
#include "cc1101pa.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
static const char *const TAG = "cc1101";
|
||||
|
||||
static void split_float(float value, int mbits, uint8_t &e, uint32_t &m) {
|
||||
int e_tmp;
|
||||
float m_tmp = std::frexp(value, &e_tmp);
|
||||
if (e_tmp <= mbits) {
|
||||
e = 0;
|
||||
m = 0;
|
||||
return;
|
||||
}
|
||||
e = static_cast<uint8_t>(e_tmp - mbits - 1);
|
||||
m = static_cast<uint32_t>(((m_tmp * 2 - 1) * (1 << (mbits + 1))) + 1) >> 1;
|
||||
if (m == (1UL << mbits)) {
|
||||
e = e + 1;
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CC1101Component::CC1101Component() {
|
||||
// Datasheet defaults
|
||||
memset(&this->state_, 0, sizeof(this->state_));
|
||||
this->state_.GDO2_CFG = 0x0D; // Serial Data (for RX on GDO2)
|
||||
this->state_.GDO1_CFG = 0x2E;
|
||||
this->state_.GDO0_CFG = 0x0D; // Serial Data (for RX on GDO0 / TX Input)
|
||||
this->state_.FIFO_THR = 7;
|
||||
this->state_.SYNC1 = 0xD3;
|
||||
this->state_.SYNC0 = 0x91;
|
||||
this->state_.PKTLEN = 0xFF;
|
||||
this->state_.APPEND_STATUS = 1;
|
||||
this->state_.LENGTH_CONFIG = 1;
|
||||
this->state_.CRC_EN = 1;
|
||||
this->state_.WHITE_DATA = 1;
|
||||
this->state_.FREQ_IF = 0x0F;
|
||||
this->state_.FREQ2 = 0x1E;
|
||||
this->state_.FREQ1 = 0xC4;
|
||||
this->state_.FREQ0 = 0xEC;
|
||||
this->state_.DRATE_E = 0x0C;
|
||||
this->state_.CHANBW_E = 0x02;
|
||||
this->state_.DRATE_M = 0x22;
|
||||
this->state_.SYNC_MODE = 2;
|
||||
this->state_.CHANSPC_E = 2;
|
||||
this->state_.NUM_PREAMBLE = 2;
|
||||
this->state_.CHANSPC_M = 0xF8;
|
||||
this->state_.DEVIATION_M = 7;
|
||||
this->state_.DEVIATION_E = 4;
|
||||
this->state_.RX_TIME = 7;
|
||||
this->state_.CCA_MODE = 3;
|
||||
this->state_.PO_TIMEOUT = 1;
|
||||
this->state_.FOC_LIMIT = 2;
|
||||
this->state_.FOC_POST_K = 1;
|
||||
this->state_.FOC_PRE_K = 2;
|
||||
this->state_.FOC_BS_CS_GATE = 1;
|
||||
this->state_.BS_POST_KP = 1;
|
||||
this->state_.BS_POST_KI = 1;
|
||||
this->state_.BS_PRE_KP = 2;
|
||||
this->state_.BS_PRE_KI = 1;
|
||||
this->state_.MAGN_TARGET = 3;
|
||||
this->state_.AGC_LNA_PRIORITY = 1;
|
||||
this->state_.FILTER_LENGTH = 1;
|
||||
this->state_.WAIT_TIME = 1;
|
||||
this->state_.HYST_LEVEL = 2;
|
||||
this->state_.WOREVT1 = 0x87;
|
||||
this->state_.WOREVT0 = 0x6B;
|
||||
this->state_.RC_CAL = 1;
|
||||
this->state_.EVENT1 = 7;
|
||||
this->state_.RC_PD = 1;
|
||||
this->state_.MIX_CURRENT = 2;
|
||||
this->state_.LODIV_BUF_CURRENT_RX = 1;
|
||||
this->state_.LNA2MIX_CURRENT = 1;
|
||||
this->state_.LNA_CURRENT = 1;
|
||||
this->state_.LODIV_BUF_CURRENT_TX = 1;
|
||||
this->state_.FSCAL3_LO = 9;
|
||||
this->state_.CHP_CURR_CAL_EN = 2;
|
||||
this->state_.FSCAL3_HI = 2;
|
||||
this->state_.FSCAL2 = 0x0A;
|
||||
this->state_.FSCAL1 = 0x20;
|
||||
this->state_.FSCAL0 = 0x0D;
|
||||
this->state_.RCCTRL1 = 0x41;
|
||||
this->state_.FSTEST = 0x59;
|
||||
this->state_.PTEST = 0x7F;
|
||||
this->state_.AGCTEST = 0x3F;
|
||||
this->state_.TEST2 = 0x88;
|
||||
this->state_.TEST1 = 0x31;
|
||||
this->state_.TEST0_LO = 1;
|
||||
this->state_.VCO_SEL_CAL_EN = 1;
|
||||
this->state_.TEST0_HI = 2;
|
||||
|
||||
// PKTCTRL0
|
||||
this->state_.PKT_FORMAT = 3;
|
||||
this->state_.LENGTH_CONFIG = 2;
|
||||
this->state_.FS_AUTOCAL = 1;
|
||||
|
||||
// Default Settings
|
||||
this->set_frequency(433920);
|
||||
this->set_if_frequency(153);
|
||||
this->set_filter_bandwidth(203);
|
||||
this->set_channel(0);
|
||||
this->set_channel_spacing(200);
|
||||
this->set_symbol_rate(5000);
|
||||
this->set_sync_mode(SyncMode::SYNC_MODE_NONE);
|
||||
this->set_carrier_sense_above_threshold(true);
|
||||
this->set_modulation_type(Modulation::MODULATION_ASK_OOK);
|
||||
this->set_magn_target(MagnTarget::MAGN_TARGET_42DB);
|
||||
this->set_max_lna_gain(MaxLnaGain::MAX_LNA_GAIN_DEFAULT);
|
||||
this->set_max_dvga_gain(MaxDvgaGain::MAX_DVGA_GAIN_MINUS_3);
|
||||
this->set_lna_priority(false);
|
||||
this->set_wait_time(WaitTime::WAIT_TIME_32_SAMPLES);
|
||||
|
||||
// CRITICAL: Initialize PA Table to avoid transmitting 0 power (Silence)
|
||||
memset(this->pa_table_, 0, sizeof(this->pa_table_));
|
||||
this->set_output_power(10.0f);
|
||||
}
|
||||
|
||||
void CC1101Component::setup() {
|
||||
this->spi_setup();
|
||||
this->cs_->digital_write(true);
|
||||
delayMicroseconds(1);
|
||||
this->cs_->digital_write(false);
|
||||
delayMicroseconds(1);
|
||||
this->cs_->digital_write(true);
|
||||
delayMicroseconds(41);
|
||||
this->cs_->digital_write(false);
|
||||
delay(5);
|
||||
|
||||
this->strobe_(Command::RES);
|
||||
delay(5);
|
||||
|
||||
this->read_(Register::PARTNUM);
|
||||
this->read_(Register::VERSION);
|
||||
this->chip_id_ = encode_uint16(this->state_.PARTNUM, this->state_.VERSION);
|
||||
ESP_LOGD(TAG, "CC1101 found! Chip ID: 0x%04X", this->chip_id_);
|
||||
if (this->state_.VERSION == 0 || this->state_.PARTNUM == 0xFF) {
|
||||
ESP_LOGE(TAG, "Failed to verify CC1101.");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
this->initialized_ = true;
|
||||
|
||||
for (uint8_t i = 0; i <= static_cast<uint8_t>(Register::TEST0); i++) {
|
||||
if (i == static_cast<uint8_t>(Register::FSTEST) || i == static_cast<uint8_t>(Register::AGCTEST)) {
|
||||
continue;
|
||||
}
|
||||
this->write_(static_cast<Register>(i));
|
||||
}
|
||||
this->write_(Register::PATABLE, this->pa_table_, sizeof(this->pa_table_));
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
|
||||
void CC1101Component::dump_config() {
|
||||
static const char *const MODULATION_NAMES[] = {"2-FSK", "GFSK", "UNUSED", "ASK/OOK",
|
||||
"4-FSK", "UNUSED", "UNUSED", "MSK"};
|
||||
int32_t freq = static_cast<int32_t>(this->state_.FREQ2 << 16 | this->state_.FREQ1 << 8 | this->state_.FREQ0) *
|
||||
XTAL_FREQUENCY / (1 << 16);
|
||||
float symbol_rate =
|
||||
(((256.0f + this->state_.DRATE_M) * (1 << this->state_.DRATE_E)) / (1 << 28)) * XTAL_FREQUENCY * 1000.0f;
|
||||
float bw = XTAL_FREQUENCY / (8.0f * (4 + this->state_.CHANBW_M) * (1 << this->state_.CHANBW_E));
|
||||
ESP_LOGCONFIG(TAG, "CC1101:");
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Chip ID: 0x%04X\n"
|
||||
" Frequency: %" PRId32 " kHz\n"
|
||||
" Channel: %u\n"
|
||||
" Modulation: %s\n"
|
||||
" Symbol Rate: %.0f baud\n"
|
||||
" Filter Bandwidth: %.1f kHz\n"
|
||||
" Output Power: %.1f dBm",
|
||||
this->chip_id_, freq, this->state_.CHANNR, MODULATION_NAMES[this->state_.MOD_FORMAT & 0x07],
|
||||
symbol_rate, bw, this->output_power_effective_);
|
||||
}
|
||||
|
||||
void CC1101Component::begin_tx() {
|
||||
// Ensure Packet Format is 3 (Async Serial), use GDO0 as input during TX
|
||||
this->write_(Register::PKTCTRL0, 0x32);
|
||||
ESP_LOGV(TAG, "Beginning TX sequence");
|
||||
this->strobe_(Command::TX);
|
||||
if (!this->wait_for_state_(State::TX, 50)) {
|
||||
ESP_LOGW(TAG, "Timed out waiting for TX state!");
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::begin_rx() {
|
||||
ESP_LOGV(TAG, "Beginning RX sequence");
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
|
||||
void CC1101Component::reset() {
|
||||
this->strobe_(Command::RES);
|
||||
this->setup();
|
||||
}
|
||||
|
||||
void CC1101Component::set_idle() {
|
||||
ESP_LOGV(TAG, "Setting IDLE state");
|
||||
this->enter_idle_();
|
||||
}
|
||||
|
||||
void CC1101Component::set_gdo0_config(uint8_t value) {
|
||||
this->state_.GDO0_CFG = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::IOCFG0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_gdo2_config(uint8_t value) {
|
||||
this->state_.GDO2_CFG = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::IOCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
bool CC1101Component::wait_for_state_(State target_state, uint32_t timeout_ms) {
|
||||
uint32_t start = millis();
|
||||
while (millis() - start < timeout_ms) {
|
||||
this->read_(Register::MARCSTATE);
|
||||
State s = static_cast<State>(this->state_.MARC_STATE);
|
||||
if (s == target_state) {
|
||||
return true;
|
||||
}
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CC1101Component::enter_idle_() {
|
||||
this->strobe_(Command::IDLE);
|
||||
this->wait_for_state_(State::IDLE);
|
||||
}
|
||||
|
||||
uint8_t CC1101Component::strobe_(Command cmd) {
|
||||
uint8_t index = static_cast<uint8_t>(cmd);
|
||||
if (cmd < Command::RES || cmd > Command::NOP) {
|
||||
return 0xFF;
|
||||
}
|
||||
this->enable();
|
||||
uint8_t status_byte = this->transfer_byte(index);
|
||||
this->disable();
|
||||
return status_byte;
|
||||
}
|
||||
|
||||
void CC1101Component::write_(Register reg) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index);
|
||||
this->write_array(&this->state_.regs()[index], 1);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void CC1101Component::write_(Register reg, uint8_t value) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->state_.regs()[index] = value;
|
||||
this->write_(reg);
|
||||
}
|
||||
|
||||
void CC1101Component::write_(Register reg, const uint8_t *buffer, size_t length) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index | BUS_WRITE | BUS_BURST);
|
||||
this->write_array(buffer, length);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void CC1101Component::read_(Register reg) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index | BUS_READ | BUS_BURST);
|
||||
this->state_.regs()[index] = this->transfer_byte(0);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void CC1101Component::read_(Register reg, uint8_t *buffer, size_t length) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index | BUS_READ | BUS_BURST);
|
||||
this->read_array(buffer, length);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
// Setters
|
||||
void CC1101Component::set_output_power(float value) {
|
||||
this->output_power_requested_ = value;
|
||||
int32_t freq = static_cast<int32_t>(this->state_.FREQ2 << 16 | this->state_.FREQ1 << 8 | this->state_.FREQ0) *
|
||||
XTAL_FREQUENCY / (1 << 16);
|
||||
uint8_t a = 0xC0;
|
||||
if (freq >= 300000 && freq <= 348000) {
|
||||
a = PowerTableItem::find(PA_TABLE_315, sizeof(PA_TABLE_315) / sizeof(PA_TABLE_315[0]), value);
|
||||
} else if (freq >= 378000 && freq <= 464000) {
|
||||
a = PowerTableItem::find(PA_TABLE_433, sizeof(PA_TABLE_433) / sizeof(PA_TABLE_433[0]), value);
|
||||
} else if (freq >= 779000 && freq < 900000) {
|
||||
a = PowerTableItem::find(PA_TABLE_868, sizeof(PA_TABLE_868) / sizeof(PA_TABLE_868[0]), value);
|
||||
} else if (freq >= 900000 && freq <= 928000) {
|
||||
a = PowerTableItem::find(PA_TABLE_915, sizeof(PA_TABLE_915) / sizeof(PA_TABLE_915[0]), value);
|
||||
}
|
||||
|
||||
if (static_cast<Modulation>(this->state_.MOD_FORMAT) == Modulation::MODULATION_ASK_OOK) {
|
||||
this->pa_table_[0] = 0;
|
||||
this->pa_table_[1] = a;
|
||||
} else {
|
||||
this->pa_table_[0] = a;
|
||||
this->pa_table_[1] = 0;
|
||||
}
|
||||
this->output_power_effective_ = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::PATABLE, this->pa_table_, sizeof(this->pa_table_));
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_rx_attenuation(RxAttenuation value) {
|
||||
this->state_.CLOSE_IN_RX = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::FIFOTHR);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_dc_blocking_filter(bool value) {
|
||||
this->state_.DEM_DCFILT_OFF = value ? 0 : 1;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_frequency(float value) {
|
||||
int32_t freq = static_cast<int32_t>(value * (1 << 16) / XTAL_FREQUENCY);
|
||||
this->state_.FREQ2 = static_cast<uint8_t>(freq >> 16);
|
||||
this->state_.FREQ1 = static_cast<uint8_t>(freq >> 8);
|
||||
this->state_.FREQ0 = static_cast<uint8_t>(freq);
|
||||
if (this->initialized_) {
|
||||
this->enter_idle_();
|
||||
this->write_(Register::FREQ2);
|
||||
this->write_(Register::FREQ1);
|
||||
this->write_(Register::FREQ0);
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_if_frequency(float value) {
|
||||
this->state_.FREQ_IF = value * (1 << 10) / XTAL_FREQUENCY;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::FSCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_filter_bandwidth(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(XTAL_FREQUENCY / (value * 8), 2, e, m);
|
||||
this->state_.CHANBW_E = e;
|
||||
this->state_.CHANBW_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG4);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_channel(uint8_t value) {
|
||||
this->state_.CHANNR = value;
|
||||
if (this->initialized_) {
|
||||
this->enter_idle_();
|
||||
this->write_(Register::CHANNR);
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_channel_spacing(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(value * (1 << 18) / XTAL_FREQUENCY, 8, e, m);
|
||||
this->state_.CHANSPC_E = e;
|
||||
this->state_.CHANSPC_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG1);
|
||||
this->write_(Register::MDMCFG0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_fsk_deviation(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(value * (1 << 17) / XTAL_FREQUENCY, 3, e, m);
|
||||
this->state_.DEVIATION_E = e;
|
||||
this->state_.DEVIATION_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::DEVIATN);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_msk_deviation(uint8_t value) {
|
||||
this->state_.DEVIATION_E = 0;
|
||||
this->state_.DEVIATION_M = value - 1;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::DEVIATN);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_symbol_rate(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(value * (1 << 28) / (XTAL_FREQUENCY * 1000), 8, e, m);
|
||||
this->state_.DRATE_E = e;
|
||||
this->state_.DRATE_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG4);
|
||||
this->write_(Register::MDMCFG3);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_sync_mode(SyncMode value) {
|
||||
this->state_.SYNC_MODE = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_carrier_sense_above_threshold(bool value) {
|
||||
this->state_.CARRIER_SENSE_ABOVE_THRESHOLD = value ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_modulation_type(Modulation value) {
|
||||
this->state_.MOD_FORMAT = static_cast<uint8_t>(value);
|
||||
this->state_.PA_POWER = value == Modulation::MODULATION_ASK_OOK ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->enter_idle_();
|
||||
this->write_(Register::MDMCFG2);
|
||||
this->write_(Register::FREND0);
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_manchester(bool value) {
|
||||
this->state_.MANCHESTER_EN = value ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_num_preamble(uint8_t value) {
|
||||
this->state_.NUM_PREAMBLE = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_sync1(uint8_t value) {
|
||||
this->state_.SYNC1 = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::SYNC1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_sync0(uint8_t value) {
|
||||
this->state_.SYNC0 = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::SYNC0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_pktlen(uint8_t value) {
|
||||
this->state_.PKTLEN = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::PKTLEN);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_magn_target(MagnTarget value) {
|
||||
this->state_.MAGN_TARGET = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_max_lna_gain(MaxLnaGain value) {
|
||||
this->state_.MAX_LNA_GAIN = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_max_dvga_gain(MaxDvgaGain value) {
|
||||
this->state_.MAX_DVGA_GAIN = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_carrier_sense_abs_thr(int8_t value) {
|
||||
this->state_.CARRIER_SENSE_ABS_THR = static_cast<uint8_t>(value & 0b1111);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_carrier_sense_rel_thr(CarrierSenseRelThr value) {
|
||||
this->state_.CARRIER_SENSE_REL_THR = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_lna_priority(bool value) {
|
||||
this->state_.AGC_LNA_PRIORITY = value ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_filter_length_fsk_msk(FilterLengthFskMsk value) {
|
||||
this->state_.FILTER_LENGTH = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_filter_length_ask_ook(FilterLengthAskOok value) {
|
||||
this->state_.FILTER_LENGTH = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_freeze(Freeze value) {
|
||||
this->state_.AGC_FREEZE = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_wait_time(WaitTime value) {
|
||||
this->state_.WAIT_TIME = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_hyst_level(HystLevel value) {
|
||||
this->state_.HYST_LEVEL = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::cc1101
|
||||
110
esphome/components/cc1101/cc1101.h
Normal file
110
esphome/components/cc1101/cc1101.h
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "cc1101defs.h"
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
class CC1101Component : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1MHZ> {
|
||||
public:
|
||||
CC1101Component();
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
// Actions
|
||||
void begin_tx();
|
||||
void begin_rx();
|
||||
void reset();
|
||||
void set_idle();
|
||||
|
||||
// GDO Pin Configuration
|
||||
void set_gdo0_config(uint8_t value);
|
||||
void set_gdo2_config(uint8_t value);
|
||||
|
||||
// Configuration Setters
|
||||
void set_output_power(float value);
|
||||
void set_rx_attenuation(RxAttenuation value);
|
||||
void set_dc_blocking_filter(bool value);
|
||||
|
||||
// Tuner settings
|
||||
void set_frequency(float value);
|
||||
void set_if_frequency(float value);
|
||||
void set_filter_bandwidth(float value);
|
||||
void set_channel(uint8_t value);
|
||||
void set_channel_spacing(float value);
|
||||
void set_fsk_deviation(float value);
|
||||
void set_msk_deviation(uint8_t value);
|
||||
void set_symbol_rate(float value);
|
||||
void set_sync_mode(SyncMode value);
|
||||
void set_carrier_sense_above_threshold(bool value);
|
||||
void set_modulation_type(Modulation value);
|
||||
void set_manchester(bool value);
|
||||
void set_num_preamble(uint8_t value);
|
||||
void set_sync1(uint8_t value);
|
||||
void set_sync0(uint8_t value);
|
||||
void set_pktlen(uint8_t value);
|
||||
|
||||
// AGC settings
|
||||
void set_magn_target(MagnTarget value);
|
||||
void set_max_lna_gain(MaxLnaGain value);
|
||||
void set_max_dvga_gain(MaxDvgaGain value);
|
||||
void set_carrier_sense_abs_thr(int8_t value);
|
||||
void set_carrier_sense_rel_thr(CarrierSenseRelThr value);
|
||||
void set_lna_priority(bool value);
|
||||
void set_filter_length_fsk_msk(FilterLengthFskMsk value);
|
||||
void set_filter_length_ask_ook(FilterLengthAskOok value);
|
||||
void set_freeze(Freeze value);
|
||||
void set_wait_time(WaitTime value);
|
||||
void set_hyst_level(HystLevel value);
|
||||
|
||||
protected:
|
||||
uint16_t chip_id_{0};
|
||||
bool initialized_{false};
|
||||
|
||||
float output_power_requested_{10.0f};
|
||||
float output_power_effective_{10.0f};
|
||||
uint8_t pa_table_[PA_TABLE_SIZE]{};
|
||||
|
||||
CC1101State state_;
|
||||
|
||||
// Low-level Helpers
|
||||
uint8_t strobe_(Command cmd);
|
||||
void write_(Register reg);
|
||||
void write_(Register reg, uint8_t value);
|
||||
void write_(Register reg, const uint8_t *buffer, size_t length);
|
||||
void read_(Register reg);
|
||||
void read_(Register reg, uint8_t *buffer, size_t length);
|
||||
|
||||
// State Management
|
||||
bool wait_for_state_(State target_state, uint32_t timeout_ms = 100);
|
||||
void enter_idle_();
|
||||
};
|
||||
|
||||
// Action Wrappers
|
||||
template<typename... Ts> class BeginTxAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->begin_tx(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class BeginRxAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->begin_rx(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class ResetAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->reset(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetIdleAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->set_idle(); }
|
||||
};
|
||||
|
||||
} // namespace esphome::cc1101
|
||||
644
esphome/components/cc1101/cc1101defs.h
Normal file
644
esphome/components/cc1101/cc1101defs.h
Normal file
@@ -0,0 +1,644 @@
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
static constexpr float XTAL_FREQUENCY = 26000;
|
||||
|
||||
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
|
||||
static constexpr size_t PA_TABLE_SIZE = 8;
|
||||
|
||||
enum class Register : uint8_t {
|
||||
IOCFG2 = 0x00, // GDO2 output pin configuration
|
||||
IOCFG1 = 0x01, // GDO1 output pin configuration
|
||||
IOCFG0 = 0x02, // GDO0 output pin configuration
|
||||
FIFOTHR = 0x03, // RX FIFO and TX FIFO thresholds
|
||||
SYNC1 = 0x04, // Sync word, high INT8U
|
||||
SYNC0 = 0x05, // Sync word, low INT8U
|
||||
PKTLEN = 0x06, // Packet length
|
||||
PKTCTRL1 = 0x07, // Packet automation control
|
||||
PKTCTRL0 = 0x08, // Packet automation control
|
||||
ADDR = 0x09, // Device address
|
||||
CHANNR = 0x0A, // Channel number
|
||||
FSCTRL1 = 0x0B, // Frequency synthesizer control
|
||||
FSCTRL0 = 0x0C, // Frequency synthesizer control
|
||||
FREQ2 = 0x0D, // Frequency control word, high INT8U
|
||||
FREQ1 = 0x0E, // Frequency control word, middle INT8U
|
||||
FREQ0 = 0x0F, // Frequency control word, low INT8U
|
||||
MDMCFG4 = 0x10, // Modem configuration
|
||||
MDMCFG3 = 0x11, // Modem configuration
|
||||
MDMCFG2 = 0x12, // Modem configuration
|
||||
MDMCFG1 = 0x13, // Modem configuration
|
||||
MDMCFG0 = 0x14, // Modem configuration
|
||||
DEVIATN = 0x15, // Modem deviation setting
|
||||
MCSM2 = 0x16, // Main Radio Control State Machine configuration
|
||||
MCSM1 = 0x17, // Main Radio Control State Machine configuration
|
||||
MCSM0 = 0x18, // Main Radio Control State Machine configuration
|
||||
FOCCFG = 0x19, // Frequency Offset Compensation configuration
|
||||
BSCFG = 0x1A, // Bit Synchronization configuration
|
||||
AGCCTRL2 = 0x1B, // AGC control
|
||||
AGCCTRL1 = 0x1C, // AGC control
|
||||
AGCCTRL0 = 0x1D, // AGC control
|
||||
WOREVT1 = 0x1E, // High INT8U Event 0 timeout
|
||||
WOREVT0 = 0x1F, // Low INT8U Event 0 timeout
|
||||
WORCTRL = 0x20, // Wake On Radio control
|
||||
FREND1 = 0x21, // Front end RX configuration
|
||||
FREND0 = 0x22, // Front end TX configuration
|
||||
FSCAL3 = 0x23, // Frequency synthesizer calibration
|
||||
FSCAL2 = 0x24, // Frequency synthesizer calibration
|
||||
FSCAL1 = 0x25, // Frequency synthesizer calibration
|
||||
FSCAL0 = 0x26, // Frequency synthesizer calibration
|
||||
RCCTRL1 = 0x27, // RC oscillator configuration
|
||||
RCCTRL0 = 0x28, // RC oscillator configuration
|
||||
FSTEST = 0x29, // Frequency synthesizer calibration control
|
||||
PTEST = 0x2A, // Production test
|
||||
AGCTEST = 0x2B, // AGC test
|
||||
TEST2 = 0x2C, // Various test settings
|
||||
TEST1 = 0x2D, // Various test settings
|
||||
TEST0 = 0x2E, // Various test settings
|
||||
UNUSED = 0x2F,
|
||||
PARTNUM = 0x30,
|
||||
VERSION = 0x31,
|
||||
FREQEST = 0x32,
|
||||
LQI = 0x33,
|
||||
RSSI = 0x34,
|
||||
MARCSTATE = 0x35,
|
||||
WORTIME1 = 0x36,
|
||||
WORTIME0 = 0x37,
|
||||
PKTSTATUS = 0x38,
|
||||
VCO_VC_DAC = 0x39,
|
||||
TXBYTES = 0x3A,
|
||||
RXBYTES = 0x3B,
|
||||
RCCTRL1_STATUS = 0x3C,
|
||||
RCCTRL0_STATUS = 0x3D,
|
||||
PATABLE = 0x3E,
|
||||
FIFO = 0x3F,
|
||||
};
|
||||
|
||||
enum class Command : uint8_t {
|
||||
RES = 0x30, // Reset chip.
|
||||
FSTXON = 0x31, // Enable and calibrate frequency synthesizer
|
||||
XOFF = 0x32, // Turn off crystal oscillator.
|
||||
CAL = 0x33, // Calibrate frequency synthesizer and turn it off
|
||||
RX = 0x34, // Enable RX.
|
||||
TX = 0x35, // Enable TX.
|
||||
IDLE = 0x36, // Exit RX / TX
|
||||
// 0x37 is RESERVED / UNDEFINED in CC1101 Datasheet
|
||||
WOR = 0x38, // Start automatic RX polling sequence (Wake-on-Radio)
|
||||
PWD = 0x39, // Enter power down mode when CSn goes high.
|
||||
FRX = 0x3A, // Flush the RX FIFO buffer.
|
||||
FTX = 0x3B, // Flush the TX FIFO buffer.
|
||||
WORRST = 0x3C, // Reset real time clock.
|
||||
NOP = 0x3D, // No operation.
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
enum class SyncMode : uint8_t {
|
||||
SYNC_MODE_NONE,
|
||||
SYNC_MODE_15_16,
|
||||
SYNC_MODE_16_16,
|
||||
SYNC_MODE_30_32,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
enum class MaxDvgaGain : uint8_t {
|
||||
MAX_DVGA_GAIN_DEFAULT,
|
||||
MAX_DVGA_GAIN_MINUS_1,
|
||||
MAX_DVGA_GAIN_MINUS_2,
|
||||
MAX_DVGA_GAIN_MINUS_3,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
enum class FilterLengthFskMsk : uint8_t {
|
||||
FILTER_LENGTH_8DB,
|
||||
FILTER_LENGTH_16DB,
|
||||
FILTER_LENGTH_32DB,
|
||||
FILTER_LENGTH_64DB,
|
||||
};
|
||||
|
||||
enum class FilterLengthAskOok : uint8_t {
|
||||
FILTER_LENGTH_4DB,
|
||||
FILTER_LENGTH_8DB,
|
||||
FILTER_LENGTH_12DB,
|
||||
FILTER_LENGTH_16DB,
|
||||
};
|
||||
|
||||
enum class Freeze : uint8_t {
|
||||
FREEZE_DEFAULT,
|
||||
FREEZE_ON_SYNC,
|
||||
FREEZE_ANALOG_ONLY,
|
||||
FREEZE_ANALOG_AND_DIGITAL,
|
||||
};
|
||||
|
||||
enum class WaitTime : uint8_t {
|
||||
WAIT_TIME_8_SAMPLES,
|
||||
WAIT_TIME_16_SAMPLES,
|
||||
WAIT_TIME_24_SAMPLES,
|
||||
WAIT_TIME_32_SAMPLES,
|
||||
};
|
||||
|
||||
enum class HystLevel : uint8_t {
|
||||
HYST_LEVEL_NONE,
|
||||
HYST_LEVEL_LOW,
|
||||
HYST_LEVEL_MEDIUM,
|
||||
HYST_LEVEL_HIGH,
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) CC1101State {
|
||||
// Byte array accessors for bulk SPI transfers
|
||||
uint8_t *regs() { return reinterpret_cast<uint8_t *>(this); }
|
||||
const uint8_t *regs() const { return reinterpret_cast<const uint8_t *>(this); }
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
static_assert(sizeof(CC1101State) == 0x40, "CC1101State size mismatch");
|
||||
|
||||
} // namespace esphome::cc1101
|
||||
174
esphome/components/cc1101/cc1101pa.h
Normal file
174
esphome/components/cc1101/cc1101pa.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
// CC1101 Design Note DN013
|
||||
|
||||
struct PowerTableItem {
|
||||
uint8_t value;
|
||||
uint8_t dbm_diff; // starts from 12.0, diff to previous entry, scaled by 10
|
||||
|
||||
static uint8_t find(const PowerTableItem *items, size_t count, float &dbm_target) {
|
||||
int32_t dbmi = 120;
|
||||
int32_t dbmi_target = static_cast<int32_t>(std::lround(dbm_target * 10));
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
dbmi -= items[i].dbm_diff;
|
||||
if (dbmi_target >= dbmi) {
|
||||
// Skip invalid PA settings (magic numbers derived from TI DN013/SmartRC logic)
|
||||
if (items[i].value >= 0x61 && items[i].value <= 0x6F) {
|
||||
continue;
|
||||
}
|
||||
dbm_target = static_cast<float>(dbmi) / 10.0f;
|
||||
return items[i].value;
|
||||
}
|
||||
}
|
||||
dbm_target = -30.0f;
|
||||
return 0x03;
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
} // namespace esphome::cc1101
|
||||
20
tests/components/cc1101/common.yaml
Normal file
20
tests/components/cc1101/common.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
cc1101:
|
||||
id: transceiver
|
||||
cs_pin: ${cs_pin}
|
||||
frequency: 433920
|
||||
if_frequency: 153
|
||||
filter_bandwidth: 203
|
||||
channel: 0
|
||||
channel_spacing: 200
|
||||
symbol_rate: 5000
|
||||
modulation_type: ASK/OOK
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: "CC1101 Button"
|
||||
on_press:
|
||||
then:
|
||||
- cc1101.begin_tx: transceiver
|
||||
- cc1101.begin_rx: transceiver
|
||||
- cc1101.set_idle: transceiver
|
||||
- cc1101.reset: transceiver
|
||||
8
tests/components/cc1101/test.esp32-idf.yaml
Normal file
8
tests/components/cc1101/test.esp32-idf.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO5
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp32-idf.yaml
|
||||
remote_receiver: !include ../../test_build_components/common/remote_receiver/esp32-idf.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
8
tests/components/cc1101/test.esp8266.yaml
Normal file
8
tests/components/cc1101/test.esp8266.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO5
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp8266-ard.yaml
|
||||
remote_receiver: !include ../../test_build_components/common/remote_receiver/esp8266-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
Reference in New Issue
Block a user