mirror of
https://github.com/esphome/esphome.git
synced 2024-11-24 07:58:09 +01:00
si4713 wip
This commit is contained in:
parent
8033ef48a8
commit
b695d1e804
9 changed files with 677 additions and 522 deletions
27
esphome/components/si4713_i2c/output/__init__.py
Normal file
27
esphome/components/si4713_i2c/output/__init__.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import output
|
||||||
|
from esphome.const import CONF_ID, CONF_PIN
|
||||||
|
from .. import (
|
||||||
|
CONF_SI4713_ID,
|
||||||
|
Si4713Component,
|
||||||
|
si4713_ns,
|
||||||
|
)
|
||||||
|
|
||||||
|
BinaryOutput = si4713_ns.class_("BinaryOutput", output.BinaryOutput, cg.Component)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = output.BINARY_OUTPUT_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(BinaryOutput),
|
||||||
|
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
|
||||||
|
cv.Required(CONF_PIN): cv.int_range(min=1, max=3),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await output.register_output(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await cg.register_parented(var, config[CONF_SI4713_ID])
|
||||||
|
cg.add(var.set_pin(config[CONF_PIN]))
|
25
esphome/components/si4713_i2c/output/binary_output.cpp
Normal file
25
esphome/components/si4713_i2c/output/binary_output.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "binary_output.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
static const char *const TAG = "si4713";
|
||||||
|
|
||||||
|
void BinaryOutput::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Si4713 Output:");
|
||||||
|
LOG_BINARY_OUTPUT(this);
|
||||||
|
ESP_LOGCONFIG(TAG, " Pin: %d", this->pin_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713BinaryOutput::write_state(bool state) {
|
||||||
|
this->parent_->set_gpio(this->pin_, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
23
esphome/components/si4713_i2c/output/binary_output.h
Normal file
23
esphome/components/si4713_i2c/output/binary_output.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/output/binary_output.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class BinaryOutput : public output::BinaryOutput, public Component, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
void set_pin(uint8_t pin) { this->pin_ = pin - 1; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
|
||||||
|
uint8_t pin_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
|
@ -15,6 +15,7 @@ static const char *const TAG = "si4713";
|
||||||
Si4713Component::Si4713Component() {
|
Si4713Component::Si4713Component() {
|
||||||
this->reset_pin_ = nullptr;
|
this->reset_pin_ = nullptr;
|
||||||
this->reset_ = false;
|
this->reset_ = false;
|
||||||
|
memset(this->gpio_, 0, sizeof(gpio_));
|
||||||
// memset(&this->state_, 0, sizeof(this->state_));
|
// memset(&this->state_, 0, sizeof(this->state_));
|
||||||
this->rds_station_pos_ = 0;
|
this->rds_station_pos_ = 0;
|
||||||
this->rds_text_pos_ = 0;
|
this->rds_text_pos_ = 0;
|
||||||
|
@ -22,45 +23,7 @@ Si4713Component::Si4713Component() {
|
||||||
// our defaults
|
// our defaults
|
||||||
// this->state_. = ; // start with tx enabled
|
// this->state_. = ; // start with tx enabled
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
void Si4713Component::write_reg_(uint8_t addr) {
|
|
||||||
switch (addr) {
|
|
||||||
case 0x00: // REG_..
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGE(TAG, "write_reg_(0x%02X) invalid register address", addr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->reset_) {
|
|
||||||
uint8_t value = this->regs_[addr];
|
|
||||||
ESP_LOGV(TAG, "write_reg_(0x%02X) = 0x%02X", addr, value);
|
|
||||||
this->write_byte(addr, value);
|
|
||||||
} else {
|
|
||||||
if (this->get_component_state() & COMPONENT_STATE_LOOP) {
|
|
||||||
ESP_LOGE(TAG, "write_reg_(0x%02X) device was not reset", addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Si4713Component::read_reg_(uint8_t addr) {
|
|
||||||
switch (addr) {
|
|
||||||
case 0x00: // REG_..
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGE(TAG, "read_reg_(0x%02X) trying to read invalid register", addr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto b = this->read_byte(addr)) {
|
|
||||||
this->regs_[addr] = *b;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGE(TAG, "read_reg_(0x%02X) cannot read register", addr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size) {
|
bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size) {
|
||||||
const uint8_t *buff = (const uint8_t *) cmd;
|
const uint8_t *buff = (const uint8_t *) cmd;
|
||||||
|
|
||||||
|
@ -74,7 +37,7 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size
|
||||||
i2c::ErrorCode err = this->write(buff, cmd_size);
|
i2c::ErrorCode err = this->write(buff, cmd_size);
|
||||||
if (err != i2c::ERROR_OK) {
|
if (err != i2c::ERROR_OK) {
|
||||||
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) write error", buff[0], cmd_size);
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) write error", buff[0], cmd_size);
|
||||||
this->mark_failed();
|
// this->mark_failed();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +46,7 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size
|
||||||
err = this->read(&status, 1); // TODO: read res_size into res here?
|
err = this->read(&status, 1); // TODO: read res_size into res here?
|
||||||
if (err != i2c::ERROR_OK) {
|
if (err != i2c::ERROR_OK) {
|
||||||
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read status error", buff[0], cmd_size);
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read status error", buff[0], cmd_size);
|
||||||
this->mark_failed();
|
// this->mark_failed();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +56,7 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size
|
||||||
err = this->read((uint8_t *) res, res_size);
|
err = this->read((uint8_t *) res, res_size);
|
||||||
if (err != i2c::ERROR_OK) {
|
if (err != i2c::ERROR_OK) {
|
||||||
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read response error", buff[0], cmd_size);
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read response error", buff[0], cmd_size);
|
||||||
this->mark_failed();
|
// this->mark_failed();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,112 +64,131 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Si4713Component::power_up() {
|
|
||||||
// Note: In FMTX component 1.0 and 2.0, a reset is required when the system controller writes a command other than
|
|
||||||
// POWER_UP when in powerdown mode
|
|
||||||
this->reset_pin_->digital_write(true);
|
|
||||||
delay_microseconds_safe(10);
|
|
||||||
this->reset_pin_->digital_write(false);
|
|
||||||
delay_microseconds_safe(10);
|
|
||||||
this->reset_pin_->digital_write(true);
|
|
||||||
|
|
||||||
CmdPowerUp cmd;
|
|
||||||
cmd.FUNC = 2;
|
|
||||||
cmd.XOSCEN = 1; // TODO: external oscillator
|
|
||||||
cmd.OPMODE = 0x50; // TODO: digital
|
|
||||||
cmd.GPO2OEN = 0; // TODO: GPIO2 enable
|
|
||||||
return this->send_cmd(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Si4713Component::power_down() { return this->send_cmd(CmdPowerDown()); }
|
|
||||||
|
|
||||||
bool Si4713Component::detect_chip_id() {
|
|
||||||
ResGetRev res;
|
|
||||||
if (!this->send_cmd(CmdGetRev(), res)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buff[32] = {0};
|
|
||||||
snprintf(buff, sizeof(buff), "Si47%02d Rev %d", res.PN, res.CHIPREV);
|
|
||||||
this->chip_id_ = buff;
|
|
||||||
|
|
||||||
// TODO: support all transmitters 10/11/12/13/20/21
|
|
||||||
|
|
||||||
if (res.PN != 10 && res.PN != 11 && res.PN != 12 && res.PN != 13) {
|
|
||||||
ESP_LOGE(TAG, "Si47%02d is not supported", res.PN);
|
|
||||||
this->mark_failed();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Si4713Component::tune_power(uint8_t power, uint8_t antcap) {
|
|
||||||
if (!this->send_cmd(CmdTxTunePower(power, antcap))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this->tune_ready();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Si4713Component::tune_freq(uint16_t freq) {
|
|
||||||
if (!this->send_cmd(CmdTxTuneFreq(freq))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this->tune_ready();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Si4713Component::tune_ready() {
|
|
||||||
ResGetIntStatus res;
|
|
||||||
while (res.CTS != 1 || res.STCINT != 1) {
|
|
||||||
if (!this->send_cmd(CmdGetIntStatus(), res)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Si4713Component::rds_update_() {}
|
void Si4713Component::rds_update_() {}
|
||||||
|
|
||||||
// overrides
|
// overrides
|
||||||
|
|
||||||
void Si4713Component::setup() {
|
void Si4713Component::setup() {
|
||||||
if (this->reset_pin_ == nullptr) {
|
// CHIP STATE: POWER DOWN
|
||||||
ESP_LOGE(TAG, "setup cannot reset device, reset pin is not set");
|
|
||||||
|
if (!this->power_up()) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset
|
|
||||||
|
|
||||||
this->reset_ = true;
|
|
||||||
this->reset_pin_->setup();
|
|
||||||
|
|
||||||
if (!this->power_up()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->detect_chip_id()) {
|
if (!this->detect_chip_id()) {
|
||||||
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHIP STATE: POWER UP
|
||||||
|
|
||||||
|
uint16_t pilot = 1;
|
||||||
|
uint16_t stereo = 1;
|
||||||
|
uint16_t rds = 0;
|
||||||
|
uint16_t fmpe = 1;
|
||||||
|
uint16_t acen = 0;
|
||||||
|
uint16_t limiter = 1;
|
||||||
|
uint16_t digital = 0;
|
||||||
|
|
||||||
|
// Use GPO?
|
||||||
|
|
||||||
|
// Set RCLK settings
|
||||||
this->set_prop(PropRefClkFreq(32768));
|
this->set_prop(PropRefClkFreq(32768));
|
||||||
this->set_prop(PropTxPreEmphasis());
|
this->set_prop(PropRefClkPreScale(1, 0)); // div1, RCLK source
|
||||||
/*
|
|
||||||
// configuration! see page 254
|
|
||||||
setProperty(SI4713_PROP_REFCLK_FREQ, 32768); // crystal is 32.768
|
|
||||||
setProperty(SI4713_PROP_TX_PREEMPHASIS, 0); // 74uS pre-emph (USA std)
|
|
||||||
setProperty(SI4713_PROP_TX_ACOMP_GAIN, 10); // max gain?
|
|
||||||
// setProperty(SI4713_PROP_TX_ACOMP_ENABLE, 0x02); // turn on limiter, but no
|
|
||||||
// dynamic ranging
|
|
||||||
setProperty(SI4713_PROP_TX_ACOMP_ENABLE, 0x0); // turn on limiter and AGC
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: set properties
|
// Mono/Stereo?
|
||||||
|
this->set_prop(PropTxPilotFrequency(19000));
|
||||||
|
this->set_prop(PropTxPilotDeviation(675));
|
||||||
|
this->set_prop(PropTxComponentEnable(pilot, stereo, rds));
|
||||||
|
|
||||||
|
// Set Audio Deviation
|
||||||
|
this->set_prop(PropTxAudioDeviation(6825));
|
||||||
|
|
||||||
|
// Transmit RDS?
|
||||||
|
// this->set_prop(PropTxRdsDeviation(200));
|
||||||
|
// if(rds) PropTxRds*
|
||||||
|
// if(rds) CmdTxRdsPs
|
||||||
|
// if(rds) CmdTxRdsBuff
|
||||||
|
|
||||||
|
// Preemphasis?
|
||||||
|
this->set_prop(PropTxPreEmphasis(fmpe));
|
||||||
|
this->set_prop(PropTxAcompEnable(acen, limiter));
|
||||||
|
|
||||||
|
// Compressor?
|
||||||
|
if (acen) {
|
||||||
|
// minimal compression
|
||||||
|
this->set_prop(PropTxAcompThreshold(-40)); // -40dBFS
|
||||||
|
this->set_prop(PropTxAcompAttackTime(0)); // 5ms
|
||||||
|
this->set_prop(PropTxAcompReleaseTime(0)); // 100ms
|
||||||
|
this->set_prop(PropTxAcompGain(15)); // 15dB
|
||||||
|
// aggressive compression
|
||||||
|
// this->set_prop(PropTxAcompThreshold(-15)); // -15dBFS
|
||||||
|
// this->set_prop(PropTxAcompAttackTime(9)); // 0.5ms
|
||||||
|
// this->set_prop(PropTxAcompReleaseTime(4)); // 1000ms
|
||||||
|
// this->set_prop(PropTxAcompGain(5)); // 5dB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limiter?
|
||||||
|
if (limiter) {
|
||||||
|
this->set_prop(PropTxLimiterReleaseTime(102)); // 5.01 ms
|
||||||
|
}
|
||||||
|
|
||||||
this->tune_power(115);
|
|
||||||
this->tune_freq(8750);
|
this->tune_freq(8750);
|
||||||
|
this->tune_power(115);
|
||||||
|
|
||||||
//
|
// CHIP STATE: TRANSMITTING
|
||||||
|
|
||||||
|
if (digital) {
|
||||||
|
// Digital Audio Input?
|
||||||
|
this->set_prop(PropDigitalInputFormat(0, 0, 1, 0)); // 16-bit, stereo, I2S mode, rising edge
|
||||||
|
this->set_prop(PropDigitalInputSampleRate(44100));
|
||||||
|
} else {
|
||||||
|
// Analog Audio Input?
|
||||||
|
this->set_prop(PropTxLineInputLevel(636, 3)); // 636 mvPK, 60 kOhm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mute?
|
||||||
|
this->set_prop(PropTxLineInputMute(0, 0)); // left no mute, right no mute
|
||||||
|
// Optional: Mute or Unmute Audio based on ASQ status
|
||||||
|
|
||||||
|
// Enable GPIO1, GPIO2
|
||||||
|
// TOOD:
|
||||||
|
// output:
|
||||||
|
// - platform: si4713
|
||||||
|
// pin: 1/2
|
||||||
|
// ...
|
||||||
|
this->send_cmd(CmdGpioCtl(1, 1));
|
||||||
|
/*
|
||||||
|
this->set_interval(3000, [this]() {
|
||||||
|
static uint8_t gpio1 = 0, gpio2 = 0;
|
||||||
|
this->send_cmd(CmdGpioSet(gpio1++ & 1, gpio2++ & 1));
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
this->set_interval(3000, [this]() {
|
||||||
|
ResTxTuneStatus res;
|
||||||
|
if (this->send_cmd(CmdTxTuneStatus(), res)) {
|
||||||
|
ESP_LOGD(TAG, "ResTxTuneStatus FREQ %d RFdBuV %d ANTCAP %d NL %d", (res.READFREQH << 8) | res.READFREQL,
|
||||||
|
res.READRFdBuV, res.READANTCAP, res.RNL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Monitor Audio Signal Quality (ASQ)?
|
||||||
|
// TODO: PropTxAsqInterruptSource
|
||||||
|
// TODO: PropTxAsqLevelLow
|
||||||
|
// TODO: PropTxAsqDurationLow
|
||||||
|
// TODO: PropTxAsqLevelHigh
|
||||||
|
// TODO: PropTxAsqDurationHigh
|
||||||
|
|
||||||
|
this->set_interval(3000, [this]() {
|
||||||
|
ResTxAsqStatus res;
|
||||||
|
if (this->send_cmd(CmdTxAsqStatus(), res)) {
|
||||||
|
ESP_LOGD(TAG, "ResTxAsqStatus OVERMOD %d IALH %d IALL %d INLEVEL %d", res.OVERMOD, res.IALH, res.IALL,
|
||||||
|
res.INLEVEL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
this->publish_frequency();
|
this->publish_frequency();
|
||||||
this->publish_mute();
|
this->publish_mute();
|
||||||
|
@ -214,6 +196,9 @@ void Si4713Component::setup() {
|
||||||
this->publish_rds_enable();
|
this->publish_rds_enable();
|
||||||
this->publish_rds_station();
|
this->publish_rds_station();
|
||||||
this->publish_rds_text();
|
this->publish_rds_text();
|
||||||
|
this->publish_gpio(0);
|
||||||
|
this->publish_gpio(1);
|
||||||
|
this->publish_gpio(2);
|
||||||
|
|
||||||
this->set_interval(1000, [this]() { this->rds_update_(); });
|
this->set_interval(1000, [this]() { this->rds_update_(); });
|
||||||
}
|
}
|
||||||
|
@ -244,6 +229,94 @@ void Si4713Component::update() {
|
||||||
|
|
||||||
void Si4713Component::loop() {}
|
void Si4713Component::loop() {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool Si4713Component::reset() {
|
||||||
|
if (this->reset_pin_ == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "cannot reset device, reset pin is not set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->reset_) {
|
||||||
|
this->reset_pin_->setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->reset_pin_->digital_write(true);
|
||||||
|
delay_microseconds_safe(10);
|
||||||
|
this->reset_pin_->digital_write(false);
|
||||||
|
delay_microseconds_safe(10);
|
||||||
|
this->reset_pin_->digital_write(true);
|
||||||
|
|
||||||
|
this->reset_ = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::power_up() {
|
||||||
|
// Note: In FMTX component 1.0 and 2.0, a reset is required when the system
|
||||||
|
// controller writes a command other than POWER_UP when in powerdown mode
|
||||||
|
this->reset();
|
||||||
|
|
||||||
|
CmdPowerUp cmd;
|
||||||
|
cmd.FUNC = 2;
|
||||||
|
cmd.XOSCEN = 1; // TODO: external oscillator
|
||||||
|
cmd.OPMODE = 0x50; // TODO: digital
|
||||||
|
cmd.GPO2OEN = 0; // TODO: GPIO2 enable
|
||||||
|
return this->send_cmd(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::power_down() { return this->send_cmd(CmdPowerDown()); }
|
||||||
|
|
||||||
|
bool Si4713Component::detect_chip_id() {
|
||||||
|
ResGetRev res;
|
||||||
|
if (!this->send_cmd(CmdGetRev(), res)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buff[32] = {0};
|
||||||
|
snprintf(buff, sizeof(buff), "Si47%02d Rev %d", res.PN, res.CHIPREV);
|
||||||
|
this->chip_id_ = buff;
|
||||||
|
|
||||||
|
// TODO: support all transmitters 10/11/12/13/20/21
|
||||||
|
|
||||||
|
if (res.PN != 10 && res.PN != 11 && res.PN != 12 && res.PN != 13) {
|
||||||
|
ESP_LOGE(TAG, "Si47%02d is not supported", res.PN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::tune_freq(uint16_t freq) {
|
||||||
|
if (!this->send_cmd(CmdTxTuneFreq(freq))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this->tune_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::tune_power(uint8_t power, uint8_t antcap) {
|
||||||
|
if (!this->send_cmd(CmdTxTunePower(power, antcap))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this->tune_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::tune_wait() {
|
||||||
|
ResGetIntStatus res;
|
||||||
|
while (res.CTS != 1 || res.STCINT != 1) {
|
||||||
|
if (!this->send_cmd(CmdGetIntStatus(), res)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResTxTuneStatus res2; // TODO: maybe store this as the last tune result and report it through sensors
|
||||||
|
if (!this->send_cmd(CmdTxTuneStatus(), res2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// config
|
// config
|
||||||
|
|
||||||
void Si4713Component::set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; }
|
void Si4713Component::set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; }
|
||||||
|
@ -326,6 +399,26 @@ void Si4713Component::set_rds_text(const std::string &value) {
|
||||||
this->publish_rds_text();
|
this->publish_rds_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Si4713Component::set_gpio(uint8_t pin, bool value) {
|
||||||
|
if (pin > 2) {
|
||||||
|
ESP_LOGE(TAG, "set_gpio(%d, %d) invalid pin number, 0 to 2", pin, value ? 1 : 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "set_gpio(%d, %d)", pin, value ? 1 : 0);
|
||||||
|
this->gpio_[pin] = value ? 1 : 0;
|
||||||
|
this->send_cmd(CmdGpioCtl(this->gpio_[0], this->gpio_[1], this->gpio_[2]));
|
||||||
|
|
||||||
|
this->publish_gpio(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::get_gpio(uint8_t pin) {
|
||||||
|
if (pin > 2) {
|
||||||
|
ESP_LOGE(TAG, "get_gpio(%d) invalid pin number, 0 to 2", pin);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this->gpio_[pin];
|
||||||
|
}
|
||||||
|
|
||||||
// publish
|
// publish
|
||||||
|
|
||||||
void Si4713Component::publish_() {
|
void Si4713Component::publish_() {
|
||||||
|
@ -346,6 +439,22 @@ void Si4713Component::publish_rds_station() { this->publish(this->rds_station_te
|
||||||
|
|
||||||
void Si4713Component::publish_rds_text() { this->publish(this->rds_text_text_, this->rds_text_); }
|
void Si4713Component::publish_rds_text() { this->publish(this->rds_text_text_, this->rds_text_); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_gpio(uint8_t pin) {
|
||||||
|
switch (pin) {
|
||||||
|
case 0:
|
||||||
|
this->publish(this->gpio1_switch_, this->gpio_[pin]);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this->publish(this->gpio2_switch_, this->gpio_[pin]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this->publish(this->gpio3_switch_, this->gpio_[pin]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Si4713Component::publish(text_sensor::TextSensor *s, const std::string &state) {
|
void Si4713Component::publish(text_sensor::TextSensor *s, const std::string &state) {
|
||||||
if (s != nullptr) {
|
if (s != nullptr) {
|
||||||
if (!s->has_state() || s->state != state) {
|
if (!s->has_state() || s->state != state) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
std::string chip_id_;
|
std::string chip_id_;
|
||||||
InternalGPIOPin *reset_pin_;
|
InternalGPIOPin *reset_pin_;
|
||||||
bool reset_;
|
bool reset_;
|
||||||
|
bool gpio_[3];
|
||||||
/*
|
/*
|
||||||
union {
|
union {
|
||||||
struct Si4713State state_;
|
struct Si4713State state_;
|
||||||
|
@ -63,13 +64,6 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool power_up();
|
|
||||||
bool power_down();
|
|
||||||
bool detect_chip_id();
|
|
||||||
bool tune_power(uint8_t power = 0, uint8_t antcap = 0);
|
|
||||||
bool tune_freq(uint16_t freq);
|
|
||||||
bool tune_ready();
|
|
||||||
|
|
||||||
std::string rds_station_;
|
std::string rds_station_;
|
||||||
std::string rds_text_;
|
std::string rds_text_;
|
||||||
uint8_t rds_station_pos_;
|
uint8_t rds_station_pos_;
|
||||||
|
@ -87,7 +81,9 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
SUB_SWITCH(rds_enable)
|
SUB_SWITCH(rds_enable)
|
||||||
SUB_TEXT(rds_station)
|
SUB_TEXT(rds_station)
|
||||||
SUB_TEXT(rds_text)
|
SUB_TEXT(rds_text)
|
||||||
// TODO: GPIO switches
|
SUB_SWITCH(gpio1)
|
||||||
|
SUB_SWITCH(gpio2)
|
||||||
|
SUB_SWITCH(gpio3)
|
||||||
|
|
||||||
void publish_();
|
void publish_();
|
||||||
void publish_chip_id();
|
void publish_chip_id();
|
||||||
|
@ -97,6 +93,7 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
void publish_rds_enable();
|
void publish_rds_enable();
|
||||||
void publish_rds_station();
|
void publish_rds_station();
|
||||||
void publish_rds_text();
|
void publish_rds_text();
|
||||||
|
void publish_gpio(uint8_t pin);
|
||||||
void publish(sensor::Sensor *s, float state);
|
void publish(sensor::Sensor *s, float state);
|
||||||
void publish(text_sensor::TextSensor *s, const std::string &state);
|
void publish(text_sensor::TextSensor *s, const std::string &state);
|
||||||
void publish(number::Number *n, float state);
|
void publish(number::Number *n, float state);
|
||||||
|
@ -113,6 +110,14 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
void update() override;
|
void update() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
|
bool reset();
|
||||||
|
bool power_up();
|
||||||
|
bool power_down();
|
||||||
|
bool detect_chip_id();
|
||||||
|
bool tune_freq(uint16_t freq);
|
||||||
|
bool tune_power(uint8_t power = 0, uint8_t antcap = 0);
|
||||||
|
bool tune_wait();
|
||||||
|
|
||||||
void set_reset_pin(InternalGPIOPin *pin);
|
void set_reset_pin(InternalGPIOPin *pin);
|
||||||
void set_frequency(float value);
|
void set_frequency(float value);
|
||||||
float get_frequency();
|
float get_frequency();
|
||||||
|
@ -124,6 +129,8 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
bool get_rds_enable();
|
bool get_rds_enable();
|
||||||
void set_rds_station(const std::string &value);
|
void set_rds_station(const std::string &value);
|
||||||
void set_rds_text(const std::string &value);
|
void set_rds_text(const std::string &value);
|
||||||
|
void set_gpio(uint8_t pin, bool value);
|
||||||
|
bool get_gpio(uint8_t pin);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace si4713
|
} // namespace si4713
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,9 +18,14 @@ from .. import (
|
||||||
ICON_FORMAT_TEXT,
|
ICON_FORMAT_TEXT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
CONF_GPIO1="gpio1"
|
||||||
|
CONF_GPIO2="gpio2"
|
||||||
|
CONF_GPIO3="gpio3"
|
||||||
|
|
||||||
MuteSwitch = si4713_ns.class_("MuteSwitch", switch.Switch)
|
MuteSwitch = si4713_ns.class_("MuteSwitch", switch.Switch)
|
||||||
MonoSwitch = si4713_ns.class_("MonoSwitch", switch.Switch)
|
MonoSwitch = si4713_ns.class_("MonoSwitch", switch.Switch)
|
||||||
RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch)
|
RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch)
|
||||||
|
GPIOSwitch = si4713_ns.class_("GPIOSwitch", switch.Switch)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
|
@ -43,6 +48,24 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
icon=ICON_FORMAT_TEXT,
|
icon=ICON_FORMAT_TEXT,
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_GPIO1): switch.switch_schema(
|
||||||
|
GPIOSwitch,
|
||||||
|
device_class=DEVICE_CLASS_SWITCH,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
# icon=,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GPIO2): switch.switch_schema(
|
||||||
|
GPIOSwitch,
|
||||||
|
device_class=DEVICE_CLASS_SWITCH,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
# icon=,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GPIO3): switch.switch_schema(
|
||||||
|
GPIOSwitch,
|
||||||
|
device_class=DEVICE_CLASS_SWITCH,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
# icon=,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,6 +75,7 @@ async def new_switch(config, id, setter):
|
||||||
s = await switch.new_switch(c)
|
s = await switch.new_switch(c)
|
||||||
await cg.register_parented(s, config[CONF_SI4713_ID])
|
await cg.register_parented(s, config[CONF_SI4713_ID])
|
||||||
cg.add(setter(s))
|
cg.add(setter(s))
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
|
@ -59,3 +83,9 @@ async def to_code(config):
|
||||||
await new_switch(config, CONF_MUTE, c.set_mute_switch)
|
await new_switch(config, CONF_MUTE, c.set_mute_switch)
|
||||||
await new_switch(config, CONF_MONO, c.set_mono_switch)
|
await new_switch(config, CONF_MONO, c.set_mono_switch)
|
||||||
await new_switch(config, CONF_RDS_ENABLE, c.set_rds_enable_switch)
|
await new_switch(config, CONF_RDS_ENABLE, c.set_rds_enable_switch)
|
||||||
|
s = await new_switch(config, CONF_GPIO1, c.set_gpio1_switch)
|
||||||
|
s.set_pin(1)
|
||||||
|
s = await new_switch(config, CONF_GPIO2, c.set_gpio2_switch)
|
||||||
|
s.set_pin(2)
|
||||||
|
s = await new_switch(config, CONF_GPIO3, c.set_gpio3_switch)
|
||||||
|
s.set_pin(3)
|
||||||
|
|
12
esphome/components/si4713_i2c/switch/gpio_switch.cpp
Normal file
12
esphome/components/si4713_i2c/switch/gpio_switch.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "gpio_switch.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void GPIOSwitch::write_state(bool value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_gpio(this->pin_, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
22
esphome/components/si4713_i2c/switch/gpio_switch.h
Normal file
22
esphome/components/si4713_i2c/switch/gpio_switch.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class GPIOSwitch : public switch_::Switch, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
GPIOSwitch() = default;
|
||||||
|
|
||||||
|
void set_pin(uint8_t pin) { this->pin_ = pin - 1; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool value) override;
|
||||||
|
|
||||||
|
uint8_t pin_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
Loading…
Reference in a new issue