cc1101 radio transmitter component initial commit

This commit is contained in:
Gábor Poczkodi 2024-02-28 10:01:35 +01:00
parent 3c651f4091
commit abc1c3aba4
5 changed files with 1010 additions and 0 deletions

View file

View file

@ -0,0 +1,702 @@
/*
https://github.com/gabest11/esphome-cc1101
This is a CC1101 transceiver component that works with esphome's remote_transmitter/remote_receiver.
It can be compiled with Arduino and esp-idf framework and should support any esphome compatible board through the SPI Bus.
On ESP8266, you can use the same pin for GDO and GD2 (it is an optional parameter).
The source code is a mashup of the following github projects with some special esphome sauce:
https://github.com/dbuezas/esphome-cc1101 (the original esphome component)
https://github.com/nistvan86/esphome-q7rf (how to use esphome with spi)
https://github.com/LSatan/SmartRC-CC1101-Driver-Lib (cc1101 setup code)
TODO: RP2040? (USE_RP2040)
TODO: Libretiny? (USE_LIBRETINY)
*/
#include "esphome/core/log.h"
#include "cc1101.h"
#include "cc1101defs.h"
#include <limits.h>
#ifdef USE_ARDUINO
#include <Arduino.h>
#else // USE_ESP_IDF
#include <driver/gpio.h>
long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
#endif
namespace esphome {
namespace cc1101 {
static const char *TAG = "cc1101";
uint8_t PA_TABLE[8] {0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00};
// -30 -20 -15 -10 0 5 7 10
uint8_t PA_TABLE_315[8] {0x12,0x0D,0x1C,0x34,0x51,0x85,0xCB,0xC2}; // 300 - 348
uint8_t PA_TABLE_433[8] {0x12,0x0E,0x1D,0x34,0x60,0x84,0xC8,0xC0}; // 387 - 464
// -30 -20 -15 -10 -6 0 5 7 10 12
uint8_t PA_TABLE_868[10] {0x03,0x17,0x1D,0x26,0x37,0x50,0x86,0xCD,0xC5,0xC0}; // 779 - 899.99
// -30 -20 -15 -10 -6 0 5 7 10 11
uint8_t PA_TABLE_915[10] {0x03,0x0E,0x1E,0x27,0x38,0x8E,0x84,0xCC,0xC3,0xC0}; // 900 - 928
CC1101::CC1101()
{
this->gdo0_ = NULL;
this->gdo2_ = NULL;
this->bandwidth_ = 200;
this->frequency_ = 433920;
this->rssi_sensor_ = NULL;
this->lqi_sensor_ = NULL;
this->partnum_ = 0;
this->version_ = 0;
this->last_rssi_ = INT_MIN;
this->last_lqi_ = INT_MIN;
this->mode_ = false;
this->modulation_ = 2;
this->chan_ = 0;
this->pa_ = 12;
this->last_pa_ = -1;
this->m4RxBw_ = 0;
this->trxstate_ = 0;
this->clb_[0][0] = 24;
this->clb_[0][1] = 28;
this->clb_[1][0] = 31;
this->clb_[1][1] = 38;
this->clb_[2][0] = 65;
this->clb_[2][1] = 76;
this->clb_[3][0] = 77;
this->clb_[3][1] = 79;
}
void CC1101::set_config_gdo0(InternalGPIOPin* pin)
{
gdo0_ = pin;
if(gdo2_ == NULL) gdo2_ = pin;
}
void CC1101::set_config_gdo2(InternalGPIOPin* pin)
{
gdo2_ = pin;
}
void CC1101::set_config_bandwidth(uint32_t bandwidth)
{
bandwidth_ = bandwidth;
}
void CC1101::set_config_frequency(uint32_t frequency)
{
frequency_ = frequency;
}
void CC1101::set_config_rssi_sensor(sensor::Sensor* rssi_sensor)
{
rssi_sensor_ = rssi_sensor;
}
void CC1101::set_config_lqi_sensor(sensor::Sensor* lqi_sensor)
{
lqi_sensor_ = lqi_sensor;
}
void CC1101::setup()
{
this->gdo0_->setup();
this->gdo2_->setup();
this->gdo0_->pin_mode(gpio::FLAG_OUTPUT);
this->gdo2_->pin_mode(gpio::FLAG_INPUT);
this->spi_setup();
if(!this->reset())
{
mark_failed();
ESP_LOGE(TAG, "Failed to reset CC1101 modem. Check connection.");
return;
}
// ELECHOUSE_cc1101.Init();
this->write_register(CC1101_FSCTRL1, 0x06);
this->set_mode(false);
this->set_frequency(this->frequency_);
this->write_register(CC1101_MDMCFG1, 0x02);
this->write_register(CC1101_MDMCFG0, 0xF8);
this->write_register(CC1101_CHANNR, this->chan_);
this->write_register(CC1101_DEVIATN, 0x47);
this->write_register(CC1101_FREND1, 0x56);
this->write_register(CC1101_MCSM0, 0x18);
this->write_register(CC1101_FOCCFG, 0x16);
this->write_register(CC1101_BSCFG, 0x1C);
this->write_register(CC1101_AGCCTRL2, 0xC7);
this->write_register(CC1101_AGCCTRL1, 0x00);
this->write_register(CC1101_AGCCTRL0, 0xB2);
this->write_register(CC1101_FSCAL3, 0xE9);
this->write_register(CC1101_FSCAL2, 0x2A);
this->write_register(CC1101_FSCAL1, 0x00);
this->write_register(CC1101_FSCAL0, 0x1F);
this->write_register(CC1101_FSTEST, 0x59);
this->write_register(CC1101_TEST2, 0x81);
this->write_register(CC1101_TEST1, 0x35);
this->write_register(CC1101_TEST0, 0x09);
this->write_register(CC1101_PKTCTRL1, 0x04);
this->write_register(CC1101_ADDR, 0x00);
this->write_register(CC1101_PKTLEN, 0x00);
// ELECHOUSE_cc1101.setRxBW(_bandwidth);
this->set_rxbw(this->bandwidth_);
// ELECHOUSE_cc1101.setMHZ(_freq);
this->set_frequency(this->frequency_); // TODO: already set
//
this->set_rx();
//
ESP_LOGI(TAG, "CC1101 initialized.");
}
void CC1101::update()
{
if(this->rssi_sensor_ != NULL)
{
int32_t rssi = this->get_rssi();
if(rssi != this->last_rssi_)
{
this->rssi_sensor_->publish_state(rssi);
this->last_rssi_ = rssi;
}
}
if(this->lqi_sensor_ != NULL)
{
int32_t lqi = this->get_lqi() & 0x7f; // msb = CRC ok or not set
if(lqi != this->last_lqi_)
{
this->lqi_sensor_->publish_state(lqi);
this->last_lqi_ = lqi;
}
}
}
void CC1101::dump_config()
{
ESP_LOGCONFIG(TAG, "CC1101 partnum %02x version %02x:", this->partnum_, this->version_);
LOG_PIN(" CC1101 CS Pin: ", this->cs_);
LOG_PIN(" CC1101 GDO0: ", this->gdo0_);
LOG_PIN(" CC1101 GDO2: ", this->gdo2_);
ESP_LOGCONFIG(TAG, " CC1101 Bandwith: %d KHz", this->bandwidth_);
ESP_LOGCONFIG(TAG, " CC1101 Frequency: %d KHz", this->frequency_);
LOG_SENSOR(" ", "RSSI", this->rssi_sensor_);
LOG_SENSOR(" ", "LQI", this->lqi_sensor_);
}
bool CC1101::reset()
{
// Chip reset sequence. CS wiggle (CC1101 manual page 45)
//this->disable(); // esp-idf calls end_transaction and asserts, because no begin_transaction was called
this->cs_->digital_write(false);
delayMicroseconds(5);
//this->enable();
this->cs_->digital_write(true);
delayMicroseconds(10);
//this->disable();
this->cs_->digital_write(false);
delayMicroseconds(41);
this->send_cmd(CC1101_SRES);
ESP_LOGD(TAG, "Issued CC1101 reset sequence.");
// Read part number and version
this->partnum_ = this->read_status_register(CC1101_PARTNUM);
this->version_ = this->read_status_register(CC1101_VERSION);
ESP_LOGI(TAG, "CC1101 found with partnum: %02x and version: %02x", this->partnum_, this->version_);
return this->version_ > 0;
}
void CC1101::send_cmd(uint8_t cmd)
{
this->enable();
this->transfer_byte(cmd);
this->disable();
}
uint8_t CC1101::read_register(uint8_t reg)
{
this->enable();
this->transfer_byte(reg);
uint8_t value = this->transfer_byte(0);
this->disable();
return value;
}
uint8_t CC1101::read_config_register(uint8_t reg)
{
return this->read_register(reg | CC1101_READ_SINGLE);
}
uint8_t CC1101::read_status_register(uint8_t reg)
{
return this->read_register(reg | CC1101_READ_BURST);
}
void CC1101::read_register_burst(uint8_t reg, uint8_t* buffer, size_t length)
{
this->enable();
this->write_byte(reg | CC1101_READ_BURST);
this->read_array(buffer, length);
this->disable();
}
void CC1101::write_register(uint8_t reg, uint8_t* value, size_t length)
{
this->enable();
this->transfer_byte(reg);
this->transfer_array(value, length);
this->disable();
}
void CC1101::write_register(uint8_t reg, uint8_t value)
{
uint8_t arr[1] = {value};
this->write_register(reg, arr, 1);
}
void CC1101::write_register_burst(uint8_t reg, uint8_t* buffer, size_t length)
{
this->write_register(reg | CC1101_WRITE_BURST, buffer, length);
}
/*
bool CC1101::send_data(const uint8_t* data, size_t length)
{
uint8_t buffer[length];
memcpy(buffer, data, lenght);
this->send_cmd(CC1101_SIDLE);
this->send_cmd(CC1101_SFRX);
this->send_cmd(CC1101_SFTX);
this->write_register_burst(CC1101_TXFIFO, buffer, length);
this->send_cmd(CC1101_STX);
uint8_t state = this->read_status_register(CC1101_MARCSTATE) & 0x1f;
if(state != CC1101_MARCSTATE_TX && state != CC1101_MARCSTATE_TX_END && state != CC1101_MARCSTATE_RXTX_SWITCH)
{
ESP_LOGE(TAG, "CC1101 in invalid state after sending, returning to idle. State: 0x%02x", state);
this->send_cmd(CC1101_SIDLE);
return false;
}
return true;
}
*/
// ELECHOUSE_CC1101 stuff
void CC1101::set_mode(bool s)
{
this->mode_ = s;
if(s)
{
this->write_register(CC1101_IOCFG2, 0x0B);
this->write_register(CC1101_IOCFG0, 0x06);
this->write_register(CC1101_PKTCTRL0, 0x05);
this->write_register(CC1101_MDMCFG3, 0xF8);
this->write_register(CC1101_MDMCFG4, 11 + this->m4RxBw_);
}
else
{
this->write_register(CC1101_IOCFG2, 0x0D);
this->write_register(CC1101_IOCFG0, 0x0D);
this->write_register(CC1101_PKTCTRL0, 0x32);
this->write_register(CC1101_MDMCFG3, 0x93);
this->write_register(CC1101_MDMCFG4, 7 + this->m4RxBw_);
}
this->set_modulation(this->modulation_);
}
void CC1101::set_modulation(uint8_t m)
{
if(m > 4) m = 4;
this->modulation_ = m;
this->split_MDMCFG2();
switch(m)
{
case 0: this->m2MODFM_ = 0x00; this->frend0_ = 0x10; break; // 2-FSK
case 1: this->m2MODFM_ = 0x10; this->frend0_ = 0x10; break; // GFSK
case 2: this->m2MODFM_ = 0x30; this->frend0_ = 0x11; break; // ASK
case 3: this->m2MODFM_ = 0x40; this->frend0_ = 0x10; break; // 4-FSK
case 4: this->m2MODFM_ = 0x70; this->frend0_ = 0x10; break; // MSK
}
this->write_register(CC1101_MDMCFG2, this->m2DCOFF_ + this->m2MODFM_ + this->m2MANCH_ + this->m2SYNCM_);
this->write_register(CC1101_FREND0, this->frend0_);
this->set_pa(this->pa_);
}
void CC1101::set_pa(int8_t pa)
{
this->pa_ = pa;
int a;
if(this->frequency_ >= 300000 && this->frequency_ <= 348000)
{
if(pa <= -30) a = PA_TABLE_315[0];
else if(pa > -30 && pa <= -20) a = PA_TABLE_315[1];
else if(pa > -20 && pa <= -15) a = PA_TABLE_315[2];
else if(pa > -15 && pa <= -10) a = PA_TABLE_315[3];
else if(pa > -10 && pa <= 0) a = PA_TABLE_315[4];
else if(pa > 0 && pa <= 5) a = PA_TABLE_315[5];
else if(pa > 5 && pa <= 7) a = PA_TABLE_315[6];
else a = PA_TABLE_315[7];
this->last_pa_ = 1;
}
else if(this->frequency_ >= 378000 && this->frequency_ <= 464000)
{
if(pa <= -30) a = PA_TABLE_433[0];
else if(pa > -30 && pa <= -20) a = PA_TABLE_433[1];
else if(pa > -20 && pa <= -15) a = PA_TABLE_433[2];
else if(pa > -15 && pa <= -10) a = PA_TABLE_433[3];
else if(pa > -10 && pa <= 0) a = PA_TABLE_433[4];
else if(pa > 0 && pa <= 5) a = PA_TABLE_433[5];
else if(pa > 5 && pa <= 7) a = PA_TABLE_433[6];
else a = PA_TABLE_433[7];
this->last_pa_ = 2;
}
else if(this->frequency_ >= 779000 && this->frequency_ < 900000)
{
if(pa <= -30) a = PA_TABLE_868[0];
else if(pa > -30 && pa <= -20) a = PA_TABLE_868[1];
else if(pa > -20 && pa <= -15) a = PA_TABLE_868[2];
else if(pa > -15 && pa <= -10) a = PA_TABLE_868[3];
else if(pa > -10 && pa <= -6) a = PA_TABLE_868[4];
else if(pa > -6 && pa <= 0) a = PA_TABLE_868[5];
else if(pa > 0 && pa <= 5) a = PA_TABLE_868[6];
else if(pa > 5 && pa <= 7) a = PA_TABLE_868[7];
else if(pa > 7 && pa <= 10) a = PA_TABLE_868[8];
else a = PA_TABLE_868[9];
this->last_pa_ = 3;
}
else if(this->frequency_ >= 900000 && this->frequency_ <= 928000)
{
if(pa <= -30) a = PA_TABLE_915[0];
else if(pa > -30 && pa <= -20) a = PA_TABLE_915[1];
else if(pa > -20 && pa <= -15) a = PA_TABLE_915[2];
else if(pa > -15 && pa <= -10) a = PA_TABLE_915[3];
else if(pa > -10 && pa <= -6) a = PA_TABLE_915[4];
else if(pa > -6 && pa <= 0) a = PA_TABLE_915[5];
else if(pa > 0 && pa <= 5) a = PA_TABLE_915[6];
else if(pa > 5 && pa <= 7) a = PA_TABLE_915[7];
else if(pa > 7 && pa <= 10) a = PA_TABLE_915[8];
else a = PA_TABLE_915[9];
this->last_pa_ = 4;
}
else
{
ESP_LOGE(TAG, "CC1101 set_pa(%d) frequency out of range: %d", pa, this->frequency_);
return;
}
if(this->modulation_ == 2)
{
PA_TABLE[0] = 0;
PA_TABLE[1] = a;
}
else
{
PA_TABLE[0] = a;
PA_TABLE[1] = 0;
}
this->write_register_burst(CC1101_PATABLE, PA_TABLE, sizeof(PA_TABLE));
}
void CC1101::set_frequency(uint32_t f)
{
this->frequency_ = f;
uint8_t freq2 = 0;
uint8_t freq1 = 0;
uint8_t freq0 = 0;
float mhz = (float)f / 1000;
while(true)
{
if(mhz >= 26) { mhz -= 26; freq2++; }
else if(mhz >= 0.1015625) { mhz -= 0.1015625; freq1++; }
else if(mhz >= 0.00039675) { mhz -= 0.00039675; freq0++; }
else break;
}
/*
// TODO: impossible, freq0 being uint8_t, also 0.1015625/0.00039675 = 255.9861373660996, it would never reach 256
if(freq0 > 255)
{
freq1 += 1;
freq0 -= 256;
}
*/
this->write_register(CC1101_FREQ2, freq2);
this->write_register(CC1101_FREQ1, freq1);
this->write_register(CC1101_FREQ0, freq0);
// calibrate
mhz = (float)f / 1000;
if(mhz >= 300 && mhz <= 348)
{
this->write_register(CC1101_FSCTRL0, map(mhz, 300, 348, this->clb_[0][0], this->clb_[0][1]));
if(mhz < 322.88)
{
this->write_register(CC1101_TEST0, 0x0B);
}
else
{
this->write_register(CC1101_TEST0, 0x09);
uint8_t s = this->read_status_register(CC1101_FSCAL2);
if(s < 32)
{
this->write_register(CC1101_FSCAL2, s + 32);
}
if(this->last_pa_ != 1) this->set_pa(this->pa_);
}
}
else if(mhz >= 378 && mhz <= 464)
{
this->write_register(CC1101_FSCTRL0, map(mhz, 378, 464, this->clb_[1][0], this->clb_[1][1]));
if(mhz < 430.5)
{
this->write_register(CC1101_TEST0, 0x0B);
}
else
{
this->write_register(CC1101_TEST0, 0x09);
uint8_t s = this->read_status_register(CC1101_FSCAL2);
if(s < 32)
{
this->write_register(CC1101_FSCAL2, s + 32);
}
if(this->last_pa_ != 2) this->set_pa(this->pa_);
}
}
else if(mhz >= 779 && mhz <= 899.99)
{
this->write_register(CC1101_FSCTRL0, map(mhz, 779, 899, this->clb_[2][0], this->clb_[2][1]));
if(mhz < 861)
{
this->write_register(CC1101_TEST0, 0x0B);
}
else
{
this->write_register(CC1101_TEST0, 0x09);
uint8_t s = this->read_status_register(CC1101_FSCAL2);
if(s < 32)
{
this->write_register(CC1101_FSCAL2, s + 32);
}
if(this->last_pa_ != 3) this->set_pa(this->pa_);
}
}
else if(mhz >= 900 && mhz <= 928)
{
this->write_register(CC1101_FSCTRL0, map(mhz, 900, 928, this->clb_[3][0], this->clb_[3][1]));
this->write_register(CC1101_TEST0, 0x09);
uint8_t s = this->read_status_register(CC1101_FSCAL2);
if(s < 32)
{
this->write_register(CC1101_FSCAL2, s + 32);
}
if(this->last_pa_ != 4) this->set_pa(this->pa_);
}
}
void CC1101::set_clb(uint8_t b, uint8_t s, uint8_t e)
{
if(b < 4)
{
this->clb_[b][0] = s;
this->clb_[b][1] = e;
}
}
void CC1101::set_rxbw(uint32_t bw)
{
this->bandwidth_ = bw;
float f = (float)this->bandwidth_;
int s1 = 3;
int s2 = 3;
for(int i = 0; i < 3 && f > 101.5625f; i++)
{
f /= 2;
s1--;
}
for(int i = 0; i < 3 && f > 58.1f; i++)
{
f /= 1.25f;
s2--;
}
this->split_MDMCFG4();
this->m4RxBw_ = (s1 << 6) | (s2 << 4);
this->write_register(CC1101_MDMCFG4, this->m4RxBw_ + this->m4DaRa_);
}
void CC1101::set_tx()
{
ESP_LOGI(TAG, "CC1101 set_tx");
this->send_cmd(CC1101_SIDLE);
this->send_cmd(CC1101_STX);
this->trxstate_ = 1;
}
void CC1101::set_rx()
{
ESP_LOGI(TAG, "CC1101 set_rx");
this->send_cmd(CC1101_SIDLE);
this->send_cmd(CC1101_SRX);
this->trxstate_ = 2;
}
void CC1101::set_sres()
{
this->send_cmd(CC1101_SRES);
this->trxstate_ = 0;
}
void CC1101::set_sidle()
{
this->send_cmd(CC1101_SIDLE);
this->trxstate_ = 0;
}
void CC1101::set_sleep()
{
this->send_cmd(CC1101_SIDLE); // Exit RX / TX, turn off frequency synthesizer and exit
this->send_cmd(CC1101_SPWD); // Enter power down mode when CSn goes high.
this->trxstate_ = 0;
}
void CC1101::split_MDMCFG2()
{
uint8_t calc = this->read_status_register(CC1101_MDMCFG2);
this->m2DCOFF_ = calc & 0x80;
this->m2MODFM_ = calc & 0x70;
this->m2MANCH_ = calc & 0x08;
this->m2SYNCM_ = calc & 0x07;
}
void CC1101::split_MDMCFG4()
{
uint8_t calc = this->read_status_register(CC1101_MDMCFG4);
this->m4RxBw_ = calc & 0xf0;
this->m4DaRa_ = calc & 0x0f;
}
int32_t CC1101::get_rssi()
{
int32_t rssi;
rssi = this->read_status_register(CC1101_RSSI);
if(rssi >= 128) rssi -= 256;
return (rssi / 2) - 74;
}
uint8_t CC1101::get_lqi()
{
return this->read_status_register(CC1101_LQI);
}
void CC1101::begin_tx()
{
this->set_tx();
if(this->gdo0_ == this->gdo2_)
{
#ifdef USE_ESP8266
#ifdef USE_ARDUINO
noInterrupts();
#else // USE_ESP_IDF
portDISABLE_INTERRUPTS()
#endif
#endif
this->gdo0_->pin_mode(gpio::FLAG_OUTPUT);
}
}
void CC1101::end_tx()
{
if(this->gdo0_ == this->gdo2_)
{
#ifdef USE_ESP8266
#ifdef USE_ARDUINO
interrupts();
#else // USE_ESP_IDF
portENABLE_INTERRUPTS()
#endif
#endif
this->gdo0_->pin_mode(gpio::FLAG_INPUT);
}
this->set_rx();
this->set_rx(); // yes, twice (really?)
}
} // namespace cc1101
} // namespace esphome

