From b695d1e804d6518cd12e31f82446591c4937c685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Tue, 15 Oct 2024 22:07:07 +0200 Subject: [PATCH] si4713 wip --- .../components/si4713_i2c/output/__init__.py | 27 + .../si4713_i2c/output/binary_output.cpp | 25 + .../si4713_i2c/output/binary_output.h | 23 + esphome/components/si4713_i2c/si4713.cpp | 367 ++++++---- esphome/components/si4713_i2c/si4713.h | 23 +- esphome/components/si4713_i2c/si4713defs.h | 670 ++++++++---------- .../components/si4713_i2c/switch/__init__.py | 30 + .../si4713_i2c/switch/gpio_switch.cpp | 12 + .../si4713_i2c/switch/gpio_switch.h | 22 + 9 files changed, 677 insertions(+), 522 deletions(-) create mode 100644 esphome/components/si4713_i2c/output/__init__.py create mode 100644 esphome/components/si4713_i2c/output/binary_output.cpp create mode 100644 esphome/components/si4713_i2c/output/binary_output.h create mode 100644 esphome/components/si4713_i2c/switch/gpio_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/gpio_switch.h diff --git a/esphome/components/si4713_i2c/output/__init__.py b/esphome/components/si4713_i2c/output/__init__.py new file mode 100644 index 0000000000..27be53c85e --- /dev/null +++ b/esphome/components/si4713_i2c/output/__init__.py @@ -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])) diff --git a/esphome/components/si4713_i2c/output/binary_output.cpp b/esphome/components/si4713_i2c/output/binary_output.cpp new file mode 100644 index 0000000000..0ac2c4d976 --- /dev/null +++ b/esphome/components/si4713_i2c/output/binary_output.cpp @@ -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 + + + + + diff --git a/esphome/components/si4713_i2c/output/binary_output.h b/esphome/components/si4713_i2c/output/binary_output.h new file mode 100644 index 0000000000..d97fff656b --- /dev/null +++ b/esphome/components/si4713_i2c/output/binary_output.h @@ -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 { + 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 diff --git a/esphome/components/si4713_i2c/si4713.cpp b/esphome/components/si4713_i2c/si4713.cpp index a6976aec07..4d26640532 100644 --- a/esphome/components/si4713_i2c/si4713.cpp +++ b/esphome/components/si4713_i2c/si4713.cpp @@ -15,6 +15,7 @@ static const char *const TAG = "si4713"; Si4713Component::Si4713Component() { this->reset_pin_ = nullptr; this->reset_ = false; + memset(this->gpio_, 0, sizeof(gpio_)); // memset(&this->state_, 0, sizeof(this->state_)); this->rds_station_pos_ = 0; this->rds_text_pos_ = 0; @@ -22,45 +23,7 @@ Si4713Component::Si4713Component() { // our defaults // 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) { 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); if (err != i2c::ERROR_OK) { ESP_LOGE(TAG, "send_cmd(0x%02X, %d) write error", buff[0], cmd_size); - this->mark_failed(); + // this->mark_failed(); 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? if (err != i2c::ERROR_OK) { ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read status error", buff[0], cmd_size); - this->mark_failed(); + // this->mark_failed(); 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); if (err != i2c::ERROR_OK) { ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read response error", buff[0], cmd_size); - this->mark_failed(); + // this->mark_failed(); return false; } } @@ -101,112 +64,131 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size 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_() {} // overrides void Si4713Component::setup() { - if (this->reset_pin_ == nullptr) { - ESP_LOGE(TAG, "setup cannot reset device, reset pin is not set"); + // CHIP STATE: POWER DOWN + + if (!this->power_up()) { this->mark_failed(); return; } - // reset - - this->reset_ = true; - this->reset_pin_->setup(); - - if (!this->power_up()) { - return; - } - if (!this->detect_chip_id()) { + this->mark_failed(); 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(PropTxPreEmphasis()); - /* - // 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 - */ + this->set_prop(PropRefClkPreScale(1, 0)); // div1, RCLK source - // 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_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_mute(); @@ -214,6 +196,9 @@ void Si4713Component::setup() { this->publish_rds_enable(); this->publish_rds_station(); this->publish_rds_text(); + this->publish_gpio(0); + this->publish_gpio(1); + this->publish_gpio(2); this->set_interval(1000, [this]() { this->rds_update_(); }); } @@ -244,6 +229,94 @@ void Si4713Component::update() { 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 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(); } +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 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_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) { if (s != nullptr) { if (!s->has_state() || s->state != state) { diff --git a/esphome/components/si4713_i2c/si4713.h b/esphome/components/si4713_i2c/si4713.h index 6e8be2a7d8..33558c2e9a 100644 --- a/esphome/components/si4713_i2c/si4713.h +++ b/esphome/components/si4713_i2c/si4713.h @@ -29,6 +29,7 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { std::string chip_id_; InternalGPIOPin *reset_pin_; bool reset_; + bool gpio_[3]; /* union { struct Si4713State state_; @@ -63,13 +64,6 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { 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_text_; uint8_t rds_station_pos_; @@ -87,7 +81,9 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { SUB_SWITCH(rds_enable) SUB_TEXT(rds_station) SUB_TEXT(rds_text) - // TODO: GPIO switches + SUB_SWITCH(gpio1) + SUB_SWITCH(gpio2) + SUB_SWITCH(gpio3) void publish_(); void publish_chip_id(); @@ -97,6 +93,7 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { void publish_rds_enable(); void publish_rds_station(); void publish_rds_text(); + void publish_gpio(uint8_t pin); void publish(sensor::Sensor *s, float state); void publish(text_sensor::TextSensor *s, const std::string &state); void publish(number::Number *n, float state); @@ -113,6 +110,14 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { void update() 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_frequency(float value); float get_frequency(); @@ -124,6 +129,8 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { bool get_rds_enable(); void set_rds_station(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 diff --git a/esphome/components/si4713_i2c/si4713defs.h b/esphome/components/si4713_i2c/si4713defs.h index b3edb81259..1c6c948a62 100644 --- a/esphome/components/si4713_i2c/si4713defs.h +++ b/esphome/components/si4713_i2c/si4713defs.h @@ -164,26 +164,23 @@ struct ResBase { struct CmdPowerUp : CmdBase { union { - uint8_t ARG1; + uint8_t ARG[2]; struct { + // ARG1 uint8_t FUNC : 4; // Function (2 transmit, 15 query library) uint8_t XOSCEN : 1; // Crystal Oscillator Enable uint8_t PATCH : 1; // Patch Enable uint8_t GPO2OEN : 1; // GPO2 Output Enable uint8_t CTSIEN : 1; // CTS Interrupt Enable - }; - }; - union { - uint8_t ARG2; - struct { - uint8_t OPMODE : 8; // Application Setting (0x50 analog, 0x0F digital) + // ARG2 + uint8_t OPMODE; // Application Setting (0x50 analog, 0x0F digital) }; }; CmdPowerUp() { this->CMD = CmdType::POWER_UP; - this->ARG1 = 0; - this->ARG1 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; } }; @@ -191,35 +188,22 @@ struct ResPowerUpTX : ResBase {}; struct ResPowerUpQueryLibrary : ResBase { union { - uint8_t RESP1; + uint8_t RESP[7]; struct { - uint8_t PN : 8; // Final 2 digits of part number - }; - }; - union { - uint8_t RESP2; - struct { - uint8_t FWMAJOR : 8; // Firmware Major Revision - }; - }; - union { - uint8_t RESP3; - struct { - uint8_t FWMINOR : 8; // Firmware Minor Revision - }; - }; - uint8_t RESP4; // Reserved - uint8_t RESP5; // Reserved - union { - uint8_t RESP6; - struct { - uint8_t CHIPREV : 8; // Chip Revision - }; - }; - union { - uint8_t RESP7; - struct { - uint8_t LIBRARYID : 8; // Library Revision + // RESP1 + uint8_t PN; // Final 2 digits of part number + // RESP2 + uint8_t FWMAJOR; // Firmware Major Revision + // RESP3 + uint8_t FWMINOR; // Firmware Minor Revision + // RESP4 + uint8_t : 8; + // RESP5 + uint8_t : 8; + // RESP6 + uint8_t CHIPREV; // Chip Revision + // RESP7 + uint8_t LIBRARYID; // Library Revision }; }; }; @@ -230,51 +214,24 @@ struct CmdGetRev : CmdBase { struct ResGetRev : ResBase { union { - uint8_t RESP1; + uint8_t RESP[8]; struct { - uint8_t PN : 8; // Final 2 digits of part number - }; - }; - union { - uint8_t RESP2; - struct { - uint8_t FWMAJOR : 8; // Firmware Major Revision - }; - }; - union { - uint8_t RESP3; - struct { - uint8_t FWMINOR : 8; // Firmware Minor Revision - }; - }; - union { - uint8_t RESP4; - struct { - uint8_t PATCHH : 8; // Patch ID High Byte - }; - }; - union { - uint8_t RESP5; - struct { - uint8_t PATCHL : 8; // Patch ID Low Byte - }; - }; - union { - uint8_t RESP6; - struct { - uint8_t CMPMAJOR : 8; // Component Major Revision - }; - }; - union { - uint8_t RESP7; - struct { - uint8_t CMPMINOR : 8; // Component Minor Revision - }; - }; - union { - uint8_t RESP8; - struct { - uint8_t CHIPREV : 8; // Chip Revision + // RESP1 + uint8_t PN; // Final 2 digits of part number + // RESP2 + uint8_t FWMAJOR; // Firmware Major Revision + // RESP3 + uint8_t FWMINOR; // Firmware Minor Revision + // RESP4 + uint8_t PATCHH; // Patch ID High Byte + // RESP5 + uint8_t PATCHL; // Patch ID Low Byte + // RESP6 + uint8_t CMPMAJOR; // Component Major Revision + // RESP7 + uint8_t CMPMINOR; // Component Minor Revision + // RESP8 + uint8_t CHIPREV; // Chip Revision }; }; }; @@ -286,99 +243,85 @@ struct CmdPowerDown : CmdBase { struct ResPowerDown : ResBase {}; struct CmdSetProperty : CmdBase { - uint8_t ARG1; // zero union { - uint8_t ARG2; + uint8_t ARG[5]; struct { - uint8_t PROPH : 8; - }; - }; - union { - uint8_t ARG3; - struct { - uint8_t PROPL : 8; - }; - }; - union { - uint8_t ARG4; - struct { - uint8_t PROPDH : 8; - }; - }; - union { - uint8_t ARG5; - struct { - uint8_t PROPDL : 8; + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t PROPH; + // ARG3 + uint8_t PROPL; + // ARG4 + uint8_t PROPDH; + // ARG5 + uint8_t PROPDL; }; }; CmdSetProperty() { this->CMD = CmdType::SET_PROPERTY; - this->ARG1 = 0; - this->ARG2 = 0; - this->ARG3 = 0; - this->ARG4 = 0; - this->ARG5 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->ARG[2] = 0; + this->ARG[3] = 0; + this->ARG[4] = 0; } CmdSetProperty(PropType prop, uint16_t value) { this->CMD = CmdType::SET_PROPERTY; - this->ARG1 = 0; - this->ARG2 = ((uint16_t) prop) >> 8; - this->ARG3 = ((uint16_t) prop) & 0xff; - this->ARG4 = value >> 8; - this->ARG5 = value & 0xff; + this->ARG[0] = 0; + this->ARG[1] = ((uint16_t) prop) >> 8; + this->ARG[2] = ((uint16_t) prop) & 0xff; + this->ARG[3] = value >> 8; + this->ARG[4] = value & 0xff; } }; struct ResSetProperty : ResBase {}; struct CmdGetProperty : CmdBase { - uint8_t ARG1; // zero union { - uint8_t ARG2; + uint8_t ARG[3]; struct { - uint8_t PROPH : 8; - }; - }; - union { - uint8_t ARG3; - struct { - uint8_t PROPL : 8; + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t PROPH; + // ARG3 + uint8_t PROPL; }; }; CmdGetProperty() { this->CMD = CmdType::GET_PROPERTY; - this->ARG1 = 0; - this->ARG2 = 0; - this->ARG3 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->ARG[2] = 0; } CmdGetProperty(PropType prop) { this->CMD = CmdType::GET_PROPERTY; - this->ARG1 = 0; - this->ARG2 = (uint16_t) prop >> 8; - this->ARG3 = (uint16_t) prop & 0xff; + this->ARG[0] = 0; + this->ARG[1] = (uint16_t) prop >> 8; + this->ARG[2] = (uint16_t) prop & 0xff; } }; struct ResGetProperty : ResBase { - uint8_t RESP1; // zero union { - uint8_t RESP2; + uint8_t RESP[3]; struct { - uint8_t PROPDH : 8; // Property Get High Byte - }; - }; - union { - uint8_t RESP3; - struct { - uint8_t PROPDL : 8; // Property Get Low Byte + // RESP1 + uint8_t : 8; // zero + // RESP2 + uint8_t PROPDH; // Property Get High Byte + // RESP3 + uint8_t PROPDL; // Property Get Low Byte }; }; - operator uint16_t() const { return ((uint16_t) PROPDH << 8) | PROPDL; } + operator uint16_t() const { return ((uint16_t) this->PROPDH << 8) | this->PROPDL; } }; struct CmdGetIntStatus : CmdBase { @@ -388,280 +331,226 @@ struct CmdGetIntStatus : CmdBase { struct ResGetIntStatus : ResBase {}; struct CmdTxTuneFreq : CmdBase { - uint8_t ARG1; // zero union { - uint8_t ARG2; + uint8_t ARG[3]; struct { - uint8_t FREQH : 8; // Tune Frequency High Byte - }; - }; - union { - uint8_t ARG3; - struct { - uint8_t FREQL : 8; // Tune Frequency Low Byte + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t FREQH; // Tune Frequency High Byte + // ARG3 + uint8_t FREQL; // Tune Frequency Low Byte }; }; CmdTxTuneFreq(uint16_t freq = 0) { // 7600 to 10800, 10 kHz resolution, multiples of 50 kHz this->CMD = CmdType::TX_TUNE_FREQ; - this->ARG1 = 0; - this->ARG2 = (uint16_t) freq >> 8; - this->ARG3 = (uint16_t) freq & 0xff; + this->ARG[0] = 0; + this->ARG[1] = (uint16_t) freq >> 8; + this->ARG[2] = (uint16_t) freq & 0xff; } }; struct ResTxTuneFreq : ResBase {}; struct CmdTxTunePower : CmdBase { - uint8_t ARG1; // zero - uint8_t ARG2; // zero union { - uint8_t ARG3; + uint8_t ARG[4]; struct { - uint8_t RFdBuV : 8; // Tune Power Byte, 88 to 115 dBuV - }; - }; - union { - uint8_t ARG4; - struct { - uint8_t ANTCAP : 8; // Antenna Tuning Capacitor, 0.25 pF x 0 to 191 + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t : 8; // zero + // ARG3 + uint8_t RFdBuV; // Tune Power Byte, 88 to 115 dBuV + // ARG4 + uint8_t ANTCAP; // Antenna Tuning Capacitor, 0.25 pF x 0 to 191 }; }; CmdTxTunePower(uint8_t power = 0, uint8_t antcap = 0) { this->CMD = CmdType::TX_TUNE_POWER; - this->ARG1 = 0; - this->ARG2 = 0; - this->ARG3 = power; - this->ARG4 = antcap; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->ARG[2] = power; + this->ARG[3] = antcap; } }; struct ResTxTunePower : ResBase {}; struct CmdTxTuneMeasure : CmdBase { - uint8_t ARG1; // zero union { - uint8_t ARG2; + uint8_t ARG[4]; struct { - uint8_t FREQH : 8; // Tune Frequency High Byte - }; - }; - union { - uint8_t ARG3; - struct { - uint8_t FREQL : 8; // Tune Frequency Low Byte - }; - }; - union { - uint8_t ARG4; - struct { - uint8_t ANTCAP : 8; // Antenna Tuning Capacitor, 0.25 pF x 0 to 191 + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t FREQH; // Tune Frequency High Byte + // ARG3 + uint8_t FREQL; // Tune Frequency Low Byte + // ARG4 + uint8_t ANTCAP; // Antenna Tuning Capacitor, 0.25 pF x 0 to 191 }; }; CmdTxTuneMeasure(uint8_t freq = 0, uint8_t antcap = 0) { this->CMD = CmdType::TX_TUNE_MEASURE; - this->ARG1 = 0; - this->ARG2 = (uint16_t) freq >> 8; - this->ARG3 = (uint16_t) freq & 0xff; - this->ARG4 = antcap; + this->ARG[0] = 0; + this->ARG[1] = (uint16_t) freq >> 8; + this->ARG[2] = (uint16_t) freq & 0xff; + this->ARG[3] = antcap; } }; struct ResTxTuneMeasure : ResBase {}; struct CmdTxTuneStatus : CmdBase { - uint8_t ARG1; // zero union { - uint8_t ARG2; + uint8_t ARG[2]; struct { - uint8_t INTACK : 1; // Clears the seek/tune complete interrupt status indicator - uint8_t RESERVED : 7; + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t INTACK : 1; // Seek/Tune Interrupt Clear. + uint8_t : 7; }; }; - CmdTxTuneStatus() { + CmdTxTuneStatus(uint8_t intack = 1) { this->CMD = CmdType::TX_TUNE_STATUS; - this->ARG1 = 0; - this->ARG2 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->INTACK = intack; } }; struct ResTxTuneStatus : ResBase { - uint8_t RESP1; union { - uint8_t RESP2; + uint8_t RESP[7]; struct { - uint8_t READFREQH : 8; // Read Frequency High Byte - }; - }; - union { - uint8_t RESP3; - struct { - uint8_t READFREQL : 8; // Read Frequency Low Byte - }; - }; - uint8_t RESP4; - union { - uint8_t RESP5; - struct { - uint8_t RFdBuV : 8; // Read Power - }; - }; - union { - uint8_t RESP6; - struct { - uint8_t ANTCAP : 8; // Read Antenna Tuning Capacitor - }; - }; - union { - uint8_t RESP7; - struct { - uint8_t RNL : 8; // Read Received Noise Level (Si4712/13 Only) + // RESP1 + uint8_t : 8; + // RESP2 + uint8_t READFREQH; // Read Frequency High Byte + // RESP3 + uint8_t READFREQL; // Read Frequency Low Byte + // RESP4 + uint8_t : 8; + // RESP5 + uint8_t READRFdBuV; // Read Power + // RESP6 + uint8_t READANTCAP; // Read Antenna Tuning Capacitor + // RESP7 + uint8_t RNL; // Read Received Noise Level (Si4712/13 Only) }; }; }; struct CmdTxAsqStatus : CmdBase { - uint8_t ARG1; // zero union { - uint8_t ARG2; + uint8_t ARG[2]; struct { - uint8_t INTACK : 1; // Clears the seek/tune complete interrupt status indicator - uint8_t RESERVED : 7; + // ARG1 + uint8_t : 8; // zero + // ARG2 + uint8_t INTACK : 1; // Interrupt Acknowledge. Clears ASQINT, OVERMOD, IALDH, and IALDL + uint8_t : 7; }; }; - CmdTxAsqStatus() { + CmdTxAsqStatus(uint8_t intack = 1) { this->CMD = CmdType::TX_ASQ_STATUS; - this->ARG1 = 0; - this->ARG2 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->INTACK = intack; } }; struct ResTxAsqStatus : ResBase { union { - uint8_t RESP1; + uint8_t RESP[4]; struct { + // RESP1 uint8_t OVERMOD : 1; // Overmodulation Detection uint8_t IALH : 1; // Input Audio Level Threshold Detect High uint8_t IALL : 1; // Input Audio Level Threshold Detect Low - uint8_t RESERVED : 5; - }; - }; - uint8_t RESP2; - uint8_t RESP3; - union { - uint8_t RESP4; - struct { - int8_t INLEVEL : 8; // Input Audio Level + uint8_t : 5; + // RESP2 + uint8_t : 8; + // RESP3 + uint8_t : 8; + // RESP4 + int8_t INLEVEL; // Input Audio Level }; }; }; struct CmdTxRdsBuff : CmdBase { union { - uint8_t ARG1; + uint8_t ARG[7]; struct { + // ARG1 uint8_t INTACK : 1; // Clear RDS Group buffer interrupt uint8_t MTBUFF : 1; // Empty RDS Group Buffer uint8_t LDBUFF : 1; // Load RDS Group Buffer - uint8_t RESERVED : 4; + uint8_t : 4; uint8_t FIFO : 1; // Operate on FIFO - }; - }; - union { - uint8_t ARG2; - struct { + // ARG2 uint8_t RDSBH; // RDS Block B High Byte - }; - }; - union { - uint8_t ARG3; - struct { + // ARG3 uint8_t RDSBL; // RDS Block B Low Byte - }; - }; - union { - uint8_t ARG4; - struct { + // ARG4 uint8_t RDSCH; // RDS Block C High Byte - }; - }; - union { - uint8_t ARG5; - struct { + // ARG5 uint8_t RDSCL; // RDS Block C Low Byte - }; - }; - union { - uint8_t ARG6; - struct { + // ARG6 uint8_t RDSDH; // RDS Block D High Byte - }; - }; - union { - uint8_t ARG7; - struct { + // ARG7 uint8_t RDSDL; // RDS Block D Low Byte }; }; CmdTxRdsBuff() { this->CMD = CmdType::TX_RDS_BUFF; - this->ARG1 = 0; - this->ARG2 = 0; - this->ARG3 = 0; - this->ARG4 = 0; - this->ARG5 = 0; - this->ARG6 = 0; - this->ARG7 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->ARG[2] = 0; + this->ARG[3] = 0; + this->ARG[4] = 0; + this->ARG[5] = 0; + this->ARG[6] = 0; } }; struct ResTxRdsBuff : ResBase { union { - uint8_t RESP1; + uint8_t RESP[5]; struct { + // RESP1 uint8_t FIFOMT : 1; // Interrupt source: RDS Group FIFO Buffer is empty uint8_t CBUFWRAP : 1; // Interrupt source: RDS Group Circular Buffer has wrapped uint8_t FIFOXMIT : 1; // Interrupt source: RDS Group has been transmitted from the circular buffer uint8_t CBUFXMIT : 1; // Interrupt source: RDS Group has been transmitted from the FIFO buffer uint8_t RDSPSXMIT : 1; // Interrupt source: RDS PS Group has been transmitted - uint8_t RESERVED : 3; - }; - }; - union { - uint8_t RESP2; - struct { - uint8_t CBAVAIL : 8; // Returns the number of available Circular Buffer blocks - }; - }; - union { - uint8_t RESP3; - struct { - uint8_t CBUSED : 8; // Returns the number of used Circular Buffer blocks - }; - }; - union { - uint8_t RESP4; - struct { - uint8_t FIFOAVAIL : 8; // Returns the number of available FIFO blocks - }; - }; - union { - uint8_t RESP5; - struct { - uint8_t FIFOUSED : 8; // Returns the number of used FIFO blocks + uint8_t : 3; + // RESP2 + uint8_t CBAVAIL; // Returns the number of available Circular Buffer blocks + // RESP3 + uint8_t CBUSED; // Returns the number of used Circular Buffer blocks + // RESP4 + uint8_t FIFOAVAIL; // Returns the number of available FIFO blocks + // RESP5 + uint8_t FIFOUSED; // Returns the number of used FIFO blocks }; }; }; struct CmdTxRdsPs : CmdBase { union { - uint8_t ARG1; + uint8_t ARG[5]; struct { + // ARG1 // Selects which PS data to load (0-23) // 0 = First 4 characters of PS0 // 1 = Last 4 characters of PS0 @@ -671,41 +560,25 @@ struct CmdTxRdsPs : CmdBase { // 22 = First 4 characters of PS11 // 23 = Last 4 characters of PS11 uint8_t PSID : 4; - uint8_t RESERVED : 4; - }; - }; - union { - uint8_t ARG2; - struct { + uint8_t : 4; + // ARG2 uint8_t PSCHAR0; // RDS PSID CHAR0 - }; - }; - union { - uint8_t ARG3; - struct { + // ARG3 uint8_t PSCHAR1; // RDS PSID CHAR1 - }; - }; - union { - uint8_t ARG4; - struct { + // ARG4 uint8_t PSCHAR2; // RDS PSID CHAR2 - }; - }; - union { - uint8_t ARG5; - struct { + // ARG5 uint8_t PSCHAR3; // RDS PSID CHAR3 }; }; CmdTxRdsPs() { this->CMD = CmdType::TX_RDS_PS; - this->ARG1 = 0; - this->ARG2 = 0; - this->ARG3 = 0; - this->ARG4 = 0; - this->ARG5 = 0; + this->ARG[0] = 0; + this->ARG[1] = 0; + this->ARG[2] = 0; + this->ARG[3] = 0; + this->ARG[4] = 0; } }; @@ -713,18 +586,22 @@ struct ResTxRdsPs : ResBase {}; struct CmdGpioCtl : CmdBase { union { - uint8_t ARG1; + uint8_t ARG[1]; struct { - uint8_t RESERVED1 : 1; + // ARG1 + uint8_t : 1; uint8_t GPO1OEN : 1; // GPO1 Output Enable - uint8_t GPO2OEN : 1; // GPO2 Output Enable - uint8_t GPO3OEN : 1; // GPO3 Output Enable + uint8_t GPO2OEN : 1; // GPO2 Output Enable () + uint8_t GPO3OEN : 1; // GPO3 Output Enable (XTAL or digital audio clock is connected to this) }; }; - CmdGpioCtl() { + CmdGpioCtl(uint8_t gpo1oen = 0, uint8_t gpo2oen = 0, uint8_t gpo3oen = 0) { this->CMD = CmdType::GPIO_CTL; - this->ARG1 = 0; + this->ARG[0] = 0; + this->GPO1OEN = gpo1oen; + this->GPO2OEN = gpo2oen; + this->GPO3OEN = gpo3oen; } }; @@ -732,19 +609,23 @@ struct ResGpioCtl : ResBase {}; struct CmdGpioSet : CmdBase { union { - uint8_t ARG1; + uint8_t ARG[1]; struct { - uint8_t RESERVED1 : 1; + // ARG1 + uint8_t : 1; uint8_t GPO1OEN : 1; // GPO1 Output Level uint8_t GPO2OEN : 1; // GPO2 Output Level uint8_t GPO3OEN : 1; // GPO3 Output Level - uint8_t RESERVED2 : 4; + uint8_t : 4; }; }; - CmdGpioSet() { + CmdGpioSet(uint8_t gpo1oen = 0, uint8_t gpo2oen = 0, uint8_t gpo3oen = 0) { this->CMD = CmdType::GPIO_SET; - this->ARG1 = 0; + this->ARG[0] = 0; + this->GPO1OEN = gpo1oen; + this->GPO2OEN = gpo2oen; + this->GPO3OEN = gpo3oen; } }; @@ -762,16 +643,16 @@ struct PropGpoIen : PropBase { union { uint16_t PROPD; struct { - uint16_t STCIEN : 1; // Seek/Tune Complete Interrupt Enable - uint16_t ASQIEN : 1; // Audio Signal Quality Interrupt Enable - uint16_t RDSIEN : 1; // RDS Interrupt Enable (Si4711/13/21 Only) - uint16_t RESERVED1 : 3; // - uint16_t ERRIEN : 1; // ERR Interrupt Enable - uint16_t CTSIEN : 1; // CTS Interrupt Enable - uint16_t STCREP : 1; // STC Interrupt Repeat - uint16_t ASQREP : 1; // ASQ Interrupt Repeat - uint16_t RDSREP : 1; // RDS Interrupt Repeat. (Si4711/13/21 Only) - uint16_t RESERVED2 : 5; + uint16_t STCIEN : 1; // Seek/Tune Complete Interrupt Enable + uint16_t ASQIEN : 1; // Audio Signal Quality Interrupt Enable + uint16_t RDSIEN : 1; // RDS Interrupt Enable (Si4711/13/21 Only) + uint16_t : 3; // + uint16_t ERRIEN : 1; // ERR Interrupt Enable + uint16_t CTSIEN : 1; // CTS Interrupt Enable + uint16_t STCREP : 1; // STC Interrupt Repeat + uint16_t ASQREP : 1; // ASQ Interrupt Repeat + uint16_t RDSREP : 1; // RDS Interrupt Repeat. (Si4711/13/21 Only) + uint16_t : 5; }; }; @@ -792,9 +673,13 @@ struct PropDigitalInputFormat : PropBase { }; }; - PropDigitalInputFormat() { + PropDigitalInputFormat(uint16_t isize = 0, uint16_t imono = 0, uint16_t imode = 0, uint16_t ifall = 0) { this->PROP = PropType::DIGITAL_INPUT_FORMAT; this->PROPD = 0x0000; + this->ISIZE = isize; + this->IMONO = imono; + this->IMODE = imode; + this->IFALL = ifall; } }; @@ -833,15 +718,17 @@ struct PropRefClkPreScale : PropBase { union { uint16_t PROPD; struct { - uint16_t RCLKP : 12; // Prescaler for Reference Clock (31130 and 34406 Hz, 0 Disabled) + uint16_t RCLKP : 12; // Integer number to divide RCLK down to REFCLK frequency uint16_t RCLKSEL : 1; // RCLK/DCLK pin is clock source - uint16_t RESERVED : 3; + uint16_t : 3; }; }; - PropRefClkPreScale() { + PropRefClkPreScale(uint16_t rclkp = 1, uint16_t rclksel = 0) { this->PROP = PropType::REFCLK_PRESCALE; this->PROPD = 0x0001; + this->RCLKP = rclkp; + this->RCLKSEL = rclksel; } }; @@ -852,11 +739,11 @@ struct PropTxComponentEnable : PropBase { uint16_t PILOT : 1; // Pilot Tone uint16_t LMR : 1; // Left Minus Right uint16_t RDS : 1; // RDS Enable - uint16_t RESERVED : 13; + uint16_t : 13; }; }; - PropTxComponentEnable() { + PropTxComponentEnable(uint16_t pilot = 1, uint16_t lmr = 1, uint16_t rds = 0) { this->PROP = PropType::TX_COMPONENT_ENABLE; this->PROPD = 0x0003; } @@ -911,16 +798,18 @@ struct PropTxLineInputLevel : PropBase { union { uint16_t PROPD; struct { - uint16_t LILEVEL : 10; // Line Level (mV) - uint16_t RESERVED1 : 2; - uint16_t LIATTEN : 2; // Line Attenuation (for 190, 301, 416, 636 mV) - uint16_t RESERVED2 : 2; + uint16_t LILEVEL : 10; // Line Level. Max amplitude on LIN/RIN in mVPK (default 636 mV) + uint16_t : 2; + uint16_t LIATTEN : 2; // Line Attenuation (190, 301, 416, 636 mV / 396, 100, 74, 60 kOhm) + uint16_t : 2; }; }; - PropTxLineInputLevel() { + PropTxLineInputLevel(uint16_t lilevel = 636, uint16_t liatten = 3) { this->PROP = PropType::TX_LINE_INPUT_LEVEL; this->PROPD = 0x327C; + this->LILEVEL = lilevel; + this->LIATTEN = liatten; } }; @@ -930,13 +819,15 @@ struct PropTxLineInputMute : PropBase { struct { uint16_t RIMUTE : 1; // Mutes R Line Input uint16_t LIMUTE : 1; // Mutes L Line Input - uint16_t RESERVED : 14; + uint16_t : 14; }; }; - PropTxLineInputMute() { + PropTxLineInputMute(uint16_t limute = 0, uint16_t rimute = 0) { this->PROP = PropType::TX_LINE_INPUT_MUTE; this->PROPD = 0x0000; + this->LIMUTE = limute; + this->RIMUTE = rimute; } }; @@ -945,13 +836,14 @@ struct PropTxPreEmphasis : PropBase { uint16_t PROPD; struct { uint16_t FMPE : 2; // FM Pre-Emphasis (75us, 50us, Disabled, Reserved) - uint16_t RESERVED : 14; + uint16_t : 14; }; }; - PropTxPreEmphasis() { + PropTxPreEmphasis(uint16_t fmpe = 0) { this->PROP = PropType::TX_PREEMPHASIS; this->PROPD = 0x0000; + this->FMPE = fmpe; } }; @@ -963,9 +855,10 @@ struct PropTxPilotFrequency : PropBase { }; }; - PropTxPilotFrequency() { + PropTxPilotFrequency(uint16_t freq = 19000) { this->PROP = PropType::TX_PILOT_FREQUENCY; this->PROPD = 0x4A38; + this->FREQ = freq; } }; @@ -975,13 +868,15 @@ struct PropTxAcompEnable : PropBase { struct { uint16_t ACEN : 1; // Transmit Audio Dynamic Range Control Enable uint16_t LIMITEN : 1; // Audio Limiter - uint16_t RESERVED : 14; + uint16_t : 14; }; }; - PropTxAcompEnable() { + PropTxAcompEnable(uint16_t acen = 0, uint16_t limiten = 1) { this->PROP = PropType::TX_ACOMP_ENABLE; this->PROPD = 0x0002; + this->ACEN = acen; + this->LIMITEN = limiten; } }; @@ -993,9 +888,10 @@ struct PropTxAcompThreshold : PropBase { }; }; - PropTxAcompThreshold() { + PropTxAcompThreshold(int16_t threshold = -40) { this->PROP = PropType::TX_ACOMP_THRESHOLD; this->PROPD = 0xFFD8; + this->THRESHOLD = -40; } }; @@ -1003,14 +899,15 @@ struct PropTxAcompAttackTime : PropBase { union { uint16_t PROPD; struct { - uint16_t ATTACK : 4; // Transmit Audio Dynamic Range Control Attack Time (0.5 (=0) to 5ms (=9)) - uint16_t RESERVED : 12; + uint16_t ATTACK : 4; // Transmit Audio Dynamic Range Control Attack Time (0.5 to 5ms) + uint16_t : 12; }; }; - PropTxAcompAttackTime() { + PropTxAcompAttackTime(uint16_t attack = 0) { this->PROP = PropType::TX_ACOMP_ATTACK_TIME; this->PROPD = 0x0000; + this->ATTACK = attack; } }; @@ -1019,13 +916,14 @@ struct PropTxAcompReleaseTime : PropBase { uint16_t PROPD; struct { uint16_t RELEASE : 3; // Transmit Audio Dynamic Range Control Release Time (100, 200, 350, 525, 1000 ms) - uint16_t RESERVED : 13; + uint16_t : 13; }; }; - PropTxAcompReleaseTime() { + PropTxAcompReleaseTime(uint16_t release = 4) { this->PROP = PropType::TX_ACOMP_RELEASE_TIME; this->PROPD = 0x0004; + this->RELEASE = release; } }; @@ -1034,13 +932,14 @@ struct PropTxAcompGain : PropBase { uint16_t PROPD; struct { uint16_t GAIN : 6; // Transmit Audio Dynamic Range Control Gain (0 to 20 dB) - uint16_t RESERVED : 10; + uint16_t : 10; }; }; - PropTxAcompGain() { + PropTxAcompGain(uint16_t gain = 15) { this->PROP = PropType::TX_ACOMP_GAIN; this->PROPD = 0x000F; + this->GAIN = gain; } }; struct PropTxLimiterReleaseTime : PropBase { @@ -1051,9 +950,10 @@ struct PropTxLimiterReleaseTime : PropBase { }; }; - PropTxLimiterReleaseTime() { + PropTxLimiterReleaseTime(uint16_t lmitertc = 102) { this->PROP = PropType::TX_LIMITER_RELEASE_TIME; this->PROPD = 0x0066; + this->LMITERTC = lmitertc; } }; @@ -1064,7 +964,7 @@ struct PropTxAsqInterruptSource : PropBase { uint16_t IALLIEN : 1; // Input Audio Level Detection Low Threshold Enable uint16_t IALHIEN : 1; // Input Audio Level Detection High Threshold Enable uint16_t OVERMODIEN : 1; // Overmodulation Detection Enable - uint16_t RESERVED : 13; + uint16_t : 13; }; }; @@ -1079,7 +979,7 @@ struct PropTxAsqLevelLow : PropBase { uint16_t PROPD; struct { uint16_t IALLTH : 8; // Input Audio Level Low Threshold (-70 to 0 dB) - uint16_t RESERVED : 8; + uint16_t : 8; }; }; @@ -1103,16 +1003,16 @@ struct PropTxAsqDurationLow : PropBase { } }; -struct PropTxAsqDurationHigh : PropBase { +struct PropTxAsqLevelHigh : PropBase { union { uint16_t PROPD; struct { uint16_t IALHTH : 8; // Input Audio Level High Threshold (-70 to 0 dB) - uint16_t RESERVED : 8; + uint16_t : 8; }; }; - PropTxAsqDurationHigh() { + PropTxAsqLevelHigh() { this->PROP = PropType::TX_ASQ_LEVEL_HIGH; this->PROPD = 0x0000; } @@ -1141,7 +1041,7 @@ struct PropTxRdsInterruptSource : PropBase { uint16_t RDSFIFOXMIT : 1; // Interrupt when a RDS Group has been transmitted from the FIFO Buffer uint16_t RDSCBUFXMIT : 1; // Interrupt when a RDS Group has been transmitted from the Circular Buffer uint16_t RDSPSXMIT : 1; // Interrupt when a RDS PS Group has been transmitted - uint16_t RESERVED : 11; + uint16_t : 11; }; }; @@ -1170,7 +1070,7 @@ struct PropTxRdsPsMix : PropBase { uint16_t PROPD; struct { uint16_t RDSPSMIX : 3; // Transmit RDS Mix - uint16_t RESERVED : 13; + uint16_t : 13; }; }; @@ -1184,7 +1084,7 @@ struct PropTxRdsPsMisc : PropBase { union { uint16_t PROPD; struct { - uint16_t RESERVED : 3; + uint16_t : 3; uint16_t RDSMS : 1; // Music/Speech Switch Code uint16_t RDSTA : 1; // Traffic Announcement Code uint16_t RDSPTY : 1; // Program Type Code @@ -1208,7 +1108,7 @@ struct PropTxRdsRepeatCount : PropBase { uint16_t PROPD; struct { uint16_t RDSPSRC : 8; // Transmit RDS PS Repeat Count - uint16_t RESERVED : 8; + uint16_t : 8; }; }; @@ -1223,7 +1123,7 @@ struct PropTxRdsMessageCount : PropBase { uint16_t PROPD; struct { uint16_t RDSPSMC : 4; // Transmit RDS PS Message Count. - uint16_t RESERVED : 12; + uint16_t : 12; }; }; @@ -1252,7 +1152,7 @@ struct PropTxRdsFifoSize : PropBase { uint16_t PROPD; struct { uint16_t RDSFIFOSZ : 8; // Transmit RDS FIFO Size (0 = FIFO disabled) - uint16_t RESERVED : 8; + uint16_t : 8; }; }; diff --git a/esphome/components/si4713_i2c/switch/__init__.py b/esphome/components/si4713_i2c/switch/__init__.py index 9971203f5c..27f6714ba9 100644 --- a/esphome/components/si4713_i2c/switch/__init__.py +++ b/esphome/components/si4713_i2c/switch/__init__.py @@ -18,9 +18,14 @@ from .. import ( ICON_FORMAT_TEXT, ) +CONF_GPIO1="gpio1" +CONF_GPIO2="gpio2" +CONF_GPIO3="gpio3" + MuteSwitch = si4713_ns.class_("MuteSwitch", switch.Switch) MonoSwitch = si4713_ns.class_("MonoSwitch", switch.Switch) RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch) +GPIOSwitch = si4713_ns.class_("GPIOSwitch", switch.Switch) CONFIG_SCHEMA = cv.Schema( { @@ -43,6 +48,24 @@ CONFIG_SCHEMA = cv.Schema( entity_category=ENTITY_CATEGORY_CONFIG, 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) await cg.register_parented(s, config[CONF_SI4713_ID]) cg.add(setter(s)) + return s 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_MONO, c.set_mono_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) diff --git a/esphome/components/si4713_i2c/switch/gpio_switch.cpp b/esphome/components/si4713_i2c/switch/gpio_switch.cpp new file mode 100644 index 0000000000..3cc922e19b --- /dev/null +++ b/esphome/components/si4713_i2c/switch/gpio_switch.cpp @@ -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 diff --git a/esphome/components/si4713_i2c/switch/gpio_switch.h b/esphome/components/si4713_i2c/switch/gpio_switch.h new file mode 100644 index 0000000000..9a0a9fc43e --- /dev/null +++ b/esphome/components/si4713_i2c/switch/gpio_switch.h @@ -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 { + 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