9#include <esp_memory_utils.h>
15static constexpr size_t TX_FIFO_SIZE = 64;
17static void split_float(
float value,
int mbits, uint8_t &e,
uint32_t &
m) {
19 float m_tmp = std::frexp(value, &e_tmp);
25 e =
static_cast<uint8_t
>(e_tmp - mbits - 1);
26 m =
static_cast<uint32_t>(((m_tmp * 2 - 1) * (1 << (mbits + 1))) + 1) >> 1;
27 if (
m == (1UL << mbits)) {
36 this->
state_.GDO2_CFG = 0x0D;
37 this->
state_.GDO1_CFG = 0x2E;
38 this->
state_.GDO0_CFG = 0x0D;
42 this->
state_.PKTLEN = 0xFF;
43 this->
state_.APPEND_STATUS = 1;
44 this->
state_.LENGTH_CONFIG = 1;
46 this->
state_.WHITE_DATA = 1;
47 this->
state_.FREQ_IF = 0x0F;
51 this->
state_.DRATE_E = 0x0C;
52 this->
state_.CHANBW_E = 0x02;
53 this->
state_.DRATE_M = 0x22;
54 this->
state_.SYNC_MODE = 2;
55 this->
state_.CHANSPC_E = 2;
56 this->
state_.NUM_PREAMBLE = 2;
57 this->
state_.CHANSPC_M = 0xF8;
58 this->
state_.DEVIATION_M = 7;
59 this->
state_.DEVIATION_E = 4;
62 this->
state_.PO_TIMEOUT = 1;
63 this->
state_.FOC_LIMIT = 2;
64 this->
state_.FOC_POST_K = 1;
65 this->
state_.FOC_PRE_K = 2;
66 this->
state_.FOC_BS_CS_GATE = 1;
67 this->
state_.BS_POST_KP = 1;
68 this->
state_.BS_POST_KI = 1;
69 this->
state_.BS_PRE_KP = 2;
70 this->
state_.BS_PRE_KI = 1;
71 this->
state_.MAGN_TARGET = 3;
72 this->
state_.AGC_LNA_PRIORITY = 1;
73 this->
state_.FILTER_LENGTH = 1;
74 this->
state_.WAIT_TIME = 1;
75 this->
state_.HYST_LEVEL = 2;
76 this->
state_.WOREVT1 = 0x87;
77 this->
state_.WOREVT0 = 0x6B;
81 this->
state_.MIX_CURRENT = 2;
82 this->
state_.LODIV_BUF_CURRENT_RX = 1;
83 this->
state_.LNA2MIX_CURRENT = 1;
84 this->
state_.LNA_CURRENT = 1;
85 this->
state_.LODIV_BUF_CURRENT_TX = 1;
86 this->
state_.FSCAL3_LO = 9;
87 this->
state_.CHP_CURR_CAL_EN = 2;
88 this->
state_.FSCAL3_HI = 2;
89 this->
state_.FSCAL2 = 0x0A;
90 this->
state_.FSCAL1 = 0x20;
91 this->
state_.FSCAL0 = 0x0D;
92 this->
state_.RCCTRL1 = 0x41;
93 this->
state_.FSTEST = 0x59;
95 this->
state_.AGCTEST = 0x3F;
99 this->
state_.VCO_SEL_CAL_EN = 1;
100 this->
state_.TEST0_HI = 2;
103 this->
state_.PKT_FORMAT = 3;
104 this->
state_.LENGTH_CONFIG = 2;
105 this->
state_.FS_AUTOCAL = 1;
128 this->
defer([
this]() {
154 ESP_LOGD(TAG,
"CC1101 found! Chip ID: 0x%04X", this->
chip_id_);
155 if (this->
state_.VERSION == 0 || this->state_.PARTNUM == 0xFF) {
156 ESP_LOGE(TAG,
"Failed to verify CC1101.");
179 listener->on_packet(packet, freq_offset, rssi, lqi);
187 !this->gdo0_pin_->digital_read()) {
193 uint8_t rx_bytes = this->
state_.NUM_RXBYTES;
194 bool overflow = this->
state_.RXFIFO_OVERFLOW;
195 if (overflow || rx_bytes == 0) {
196 ESP_LOGW(TAG,
"RX FIFO overflow, flushing");
204 uint8_t payload_length, expected_rx;
207 expected_rx = payload_length + 1;
209 payload_length = this->
state_.PKTLEN;
210 expected_rx = payload_length;
212 if (payload_length == 0 || payload_length > 64 || rx_bytes != expected_rx) {
213 ESP_LOGW(TAG,
"Invalid packet: rx_bytes %u, payload_length %u", rx_bytes, payload_length);
219 this->
packet_.resize(payload_length);
226 float freq_offset =
static_cast<int8_t
>(this->
state_.FREQEST) * (XTAL_FREQUENCY / (1 << 14));
227 float rssi = (this->
state_.RSSI * RSSI_STEP) - RSSI_OFFSET;
228 bool crc_ok = (this->
state_.LQI & STATUS_CRC_OK_MASK) != 0;
229 uint8_t lqi = this->
state_.LQI & STATUS_LQI_MASK;
230 if (this->
state_.CRC_EN == 0 || crc_ok) {
241 static const char *
const MODULATION_NAMES[] = {
"2-FSK",
"GFSK",
"UNUSED",
"ASK/OOK",
242 "4-FSK",
"UNUSED",
"UNUSED",
"MSK"};
243 int32_t freq =
static_cast<int32_t
>(this->
state_.FREQ2 << 16 | this->
state_.FREQ1 << 8 | this->
state_.FREQ0) *
244 XTAL_FREQUENCY / (1 << 16);
245 float symbol_rate = (((256.0f + this->
state_.DRATE_M) * (1 << this->
state_.DRATE_E)) / (1 << 28)) * XTAL_FREQUENCY;
246 float bw = XTAL_FREQUENCY / (8.0f * (4 + this->
state_.CHANBW_M) * (1 << this->
state_.CHANBW_E));
250 " Frequency: %" PRId32
" Hz\n"
253 " Symbol Rate: %.0f baud\n"
254 " Filter Bandwidth: %.1f Hz\n"
255 " Output Power: %.1f dBm",
256 this->
chip_id_, freq, this->
state_.CHANNR, MODULATION_NAMES[this->state_.MOD_FORMAT & 0x07],
257 symbol_rate, bw, this->output_power_effective_);
258 LOG_PIN(
" CS Pin: ", this->
cs_);
266 ESP_LOGV(TAG,
"Beginning TX sequence");
279 ESP_LOGW(TAG,
"Failed to enter TX state!");
284 ESP_LOGV(TAG,
"Beginning RX sequence");
291 ESP_LOGW(TAG,
"Failed to enter RX state!");
301 ESP_LOGV(TAG,
"Setting IDLE state");
307 while (
millis() - start < timeout_ms) {
310 if (s == target_state) {
320 for (uint8_t retries = PLL_LOCK_RETRIES; retries > 0; retries--) {
326 if (this->
state_.FSCAL1 != FSCAL1_PLL_NOT_LOCKED) {
329 ESP_LOGW(TAG,
"PLL lock failed, retrying calibration");
332 ESP_LOGE(TAG,
"PLL lock failed after retries");
346 uint8_t index =
static_cast<uint8_t
>(cmd);
357 uint8_t index =
static_cast<uint8_t
>(reg);
365 uint8_t index =
static_cast<uint8_t
>(reg);
366 this->
state_.regs()[index] = value;
371 uint8_t index =
static_cast<uint8_t
>(reg);
373 this->
write_byte(index | BUS_WRITE | BUS_BURST);
379 uint8_t index =
static_cast<uint8_t
>(reg);
381 this->
write_byte(index | BUS_READ | BUS_BURST);
387 uint8_t index =
static_cast<uint8_t
>(reg);
389 this->
write_byte(index | BUS_READ | BUS_BURST);
400 if (
len + (variable ? 1 : 0) > TX_FIFO_SIZE) {
401 ESP_LOGE(TAG,
"Packet of %u bytes does not fit the TX FIFO",
static_cast<unsigned>(
len));
413 alignas(4) uint8_t staged[TX_FIFO_SIZE];
414 if (
len != 0 && (!esp_ptr_dma_capable(data) || (
reinterpret_cast<uintptr_t
>(data) & 3) != 0)) {
415 std::memcpy(staged, data,
len);
423 ESP_LOGW(TAG,
"PLL lock failed during TX");
432 ESP_LOGW(TAG,
"TX timeout");
446 int32_t freq =
static_cast<int32_t
>(this->
state_.FREQ2 << 16 | this->
state_.FREQ1 << 8 | this->
state_.FREQ0) *
447 XTAL_FREQUENCY / (1 << 16);
449 if (freq >= 300000000 && freq <= 348000000) {
451 }
else if (freq >= 378000000 && freq <= 464000000) {
453 }
else if (freq >= 779000000 && freq < 900000000) {
455 }
else if (freq >= 900000000 && freq <= 928000000) {
473 this->
state_.CLOSE_IN_RX =
static_cast<uint8_t
>(value);
480 this->
state_.DEM_DCFILT_OFF = value ? 0 : 1;
487 int32_t freq =
static_cast<int32_t
>(value * (1 << 16) / XTAL_FREQUENCY);
488 this->
state_.FREQ2 =
static_cast<uint8_t
>(freq >> 16);
489 this->
state_.FREQ1 =
static_cast<uint8_t
>(freq >> 8);
490 this->
state_.FREQ0 =
static_cast<uint8_t
>(freq);
501 this->
state_.FREQ_IF = value * (1 << 10) / XTAL_FREQUENCY;
510 split_float(XTAL_FREQUENCY / (value * 8), 2, e,
m);
511 this->
state_.CHANBW_E = e;
512 this->
state_.CHANBW_M =
static_cast<uint8_t
>(
m);
519 this->
state_.CHANNR = value;
530 split_float(value * (1 << 18) / XTAL_FREQUENCY, 8, e,
m);
531 this->
state_.CHANSPC_E = e;
532 this->
state_.CHANSPC_M =
static_cast<uint8_t
>(
m);
542 split_float(value * (1 << 17) / XTAL_FREQUENCY, 3, e,
m);
543 this->
state_.DEVIATION_E = e;
544 this->
state_.DEVIATION_M =
static_cast<uint8_t
>(
m);
551 this->
state_.DEVIATION_E = 0;
552 this->
state_.DEVIATION_M = value - 1;
561 split_float(value * (1 << 28) / XTAL_FREQUENCY, 8, e,
m);
563 this->
state_.DRATE_M =
static_cast<uint8_t
>(
m);
571 this->
state_.SYNC_MODE =
static_cast<uint8_t
>(value);
578 this->
state_.CARRIER_SENSE_ABOVE_THRESHOLD = value ? 1 : 0;
585 this->
state_.MOD_FORMAT =
static_cast<uint8_t
>(value);
597 this->
state_.MANCHESTER_EN = value ? 1 : 0;
604 this->
state_.NUM_PREAMBLE = value;
611 this->
state_.SYNC1 = value;
618 this->
state_.SYNC0 = value;
625 this->
state_.MAGN_TARGET =
static_cast<uint8_t
>(value);
632 this->
state_.MAX_LNA_GAIN =
static_cast<uint8_t
>(value);
639 this->
state_.MAX_DVGA_GAIN =
static_cast<uint8_t
>(value);
646 this->
state_.CARRIER_SENSE_ABS_THR =
static_cast<uint8_t
>(value & 0b1111);
653 this->
state_.CARRIER_SENSE_REL_THR =
static_cast<uint8_t
>(value);
660 this->
state_.AGC_LNA_PRIORITY = value ? 1 : 0;
667 this->
state_.FILTER_LENGTH =
static_cast<uint8_t
>(value);
674 this->
state_.FILTER_LENGTH =
static_cast<uint8_t
>(value);
681 this->
state_.AGC_FREEZE =
static_cast<uint8_t
>(value);
688 this->
state_.WAIT_TIME =
static_cast<uint8_t
>(value);
695 this->
state_.HYST_LEVEL =
static_cast<uint8_t
>(value);
702 this->
state_.FOC_BS_CS_GATE = value ? 1 : 0;
709 this->
state_.FOC_LIMIT =
static_cast<uint8_t
>(value);
716 this->
state_.FOC_PRE_K =
static_cast<uint8_t
>(value);
723 this->
state_.FOC_POST_K =
static_cast<uint8_t
>(value);
730 this->
state_.BS_LIMIT =
static_cast<uint8_t
>(value);
737 this->
state_.BS_PRE_KI =
static_cast<uint8_t
>(value);
744 this->
state_.BS_PRE_KP =
static_cast<uint8_t
>(value);
751 this->
state_.BS_POST_KI =
static_cast<uint8_t
>(value);
758 this->
state_.BS_POST_KP =
static_cast<uint8_t
>(value);
769 this->
state_.GDO0_CFG = 0x01;
771 this->
state_.FIFO_THR = 15;
773 this->
state_.APPEND_STATUS = 0;
776 this->
state_.GDO0_CFG = 0x0D;
798 this->
state_.PKTLEN = value;
807 this->
state_.CRC_EN = value ? 1 : 0;
814 this->
state_.WHITE_DATA = value ? 1 : 0;
void mark_failed()
Mark this component as failed.
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void defer(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call with a const char* name.
void disable_loop()
Disable this component's loop.
virtual void digital_write(bool value)=0
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
void set_bs_post_kp(BsPostKp value)
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)
void set_bs_pre_ki(BsPreKi value)
uint8_t strobe_(Command cmd)
void set_sync_mode(SyncMode value)
void set_fsk_deviation(float value)
void dump_config() override
void set_bs_pre_kp(BsPreKp value)
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)
void set_foc_bs_cs_gate(bool value)
void set_foc_pre_k(FocPreK 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)
void set_bs_post_ki(BsPostKi 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_foc_limit(FocLimit 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)
void set_bs_limit(BsLimit value)
void set_foc_post_k(FocPostK value)
Trigger< std::vector< uint8_t >, float, float, uint8_t > packet_trigger_
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
void detach_interrupt() const
void pin_mode(gpio::Flags flags) override
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
ESPHOME_LOG_TAG(TAG, "cc1101")
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)