View file

@ -0,0 +1,109 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/spi/spi.h"
namespace esphome {
namespace cc1101 {
class CC1101
: public sensor::Sensor,
public PollingComponent,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1KHZ>
{
protected:
InternalGPIOPin* gdo0_;
InternalGPIOPin* gdo2_;
uint32_t bandwidth_;
uint32_t frequency_;
sensor::Sensor* rssi_sensor_;
sensor::Sensor* lqi_sensor_;
uint8_t partnum_;
uint8_t version_;
int32_t last_rssi_;
int32_t last_lqi_;
bool reset();
void send_cmd(uint8_t cmd);
uint8_t read_register(uint8_t reg);
uint8_t read_config_register(uint8_t reg);
uint8_t read_status_register(uint8_t reg);
void read_register_burst(uint8_t reg, uint8_t* buffer, size_t length);
void write_register(uint8_t reg, uint8_t* value, size_t length);
void write_register(uint8_t reg, uint8_t value);
void write_register_burst(uint8_t reg, uint8_t* buffer, size_t length);
//bool send_data(const uint8_t* data, size_t length);
// ELECHOUSE_CC1101 stuff
bool mode_;
uint8_t modulation_;
uint8_t frend0_;
uint8_t chan_;
int8_t pa_;
uint8_t last_pa_;
uint8_t m4RxBw_;
uint8_t m4DaRa_;
uint8_t m2DCOFF_;
uint8_t m2MODFM_;
uint8_t m2MANCH_;
uint8_t m2SYNCM_;
uint8_t m1FEC_;
uint8_t m1PRE_;
uint8_t m1CHSP_;
uint8_t trxstate_;
uint8_t clb_[4][2];
void set_mode(bool s);
void set_frequency(uint32_t f);
void set_modulation(uint8_t m);
void set_pa(int8_t pa);
void set_clb(uint8_t b, uint8_t s, uint8_t e);
void set_rxbw(uint32_t bw);
void set_tx();
void set_rx();
void set_sres();
void set_sidle();
void set_sleep();
void split_MDMCFG2();
void split_MDMCFG4();
public:
CC1101();
void set_config_gdo0(InternalGPIOPin* pin);
void set_config_gdo2(InternalGPIOPin* pin);
void set_config_bandwidth(uint32_t bandwidth);
void set_config_frequency(uint32_t frequency);
void set_config_rssi_sensor(sensor::Sensor* rssi_sensor);
void set_config_lqi_sensor(sensor::Sensor* lqi_sensor);
void setup() override;
void update() override;
void dump_config() override;
int32_t get_rssi();
uint8_t get_lqi();
void begin_tx();
void end_tx();
};
template<typename... Ts> class BeginTxAction : public Action<Ts...>, public Parented<CC1101>
{
public:
void play(Ts... x) override { this->parent_->begin_tx(); }
};
template<typename... Ts> class EndTxAction : public Action<Ts...>, public Parented<CC1101>
{
public:
void play(Ts... x) override { this->parent_->end_tx(); }
};
} // namespace cc1101
} // namespace esphome

