9static const char *
const TAG =
"cc1101";
11static void split_float(
float value,
int mbits, uint8_t &e,
uint32_t &
m) {
13 float m_tmp = std::frexp(value, &e_tmp);
19 e =
static_cast<uint8_t
>(e_tmp - mbits - 1);
20 m =
static_cast<uint32_t>(((m_tmp * 2 - 1) * (1 << (mbits + 1))) + 1) >> 1;
21 if (
m == (1UL << mbits)) {
30 this->
state_.GDO2_CFG = 0x0D;
31 this->
state_.GDO1_CFG = 0x2E;
32 this->
state_.GDO0_CFG = 0x0D;
36 this->
state_.PKTLEN = 0xFF;
37 this->
state_.APPEND_STATUS = 1;
38 this->
state_.LENGTH_CONFIG = 1;
40 this->
state_.WHITE_DATA = 1;
41 this->
state_.FREQ_IF = 0x0F;
45 this->
state_.DRATE_E = 0x0C;
46 this->
state_.CHANBW_E = 0x02;
47 this->
state_.DRATE_M = 0x22;
48 this->
state_.SYNC_MODE = 2;
49 this->
state_.CHANSPC_E = 2;
50 this->
state_.NUM_PREAMBLE = 2;
51 this->
state_.CHANSPC_M = 0xF8;
52 this->
state_.DEVIATION_M = 7;
53 this->
state_.DEVIATION_E = 4;
56 this->
state_.PO_TIMEOUT = 1;
57 this->
state_.FOC_LIMIT = 2;
58 this->
state_.FOC_POST_K = 1;
59 this->
state_.FOC_PRE_K = 2;
60 this->
state_.FOC_BS_CS_GATE = 1;
61 this->
state_.BS_POST_KP = 1;
62 this->
state_.BS_POST_KI = 1;
63 this->
state_.BS_PRE_KP = 2;
64 this->
state_.BS_PRE_KI = 1;
65 this->
state_.MAGN_TARGET = 3;
66 this->
state_.AGC_LNA_PRIORITY = 1;
67 this->
state_.FILTER_LENGTH = 1;
68 this->
state_.WAIT_TIME = 1;
69 this->
state_.HYST_LEVEL = 2;
70 this->
state_.WOREVT1 = 0x87;
71 this->
state_.WOREVT0 = 0x6B;
75 this->
state_.MIX_CURRENT = 2;
76 this->
state_.LODIV_BUF_CURRENT_RX = 1;
77 this->
state_.LNA2MIX_CURRENT = 1;
78 this->
state_.LNA_CURRENT = 1;
79 this->
state_.LODIV_BUF_CURRENT_TX = 1;
80 this->
state_.FSCAL3_LO = 9;
81 this->
state_.CHP_CURR_CAL_EN = 2;
82 this->
state_.FSCAL3_HI = 2;
83 this->
state_.FSCAL2 = 0x0A;
84 this->
state_.FSCAL1 = 0x20;
85 this->
state_.FSCAL0 = 0x0D;
86 this->
state_.RCCTRL1 = 0x41;
87 this->
state_.FSTEST = 0x59;
89 this->
state_.AGCTEST = 0x3F;
93 this->
state_.VCO_SEL_CAL_EN = 1;
97 this->
state_.PKT_FORMAT = 3;
98 this->
state_.LENGTH_CONFIG = 2;
99 this->
state_.FS_AUTOCAL = 1;
124 ESP_LOGD(TAG,
"CC1101 found! Chip ID: 0x%04X", this->
chip_id_);
125 if (this->
state_.VERSION == 0 || this->state_.PARTNUM == 0xFF) {
126 ESP_LOGE(TAG,
"Failed to verify CC1101.");
153 this->
defer([
this]() {
164 listener->on_packet(packet, freq_offset, rssi, lqi);
172 !this->gdo0_pin_->digital_read()) {
178 uint8_t rx_bytes = this->
state_.NUM_RXBYTES;
179 bool overflow = this->
state_.RXFIFO_OVERFLOW;
180 if (overflow || rx_bytes == 0) {
181 ESP_LOGW(TAG,
"RX FIFO overflow, flushing");
189 uint8_t payload_length, expected_rx;
192 expected_rx = payload_length + 1;
194 payload_length = this->
state_.PKTLEN;
195 expected_rx = payload_length;
197 if (payload_length == 0 || payload_length > 64 || rx_bytes != expected_rx) {
198 ESP_LOGW(TAG,
"Invalid packet: rx_bytes %u, payload_length %u", rx_bytes, payload_length);
204 this->
packet_.resize(payload_length);
211 float freq_offset =
static_cast<int8_t
>(this->
state_.FREQEST) * (XTAL_FREQUENCY / (1 << 14));
212 float rssi = (this->
state_.RSSI * RSSI_STEP) - RSSI_OFFSET;
213 bool crc_ok = (this->
state_.LQI & STATUS_CRC_OK_MASK) != 0;
214 uint8_t lqi = this->
state_.LQI & STATUS_LQI_MASK;
215 if (this->
state_.CRC_EN == 0 || crc_ok) {
226 static const char *
const MODULATION_NAMES[] = {
"2-FSK",
"GFSK",
"UNUSED",
"ASK/OOK",
227 "4-FSK",
"UNUSED",
"UNUSED",
"MSK"};
228 int32_t freq =
static_cast<int32_t
>(this->
state_.FREQ2 << 16 | this->
state_.FREQ1 << 8 | this->
state_.FREQ0) *
229 XTAL_FREQUENCY / (1 << 16);
230 float symbol_rate = (((256.0f + this->
state_.DRATE_M) * (1 << this->
state_.DRATE_E)) / (1 << 28)) * XTAL_FREQUENCY;
231 float bw = XTAL_FREQUENCY / (8.0f * (4 + this->
state_.CHANBW_M) * (1 << this->
state_.CHANBW_E));
235 " Frequency: %" PRId32
" Hz\n"
238 " Symbol Rate: %.0f baud\n"
239 " Filter Bandwidth: %.1f Hz\n"
240 " Output Power: %.1f dBm",
241 this->
chip_id_, freq, this->
state_.CHANNR, MODULATION_NAMES[this->state_.MOD_FORMAT & 0x07],
242 symbol_rate, bw, this->output_power_effective_);
243 LOG_PIN(
" CS Pin: ", this->
cs_);
249 ESP_LOGV(TAG,
"Beginning TX sequence");
258 ESP_LOGW(TAG,
"Failed to enter TX state!");
263 ESP_LOGV(TAG,
"Beginning RX sequence");
270 ESP_LOGW(TAG,
"Failed to enter RX state!");
280 ESP_LOGV(TAG,
"Setting IDLE state");
286 while (
millis() - start < timeout_ms) {
289 if (s == target_state) {
299 for (uint8_t retries = PLL_LOCK_RETRIES; retries > 0; retries--) {
305 if (this->
state_.FSCAL1 != FSCAL1_PLL_NOT_LOCKED) {
308 ESP_LOGW(TAG,
"PLL lock failed, retrying calibration");
311 ESP_LOGE(TAG,
"PLL lock failed after retries");
325 uint8_t index =
static_cast<uint8_t
>(cmd);
336 uint8_t index =
static_cast<uint8_t
>(reg);
344 uint8_t index =
static_cast<uint8_t
>(reg);
345 this->
state_.regs()[index] = value;
350 uint8_t index =
static_cast<uint8_t
>(reg);
352 this->
write_byte(index | BUS_WRITE | BUS_BURST);
358 uint8_t index =
static_cast<uint8_t
>(reg);
360 this->
write_byte(index | BUS_READ | BUS_BURST);
366 uint8_t index =
static_cast<uint8_t
>(reg);
368 this->
write_byte(index | BUS_READ | BUS_BURST);
388 ESP_LOGW(TAG,
"PLL lock failed during TX");
397 ESP_LOGW(TAG,
"TX timeout");
411 int32_t freq =
static_cast<int32_t
>(this->
state_.FREQ2 << 16 | this->
state_.FREQ1 << 8 | this->
state_.FREQ0) *
412 XTAL_FREQUENCY / (1 << 16);
414 if (freq >= 300000000 && freq <= 348000000) {
416 }
else if (freq >= 378000000 && freq <= 464000000) {
418 }
else if (freq >= 779000000 && freq < 900000000) {
420 }
else if (freq >= 900000000 && freq <= 928000000) {
438 this->
state_.CLOSE_IN_RX =
static_cast<uint8_t
>(value);
445 this->
state_.DEM_DCFILT_OFF = value ? 0 : 1;
452 int32_t freq =
static_cast<int32_t
>(value * (1 << 16) / XTAL_FREQUENCY);
453 this->
state_.FREQ2 =
static_cast<uint8_t
>(freq >> 16);
454 this->
state_.FREQ1 =
static_cast<uint8_t
>(freq >> 8);
455 this->
state_.FREQ0 =
static_cast<uint8_t
>(freq);
466 this->
state_.FREQ_IF = value * (1 << 10) / XTAL_FREQUENCY;
475 split_float(XTAL_FREQUENCY / (value * 8), 2, e,
m);
476 this->
state_.CHANBW_E = e;
477 this->
state_.CHANBW_M =
static_cast<uint8_t
>(
m);
484 this->
state_.CHANNR = value;
495 split_float(value * (1 << 18) / XTAL_FREQUENCY, 8, e,
m);
496 this->
state_.CHANSPC_E = e;
497 this->
state_.CHANSPC_M =
static_cast<uint8_t
>(
m);
507 split_float(value * (1 << 17) / XTAL_FREQUENCY, 3, e,
m);
508 this->
state_.DEVIATION_E = e;
509 this->
state_.DEVIATION_M =
static_cast<uint8_t
>(
m);
516 this->
state_.DEVIATION_E = 0;
517 this->
state_.DEVIATION_M = value - 1;
526 split_float(value * (1 << 28) / XTAL_FREQUENCY, 8, e,
m);
528 this->
state_.DRATE_M =
static_cast<uint8_t
>(
m);
536 this->
state_.SYNC_MODE =
static_cast<uint8_t
>(value);
543 this->
state_.CARRIER_SENSE_ABOVE_THRESHOLD = value ? 1 : 0;
550 this->
state_.MOD_FORMAT =
static_cast<uint8_t
>(value);
562 this->
state_.MANCHESTER_EN = value ? 1 : 0;
569 this->
state_.NUM_PREAMBLE = value;
576 this->
state_.SYNC1 = value;
583 this->
state_.SYNC0 = value;
590 this->
state_.MAGN_TARGET =
static_cast<uint8_t
>(value);
597 this->
state_.MAX_LNA_GAIN =
static_cast<uint8_t
>(value);
604 this->
state_.MAX_DVGA_GAIN =
static_cast<uint8_t
>(value);
611 this->
state_.CARRIER_SENSE_ABS_THR =
static_cast<uint8_t
>(value & 0b1111);
618 this->
state_.CARRIER_SENSE_REL_THR =
static_cast<uint8_t
>(value);
625 this->
state_.AGC_LNA_PRIORITY = value ? 1 : 0;
632 this->
state_.FILTER_LENGTH =
static_cast<uint8_t
>(value);
639 this->
state_.FILTER_LENGTH =
static_cast<uint8_t
>(value);
646 this->
state_.AGC_FREEZE =
static_cast<uint8_t
>(value);
653 this->
state_.WAIT_TIME =
static_cast<uint8_t
>(value);
660 this->
state_.HYST_LEVEL =
static_cast<uint8_t
>(value);
671 this->
state_.GDO0_CFG = 0x01;
673 this->
state_.FIFO_THR = 15;
675 this->
state_.APPEND_STATUS = 0;
678 this->
state_.GDO0_CFG = 0x0D;
700 this->
state_.PKTLEN = value;
709 this->
state_.CRC_EN = value ? 1 : 0;
716 this->
state_.WHITE_DATA = value ? 1 : 0;
void mark_failed()
Mark this component as failed.
ESPDEPRECATED("Use const char* overload instead. Removed in 2026.7.0", "2026.1.0") void defer(const std voi defer)(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call.
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void disable_loop()
Disable this component's loop.
virtual void pin_mode(gpio::Flags flags)=0
virtual void digital_write(bool value)=0
virtual void detach_interrupt() const =0
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
void set_packet_mode(bool value)
void set_max_dvga_gain(MaxDvgaGain value)
void set_whitening(bool value)
void set_carrier_sense_above_threshold(bool value)
void write_(Register reg)
void set_sync0(uint8_t value)
void set_freeze(Freeze value)
void call_listeners_(const std::vector< uint8_t > &packet, float freq_offset, float rssi, uint8_t lqi)
void set_rx_attenuation(RxAttenuation value)
InternalGPIOPin * gdo0_pin_
void set_symbol_rate(float value)
uint8_t strobe_(Command cmd)
void set_sync_mode(SyncMode value)
void set_fsk_deviation(float value)
void dump_config() override
float output_power_requested_
void set_msk_deviation(uint8_t value)
void set_carrier_sense_rel_thr(CarrierSenseRelThr value)
uint8_t pa_table_[PA_TABLE_SIZE]
void set_lna_priority(bool value)
float output_power_effective_
void set_output_power(float value)
void set_modulation_type(Modulation value)
void set_if_frequency(float value)
void set_frequency(float value)
void set_num_preamble(uint8_t value)
void set_hyst_level(HystLevel value)
void set_filter_bandwidth(float value)
void set_filter_length_fsk_msk(FilterLengthFskMsk value)
void set_crc_enable(bool value)
static void IRAM_ATTR gpio_intr(CC1101Component *arg)
void set_carrier_sense_abs_thr(int8_t value)
bool enter_calibrated_(State target_state, Command cmd)
void set_magn_target(MagnTarget value)
void set_channel_spacing(float value)
CC1101Error transmit_packet(const std::vector< uint8_t > &packet)
void set_wait_time(WaitTime value)
std::vector< CC1101Listener * > listeners_
void set_dc_blocking_filter(bool value)
void set_packet_length(uint8_t value)
void set_manchester(bool value)
std::vector< uint8_t > packet_
void set_channel(uint8_t value)
void set_filter_length_ask_ook(FilterLengthAskOok value)
void set_max_lna_gain(MaxLnaGain value)
void set_sync1(uint8_t value)
bool wait_for_state_(State target_state, uint32_t timeout_ms=100)
Trigger< std::vector< uint8_t >, float, float, uint8_t > packet_trigger_
void spi_setup() override
void write_byte(uint8_t data)
uint8_t transfer_byte(uint8_t data)
void write_array(const uint8_t *data, size_t length)
void read_array(uint8_t *data, size_t length)
@ PACKET_FORMAT_ASYNC_SERIAL
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
void HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
static uint8_t find(const PowerTableItem *items, size_t count, float &dbm_target)