#pragma once #include namespace esphome::cc1101 { static constexpr float XTAL_FREQUENCY = 26000000; static constexpr float RSSI_OFFSET = 74.0f; static constexpr float RSSI_STEP = 0.5f; static constexpr uint8_t FSCAL1_PLL_NOT_LOCKED = 0x3F; static constexpr uint8_t PLL_LOCK_RETRIES = 3; static constexpr uint8_t STATUS_CRC_OK_MASK = 0x80; static constexpr uint8_t STATUS_LQI_MASK = 0x7F; 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, SYNC_MODE_NONE_CS, SYNC_MODE_15_16_CS, SYNC_MODE_16_16_CS, SYNC_MODE_30_32_CS, }; 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, }; enum class PacketFormat : uint8_t { PACKET_FORMAT_FIFO, PACKET_FORMAT_SYNC_SERIAL, PACKET_FORMAT_RANDOM_TX, PACKET_FORMAT_ASYNC_SERIAL, }; enum class LengthConfig : uint8_t { LENGTH_CONFIG_FIXED, LENGTH_CONFIG_VARIABLE, LENGTH_CONFIG_INFINITE, }; struct __attribute__((packed)) CC1101State { // Byte array accessors for bulk SPI transfers uint8_t *regs() { return reinterpret_cast(this); } const uint8_t *regs() const { return reinterpret_cast(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