View file

@ -0,0 +1,110 @@
#pragma once
// Datasheet: https://www.ti.com/lit/ds/symlink/cc1101.pdf
namespace esphome {
namespace cc1101 {
//***************************************CC1101 define**************************************************//
// CC1101 CONFIG REGSITER
static const uint32_t CC1101_IOCFG2 = 0x00; // GDO2 output pin configuration
static const uint32_t CC1101_IOCFG1 = 0x01; // GDO1 output pin configuration
static const uint32_t CC1101_IOCFG0 = 0x02; // GDO0 output pin configuration
static const uint32_t CC1101_FIFOTHR = 0x03; // RX FIFO and TX FIFO thresholds
static const uint32_t CC1101_SYNC1 = 0x04; // Sync word, high INT8U
static const uint32_t CC1101_SYNC0 = 0x05; // Sync word, low INT8U
static const uint32_t CC1101_PKTLEN = 0x06; // Packet length
static const uint32_t CC1101_PKTCTRL1 = 0x07; // Packet automation control
static const uint32_t CC1101_PKTCTRL0 = 0x08; // Packet automation control
static const uint32_t CC1101_ADDR = 0x09; // Device address
static const uint32_t CC1101_CHANNR = 0x0A; // Channel number
static const uint32_t CC1101_FSCTRL1 = 0x0B; // Frequency synthesizer control
static const uint32_t CC1101_FSCTRL0 = 0x0C; // Frequency synthesizer control
static const uint32_t CC1101_FREQ2 = 0x0D; // Frequency control word, high INT8U
static const uint32_t CC1101_FREQ1 = 0x0E; // Frequency control word, middle INT8U
static const uint32_t CC1101_FREQ0 = 0x0F; // Frequency control word, low INT8U
static const uint32_t CC1101_MDMCFG4 = 0x10; // Modem configuration
static const uint32_t CC1101_MDMCFG3 = 0x11; // Modem configuration
static const uint32_t CC1101_MDMCFG2 = 0x12; // Modem configuration
static const uint32_t CC1101_MDMCFG1 = 0x13; // Modem configuration
static const uint32_t CC1101_MDMCFG0 = 0x14; // Modem configuration
static const uint32_t CC1101_DEVIATN = 0x15; // Modem deviation setting
static const uint32_t CC1101_MCSM2 = 0x16; // Main Radio Control State Machine configuration
static const uint32_t CC1101_MCSM1 = 0x17; // Main Radio Control State Machine configuration
static const uint32_t CC1101_MCSM0 = 0x18; // Main Radio Control State Machine configuration
static const uint32_t CC1101_FOCCFG = 0x19; // Frequency Offset Compensation configuration
static const uint32_t CC1101_BSCFG = 0x1A; // Bit Synchronization configuration
static const uint32_t CC1101_AGCCTRL2 = 0x1B; // AGC control
static const uint32_t CC1101_AGCCTRL1 = 0x1C; // AGC control
static const uint32_t CC1101_AGCCTRL0 = 0x1D; // AGC control
static const uint32_t CC1101_WOREVT1 = 0x1E; // High INT8U Event 0 timeout
static const uint32_t CC1101_WOREVT0 = 0x1F; // Low INT8U Event 0 timeout
static const uint32_t CC1101_WORCTRL = 0x20; // Wake On Radio control
static const uint32_t CC1101_FREND1 = 0x21; // Front end RX configuration
static const uint32_t CC1101_FREND0 = 0x22; // Front end TX configuration
static const uint32_t CC1101_FSCAL3 = 0x23; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL2 = 0x24; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL1 = 0x25; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL0 = 0x26; // Frequency synthesizer calibration
static const uint32_t CC1101_RCCTRL1 = 0x27; // RC oscillator configuration
static const uint32_t CC1101_RCCTRL0 = 0x28; // RC oscillator configuration
static const uint32_t CC1101_FSTEST = 0x29; // Frequency synthesizer calibration control
static const uint32_t CC1101_PTEST = 0x2A; // Production test
static const uint32_t CC1101_AGCTEST = 0x2B; // AGC test
static const uint32_t CC1101_TEST2 = 0x2C; // Various test settings
static const uint32_t CC1101_TEST1 = 0x2D; // Various test settings
static const uint32_t CC1101_TEST0 = 0x2E; // Various test settings
//CC1101 Strobe commands
static const uint32_t CC1101_SRES = 0x30; // Reset chip.
static const uint32_t CC1101_SFSTXON = 0x31; // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
// If in RX/TX: Go to a wait state where only the synthesizer is
// running (for quick RX / TX turnaround).
static const uint32_t CC1101_SXOFF = 0x32; // Turn off crystal oscillator.
static const uint32_t CC1101_SCAL = 0x33; // Calibrate frequency synthesizer and turn it off
// (enables quick start).
static const uint32_t CC1101_SRX = 0x34; // Enable RX. Perform calibration first if coming from IDLE and
// MCSM0.FS_AUTOCAL=1.
static const uint32_t CC1101_STX = 0x35; // In IDLE state: Enable TX. Perform calibration first if
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
// Only go to TX if channel is clear.
static const uint32_t CC1101_SIDLE = 0x36; // Exit RX / TX, turn off frequency synthesizer and exit
// Wake-On-Radio mode if applicable.
static const uint32_t CC1101_SAFC = 0x37; // Perform AFC adjustment of the frequency synthesizer
static const uint32_t CC1101_SWOR = 0x38; // Start automatic RX polling sequence (Wake-on-Radio)
static const uint32_t CC1101_SPWD = 0x39; // Enter power down mode when CSn goes high.
static const uint32_t CC1101_SFRX = 0x3A; // Flush the RX FIFO buffer.
static const uint32_t CC1101_SFTX = 0x3B; // Flush the TX FIFO buffer.
static const uint32_t CC1101_SWORRST = 0x3C; // Reset real time clock.
static const uint32_t CC1101_SNOP = 0x3D; // No operation. May be used to pad strobe commands to two
// INT8Us for simpler software.
//CC1101 STATUS REGSITER
static const uint32_t CC1101_PARTNUM = 0x30;
static const uint32_t CC1101_VERSION = 0x31;
static const uint32_t CC1101_FREQEST = 0x32;
static const uint32_t CC1101_LQI = 0x33;
static const uint32_t CC1101_RSSI = 0x34;
static const uint32_t CC1101_MARCSTATE = 0x35;
static const uint32_t CC1101_WORTIME1 = 0x36;
static const uint32_t CC1101_WORTIME0 = 0x37;
static const uint32_t CC1101_PKTSTATUS = 0x38;
static const uint32_t CC1101_VCO_VC_DAC = 0x39;
static const uint32_t CC1101_TXBYTES = 0x3A;
static const uint32_t CC1101_RXBYTES = 0x3B;
//CC1101 PATABLE,TXFIFO,RXFIFO
static const uint32_t CC1101_PATABLE = 0x3E;
static const uint32_t CC1101_TXFIFO = 0x3F;
static const uint32_t CC1101_RXFIFO = 0x3F;
static const uint32_t CC1101_WRITE_BURST = 0x40; // write burst
static const uint32_t CC1101_READ_SINGLE = 0x80; // read single
static const uint32_t CC1101_READ_BURST = 0xC0; // read burst
static const uint32_t CC1101_BYTES_IN_RXFIFO = 0x7F; // byte number in RXfifo
static const uint32_t CC1101_MARCSTATE_TX = 0x13;
static const uint32_t CC1101_MARCSTATE_TX_END = 0x14;
static const uint32_t CC1101_MARCSTATE_RXTX_SWITCH = 0x15;
}
}

View file

@ -0,0 +1,89 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation, pins
from esphome.components import sensor
from esphome.components import spi
from esphome.automation import maybe_simple_id
from esphome.const import (
CONF_ID,
UNIT_EMPTY,
UNIT_DECIBEL_MILLIWATT,
DEVICE_CLASS_SIGNAL_STRENGTH,
STATE_CLASS_MEASUREMENT
)
CODEOWNERS = ["@gabest11", "@dbuezas", "@nistvan86", "@LSatan"]
DEPENDENCIES = ["spi"]
CONF_GDO0 = "gdo0"
CONF_GDO2 = "gdo2"
CONF_BANDWIDTH = "bandwidth"
CONF_FREQUENCY = "frequency"
CONF_RSSI = "rssi"
CONF_LQI = "lqi"
cc1101_ns = cg.esphome_ns.namespace("cc1101")
CC1101 = cc1101_ns.class_("CC1101", sensor.Sensor, cg.PollingComponent, spi.SPIDevice)
BeginTxAction = cc1101_ns.class_("BeginTxAction", automation.Action)
EndTxAction = cc1101_ns.class_("EndTxAction", automation.Action)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(CC1101),
cv.Required(CONF_GDO0): pins.gpio_output_pin_schema,
cv.Optional(CONF_GDO2): pins.gpio_input_pin_schema,
cv.Optional(CONF_BANDWIDTH, default=200): cv.uint32_t,
cv.Optional(CONF_FREQUENCY, default=433920): cv.uint32_t,
cv.Optional(CONF_RSSI): sensor.sensor_schema(
unit_of_measurement = UNIT_DECIBEL_MILLIWATT,
accuracy_decimals = 0,
device_class = DEVICE_CLASS_SIGNAL_STRENGTH,
state_class = STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_LQI): sensor.sensor_schema(
unit_of_measurement = UNIT_EMPTY,
accuracy_decimals = 0,
state_class = STATE_CLASS_MEASUREMENT,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(spi.spi_device_schema(cs_pin_required=True))
)
CC1101_ACTION_SCHEMA = maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(CC1101),
}
)
@automation.register_action("cc1101.begin_tx", BeginTxAction, CC1101_ACTION_SCHEMA)
@automation.register_action("cc1101.end_tx", EndTxAction, CC1101_ACTION_SCHEMA)
async def cc1101_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
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)
gdo0 = await cg.gpio_pin_expression(config[CONF_GDO0])
cg.add(var.set_config_gdo0(gdo0))
if CONF_GDO2 in config:
gdo2 = await cg.gpio_pin_expression(config[CONF_GDO2])
cg.add(var.set_config_gdo2(gdo2))
cg.add(var.set_config_bandwidth(config[CONF_BANDWIDTH]))
cg.add(var.set_config_frequency(config[CONF_FREQUENCY]))
if CONF_RSSI in config:
rssi = await sensor.new_sensor(config[CONF_RSSI])
cg.add(var.set_config_rssi_sensor(rssi))
if CONF_LQI in config:
lqi = await sensor.new_sensor(config[CONF_LQI])
cg.add(var.set_config_lqi_sensor(lqi))