config done

This commit is contained in:
Gábor Poczkodi 2024-10-16 17:38:00 +02:00
parent b695d1e804
commit 58f63e38be
61 changed files with 2612 additions and 417 deletions

View file

@ -22,6 +22,8 @@ UNIT_KILO_HERTZ = "kHz"
UNIT_MILLI_VOLT = "mV" UNIT_MILLI_VOLT = "mV"
UNIT_MICRO_AMPERE = "mA" UNIT_MICRO_AMPERE = "mA"
UNIT_DECIBEL_MICRO_VOLT = "dBµV" UNIT_DECIBEL_MICRO_VOLT = "dBµV"
UNIT_PICO_FARAD = "pF"
UNIT_KILO_OHM = "kOhm"
ICON_VOLUME_MUTE = "mdi:volume-mute" ICON_VOLUME_MUTE = "mdi:volume-mute"
ICON_EAR_HEARING = "mdi:ear-hearing" ICON_EAR_HEARING = "mdi:ear-hearing"
@ -38,55 +40,244 @@ Si4713Component = si4713_ns.class_(
CONF_SI4713_ID = "si4713_id" CONF_SI4713_ID = "si4713_id"
CONF_RESET_PIN = "reset_pin" CONF_RESET_PIN = "reset_pin"
CONF_FREQUENCY_DEVIATION = "frequency_deviation" CONF_CHIP_ID = "chip_id"
CONF_SECTION_TUNER = "tuner"
CONF_SECTION_ANALOG = "analog"
CONF_SECTION_DIGITAL = "digital"
CONF_SECTION_PILOT = "pilot"
CONF_SECTION_REFCLK = "refclk"
CONF_SECTION_COMPRESSOR = "compressor"
CONF_SECTION_LIMITER = "limiter"
CONF_SECTION_ASQ = "asq"
CONF_SECTION_RDS = "rds"
CONF_SECTION_OUTPUT = "output"
# general config
CONF_OP_MODE = "op_mode"
CONF_MUTE = "mute" CONF_MUTE = "mute"
CONF_MONO = "mono" CONF_MONO = "mono"
CONF_TX_ENABLE = "tx_enable"
CONF_TX_PILOT = "tx_pilot"
CONF_T1M_SEL = "t1m_sel"
CONF_PRIV_EN = "priv_en"
CONF_PRE_EMPHASIS = "pre_emphasis" CONF_PRE_EMPHASIS = "pre_emphasis"
CONF_XTAL_SOURCE = "xtal_source" # tuner
CONF_XTAL_CURRENT = "xtal_current" CONF_FREQUENCY = "frequency"
CONF_XTAL_FREQUENCY = "xtal_frequency" CONF_DEVIATION = "deviation"
CONF_INPUT_IMPEDANCE = "input_impedance" CONF_POWER = "power"
CONF_INPUT_GAIN = "input_gain" CONF_ANTCAP = "antcap"
CONF_DIGITAL_GAIN = "digital_gain" # analog
CONF_POWER_TARGET = "power_target" CONF_LEVEL = "level"
CONF_RDS_ENABLE = "rds_enable" CONF_ATTENUATION = "attenuation"
CONF_RDS_FREQUENCY_DEVIATION = "rds_frequency_deviation" # digital
CONF_RDS_STATION = "rds_station" CONF_SAMPLE_RATE = "sample_rate"
CONF_RDS_TEXT = "rds_text" CONF_SAMPLE_BITS = "sample_bits"
CONF_AUD_PK = "aud_pk" CONF_CHANNELS = "channels"
CONF_FSM = "fsm" CONF_MODE = "mode"
CONF_CHIP_ID = "chip_id" CONF_CLOCK_EDGE = "clock_edge"
CONF_REG30 = "reg30" # pilot
CONF_ENABLE = "enable"
CONF_FREQUENCY = "frequency"
CONF_DEVIATION = "deviation"
# refclk
CONF_FREQUENCY = "frequency"
CONF_SOURCE = "source"
CONF_PRESCALER = "prescaler"
# compressor
CONF_ENABLE = "enable"
CONF_THRESHOLD = "threshold"
CONF_ATTACK = "attack"
CONF_RELEASE = "release"
CONF_GAIN = "gain"
CONF_PRESET = "preset"
# limiter
CONF_ENABLE = "enable"
CONF_RELEASE_TIME = "release_time"
# asq
CONF_OVERMOD = "overmod"
CONF_IALL = "iall"
CONF_IALH = "ialh"
CONF_LEVEL_LOW = "level_low"
CONF_DURATION_LOW = "duration_low"
CONF_LEVEL_HIGH = "level_high"
CONF_DURATION_HIGH = "duration_high"
# rds
CONF_ENABLE = "enable"
CONF_DEVIATION = "deviation"
CONF_STATION = "station"
CONF_TEXT = "text"
# output
CONF_GPIO1="gpio1"
CONF_GPIO2="gpio2"
CONF_GPIO3="gpio3"
SetFrequencyAction = si4713_ns.class_( SetFrequencyAction = si4713_ns.class_(
"SetFrequencyAction", automation.Action, cg.Parented.template(Si4713Component) "SetFrequencyAction", automation.Action, cg.Parented.template(Si4713Component)
) )
#T1mSel = si4713_ns.enum("T1mSel", True) OpMode = si4713_ns.enum("OpMode", True)
#T1M_SEL = { OP_MODE = {
# "58s": T1mSel.T1M_SEL_58S, "Analog": OpMode.OPMODE_ANALOG,
# "59s": T1mSel.T1M_SEL_59S, "Digital": OpMode.OPMODE_Digital,
# "60s": T1mSel.T1M_SEL_60S, }
# "Never": T1mSel.T1M_SEL_NEVER,
#}
PreEmphasis = si4713_ns.enum("PreEmphasis", True)
PRE_EMPHASIS = {
"75us": PreEmphasis.FMPE_75US,
"50us": PreEmphasis.FMPE_50US,
"Disabled": PreEmphasis.FMPE_DISABLED,
}
LineAttenuation = si4713_ns.enum("LineAttenuation", True)
LINE_ATTENUATION = {
"396kOhm": LineAttenuation.LIATTEN_396KOHM,
"100kOhm": LineAttenuation.LIATTEN_100KOHM,
"74kOhm": LineAttenuation.LIATTEN_74KOHM,
"60kOhm": LineAttenuation.LIATTEN_60KOHM,
}
SampleBits = si4713_ns.enum("SampleBits", True)
SAMPLE_BITS = {
"16": SampleBits.ISIZE_16BITS,
"20": SampleBits.ISIZE_20BITS,
"24": SampleBits.ISIZE_24BITS,
"8": SampleBits.ISIZE_8BITS,
}
SampleChannels = si4713_ns.enum("SampleChannels", True)
SAMPLE_CHANNELS = {
"Stereo": SampleChannels.IMONO_STEREO,
"Mono": SampleChannels.IMONO_MONO,
}
DigitalMode = si4713_ns.enum("DigitalMode", True)
DIGITAL_MODE = {
"Default": DigitalMode.IMODE_DEFAULT,
"I2S": DigitalMode.IMODE_I2S,
"Left Justified": DigitalMode.IMODE_LEFT_JUSTIFIED,
"MSB at 1st": DigitalMode.IMODE_MSB_AT_1ST,
"MSB at 2nd": DigitalMode.IMODE_MSB_AT_2ND,
}
DigitalClockEdge = si4713_ns.enum("DigitalClockEdge", True)
DIGITAL_CLOCK_EDGE = {
"Rising": DigitalClockEdge.IFALL_DCLK_RISING_EDGE,
"Falling": DigitalClockEdge.IFALL_DCLK_FALLING_EDGE,
}
RefClkSource = si4713_ns.enum("RefClkSource", True)
REFCLK_SOURCE = {
"RCLK": RefClkSource.RCLKSEL_RCLK,
"DCLK": RefClkSource.RCLKSEL_DCLK,
}
AcompAttack = si4713_ns.enum("AcompAttack", True)
ACOMP_ATTACK = {
"0.5ms": AcompAttack.ATTACK_05MS,
"1.0ms": AcompAttack.ATTACK_10MS,
"1.5ms": AcompAttack.ATTACK_15MS,
"2.0ms": AcompAttack.ATTACK_20MS,
"2.5ms": AcompAttack.ATTACK_25MS,
"3.0ms": AcompAttack.ATTACK_30MS,
"3.5ms": AcompAttack.ATTACK_35MS,
"4.0ms": AcompAttack.ATTACK_40MS,
"4.5ms": AcompAttack.ATTACK_45MS,
"5.0ms": AcompAttack.ATTACK_50MS,
}
AcompRelease = si4713_ns.enum("AcompRelease", True)
ACOMP_RELEASE = {
"100ms": AcompRelease.RELEASE_100MS,
"200ms": AcompRelease.RELEASE_200MS,
"350ms": AcompRelease.RELEASE_350MS,
"525ms": AcompRelease.RELEASE_525MS,
"1000ms": AcompRelease.RELEASE_1000MS,
}
AcompPreset = si4713_ns.enum("AcompPreset", True)
ACOMP_PRESET = {
"Minimal": AcompPreset.ACOMP_MINIMAL,
"Aggressive": AcompPreset.ACOMP_AGGRESSIVE,
"Custom": AcompPreset.ACOMP_CUSTOM,
}
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
cv.Schema( cv.Schema(
{ {
cv.GenerateID(): cv.declare_id(Si4713Component), cv.GenerateID(): cv.declare_id(Si4713Component),
cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_FREQUENCY, default=87.50): cv.float_range(76, 108), cv.Optional(CONF_OP_MODE, default="Analog"): cv.enum(OP_MODE),
cv.Optional(CONF_MUTE, default=False): cv.boolean, cv.Optional(CONF_MUTE, default=False): cv.boolean,
cv.Optional(CONF_MONO, default=False): cv.boolean, cv.Optional(CONF_MONO, default=False): cv.boolean,
# cv.Optional(CONF_T1M_SEL, default="60s"): cv.enum(T1M_SEL), cv.Optional(CONF_PRE_EMPHASIS, default="75us"): cv.enum(PRE_EMPHASIS),
cv.Optional(CONF_RDS_ENABLE, default=False): cv.boolean, cv.Optional(CONF_SECTION_TUNER): cv.Schema(
cv.Optional(CONF_RDS_STATION): cv.string, {
cv.Optional(CONF_RDS_TEXT): cv.string, cv.Optional(CONF_FREQUENCY, default=87.50): cv.float_range(76, 108), # MHz
cv.Optional(CONF_DEVIATION, default=68.25): cv.float_range(0, 90), # kHz
cv.Optional(CONF_POWER, default=115): cv.int_range(88, 115),
cv.Optional(CONF_ANTCAP, default=0): cv.int_range(0, 191),
}
),
cv.Optional(CONF_SECTION_ANALOG): cv.Schema(
{
cv.Optional(CONF_LEVEL, default=636): cv.int_range(0, 1023),
cv.Optional(CONF_ATTENUATION, default=636): cv.enum(LINE_ATTENUATION),
}
),
cv.Optional(CONF_SECTION_DIGITAL): cv.Schema(
{
cv.Optional(CONF_SAMPLE_RATE, default=44100): cv.int_range(32000, 48000), # Hz
cv.Optional(CONF_SAMPLE_BITS, default="16"): cv.enum(SAMPLE_BITS),
cv.Optional(CONF_CHANNELS, default="Stereo"): cv.enum(SAMPLE_CHANNELS),
cv.Optional(CONF_MODE, default="Default"): cv.enum(DIGITAL_MODE),
cv.Optional(CONF_CLOCK_EDGE, default="Rising"): cv.enum(DIGITAL_CLOCK_EDGE),
}
),
cv.Optional(CONF_SECTION_PILOT): cv.Schema(
{
cv.Optional(CONF_ENABLE, default="True"): cv.boolean,
cv.Optional(CONF_FREQUENCY, default=19): cv.float_range(0, 19), # kHz
cv.Optional(CONF_DEVIATION, default=6.75): cv.float_range(0, 90), # kHz
}
),
cv.Optional(CONF_SECTION_REFCLK): cv.Schema(
{
cv.Optional(CONF_FREQUENCY, default=32768): cv.int_range(31130, 34406), # Hz
cv.Optional(CONF_SOURCE, default="RCLK"): cv.enum(REFCLK_SOURCE),
cv.Optional(CONF_PRESCALER, default=1): cv.int_range(0, 4095),
}
),
cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema(
{
cv.Optional(CONF_ENABLE, default="False"): cv.boolean,
cv.Optional(CONF_THRESHOLD, default=-40): cv.int_range(-40, 0),
cv.Optional(CONF_ATTACK, default='0.5'): cv.enum(ACOMP_ATTACK),
cv.Optional(CONF_RELEASE, default="1000"): cv.enum(ACOMP_RELEASE),
cv.Optional(CONF_GAIN, default=15): cv.int_range(0, 20),
cv.Optional(CONF_PRESET, default="Custom"): cv.enum(ACOMP_PRESET),
}
),
cv.Optional(CONF_SECTION_LIMITER): cv.Schema(
{
cv.Optional(CONF_ENABLE, default="True"): cv.boolean,
cv.Optional(CONF_RELEASE_TIME, default=5): cv.float_range(0.25, 102.4),
}
),
cv.Optional(CONF_SECTION_ASQ): cv.Schema(
{
cv.Optional(CONF_OVERMOD, default="False"): cv.boolean,
cv.Optional(CONF_IALL, default="False"): cv.boolean,
cv.Optional(CONF_IALH, default="False"): cv.boolean,
cv.Optional(CONF_LEVEL_LOW, default=0): cv.float_range(-70, 0),
cv.Optional(CONF_DURATION_LOW, default=0): cv.int_range(0, 65535),
cv.Optional(CONF_LEVEL_HIGH, default=0): cv.float_range(-70, 0),
cv.Optional(CONF_DURATION_HIGH, default=0): cv.int_range(0, 65535),
}
),
cv.Optional(CONF_SECTION_RDS): cv.Schema(
{
cv.Optional(CONF_ENABLE, default=False): cv.boolean,
cv.Optional(CONF_DEVIATION, default=2.0): cv.float_range(0, 7.5), # kHz
cv.Optional(CONF_STATION): cv.string,
cv.Optional(CONF_TEXT): cv.string,
}
),
cv.Optional(CONF_CHIP_ID): text_sensor.text_sensor_schema( cv.Optional(CONF_CHIP_ID): text_sensor.text_sensor_schema(
entity_category=ENTITY_CATEGORY_DIAGNOSTIC, entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_CHIP, icon=ICON_CHIP,
@ -103,13 +294,13 @@ async def set_var(config, id, setter):
cg.add(setter(c)) cg.add(setter(c))
async def set_sensor(config, id, setter): async def new_sensor(config, id, setter):
if c := config.get(id): if c := config.get(id):
s = await sensor.new_sensor(c) s = await sensor.new_sensor(c)
cg.add(setter(s)) cg.add(setter(s))
async def set_text_sensor(config, id, setter): async def new_text_sensor(config, id, setter):
if c := config.get(id): if c := config.get(id):
s = await text_sensor.new_text_sensor(c) s = await text_sensor.new_text_sensor(c)
cg.add(setter(s)) cg.add(setter(s))
@ -121,11 +312,53 @@ async def to_code(config):
await i2c.register_i2c_device(var, config) await i2c.register_i2c_device(var, config)
reset_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) reset_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
cg.add(var.set_reset_pin(reset_pin)) cg.add(var.set_reset_pin(reset_pin))
await set_var(config, CONF_FREQUENCY, var.set_frequency) await set_var(config, CONF_OP_MODE, var.set_op_mode)
await set_var(config, CONF_MUTE, var.set_mute) await set_var(config, CONF_MUTE, var.set_mute)
await set_var(config, CONF_MONO, var.set_mono) await set_var(config, CONF_MONO, var.set_mono)
# await set_var(config, CONF_T1M_SEL, var.set_t1m_sel) await set_var(config, CONF_PRE_EMPHASIS, var.set_pre_emphasis)
await set_var(config, CONF_RDS_ENABLE, var.set_rds_enable) if tuner_config := config.get(CONF_SECTION_TUNER):
await set_var(config, CONF_RDS_STATION, var.set_rds_station) await set_var(tuner_config, CONF_FREQUENCY, var.set_frequency)
await set_var(config, CONF_RDS_TEXT, var.set_rds_text) await set_var(tuner_config, CONF_DEVIATION, var.set_audio_deviation)
await set_text_sensor(config, CONF_CHIP_ID, var.set_chip_id_text_sensor) await set_var(tuner_config, CONF_POWER, var.set_power)
await set_var(tuner_config, CONF_ANTCAP, var.set_antcap)
if analog_config := config.get(CONF_SECTION_ANALOG):
await set_var(analog_config, CONF_LEVEL, var.set_analog_level)
await set_var(analog_config, CONF_ATTENUATION, var.set_analog_attenuation)
if digital_config := config.get(CONF_SECTION_DIGITAL):
await set_var(digital_config, CONF_SAMPLE_RATE, var.set_digital_sample_rate)
await set_var(digital_config, CONF_SAMPLE_BITS, var.set_digital_sample_bits)
await set_var(digital_config, CONF_CHANNELS, var.set_digital_channels)
await set_var(digital_config, CONF_MODE, var.set_digital_mode)
await set_var(digital_config, CONF_CLOCK_EDGE, var.set_digital_clock_edge)
if pilot_config := config.get(CONF_SECTION_PILOT):
await set_var(pilot_config, CONF_ENABLE, var.set_pilot_enable)
await set_var(pilot_config, CONF_FREQUENCY, var.set_pilot_frequency)
await set_var(pilot_config, CONF_DEVIATION, var.set_pilot_deviation)
if refclk_config := config.get(CONF_SECTION_REFCLK):
await set_var(refclk_config, CONF_FREQUENCY, var.set_refclk_frequency)
await set_var(refclk_config, CONF_SOURCE, var.set_refclk_source)
await set_var(refclk_config, CONF_PRESCALER, var.set_refclk_prescaler)
if compressor_config := config.get(CONF_SECTION_COMPRESSOR):
await set_var(compressor_config, CONF_ENABLE, var.set_acomp_enable)
await set_var(compressor_config, CONF_THRESHOLD, var.set_acomp_threshold)
await set_var(compressor_config, CONF_ATTACK, var.set_acomp_attack)
await set_var(compressor_config, CONF_RELEASE, var.set_acomp_release)
await set_var(compressor_config, CONF_GAIN, var.set_acomp_gain)
await set_var(compressor_config, CONF_PRESET, var.set_acomp_preset)
if limiter_config := config.get(CONF_SECTION_LIMITER):
await set_var(limiter_config, CONF_ENABLE, var.set_limiter_enable)
await set_var(limiter_config, CONF_RELEASE_TIME, var.set_limiter_release_time)
if asq_config := config.get(CONF_SECTION_ASQ):
await set_var(asq_config, CONF_OVERMOD, var.set_asq_overmod_enable)
await set_var(asq_config, CONF_IALL, var.set_asq_iall_enable)
await set_var(asq_config, CONF_IALH, var.set_asq_ialh_enable)
await set_var(asq_config, CONF_LEVEL_LOW, var.set_asq_level_low)
await set_var(asq_config, CONF_DURATION_LOW, var.set_asq_duration_low)
await set_var(asq_config, CONF_LEVEL_HIGH, var.set_asq_level_high)
await set_var(asq_config, CONF_DURATION_HIGH, var.set_asq_duration_high)
if rds_config := config.get(CONF_SECTION_RDS):
await set_var(rds_config, CONF_ENABLE, var.set_rds_enable)
await set_var(rds_config, CONF_DEVIATION, var.set_rds_deviation)
await set_var(rds_config, CONF_STATION, var.set_rds_station)
await set_var(rds_config, CONF_TEXT, var.set_rds_text)
await new_text_sensor(config, CONF_CHIP_ID, var.set_chip_id_text_sensor)

View file

@ -3,11 +3,15 @@ from esphome.components import number
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_FREQUENCY, CONF_FREQUENCY,
UNIT_PERCENT, CONF_MODE,
UNIT_HERTZ,
UNIT_MILLISECOND,
UNIT_DECIBEL, UNIT_DECIBEL,
UNIT_EMPTY,
DEVICE_CLASS_FREQUENCY, DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_CURRENT, DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_DURATION,
DEVICE_CLASS_EMPTY, DEVICE_CLASS_EMPTY,
ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_CONFIG,
) )
@ -15,37 +19,245 @@ from .. import (
CONF_SI4713_ID, CONF_SI4713_ID,
Si4713Component, Si4713Component,
si4713_ns, si4713_ns,
# CONF_, CONF_SECTION_TUNER,
CONF_SECTION_ANALOG,
CONF_SECTION_DIGITAL,
CONF_SECTION_PILOT,
CONF_SECTION_REFCLK,
CONF_SECTION_COMPRESSOR,
CONF_SECTION_LIMITER,
CONF_SECTION_ASQ,
CONF_SECTION_RDS,
CONF_FREQUENCY,
CONF_DEVIATION,
CONF_POWER,
CONF_ANTCAP,
CONF_LEVEL,
CONF_SAMPLE_RATE,
CONF_PRESCALER,
CONF_THRESHOLD,
CONF_GAIN,
CONF_RELEASE_TIME,
CONF_LEVEL_LOW,
CONF_DURATION_LOW,
CONF_LEVEL_HIGH,
CONF_DURATION_HIGH,
UNIT_MEGA_HERTZ, UNIT_MEGA_HERTZ,
UNIT_KILO_HERTZ, UNIT_KILO_HERTZ,
UNIT_MICRO_AMPERE, UNIT_MILLI_VOLT,
UNIT_DECIBEL_MICRO_VOLT, UNIT_DECIBEL_MICRO_VOLT,
UNIT_PICO_FARAD,
) )
FrequencyNumber = si4713_ns.class_("FrequencyNumber", number.Number) FrequencyNumber = si4713_ns.class_("FrequencyNumber", number.Number)
AudioDeviationNumber = si4713_ns.class_("AudioDeviationNumber", number.Number)
PowerNumber = si4713_ns.class_("PowerNumber", number.Number)
AntcapNumber = si4713_ns.class_("AntcapNumber", number.Number)
AnalogLevelNumber = si4713_ns.class_("AnalogLevelNumber", number.Number)
DigitalSampleRateNumber = si4713_ns.class_("DigitalSampleRateNumber", number.Number)
PilotFrequencyNumber = si4713_ns.class_("PilotFrequencyNumber", number.Number)
PilotDeviationNumber = si4713_ns.class_("PilotDeviationNumber", number.Number)
RefClkFrequencyNumber = si4713_ns.class_("RefClkFrequencyNumber", number.Number)
RefClkPrescalerNumber = si4713_ns.class_("RefClkPrescalerNumber", number.Number)
AcompThresholdNumber = si4713_ns.class_("AcompThresholdNumber", number.Number)
AcompGainNumber = si4713_ns.class_("AcompGainNumber", number.Number)
LimiterReleaseTimeNumber = si4713_ns.class_("LimiterReleaseTimeNumber", number.Number)
AsqLevelLowNumber = si4713_ns.class_("AsqLevelLowNumber", number.Number)
AsqDurationLowNumber = si4713_ns.class_("AsqDurationLowNumber", number.Number)
AsqLevelHighNumber = si4713_ns.class_("AsqLevelHighNumber", number.Number)
AsqDurationHighNumber = si4713_ns.class_("AsqDurationHighNumber", number.Number)
RdsDeviationNumber = si4713_ns.class_("RdsDeviationNumber", number.Number)
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component), cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
cv.Optional(CONF_SECTION_TUNER): cv.Schema(
{
cv.Optional(CONF_FREQUENCY): number.number_schema( cv.Optional(CONF_FREQUENCY): number.number_schema(
FrequencyNumber, FrequencyNumber,
unit_of_measurement=UNIT_MEGA_HERTZ, unit_of_measurement=UNIT_MEGA_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY, device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG, entity_category=ENTITY_CATEGORY_CONFIG,
), ),
cv.Optional(CONF_DEVIATION): number.number_schema(
AudioDeviationNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_POWER): number.number_schema(
PowerNumber,
unit_of_measurement=UNIT_DECIBEL_MICRO_VOLT,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_ANTCAP): number.number_schema(
AntcapNumber,
unit_of_measurement=UNIT_PICO_FARAD,
device_class=DEVICE_CLASS_EMPTY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
}
),
cv.Optional(CONF_SECTION_ANALOG): cv.Schema(
{
cv.Optional(CONF_LEVEL): number.number_schema(
AnalogLevelNumber,
unit_of_measurement=UNIT_MILLI_VOLT,
device_class=DEVICE_CLASS_VOLTAGE,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
cv.Optional(CONF_SECTION_DIGITAL): cv.Schema(
{
cv.Optional(CONF_SAMPLE_RATE): number.number_schema(
DigitalSampleRateNumber,
unit_of_measurement=UNIT_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
cv.Optional(CONF_SECTION_PILOT): cv.Schema(
{
cv.Optional(CONF_FREQUENCY): number.number_schema(
PilotFrequencyNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_DEVIATION): number.number_schema(
PilotDeviationNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
cv.Optional(CONF_SECTION_REFCLK): cv.Schema(
{
cv.Optional(CONF_FREQUENCY): number.number_schema(
RefClkFrequencyNumber,
unit_of_measurement=UNIT_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_PRESCALER): number.number_schema(
RefClkPrescalerNumber,
unit_of_measurement=UNIT_EMPTY,
device_class=DEVICE_CLASS_EMPTY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema(
{
cv.Optional(CONF_THRESHOLD): number.number_schema(
AcompThresholdNumber,
unit_of_measurement=UNIT_DECIBEL,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_GAIN): number.number_schema(
AcompGainNumber,
unit_of_measurement=UNIT_DECIBEL,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
cv.Optional(CONF_SECTION_LIMITER): cv.Schema(
{
cv.Optional(CONF_RELEASE_TIME): number.number_schema(
LimiterReleaseTimeNumber,
unit_of_measurement=UNIT_MILLISECOND,
device_class=DEVICE_CLASS_DURATION,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
cv.Optional(CONF_SECTION_ASQ): cv.Schema(
{
cv.Optional(CONF_LEVEL_LOW): number.number_schema(
AsqLevelLowNumber,
unit_of_measurement=UNIT_DECIBEL,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_DURATION_LOW): number.number_schema(
AsqDurationLowNumber,
unit_of_measurement=UNIT_MILLISECOND,
device_class=DEVICE_CLASS_DURATION,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_LEVEL_HIGH): number.number_schema(
AsqLevelHighNumber,
unit_of_measurement=UNIT_DECIBEL,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_DURATION_HIGH): number.number_schema(
AsqDurationHighNumber,
unit_of_measurement=UNIT_MILLISECOND,
device_class=DEVICE_CLASS_DURATION,
entity_category=ENTITY_CATEGORY_CONFIG,
),
}
),
cv.Optional(CONF_SECTION_RDS): cv.Schema(
{
cv.Optional(CONF_DEVIATION): number.number_schema(
RdsDeviationNumber,
unit_of_measurement=UNIT_KILO_HERTZ,
device_class=DEVICE_CLASS_FREQUENCY,
entity_category=ENTITY_CATEGORY_CONFIG,
),
},
),
} }
) )
async def new_number(config, id, setter, min_value, max_value, step, *args): async def new_number(parent, config, id, setter, min_value, max_value, step, *args, **kwargs):
if c := config.get(id): if c := config.get(id):
if CONF_MODE in kwargs:
if CONF_MODE not in c or c[CONF_MODE] == number.NumberMode.NUMBER_MODE_AUTO:
c[CONF_MODE] = kwargs.get(CONF_MODE)
n = await number.new_number( n = await number.new_number(
c, *args, min_value=min_value, max_value=max_value, step=step c, *args, min_value=min_value, max_value=max_value, step=step
) )
await cg.register_parented(n, config[CONF_SI4713_ID]) await cg.register_parented(n, parent)
cg.add(setter(n)) cg.add(setter(n))
return n
async def to_code(config): async def to_code(config):
c = await cg.get_variable(config[CONF_SI4713_ID]) parent = await cg.get_variable(config[CONF_SI4713_ID])
await new_number(config, CONF_FREQUENCY, c.set_frequency_number, 76, 108, 0.05) if tuner_config := config.get(CONF_SECTION_TUNER):
await new_number(parent, tuner_config, CONF_FREQUENCY, parent.set_frequency_number, 76, 108, 0.05)
await new_number(parent, tuner_config, CONF_DEVIATION, parent.set_audio_deviation_number, 0, 90, 0.01)
await new_number(parent, tuner_config, CONF_POWER, parent.set_power_number, 88, 115, 1, mode = number.NumberMode.NUMBER_MODE_SLIDER)
await new_number(parent, tuner_config, CONF_ANTCAP, parent.set_antcap_number, 0, 191, 1, mode = number.NumberMode.NUMBER_MODE_SLIDER)
if analog_config := config.get(CONF_SECTION_ANALOG):
await new_number(parent, analog_config, CONF_LEVEL, parent.set_analog_level_number, 0, 1023, 1, mode = number.NumberMode.NUMBER_MODE_SLIDER)
if digital_config := config.get(CONF_SECTION_DIGITAL):
await new_number(parent, digital_config, CONF_SAMPLE_RATE, parent.set_digital_sample_rate_number, 32000, 48000, 1)
if pilot_config := config.get(CONF_SECTION_PILOT):
await new_number(parent, pilot_config, CONF_FREQUENCY, parent.set_pilot_frequency_number, 0, 19, 0.001)
await new_number(parent, pilot_config, CONF_DEVIATION, parent.set_pilot_deviation_number, 0, 90, 0.001)
if refclk_config := config.get(CONF_SECTION_REFCLK):
await new_number(parent, refclk_config, CONF_FREQUENCY, parent.set_refclk_frequency_number, 31130, 34406, 1)
await new_number(parent, refclk_config, CONF_PRESCALER, parent.set_refclk_prescaler_number, 0, 4095, 1)
if compressor_config := config.get(CONF_SECTION_COMPRESSOR):
await new_number(parent, compressor_config, CONF_THRESHOLD, parent.set_acomp_threshold_number, -40, 0, 1)
await new_number(parent, compressor_config, CONF_GAIN, parent.set_acomp_gain_number, 0, 20, 1)
if limiter_config := config.get(CONF_SECTION_LIMITER):
await new_number(parent, limiter_config, CONF_RELEASE_TIME, parent.set_limiter_release_time_number, 0.25, 102.4, 0.01, mode = number.NumberMode.NUMBER_MODE_SLIDER)
if asq_config := config.get(CONF_SECTION_ASQ):
await new_number(parent, asq_config, CONF_LEVEL_LOW, parent.set_asq_level_low_number, -70, 0, 1)
await new_number(parent, asq_config, CONF_DURATION_LOW, parent.set_asq_duration_low_number, 0, 65535, 1)
await new_number(parent, asq_config, CONF_LEVEL_HIGH, parent.set_asq_level_high_number, -70, 0, 1)
await new_number(parent, asq_config, CONF_DURATION_HIGH, parent.set_asq_duration_high_number, 0, 65535, 1)
if rds_config := config.get(CONF_SECTION_RDS):
await new_number(parent, rds_config, CONF_DEVIATION, parent.set_rds_deviation_number, 0, 7.5, 0.01)

View file

@ -0,0 +1,12 @@
#include "acomp_gain_number.h"
namespace esphome {
namespace si4713 {
void AcompGainNumber::control(float value) {
this->publish_state(value);
this->parent_->set_acomp_gain(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AcompGainNumber : public number::Number, public Parented<Si4713Component> {
public:
AcompGainNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "acomp_threshold_number.h"
namespace esphome {
namespace si4713 {
void AcompThresholdNumber::control(float value) {
this->publish_state(value);
this->parent_->set_acomp_threshold(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AcompThresholdNumber : public number::Number, public Parented<Si4713Component> {
public:
AcompThresholdNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "analog_level_number.h"
namespace esphome {
namespace si4713 {
void AnalogLevelNumber::control(float value) {
this->publish_state(value);
this->parent_->set_analog_level(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AnalogLevelNumber : public number::Number, public Parented<Si4713Component> {
public:
AnalogLevelNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "antcap_number.h"
namespace esphome {
namespace si4713 {
void AntcapNumber::control(float value) {
this->publish_state(value);
this->parent_->set_antcap(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AntcapNumber : public number::Number, public Parented<Si4713Component> {
public:
AntcapNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "audio_deviation_number.h"
namespace esphome {
namespace si4713 {
void AudioDeviationNumber::control(float value) {
this->publish_state(value);
this->parent_->set_audio_deviation(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AudioDeviationNumber : public number::Number, public Parented<Si4713Component> {
public:
AudioDeviationNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "digital_sample_rate_number.h"
namespace esphome {
namespace si4713 {
void DigitalSampleRateNumber::control(float value) {
this->publish_state(value);
this->parent_->set_digital_sample_rate(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class DigitalSampleRateNumber : public number::Number, public Parented<Si4713Component> {
public:
DigitalSampleRateNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "limiter_release_time_number.h"
namespace esphome {
namespace si4713 {
void LimiterReleaseTimeNumber::control(float value) {
this->publish_state(value);
this->parent_->set_limiter_release_time(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class LimiterReleaseTimeNumber : public number::Number, public Parented<Si4713Component> {
public:
LimiterReleaseTimeNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "pilot_deviation_number.h"
namespace esphome {
namespace si4713 {
void PilotDeviationNumber::control(float value) {
this->publish_state(value);
this->parent_->set_pilot_deviation(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class PilotDeviationNumber : public number::Number, public Parented<Si4713Component> {
public:
PilotDeviationNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "pilot_frequency_number.h"
namespace esphome {
namespace si4713 {
void PilotFrequencyNumber::control(float value) {
this->publish_state(value);
this->parent_->set_pilot_frequency(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class PilotFrequencyNumber : public number::Number, public Parented<Si4713Component> {
public:
PilotFrequencyNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "power_number.h"
namespace esphome {
namespace si4713 {
void PowerNumber::control(float value) {
this->publish_state(value);
this->parent_->set_power(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class PowerNumber : public number::Number, public Parented<Si4713Component> {
public:
PowerNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "rds_deviation_number.h"
namespace esphome {
namespace si4713 {
void RdsDeviationNumber::control(float value) {
this->publish_state(value);
this->parent_->set_rds_deviation(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class RdsDeviationNumber : public number::Number, public Parented<Si4713Component> {
public:
RdsDeviationNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "refclk_frequency_number.h"
namespace esphome {
namespace si4713 {
void RefClkFrequencyNumber::control(float value) {
this->publish_state(value);
this->parent_->set_refclk_frequency(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class RefClkFrequencyNumber : public number::Number, public Parented<Si4713Component> {
public:
RefClkFrequencyNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "refclk_prescaler_number.h"
namespace esphome {
namespace si4713 {
void RefClkPrescalerNumber::control(float value) {
this->publish_state(value);
this->parent_->set_refclk_prescaler(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class RefClkPrescalerNumber : public number::Number, public Parented<Si4713Component> {
public:
RefClkPrescalerNumber() = default;
protected:
void control(float value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -12,7 +12,7 @@ void BinaryOutput::dump_config() {
ESP_LOGCONFIG(TAG, " Pin: %d", this->pin_); ESP_LOGCONFIG(TAG, " Pin: %d", this->pin_);
} }
void Si4713BinaryOutput::write_state(bool state) { void BinaryOutput::write_state(bool state) {
this->parent_->set_gpio(this->pin_, state); this->parent_->set_gpio(this->pin_, state);
} }

View file

@ -9,34 +9,140 @@ from .. import (
CONF_SI4713_ID, CONF_SI4713_ID,
Si4713Component, Si4713Component,
si4713_ns, si4713_ns,
CONF_, CONF_SECTION_ANALOG,
ICON_SLEEP, CONF_SECTION_DIGITAL,
CONF_SECTION_REFCLK,
CONF_SECTION_COMPRESSOR,
CONF_PRE_EMPHASIS,
CONF_ATTENUATION,
CONF_SAMPLE_BITS,
CONF_CHANNELS,
CONF_MODE,
CONF_CLOCK_EDGE,
CONF_SOURCE,
CONF_ATTACK,
CONF_RELEASE,
CONF_PRESET,
ICON_SINE_WAVE, ICON_SINE_WAVE,
ICON_RESISTOR, ICON_RESISTOR,
# T1M_SEL, ICON_EAR_HEARING,
PRE_EMPHASIS,
LINE_ATTENUATION,
SAMPLE_BITS,
SAMPLE_CHANNELS,
DIGITAL_MODE,
DIGITAL_CLOCK_EDGE,
REFCLK_SOURCE,
ACOMP_ATTACK,
ACOMP_RELEASE,
ACOMP_PRESET,
) )
#T1mSelSelect = si4713_ns.class_("T1mSelSelect", select.Select) PreEmphasisSelect = si4713_ns.class_("PreEmphasisSelect", select.Select)
AnalogAttenuationSelect = si4713_ns.class_("AnalogAttenuationSelect", select.Select)
DigitalSampleBitsSelect = si4713_ns.class_("DigitalSampleBitsSelect", select.Select)
DigitalChannelsSelect = si4713_ns.class_("DigitalChannelsSelect", select.Select)
DigitalModeSelect = si4713_ns.class_("DigitalModeSelect", select.Select)
DigitalClockEdgeSelect = si4713_ns.class_("DigitalClockEdgeSelect", select.Select)
RefClkSourceSelect = si4713_ns.class_("RefClkSourceSelect", select.Select)
AcompAttackSelect = si4713_ns.class_("AcompAttackSelect", select.Select)
AcompReleaseSelect = si4713_ns.class_("AcompReleaseSelect", select.Select)
AcompPresetSelect = si4713_ns.class_("AcompPresetSelect", select.Select)
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component), cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
# cv.Optional(CONF_T1M_SEL): select.select_schema( cv.Optional(CONF_PRE_EMPHASIS): select.select_schema(
# T1mSelSelect, PreEmphasisSelect,
# entity_category=ENTITY_CATEGORY_CONFIG, entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_SLEEP, icon=ICON_SINE_WAVE,
# ), ),
cv.Optional(CONF_SECTION_ANALOG): cv.Schema(
{
cv.Optional(CONF_ATTENUATION): select.select_schema(
AnalogAttenuationSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESISTOR,
),
}
),
cv.Optional(CONF_SECTION_DIGITAL): cv.Schema(
{
cv.Optional(CONF_SAMPLE_BITS): select.select_schema(
DigitalSampleBitsSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
cv.Optional(CONF_CHANNELS): select.select_schema(
DigitalChannelsSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_EAR_HEARING,
),
cv.Optional(CONF_MODE): select.select_schema(
DigitalModeSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
cv.Optional(CONF_CLOCK_EDGE): select.select_schema(
DigitalClockEdgeSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_PULSE,
),
}
),
cv.Optional(CONF_SECTION_REFCLK): cv.Schema(
{
cv.Optional(CONF_SOURCE): select.select_schema(
RefClkSourceSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_PULSE,
),
}
),
cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema(
{
cv.Optional(CONF_ATTACK): select.select_schema(
AcompAttackSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SINE_WAVE,
),
cv.Optional(CONF_RELEASE): select.select_schema(
AcompReleaseSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SINE_WAVE,
),
cv.Optional(CONF_PRESET): select.select_schema(
AcompPresetSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SINE_WAVE,
),
}
),
} }
) )
async def new_select(config, id, setter, options): async def new_select(parent, config, id, setter, options):
if c := config.get(id): if c := config.get(id):
s = await select.new_select(c, options=list(options.keys())) s = await select.new_select(c, options=list(options.keys()))
await cg.register_parented(s, config[CONF_SI4713_ID]) await cg.register_parented(s, parent)
cg.add(setter(s)) cg.add(setter(s))
return s
async def to_code(config): async def to_code(config):
c = await cg.get_variable(config[CONF_SI4713_ID]) parent = await cg.get_variable(config[CONF_SI4713_ID])
# await new_select(config, CONF_T1M_SEL, c.set_t1m_sel_select, T1M_SEL) await new_select(parent, config, CONF_PRE_EMPHASIS, parent.set_pre_emphasis_select, PRE_EMPHASIS)
if analog_config := config.get(CONF_SECTION_ANALOG):
await new_select(parent, analog_config, CONF_ATTENUATION, parent.set_analog_attenuation_select, LINE_ATTENUATION)
if digital_config := config.get(CONF_SECTION_DIGITAL):
await new_select(parent, digital_config, CONF_SAMPLE_BITS, parent.set_digital_sample_bits_select, SAMPLE_BITS)
await new_select(parent, digital_config, CONF_CHANNELS, parent.set_digital_channels_select, SAMPLE_CHANNELS)
await new_select(parent, digital_config, CONF_MODE, parent.set_digital_mode_select, DIGITAL_MODE)
await new_select(parent, digital_config, CONF_CLOCK_EDGE, parent.set_digital_clock_edge_select, DIGITAL_CLOCK_EDGE)
if refclk_config := config.get(CONF_SECTION_REFCLK):
await new_select(parent, refclk_config, CONF_SOURCE, parent.set_refclk_source_select, REFCLK_SOURCE)
if compressor_config := config.get(CONF_SECTION_COMPRESSOR):
await new_select(parent, compressor_config, CONF_ATTACK, parent.set_acomp_attack_select, ACOMP_ATTACK)
await new_select(parent, compressor_config, CONF_RELEASE, parent.set_acomp_release_select, ACOMP_RELEASE)
await new_select(parent, compressor_config, CONF_PRESET, parent.set_acomp_preset_select, ACOMP_PRESET)

View file

@ -0,0 +1,14 @@
#include "acomp_attack_select.h"
namespace esphome {
namespace si4713 {
void AcompAttackSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_acomp_attack((AcompAttack) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AcompAttackSelect : public select::Select, public Parented<Si4713Component> {
public:
AcompAttackSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "acomp_preset_select.h"
namespace esphome {
namespace si4713 {
void AcompPresetSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_acomp_preset((AcompPreset) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AcompPresetSelect : public select::Select, public Parented<Si4713Component> {
public:
AcompPresetSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "acomp_release_select.h"
namespace esphome {
namespace si4713 {
void AcompReleaseSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_acomp_release((AcompRelease) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AcompReleaseSelect : public select::Select, public Parented<Si4713Component> {
public:
AcompReleaseSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "analog_attenuation_select.h"
namespace esphome {
namespace si4713 {
void AnalogAttenuationSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_analog_attenuation((LineAttenuation) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AnalogAttenuationSelect : public select::Select, public Parented<Si4713Component> {
public:
AnalogAttenuationSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "digital_channels_select.h"
namespace esphome {
namespace si4713 {
void DigitalChannelsSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_digital_channels((SampleChannels) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class DigitalChannelsSelect : public select::Select, public Parented<Si4713Component> {
public:
DigitalChannelsSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "digital_clock_edge_select.h"
namespace esphome {
namespace si4713 {
void DigitalClockEdgeSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_digital_clock_edge((DigitalClockEdge) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class DigitalClockEdgeSelect : public select::Select, public Parented<Si4713Component> {
public:
DigitalClockEdgeSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "digital_mode_select.h"
namespace esphome {
namespace si4713 {
void DigitalModeSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_digital_mode((DigitalMode) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class DigitalModeSelect : public select::Select, public Parented<Si4713Component> {
public:
DigitalModeSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "digital_sample_bits_select.h"
namespace esphome {
namespace si4713 {
void DigitalSampleBitsSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_digital_sample_bits((SampleBits) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class DigitalSampleBitsSelect : public select::Select, public Parented<Si4713Component> {
public:
DigitalSampleBitsSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "pre_emphasis_select.h"
namespace esphome {
namespace si4713 {
void PreEmphasisSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_pre_emphasis((PreEmphasis) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class PreEmphasisSelect : public select::Select, public Parented<Si4713Component> {
public:
PreEmphasisSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,14 @@
#include "refclk_source_select.h"
namespace esphome {
namespace si4713 {
void RefClkSourceSelect::control(const std::string &value) {
this->publish_state(value);
if (auto index = this->active_index()) {
this->parent_->set_refclk_source((RefClkSource) *index);
}
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/select/select.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class RefClkSourceSelect : public select::Select, public Parented<Si4713Component> {
public:
RefClkSourceSelect() = default;
protected:
void control(const std::string &value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -15,13 +15,12 @@ static const char *const TAG = "si4713";
Si4713Component::Si4713Component() { Si4713Component::Si4713Component() {
this->reset_pin_ = nullptr; this->reset_pin_ = nullptr;
this->reset_ = false; this->reset_ = false;
this->op_mode_ = OpMode::OPMODE_ANALOG;
this->frequency_ = 8750;
this->power_ = 115;
this->antcap_ = 0;
this->tx_acomp_preset_ = AcompPreset::ACOMP_CUSTOM;
memset(this->gpio_, 0, sizeof(gpio_)); memset(this->gpio_, 0, sizeof(gpio_));
// memset(&this->state_, 0, sizeof(this->state_));
this->rds_station_pos_ = 0;
this->rds_text_pos_ = 0;
// this->state_. = ;
// our defaults
// this->state_. = ; // start with tx enabled
} }
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) {
@ -66,171 +65,6 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size
void Si4713Component::rds_update_() {} void Si4713Component::rds_update_() {}
// overrides
void Si4713Component::setup() {
// CHIP STATE: POWER DOWN
if (!this->power_up()) {
this->mark_failed();
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(PropRefClkPreScale(1, 0)); // div1, RCLK source
// 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_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();
this->publish_mono();
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_(); });
}
void Si4713Component::dump_config() {
ESP_LOGCONFIG(TAG, "Si4713:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "failed!");
}
ESP_LOGCONFIG(TAG, " Chip: %s", this->chip_id_.c_str());
ESP_LOGCONFIG(TAG, " Frequency: %.2f MHz", this->get_frequency());
ESP_LOGCONFIG(TAG, " RDS station: %s", this->rds_station_.c_str());
ESP_LOGCONFIG(TAG, " RDS text: %s", this->rds_text_.c_str());
// TODO: ...and everything else...
LOG_UPDATE_INTERVAL(this);
}
void Si4713Component::update() {
/*
if (this->read_reg_(REG_)) {
this->publish_();
} else {
ESP_LOGE(TAG, "update cannot read the status register");
}
*/
}
void Si4713Component::loop() {}
//
bool Si4713Component::reset() { bool Si4713Component::reset() {
if (this->reset_pin_ == nullptr) { if (this->reset_pin_ == nullptr) {
ESP_LOGE(TAG, "cannot reset device, reset pin is not set"); ESP_LOGE(TAG, "cannot reset device, reset pin is not set");
@ -253,15 +87,16 @@ bool Si4713Component::reset() {
} }
bool Si4713Component::power_up() { bool Si4713Component::power_up() {
// Note: In FMTX component 1.0 and 2.0, a reset is required when the system // 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 // controller writes a command other than POWER_UP when in powerdown mode
this->reset(); this->reset();
CmdPowerUp cmd; CmdPowerUp cmd;
cmd.FUNC = 2; cmd.OPMODE = (uint8_t) this->op_mode_;
cmd.XOSCEN = 1; // TODO: external oscillator cmd.FUNC = 2; // transmit
cmd.OPMODE = 0x50; // TODO: digital cmd.XOSCEN = this->op_mode_ == OpMode::OPMODE_ANALOG ? 1 : 0; // auto-enable(?) xtal for analog mode
cmd.GPO2OEN = 0; // TODO: GPIO2 enable cmd.GPO2OEN = 0; // we do this later
cmd.CTSIEN = 0; // no interrupts
return this->send_cmd(cmd); return this->send_cmd(cmd);
} }
@ -277,7 +112,7 @@ bool Si4713Component::detect_chip_id() {
snprintf(buff, sizeof(buff), "Si47%02d Rev %d", res.PN, res.CHIPREV); snprintf(buff, sizeof(buff), "Si47%02d Rev %d", res.PN, res.CHIPREV);
this->chip_id_ = buff; this->chip_id_ = buff;
// TODO: support all transmitters 10/11/12/13/20/21 // TODO: support all transmitters 10/11/12/13/20/21, mask unsupported features
if (res.PN != 10 && res.PN != 11 && res.PN != 12 && res.PN != 13) { if (res.PN != 10 && res.PN != 11 && res.PN != 12 && res.PN != 13) {
ESP_LOGE(TAG, "Si47%02d is not supported", res.PN); ESP_LOGE(TAG, "Si47%02d is not supported", res.PN);
@ -317,124 +152,694 @@ bool Si4713Component::tune_wait() {
return true; return true;
} }
// config // overrides
void Si4713Component::set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; } void Si4713Component::setup() {
// CHIP STATE: POWER DOWN
void Si4713Component::set_frequency(float value) { if (!this->power_up()) {
if (!(CH_FREQ_MIN <= value && value <= CH_FREQ_MAX)) { this->mark_failed();
ESP_LOGE(TAG, "set_frequency(%.2f) invalid (%.2f - %.2f)", value, CH_FREQ_MIN, CH_FREQ_MAX);
return; return;
} }
// int f = clamp((int) std::lround((value - 76) * 20), CH_FREQ_RAW_MIN, CH_FREQ_RAW_MAX); if (!this->detect_chip_id()) {
// this->state_.CH_UPPER = (uint8_t) (f >> 8); this->mark_failed();
// this->state_.CH_LOWER = (uint8_t) (f & 0xff); return;
// this->write_reg_(REG_SYSTEM_ADDR); }
// this->write_reg_(REG_CH1_ADDR);
// CHIP STATE: POWER UP
// Set RCLK settings
this->set_prop(this->refclk_freq_);
this->set_prop(this->refclk_prescale_);
// Mono/Stereo?
this->set_prop(this->tx_pilot_frequency_);
this->set_prop(this->tx_pilot_deviation_);
this->set_prop(this->tx_component_enable_);
// Set Audio Deviation
this->set_prop(this->tx_audio_deviation_);
// Transmit RDS?
this->set_prop(this->tx_rds_deviation_);
// Preemphasis?
this->set_prop(this->tx_pre_emphasis_);
this->set_prop(this->tx_acomp_enable_);
// Compressor?
// if (tx_acomp_enable_.ACEN) {
this->set_prop(this->tx_acomp_threshold_);
this->set_prop(this->tx_acomp_attack_time_);
this->set_prop(this->tx_acomp_release_time_);
this->set_prop(this->tx_acomp_gain_);
//}
// Limiter?
// if (tx_acomp_enable_.LIMITEN) {
this->set_prop(tx_limiter_releasee_time_);
//}
// Tune
this->tune_freq(this->frequency_);
this->tune_power(this->power_, this->antcap_);
// CHIP STATE: TRANSMITTING
// if (this->op_mode_ == OpMode::OPMODE_DIGITAL) {
// Digital Audio Input?
this->set_prop(digital_input_format_);
this->set_prop(digital_input_sample_rate_);
//} else if (this->op_mode_ == OpMode::OPMODE_ANALOG) {
// Analog Audio Input?
this->set_prop(tx_line_input_level_);
//}
// Mute? Optional: Mute or Unmute Audio based on ASQ status
this->set_prop(this->tx_line_input_mute_);
// GPIO
this->send_cmd(CmdGpioCtl(1, 1, 0)); // enable gpio1 and gpio2, clock is on gpio3
this->send_cmd(CmdGpioSet(0, 0, 0)); // init gpio to low (TODO: config)
// AQS
this->set_prop(this->tx_asq_interrupt_source_);
this->set_prop(this->tx_asq_level_low_);
this->set_prop(this->tx_asq_duration_low_);
this->set_prop(this->tx_asq_level_high_);
this->set_prop(this->tx_asq_duration_high_);
// RDS
// TODO: PropTxRds*, CmdTxRdsPs, CmdTxRdsBuff
// publish
this->publish_mute();
this->publish_mono();
this->publish_pre_emphasis();
this->publish_frequency(); this->publish_frequency();
this->publish_audio_deviation();
this->publish_power();
this->publish_antcap();
this->publish_analog_level();
this->publish_analog_attenuation();
this->publish_digital_sample_rate();
this->publish_digital_sample_bits();
this->publish_digital_channels();
this->publish_digital_mode();
this->publish_digital_clock_edge();
this->publish_pilot_enable();
this->publish_pilot_frequency();
this->publish_pilot_deviation();
this->publish_refclk_frequency();
this->publish_refclk_source();
this->publish_refclk_prescaler();
this->publish_acomp_enable();
this->publish_acomp_threshold();
this->publish_acomp_attack();
this->publish_acomp_release();
this->publish_acomp_gain();
this->publish_acomp_preset();
this->publish_limiter_enable();
this->publish_limiter_release_time();
this->publish_asq_overmod_enable();
this->publish_asq_ialh_enable();
this->publish_asq_iall_enable();
this->publish_asq_level_low();
this->publish_asq_duration_low();
this->publish_asq_level_high();
this->publish_asq_duration_high();
this->publish_rds_enable();
this->publish_rds_deviation();
this->publish_rds_station();
this->publish_rds_text();
this->publish_gpio(0);
this->publish_gpio(1);
this->publish_gpio(2);
this->publish_chip_id();
this->set_interval(1000, [this]() { this->rds_update_(); });
} }
float Si4713Component::get_frequency() { void Si4713Component::dump_config() {
// uint16_t ch = ((uint16_t) this->state_.CH_UPPER << 8) | this->state_.CH_LOWER; ESP_LOGCONFIG(TAG, "Si4713:");
// return (float) ch / 20 + 76; LOG_I2C_DEVICE(this);
return 0; if (this->is_failed()) {
ESP_LOGE(TAG, "failed!");
}
ESP_LOGCONFIG(TAG, " Chip: %s", this->chip_id_.c_str());
ESP_LOGCONFIG(TAG, " Frequency: %.2f MHz", this->get_frequency());
ESP_LOGCONFIG(TAG, " RDS station: %s", this->rds_station_.c_str());
ESP_LOGCONFIG(TAG, " RDS text: %s", this->rds_text_.c_str());
// TODO: ...and everything else...
LOG_UPDATE_INTERVAL(this);
} }
void Si4713Component::update() {
// TODO: publish to sensors
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);
}
}
void Si4713Component::loop() {
ResGetIntStatus res1;
if (this->send_cmd(CmdGetIntStatus(), res1) && res1.ASQINT == 1) {
ResTxAsqStatus res2;
if (this->send_cmd(CmdTxAsqStatus(), res2)) {
ESP_LOGD(TAG, "ResTxAsqStatus %08X OVERMOD %d IALH %d IALL %d INLEVEL %d", res2.RESP[0], res2.OVERMOD, res2.IALH,
res2.IALL, res2.INLEVEL);
}
}
}
// config
#define CHECK_ENUM(value) \
if (value >= GET_ENUM_LAST(value)) { \
ESP_LOGE(TAG, "%s(%d) invalid", __func__, (int) value); \
return; \
}
#define CHECK_FLOAT_RANGE(value, min_value, max_value) \
if (!(min_value <= value && value <= max_value)) { \
ESP_LOGE(TAG, "%s(%.2f) invalid (%.2f - %.2f)", __func__, value, min_value, max_value); \
return; \
}
#define CHECK_INT_RANGE(value, min_value, max_value) \
if (!(min_value <= value && value <= max_value)) { \
ESP_LOGE(TAG, "%s(%d) invalid (%d - %d)", __func__, value, min_value, max_value); \
return; \
}
#define CHECK_TEXT_RANGE(value, max_size) \
if (value.size() > max_size) { \
ESP_LOGW(TAG, "%s(%s) invalid (max %d characters)", __func__, value.c_str(), max_size); \
value.resize(max_size); \
}
void Si4713Component::set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; }
void Si4713Component::set_op_mode(OpMode value) { this->op_mode_ = (OpMode) value; }
void Si4713Component::set_mute(bool value) { void Si4713Component::set_mute(bool value) {
// this->state_.MUTE = value ? 1 : 0; this->tx_line_input_mute_.LIMUTE = value ? 1 : 0;
// this->write_reg_(REG_SYSTEM_ADDR); this->tx_line_input_mute_.RIMUTE = value ? 1 : 0;
this->set_prop(this->tx_line_input_mute_);
this->publish_mute(); this->publish_mute();
} }
bool Si4713Component::get_mute() { bool Si4713Component::get_mute() {
// return this->state_.MUTE == 1; return this->tx_line_input_mute_.LIMUTE != 0 && this->tx_line_input_mute_.RIMUTE != 0;
return false;
} }
void Si4713Component::set_mono(bool value) { void Si4713Component::set_mono(bool value) {
// this->state_.MONO = value ? 1 : 0; // NOTE: analog/digital mono linked, easier to control this way
// this->write_reg_(REG_SYSTEM_ADDR); this->tx_component_enable_.LMR = value ? 0 : 1;
this->set_prop(this->tx_component_enable_);
this->publish_mono(); this->publish_mono();
this->digital_input_format_.IMONO = value ? 1 : 0;
this->set_prop(this->digital_input_format_);
this->publish_digital_channels();
} }
bool Si4713Component::get_mono() { bool Si4713Component::get_mono() { return this->tx_component_enable_.LMR == 0; }
// return this->state_.MONO == 1;
return false; void Si4713Component::set_pre_emphasis(PreEmphasis value) {
CHECK_ENUM(value)
this->tx_pre_emphasis_.FMPE = (uint16_t) value;
this->set_prop(this->tx_pre_emphasis_);
this->publish_pre_emphasis();
} }
PreEmphasis Si4713Component::get_pre_emphasis() { return (PreEmphasis) tx_pre_emphasis_.FMPE; }
void Si4713Component::set_frequency(float value) {
CHECK_FLOAT_RANGE(value, FREQ_MIN, FREQ_MAX)
this->frequency_ = (uint16_t) clamp((int) std::lround(value * 100), FREQ_RAW_MIN, FREQ_RAW_MAX);
this->tune_freq(this->frequency_);
this->publish_frequency();
}
float Si4713Component::get_frequency() { return (float) this->frequency_ / 100; }
void Si4713Component::set_audio_deviation(float value) {
CHECK_FLOAT_RANGE(value, TXADEV_MIN, TXADEV_MAX)
this->tx_audio_deviation_.TXADEV = (uint16_t) clamp((int) std::lround(value * 100), TXADEV_RAW_MIN, TXADEV_RAW_MAX);
this->set_prop(this->tx_audio_deviation_);
this->publish_audio_deviation();
}
float Si4713Component::get_audio_deviation() { return (float) this->tx_audio_deviation_.TXADEV / 100; }
void Si4713Component::set_power(int value) {
CHECK_INT_RANGE(value, POWER_MIN, POWER_MAX)
this->power_ = (uint8_t) value;
this->tune_power(this->power_, this->antcap_);
this->publish_power();
}
int Si4713Component::get_power() { return (int) this->power_; }
void Si4713Component::set_antcap(int value) {
CHECK_INT_RANGE(value, ANTCAP_MIN, ANTCAP_MAX)
this->antcap_ = (uint8_t) value;
this->tune_power(this->power_, this->antcap_);
this->publish_antcap();
}
int Si4713Component::get_antcap() { return (int) this->antcap_; }
void Si4713Component::set_analog_level(int value) {
CHECK_INT_RANGE(value, LILEVEL_MIN, LILEVEL_MAX)
this->tx_line_input_level_.LILEVEL = (uint16_t) value;
this->set_prop(this->tx_line_input_level_);
this->publish_analog_level();
}
int Si4713Component::get_analog_level() { return (int) this->tx_line_input_level_.LILEVEL; }
void Si4713Component::set_analog_attenuation(LineAttenuation value) {
CHECK_ENUM(value)
this->tx_line_input_level_.LIATTEN = (uint16_t) value;
this->set_prop(this->tx_line_input_level_);
this->publish_analog_attenuation();
}
LineAttenuation Si4713Component::get_analog_attenuation() {
return (LineAttenuation) this->tx_line_input_level_.LIATTEN;
}
void Si4713Component::set_digital_sample_rate(int value) {
CHECK_INT_RANGE(value, DISR_MIN, DISR_MAX)
this->digital_input_sample_rate_.DISR = (uint16_t) value;
this->set_prop(this->digital_input_sample_rate_);
this->publish_digital_sample_rate();
}
int Si4713Component::get_digital_sample_rate() { return (int) this->digital_input_sample_rate_.DISR; }
void Si4713Component::set_digital_sample_bits(SampleBits value) {
CHECK_ENUM(value)
this->digital_input_format_.ISIZE = (uint16_t) value;
this->set_prop(this->digital_input_format_);
this->publish_digital_sample_bits();
}
SampleBits Si4713Component::get_digital_sample_bits() { return (SampleBits) this->digital_input_format_.ISIZE; }
void Si4713Component::set_digital_channels(SampleChannels value) {
CHECK_ENUM(value)
this->digital_input_format_.IMONO = (uint16_t) value;
this->set_prop(this->digital_input_format_);
this->publish_digital_channels();
}
SampleChannels Si4713Component::get_digital_channels() { return (SampleChannels) this->digital_input_format_.IMONO; }
void Si4713Component::set_digital_mode(DigitalMode value) {
CHECK_ENUM(value)
this->digital_input_format_.IMODE = (uint16_t) value;
this->set_prop(this->digital_input_format_);
this->publish_digital_mode();
}
DigitalMode Si4713Component::get_digital_mode() { return (DigitalMode) this->digital_input_format_.IMODE; }
void Si4713Component::set_digital_clock_edge(DigitalClockEdge value) {
CHECK_ENUM(value)
this->digital_input_format_.IFALL = (uint16_t) value;
this->set_prop(this->digital_input_format_);
this->publish_digital_clock_edge();
}
DigitalClockEdge Si4713Component::get_digital_clock_edge() { return (DigitalClockEdge) digital_input_format_.IFALL; }
void Si4713Component::set_pilot_enable(bool value) {
this->tx_component_enable_.PILOT = value ? 1 : 0;
this->set_prop(this->tx_component_enable_);
this->publish_pilot_enable();
}
bool Si4713Component::get_pilot_enable() { return this->tx_component_enable_.PILOT != 0; }
void Si4713Component::set_pilot_frequency(float value) {
CHECK_FLOAT_RANGE(value, PILOT_FREQ_MIN, PILOT_FREQ_MAX)
this->tx_pilot_frequency_.FREQ =
(uint16_t) clamp((int) std::lround(value * 1000), PILOT_FREQ_RAW_MIN, PILOT_FREQ_RAW_MAX);
this->set_prop(this->tx_pilot_frequency_);
this->publish_pilot_frequency();
}
float Si4713Component::get_pilot_frequency() { return (float) this->tx_pilot_frequency_.FREQ / 1000; }
void Si4713Component::set_pilot_deviation(float value) {
CHECK_FLOAT_RANGE(value, TXPDEV_MIN, TXPDEV_MAX)
this->tx_pilot_deviation_.TXPDEV = (uint16_t) clamp((int) std::lround(value * 100), TXPDEV_RAW_MIN, TXPDEV_RAW_MAX);
this->set_prop(this->tx_pilot_deviation_);
this->publish_pilot_deviation();
}
float Si4713Component::get_pilot_deviation() { return (float) this->tx_pilot_deviation_.TXPDEV / 100; }
void Si4713Component::set_refclk_frequency(int value) {
CHECK_INT_RANGE(value, REFCLKF_MIN, REFCLKF_MAX)
this->refclk_freq_.REFCLKF = (uint16_t) value;
this->set_prop(this->refclk_freq_);
this->publish_refclk_frequency();
}
int Si4713Component::get_refclk_frequency() { return this->refclk_freq_.REFCLKF; }
void Si4713Component::set_refclk_source(RefClkSource value) {
CHECK_ENUM(value)
this->refclk_prescale_.RCLKSEL = (uint16_t) value;
this->set_prop(this->refclk_prescale_);
this->publish_refclk_source();
}
RefClkSource Si4713Component::get_refclk_source() { return (RefClkSource) this->refclk_prescale_.RCLKSEL; }
void Si4713Component::set_refclk_prescaler(int value) {
CHECK_INT_RANGE(value, RCLKP_MIN, RCLKP_MAX)
this->refclk_prescale_.RCLKP = (uint16_t) value;
this->set_prop(this->refclk_freq_);
this->publish_refclk_prescaler();
}
int Si4713Component::get_refclk_prescaler() { return (int) this->refclk_prescale_.RCLKP; }
void Si4713Component::set_acomp_enable(bool value) {
this->tx_acomp_enable_.ACEN = value ? 1 : 0;
this->set_prop(this->tx_acomp_enable_);
this->publish_acomp_enable();
}
bool Si4713Component::get_acomp_enable() { return this->tx_acomp_enable_.ACEN != 0; }
void Si4713Component::set_acomp_threshold(int value) {
CHECK_INT_RANGE(value, ACOMP_THRESHOLD_MIN, ACOMP_THRESHOLD_MAX)
this->tx_acomp_threshold_.THRESHOLD = (int16_t) value;
this->set_prop(this->tx_acomp_threshold_);
this->publish_acomp_threshold();
}
int Si4713Component::get_acomp_threshold() { return (int) this->tx_acomp_threshold_.THRESHOLD; }
void Si4713Component::set_acomp_attack(AcompAttack value) {
CHECK_ENUM(value)
this->tx_acomp_attack_time_.ATTACK = (uint16_t) value;
this->set_prop(this->tx_acomp_attack_time_);
this->publish_acomp_attack();
}
AcompAttack Si4713Component::get_acomp_attack() { return (AcompAttack) tx_acomp_attack_time_.ATTACK; }
void Si4713Component::set_acomp_release(AcompRelease value) {
CHECK_ENUM(value)
this->tx_acomp_release_time_.RELEASE = (uint16_t) value;
this->set_prop(this->tx_acomp_release_time_);
this->publish_acomp_release();
}
AcompRelease Si4713Component::get_acomp_release() { return (AcompRelease) this->tx_acomp_release_time_.RELEASE; }
void Si4713Component::set_acomp_gain(int value) {
CHECK_INT_RANGE(value, ACOMP_GAIN_MIN, ACOMP_GAIN_MAX)
this->tx_acomp_gain_.GAIN = (int16_t) value;
this->set_prop(this->tx_acomp_gain_);
this->publish_acomp_gain();
}
int Si4713Component::get_acomp_gain() { return (int) this->tx_acomp_gain_.GAIN; }
void Si4713Component::set_acomp_preset(AcompPreset value) {
CHECK_ENUM(value)
this->tx_acomp_preset_ = value;
switch (value) {
case AcompPreset::ACOMP_MINIMAL:
this->set_acomp_threshold(-40);
this->set_acomp_attack(AcompAttack::ATTACK_50MS);
this->set_acomp_release(AcompRelease::RELEASE_100MS);
this->set_acomp_gain(15);
break;
case AcompPreset::ACOMP_AGGRESSIVE:
this->set_acomp_threshold(-15);
this->set_acomp_attack(AcompAttack::ATTACK_05MS);
this->set_acomp_release(AcompRelease::RELEASE_1000MS);
this->set_acomp_gain(5);
break;
}
this->publish_acomp_preset();
}
AcompPreset Si4713Component::get_acomp_preset() { return this->tx_acomp_preset_; }
void Si4713Component::set_limiter_enable(bool value) {
this->tx_acomp_enable_.LIMITEN = value ? 1 : 0;
this->set_prop(this->tx_acomp_enable_);
this->publish_limiter_enable();
}
bool Si4713Component::get_limiter_enable() { return this->tx_acomp_enable_.LIMITEN != 0; }
void Si4713Component::set_limiter_release_time(float value) {
CHECK_FLOAT_RANGE(value, LMITERTC_MIN, LMITERTC_MAX)
this->tx_limiter_releasee_time_.LMITERTC =
(uint16_t) clamp((int) std::lround(512.0f / value), LMITERTC_RAW_MIN, LMITERTC_RAW_MAX);
this->set_prop(this->tx_limiter_releasee_time_);
this->publish_limiter_release_time();
}
float Si4713Component::get_limiter_release_time() { return (float) 512.0f / this->tx_limiter_releasee_time_.LMITERTC; }
void Si4713Component::set_asq_overmod_enable(bool value) {
this->tx_asq_interrupt_source_.OVERMODIEN = value ? 1 : 0;
this->set_prop(this->tx_asq_interrupt_source_);
this->publish_asq_overmod_enable();
}
bool Si4713Component::get_asq_overmod_enable() { return this->tx_asq_interrupt_source_.OVERMODIEN != 0; }
void Si4713Component::set_asq_iall_enable(bool value) {
this->tx_asq_interrupt_source_.IALLIEN = value ? 1 : 0;
this->set_prop(this->tx_asq_interrupt_source_);
this->publish_asq_iall_enable();
}
bool Si4713Component::get_asq_iall_enable() { return this->tx_asq_interrupt_source_.IALLIEN != 0; }
void Si4713Component::set_asq_ialh_enable(bool value) {
this->tx_asq_interrupt_source_.IALHIEN = value ? 1 : 0;
this->set_prop(this->tx_asq_interrupt_source_);
this->publish_asq_ialh_enable();
}
bool Si4713Component::get_asq_ialh_enable() { return this->tx_asq_interrupt_source_.IALHIEN != 0; }
void Si4713Component::set_asq_level_low(int value) {
CHECK_INT_RANGE(value, IALTH_MIN, IALTH_MAX)
this->tx_asq_level_low_.IALLTH = (int8_t) value;
this->set_prop(this->tx_asq_level_low_);
this->publish_asq_level_low();
}
int Si4713Component::get_asq_level_low() { return (int) this->tx_asq_level_low_.IALLTH; }
void Si4713Component::set_asq_duration_low(int value) {
CHECK_INT_RANGE(value, IALDUR_MIN, IALDUR_MAX)
this->tx_asq_duration_low_.IALLDUR = (uint16_t) value;
this->set_prop(this->tx_asq_duration_low_);
this->publish_asq_duration_low();
}
int Si4713Component::get_asq_duration_low() { return (int) this->tx_asq_duration_low_.IALLDUR; }
void Si4713Component::set_asq_level_high(int value) {
CHECK_INT_RANGE(value, IALTH_MIN, IALTH_MAX)
this->tx_asq_level_high_.IALHTH = (int8_t) value;
this->set_prop(this->tx_asq_level_high_);
this->publish_asq_level_high();
}
int Si4713Component::get_asq_level_high() { return (int) this->tx_asq_level_high_.IALHTH; }
void Si4713Component::set_asq_duration_high(int value) {
CHECK_INT_RANGE(value, IALDUR_MIN, IALDUR_MAX)
this->tx_asq_duration_high_.IALHDUR = (uint16_t) value;
this->set_prop(this->tx_asq_duration_high_);
this->publish_asq_duration_high();
}
int Si4713Component::get_asq_duration_high() { return (int) this->tx_asq_duration_high_.IALHDUR; }
void Si4713Component::set_rds_enable(bool value) { void Si4713Component::set_rds_enable(bool value) {
// TODO this->tx_component_enable_.RDS = value ? 0 : 1;
this->set_prop(this->tx_component_enable_);
this->publish_rds_enable(); this->publish_rds_enable();
} }
bool Si4713Component::get_rds_enable() { bool Si4713Component::get_rds_enable() { return this->tx_component_enable_.RDS != 0; }
// return this->state_.RDSEN == 1;
return false; void Si4713Component::set_rds_deviation(float value) {
CHECK_FLOAT_RANGE(value, TXRDEV_MIN, TXRDEV_MAX)
this->tx_rds_deviation_.TXRDEV = (uint16_t) clamp((int) std::lround(value * 100), TXRDEV_RAW_MIN, TXRDEV_RAW_MAX);
this->set_prop(this->tx_rds_deviation_);
this->publish_rds_deviation();
} }
float Si4713Component::get_rds_deviation() { return (float) this->tx_rds_deviation_.TXRDEV / 100; }
void Si4713Component::set_rds_station(const std::string &value) { void Si4713Component::set_rds_station(const std::string &value) {
this->rds_station_ = value; this->rds_station_ = value;
this->rds_station_pos_ = 0; // this->rds_station_pos_ = 0;
if (this->rds_station_.size() > RDS_STATION_MAX) { CHECK_TEXT_RANGE(this->rds_station_, RDS_STATION_MAX)
ESP_LOGW(TAG, "rds station too long '%s' (max %d characters)", value.c_str(), RDS_STATION_MAX);
this->rds_station_.resize(RDS_STATION_MAX);
}
this->publish_rds_station(); this->publish_rds_station();
} }
void Si4713Component::set_rds_text(const std::string &value) { void Si4713Component::set_rds_text(const std::string &value) {
this->rds_text_ = value; this->rds_text_ = value;
this->rds_text_pos_ = 0; CHECK_TEXT_RANGE(this->rds_text_, RDS_TEXT_MAX)
if (this->rds_text_.size() > RDS_TEXT_MAX) {
ESP_LOGW(TAG, "rds text to long '%s' (max %d characters)", value.c_str(), RDS_TEXT_MAX);
this->rds_text_.resize(RDS_TEXT_MAX);
}
this->publish_rds_text(); this->publish_rds_text();
} }
void Si4713Component::set_gpio(uint8_t pin, bool value) { void Si4713Component::set_gpio(uint8_t pin, bool value) {
if (pin > 2) { if (pin > 2) {
ESP_LOGE(TAG, "set_gpio(%d, %d) invalid pin number, 0 to 2", pin, value ? 1 : 0); ESP_LOGE(TAG, "%s(%d, %d) invalid pin number (0 to 2)", __func__, pin, value);
return; return;
} }
ESP_LOGD(TAG, "set_gpio(%d, %d)", pin, value ? 1 : 0);
this->gpio_[pin] = value ? 1 : 0; this->gpio_[pin] = value ? 1 : 0;
this->send_cmd(CmdGpioCtl(this->gpio_[0], this->gpio_[1], this->gpio_[2])); this->send_cmd(CmdGpioSet(this->gpio_[0], this->gpio_[1], this->gpio_[2]));
this->publish_gpio(pin); this->publish_gpio(pin);
} }
bool Si4713Component::get_gpio(uint8_t pin) { bool Si4713Component::get_gpio(uint8_t pin) {
if (pin > 2) { if (pin > 2) {
ESP_LOGE(TAG, "get_gpio(%d) invalid pin number, 0 to 2", pin); ESP_LOGE(TAG, "%s(%d) invalid pin number (0 to 2)", __func__, pin);
return false; return false;
} }
return this->gpio_[pin]; return this->gpio_[pin] != 0;
} }
// publish // publish
void Si4713Component::publish_() {
// this->publish(this->_sensor_, this->state_.);
}
void Si4713Component::publish_chip_id() { this->publish(this->chip_id_text_sensor_, this->chip_id_); }
void Si4713Component::publish_frequency() { this->publish(this->frequency_number_, this->get_frequency()); }
void Si4713Component::publish_mute() { this->publish(this->mute_switch_, this->get_mute()); } void Si4713Component::publish_mute() { this->publish(this->mute_switch_, this->get_mute()); }
void Si4713Component::publish_mono() { this->publish(this->mono_switch_, this->get_mono()); } void Si4713Component::publish_mono() { this->publish(this->mono_switch_, this->get_mono()); }
void Si4713Component::publish_pre_emphasis() {
this->publish(this->pre_emphasis_select_, (size_t) this->get_pre_emphasis());
}
void Si4713Component::publish_frequency() { this->publish(this->frequency_number_, this->get_frequency()); }
void Si4713Component::publish_audio_deviation() {
this->publish(this->audio_deviation_number_, this->get_audio_deviation());
}
void Si4713Component::publish_power() { this->publish(this->power_number_, this->get_power()); }
void Si4713Component::publish_antcap() { this->publish(this->antcap_number_, this->get_antcap()); }
void Si4713Component::publish_analog_level() { this->publish(this->analog_level_number_, this->get_analog_level()); }
void Si4713Component::publish_analog_attenuation() {
this->publish(this->analog_attenuation_select_, (size_t) this->get_analog_attenuation());
}
void Si4713Component::publish_digital_sample_bits() {
this->publish(this->digital_sample_bits_select_, (size_t) this->get_digital_sample_bits());
}
void Si4713Component::publish_digital_sample_rate() {
this->publish(this->digital_sample_rate_number_, this->get_digital_sample_rate());
}
void Si4713Component::publish_digital_channels() {
this->publish(this->digital_channels_select_, (size_t) this->get_digital_channels());
}
void Si4713Component::publish_digital_mode() {
this->publish(this->digital_mode_select_, (size_t) this->get_digital_mode());
}
void Si4713Component::publish_digital_clock_edge() {
this->publish(this->digital_clock_edge_select_, (size_t) this->get_digital_clock_edge());
}
void Si4713Component::publish_pilot_enable() { this->publish(this->pilot_enable_switch_, this->get_pilot_enable()); }
void Si4713Component::publish_pilot_frequency() {
this->publish(this->pilot_frequency_number_, this->get_pilot_frequency());
}
void Si4713Component::publish_pilot_deviation() {
this->publish(this->pilot_deviation_number_, this->get_pilot_deviation());
}
void Si4713Component::publish_refclk_frequency() {
this->publish(this->refclk_frequency_number_, this->get_refclk_frequency());
}
void Si4713Component::publish_refclk_source() {
this->publish(this->refclk_source_select_, (size_t) this->get_refclk_source());
}
void Si4713Component::publish_refclk_prescaler() {
this->publish(this->refclk_prescaler_number_, this->get_refclk_prescaler());
}
void Si4713Component::publish_acomp_enable() { this->publish(this->acomp_enable_switch_, this->get_acomp_enable()); }
void Si4713Component::publish_acomp_threshold() {
this->publish(this->acomp_threshold_number_, this->get_acomp_threshold());
}
void Si4713Component::publish_acomp_attack() {
this->publish(this->acomp_attack_select_, (size_t) this->get_acomp_attack());
}
void Si4713Component::publish_acomp_release() {
this->publish(this->acomp_release_select_, (size_t) this->get_acomp_release());
}
void Si4713Component::publish_acomp_gain() { this->publish(this->acomp_gain_number_, this->get_acomp_gain()); }
void Si4713Component::publish_acomp_preset() {
this->publish(this->acomp_preset_select_, (size_t) this->get_acomp_preset());
}
void Si4713Component::publish_limiter_enable() {
this->publish(this->limiter_enable_switch_, this->get_limiter_enable());
}
void Si4713Component::publish_limiter_release_time() {
this->publish(this->limiter_release_time_number_, this->get_limiter_release_time());
}
void Si4713Component::publish_asq_overmod_enable() {
this->publish(this->asq_overmod_enable_switch_, this->get_asq_overmod_enable());
}
void Si4713Component::publish_asq_iall_enable() {
this->publish(this->asq_iall_enable_switch_, this->get_asq_iall_enable());
}
void Si4713Component::publish_asq_ialh_enable() {
this->publish(this->asq_ialh_enable_switch_, this->get_asq_ialh_enable());
}
void Si4713Component::publish_asq_level_low() { this->publish(this->asq_level_low_number_, this->get_asq_level_low()); }
void Si4713Component::publish_asq_duration_low() {
this->publish(this->asq_duration_low_number_, this->get_asq_duration_low());
}
void Si4713Component::publish_asq_level_high() {
this->publish(this->asq_level_high_number_, this->get_asq_level_high());
}
void Si4713Component::publish_asq_duration_high() {
this->publish(this->asq_duration_high_number_, this->get_asq_duration_high());
}
void Si4713Component::publish_rds_enable() { this->publish(this->rds_enable_switch_, this->get_rds_enable()); } void Si4713Component::publish_rds_enable() { this->publish(this->rds_enable_switch_, this->get_rds_enable()); }
void Si4713Component::publish_rds_deviation() { this->publish(this->rds_deviation_number_, this->get_rds_deviation()); }
void Si4713Component::publish_rds_station() { this->publish(this->rds_station_text_, this->rds_station_); } void Si4713Component::publish_rds_station() { this->publish(this->rds_station_text_, this->rds_station_); }
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_); }
@ -442,19 +847,21 @@ void Si4713Component::publish_rds_text() { this->publish(this->rds_text_text_, t
void Si4713Component::publish_gpio(uint8_t pin) { void Si4713Component::publish_gpio(uint8_t pin) {
switch (pin) { switch (pin) {
case 0: case 0:
this->publish(this->gpio1_switch_, this->gpio_[pin]); this->publish(this->gpio1_switch_, this->gpio_[pin] != 0);
break; break;
case 1: case 1:
this->publish(this->gpio2_switch_, this->gpio_[pin]); this->publish(this->gpio2_switch_, this->gpio_[pin] != 0);
break; break;
case 2: case 2:
this->publish(this->gpio3_switch_, this->gpio_[pin]); this->publish(this->gpio3_switch_, this->gpio_[pin] != 0);
break; break;
default: default:
return; return;
} }
} }
void Si4713Component::publish_chip_id() { this->publish(this->chip_id_text_sensor_, this->chip_id_); }
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) {

View file

@ -29,16 +29,88 @@ 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 {
struct Si4713State state_;
uint8_t regs_[sizeof(struct Si4713State)];
};
void write_reg_(uint8_t addr); // config
bool read_reg_(uint8_t addr);
OpMode op_mode_;
uint16_t frequency_;
uint8_t power_;
uint8_t antcap_;
PropTxComponentEnable tx_component_enable_;
PropTxAudioDeviation tx_audio_deviation_;
PropTxPreEmphasis tx_pre_emphasis_;
PropTxPilotFrequency tx_pilot_frequency_;
PropTxPilotDeviation tx_pilot_deviation_;
PropTxLineInputLevel tx_line_input_level_;
PropTxLineInputMute tx_line_input_mute_;
PropDigitalInputFormat digital_input_format_;
PropDigitalInputSampleRate digital_input_sample_rate_;
PropRefClkFreq refclk_freq_;
PropRefClkPreScale refclk_prescale_;
PropTxAcompEnable tx_acomp_enable_;
PropTxAcompThreshold tx_acomp_threshold_;
PropTxAcompAttackTime tx_acomp_attack_time_;
PropTxAcompReleaseTime tx_acomp_release_time_;
AcompPreset tx_acomp_preset_;
PropTxAcompGain tx_acomp_gain_;
PropTxLimiterReleaseTime tx_limiter_releasee_time_;
PropTxAsqInterruptSource tx_asq_interrupt_source_;
PropTxAsqLevelLow tx_asq_level_low_;
PropTxAsqDurationLow tx_asq_duration_low_;
PropTxAsqLevelHigh tx_asq_level_high_;
PropTxAsqDurationHigh tx_asq_duration_high_;
PropTxRdsDeviation tx_rds_deviation_;
uint8_t gpio_[3];
// TODO
/*
// general
op_mode: Analog / Analog, Digital
mute: False
mono: False
pre_emphasis: 75us / 75us, 50us, Disabled, Reserved
// tune
frequency: 87.50 (MHz) / 0.05
audio_deviation: 68.25 (kHz) 0 to 90 / .01
power: 115 (dBuV) 88 to 115 / 1
antcap: 0 (auto) 0 to 191 / 1
// line input
line_level: 636 (mVPK) / ? to ?
line_attenuation: 60 (kOhm) / 190, 301, 416, 636 mV or 396, 100, 74, 60 kOhm
// digital input
digital_sample_rate: 44100 (Hz) / 32000 to 48000
digital_sample_precision: 16 (bits) / 16, 20, 24, 8
digital_channels: 0 / 0 stereo 1 mono
digital_mode: Default / Default, I2S, Left-justified, MSB at 1st DCLK rising edge after DFS Pulse, MSB ... 2nd ...
// stereo
pilot_enable: True
pilot_frequency: 19000 (Hz) 0 to 19000 / 1
pilot_deviation: 6750 (Hz) 0 to 90000 / 1
// refclk
refclkf: 32768 (Hz) 31130 to 34406 / 1
rclksel: RCLK / RCLK, DCLK
rclkp: 1
// compressor
acomp_enable: False
acomp_threshold: -40 (dBFS) -40 to 0 / 1
acomp_attack: 0.5 (ms) 0.5 to 5 / .5
acomp_release: 1000 (ms) / 100, 200, 350, 525, 1000
acomp_gain: 15 (dB) / 0 to 20
acomp_preset:
Disabled => acomp_enable: False
Minimal => acomp_enable: True, acomp_threshold: -40, acomp_attack: 5, acomp_release: 100, acomp_gain: 15
Aggressive => acomp_enable: True, acomp_threshold: -15, acomp_attack: 0.5, acomp_release: 1000, acomp_gain: 5
// limiter
limiter_enable: True
limiter_release_time: 5.01 (ms) / 5 = 102.39 ms .. 2000 = 0.25 ms
// rds
rds_enable: False
rds_deviation: 2 (kHz) 0 to 7.5 / .01
rds_station:
rds_text:
*/ */
bool send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size); bool send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size);
template<typename CMD> bool send_cmd(const CMD &cmd) { template<typename CMD> bool send_cmd(const CMD &cmd) {
@ -66,34 +138,117 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
std::string rds_station_; std::string rds_station_;
std::string rds_text_; std::string rds_text_;
uint8_t rds_station_pos_;
uint8_t rds_text_pos_;
uint8_t rds_upd_;
void rds_update_(); void rds_update_();
SUB_TEXT_SENSOR(chip_id) 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();
// TODO: sensors TX_TUNE_STATUS / FREQ, RFuV, ANTCAP, NL // TODO: sensors TX_TUNE_STATUS / FREQ, RFuV, ANTCAP, NL
// TODO: sensors TX_ASQ_STATUS / OVERMOD, IALH, IALL, INLEVEL // TODO: sensors TX_ASQ_STATUS / OVERMOD, IALH, IALL, INLEVEL
SUB_NUMBER(frequency)
// general config
SUB_SWITCH(mute) SUB_SWITCH(mute)
SUB_SWITCH(mono) SUB_SWITCH(mono)
SUB_SELECT(pre_emphasis)
// tuner
SUB_NUMBER(frequency)
SUB_NUMBER(audio_deviation)
SUB_NUMBER(power)
SUB_NUMBER(antcap)
// analog
SUB_NUMBER(analog_level)
SUB_SELECT(analog_attenuation)
// digital
SUB_NUMBER(digital_sample_rate)
SUB_SELECT(digital_sample_bits)
SUB_SELECT(digital_channels)
SUB_SELECT(digital_mode)
SUB_SELECT(digital_clock_edge)
// pilot
SUB_SWITCH(pilot_enable)
SUB_NUMBER(pilot_frequency)
SUB_NUMBER(pilot_deviation)
// refclk
SUB_NUMBER(refclk_frequency)
SUB_SELECT(refclk_source)
SUB_NUMBER(refclk_prescaler)
// compressor
SUB_SWITCH(acomp_enable)
SUB_NUMBER(acomp_threshold)
SUB_SELECT(acomp_attack)
SUB_SELECT(acomp_release)
SUB_NUMBER(acomp_gain)
SUB_SELECT(acomp_preset)
// limiter
SUB_SWITCH(limiter_enable)
SUB_NUMBER(limiter_release_time)
// asq
SUB_SWITCH(asq_overmod_enable)
SUB_SWITCH(asq_iall_enable)
SUB_SWITCH(asq_ialh_enable)
SUB_NUMBER(asq_level_low)
SUB_NUMBER(asq_duration_low)
SUB_NUMBER(asq_level_high)
SUB_NUMBER(asq_duration_high)
// rds
SUB_SWITCH(rds_enable) SUB_SWITCH(rds_enable)
SUB_NUMBER(rds_deviation)
SUB_TEXT(rds_station) SUB_TEXT(rds_station)
SUB_TEXT(rds_text) SUB_TEXT(rds_text)
// output
SUB_SWITCH(gpio1) SUB_SWITCH(gpio1)
SUB_SWITCH(gpio2) SUB_SWITCH(gpio2)
SUB_SWITCH(gpio3) SUB_SWITCH(gpio3)
// sensors
SUB_TEXT_SENSOR(chip_id)
void publish_();
void publish_chip_id();
void publish_frequency();
void publish_mute(); void publish_mute();
void publish_mono(); void publish_mono();
void publish_pre_emphasis();
void publish_frequency();
void publish_audio_deviation();
void publish_power();
void publish_antcap();
void publish_analog_level();
void publish_analog_attenuation();
void publish_digital_sample_rate();
void publish_digital_sample_bits();
void publish_digital_channels();
void publish_digital_mode();
void publish_digital_clock_edge();
void publish_pilot_enable();
void publish_pilot_frequency();
void publish_pilot_deviation();
void publish_refclk_frequency();
void publish_refclk_source();
void publish_refclk_prescaler();
void publish_acomp_enable();
void publish_acomp_threshold();
void publish_acomp_attack();
void publish_acomp_release();
void publish_acomp_gain();
void publish_acomp_preset();
void publish_limiter_enable();
void publish_limiter_release_time();
void publish_asq_overmod_enable();
void publish_asq_iall_enable();
void publish_asq_ialh_enable();
void publish_asq_level_low();
void publish_asq_duration_low();
void publish_asq_level_high();
void publish_asq_duration_high();
void publish_rds_enable(); void publish_rds_enable();
void publish_rds_deviation();
void publish_rds_station(); void publish_rds_station();
void publish_rds_text(); void publish_rds_text();
void publish_gpio(uint8_t pin); void publish_gpio(uint8_t pin);
void publish_chip_id();
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);
@ -110,23 +265,84 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice {
void update() override; void update() override;
void loop() override; void loop() override;
bool reset(); // non-mutable (opmode might be)
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_op_mode(OpMode value);
float get_frequency();
void set_mute(bool value); void set_mute(bool value);
bool get_mute(); bool get_mute();
void set_mono(bool value); void set_mono(bool value);
bool get_mono(); bool get_mono();
void set_pre_emphasis(PreEmphasis value);
PreEmphasis get_pre_emphasis();
void set_frequency(float value);
float get_frequency();
void set_audio_deviation(float value);
float get_audio_deviation();
void set_power(int value);
int get_power();
void set_antcap(int value);
int get_antcap();
void set_analog_level(int value);
int get_analog_level();
void set_analog_attenuation(LineAttenuation value);
LineAttenuation get_analog_attenuation();
void set_digital_sample_rate(int value);
int get_digital_sample_rate();
void set_digital_sample_bits(SampleBits value);
SampleBits get_digital_sample_bits();
void set_digital_channels(SampleChannels value);
SampleChannels get_digital_channels();
void set_digital_mode(DigitalMode value);
DigitalMode get_digital_mode();
void set_digital_clock_edge(DigitalClockEdge value);
DigitalClockEdge get_digital_clock_edge();
void set_pilot_enable(bool value);
bool get_pilot_enable();
void set_pilot_frequency(float value);
float get_pilot_frequency();
void set_pilot_deviation(float value);
float get_pilot_deviation();
void set_refclk_frequency(int value);
int get_refclk_frequency();
void set_refclk_source(RefClkSource value);
RefClkSource get_refclk_source();
void set_refclk_prescaler(int value);
int get_refclk_prescaler();
void set_acomp_enable(bool value);
bool get_acomp_enable();
void set_acomp_threshold(int value);
int get_acomp_threshold();
void set_acomp_attack(AcompAttack value);
AcompAttack get_acomp_attack();
void set_acomp_release(AcompRelease value);
AcompRelease get_acomp_release();
void set_acomp_gain(int value);
int get_acomp_gain();
void set_acomp_preset(AcompPreset value);
AcompPreset get_acomp_preset();
void set_limiter_enable(bool value);
bool get_limiter_enable();
void set_limiter_release_time(float value);
float get_limiter_release_time();
void set_asq_overmod_enable(bool value);
bool get_asq_overmod_enable();
void set_asq_iall_enable(bool value);
bool get_asq_iall_enable();
void set_asq_ialh_enable(bool value);
bool get_asq_ialh_enable();
void set_asq_level_low(int value);
int get_asq_level_low();
void set_asq_duration_low(int value);
int get_asq_duration_low();
void set_asq_level_high(int value);
int get_asq_level_high();
void set_asq_duration_high(int value);
int get_asq_duration_high();
void set_rds_enable(bool value); void set_rds_enable(bool value);
bool get_rds_enable(); bool get_rds_enable();
void set_rds_deviation(float value);
float get_rds_deviation();
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); void set_gpio(uint8_t pin, bool value);

View file

@ -5,11 +5,140 @@ namespace si4713 {
static const uint8_t SI4710_STATUS_CTS = 0x80; static const uint8_t SI4710_STATUS_CTS = 0x80;
static const float CH_FREQ_MIN = 76; static const float FREQ_MIN = 76;
static const float CH_FREQ_MAX = 108; static const float FREQ_MAX = 108;
static const int FREQ_RAW_MIN = 7600;
static const int FREQ_RAW_MAX = 10800;
static const int POWER_MIN = 88;
static const int POWER_MAX = 120;
static const int ANTCAP_MIN = 0;
static const int ANTCAP_MAX = 191;
static const int LILEVEL_MIN = 0;
static const int LILEVEL_MAX = 1023; // no max in the datasheet, only that it is 10 bits
static const int DISR_MIN = 32000;
static const int DISR_MAX = 48000;
static const float PILOT_FREQ_MIN = 0;
static const float PILOT_FREQ_MAX = 19;
static const int PILOT_FREQ_RAW_MIN = 0;
static const int PILOT_FREQ_RAW_MAX = 19000;
static const float TXADEV_MIN = 0;
static const float TXADEV_MAX = 90;
static const int TXADEV_RAW_MIN = 0;
static const int TXADEV_RAW_MAX = 9000;
static const float TXPDEV_MIN = 0;
static const float TXPDEV_MAX = 90;
static const int TXPDEV_RAW_MIN = 0;
static const int TXPDEV_RAW_MAX = 9000;
static const float TXRDEV_MIN = 0;
static const float TXRDEV_MAX = 7.5f;
static const int TXRDEV_RAW_MIN = 0;
static const int TXRDEV_RAW_MAX = 750;
static const int REFCLKF_MIN = 31130;
static const int REFCLKF_MAX = 34406;
static const int RCLKP_MIN = 1;
static const int RCLKP_MAX = 4095;
static const int ACOMP_THRESHOLD_MIN = -40;
static const int ACOMP_THRESHOLD_MAX = 0;
static const int ACOMP_GAIN_MIN = 0;
static const int ACOMP_GAIN_MAX = 20;
static const float ACOMP_ATTACK_MIN = 0.5f;
static const float ACOMP_ATTACK_MAX = 5.0f;
static const int ACOMP_ATTACK_RAW_MIN = 0;
static const int ACOMP_ATTACK_RAW_MAX = 9;
static const float LMITERTC_MIN = 0.25f;
static const float LMITERTC_MAX = 102.4f;
static const int LMITERTC_RAW_MIN = 5;
static const int LMITERTC_RAW_MAX = 2000;
static const int IALTH_MIN = -70;
static const int IALTH_MAX = 0;
static const int IALDUR_MIN = 0;
static const int IALDUR_MAX = 65535;
static const uint8_t RDS_STATION_MAX = 8; static const uint8_t RDS_STATION_MAX = 8; // TODO
static const uint8_t RDS_TEXT_MAX = 64; static const uint8_t RDS_TEXT_MAX = 64; // TODO
template<typename T> T GET_ENUM_LAST(T value) { return T::LAST; }
enum class OpMode {
OPMODE_ANALOG = 0b01010000, // 0x50
OPMODE_DIGITAL = 0b00001111, // 0x0F
LAST,
};
enum class PreEmphasis {
FMPE_75US, // USA
FMPE_50US, // EU
FMPE_DISABLED,
LAST,
};
enum class LineAttenuation {
LIATTEN_396KOHM,
LIATTEN_100KOHM,
LIATTEN_74KOHM,
LIATTEN_60KOHM,
LAST,
};
enum class SampleBits {
ISIZE_16BITS,
ISIZE_20BITS,
ISIZE_24BITS,
ISIZE_8BITS,
LAST,
};
enum class SampleChannels {
IMONO_STEREO,
IMONO_MONO,
LAST,
};
enum class DigitalMode {
IMODE_DEFAULT,
IMODE_I2S,
IMODE_LEFT_JUSTIFIED,
IMODE_MSB_AT_1ST,
IMODE_MSB_AT_2ND,
LAST,
};
enum class DigitalClockEdge {
IFALL_DCLK_RISING_EDGE,
IFALL_DCLK_FALLIBG_EDGE,
LAST,
};
enum class RefClkSource {
RCLKSEL_RCLK,
RCLKSEL_DCLK,
LAST,
};
enum class AcompAttack {
ATTACK_05MS,
ATTACK_10MS,
ATTACK_15MS,
ATTACK_20MS,
ATTACK_25MS,
ATTACK_30MS,
ATTACK_35MS,
ATTACK_40MS,
ATTACK_45MS,
ATTACK_50MS,
LAST,
};
enum class AcompRelease {
RELEASE_100MS,
RELEASE_200MS,
RELEASE_350MS,
RELEASE_525MS,
RELEASE_1000MS,
LAST,
};
enum class AcompPreset { ACOMP_MINIMAL, ACOMP_AGGRESSIVE, ACOMP_CUSTOM, LAST };
enum class CmdType : uint8_t { enum class CmdType : uint8_t {
POWER_UP = 0x01, // Power up device and mode selection. POWER_UP = 0x01, // Power up device and mode selection.
@ -407,11 +536,9 @@ struct ResTxTuneMeasure : ResBase {};
struct CmdTxTuneStatus : CmdBase { struct CmdTxTuneStatus : CmdBase {
union { union {
uint8_t ARG[2]; uint8_t ARG[1];
struct { struct {
// ARG1 // ARG1
uint8_t : 8; // zero
// ARG2
uint8_t INTACK : 1; // Seek/Tune Interrupt Clear. uint8_t INTACK : 1; // Seek/Tune Interrupt Clear.
uint8_t : 7; uint8_t : 7;
}; };
@ -420,7 +547,6 @@ struct CmdTxTuneStatus : CmdBase {
CmdTxTuneStatus(uint8_t intack = 1) { CmdTxTuneStatus(uint8_t intack = 1) {
this->CMD = CmdType::TX_TUNE_STATUS; this->CMD = CmdType::TX_TUNE_STATUS;
this->ARG[0] = 0; this->ARG[0] = 0;
this->ARG[1] = 0;
this->INTACK = intack; this->INTACK = intack;
} }
}; };
@ -449,11 +575,9 @@ struct ResTxTuneStatus : ResBase {
struct CmdTxAsqStatus : CmdBase { struct CmdTxAsqStatus : CmdBase {
union { union {
uint8_t ARG[2]; uint8_t ARG[1];
struct { struct {
// ARG1 // ARG1
uint8_t : 8; // zero
// ARG2
uint8_t INTACK : 1; // Interrupt Acknowledge. Clears ASQINT, OVERMOD, IALDH, and IALDL uint8_t INTACK : 1; // Interrupt Acknowledge. Clears ASQINT, OVERMOD, IALDH, and IALDL
uint8_t : 7; uint8_t : 7;
}; };
@ -462,7 +586,6 @@ struct CmdTxAsqStatus : CmdBase {
CmdTxAsqStatus(uint8_t intack = 1) { CmdTxAsqStatus(uint8_t intack = 1) {
this->CMD = CmdType::TX_ASQ_STATUS; this->CMD = CmdType::TX_ASQ_STATUS;
this->ARG[0] = 0; this->ARG[0] = 0;
this->ARG[1] = 0;
this->INTACK = intack; this->INTACK = intack;
} }
}; };
@ -472,9 +595,9 @@ struct ResTxAsqStatus : ResBase {
uint8_t RESP[4]; uint8_t RESP[4];
struct { struct {
// RESP1 // RESP1
uint8_t OVERMOD : 1; // Overmodulation Detection uint8_t IALL : 1; // Overmodulation Detection
uint8_t IALH : 1; // Input Audio Level Threshold Detect High uint8_t IALH : 1; // Input Audio Level Threshold Detect High
uint8_t IALL : 1; // Input Audio Level Threshold Detect Low uint8_t OVERMOD : 1; // Input Audio Level Threshold Detect Low
uint8_t : 5; uint8_t : 5;
// RESP2 // RESP2
uint8_t : 8; uint8_t : 8;
@ -673,13 +796,16 @@ struct PropDigitalInputFormat : PropBase {
}; };
}; };
PropDigitalInputFormat(uint16_t isize = 0, uint16_t imono = 0, uint16_t imode = 0, uint16_t ifall = 0) { PropDigitalInputFormat(SampleBits isize = SampleBits::ISIZE_16BITS,
SampleChannels imono = SampleChannels::IMONO_STEREO,
DigitalMode imode = DigitalMode::IMODE_DEFAULT,
DigitalClockEdge ifall = DigitalClockEdge::IFALL_DCLK_RISING_EDGE) {
this->PROP = PropType::DIGITAL_INPUT_FORMAT; this->PROP = PropType::DIGITAL_INPUT_FORMAT;
this->PROPD = 0x0000; this->PROPD = 0x0000;
this->ISIZE = isize; this->ISIZE = (uint16_t) isize;
this->IMONO = imono; this->IMONO = (uint16_t) imono;
this->IMODE = imode; this->IMODE = (uint16_t) imode;
this->IFALL = ifall; this->IFALL = (uint16_t) ifall;
} }
}; };
@ -724,11 +850,11 @@ struct PropRefClkPreScale : PropBase {
}; };
}; };
PropRefClkPreScale(uint16_t rclkp = 1, uint16_t rclksel = 0) { PropRefClkPreScale(uint16_t rclkp = 1, RefClkSource rclksel = RefClkSource::RCLKSEL_RCLK) {
this->PROP = PropType::REFCLK_PRESCALE; this->PROP = PropType::REFCLK_PRESCALE;
this->PROPD = 0x0001; this->PROPD = 0x0001;
this->RCLKP = rclkp; this->RCLKP = rclkp;
this->RCLKSEL = rclksel; this->RCLKSEL = (uint16_t) rclksel;
} }
}; };
@ -805,11 +931,11 @@ struct PropTxLineInputLevel : PropBase {
}; };
}; };
PropTxLineInputLevel(uint16_t lilevel = 636, uint16_t liatten = 3) { PropTxLineInputLevel(uint16_t lilevel = 636, LineAttenuation liatten = LineAttenuation::LIATTEN_60KOHM) {
this->PROP = PropType::TX_LINE_INPUT_LEVEL; this->PROP = PropType::TX_LINE_INPUT_LEVEL;
this->PROPD = 0x327C; this->PROPD = 0x327C;
this->LILEVEL = lilevel; this->LILEVEL = lilevel;
this->LIATTEN = liatten; this->LIATTEN = (uint16_t) liatten;
} }
}; };
@ -840,10 +966,10 @@ struct PropTxPreEmphasis : PropBase {
}; };
}; };
PropTxPreEmphasis(uint16_t fmpe = 0) { PropTxPreEmphasis(PreEmphasis fmpe = PreEmphasis::FMPE_75US) {
this->PROP = PropType::TX_PREEMPHASIS; this->PROP = PropType::TX_PREEMPHASIS;
this->PROPD = 0x0000; this->PROPD = 0x0000;
this->FMPE = fmpe; this->FMPE = (uint16_t) fmpe;
} }
}; };
@ -920,10 +1046,10 @@ struct PropTxAcompReleaseTime : PropBase {
}; };
}; };
PropTxAcompReleaseTime(uint16_t release = 4) { PropTxAcompReleaseTime(AcompRelease release = AcompRelease::RELEASE_1000MS) {
this->PROP = PropType::TX_ACOMP_RELEASE_TIME; this->PROP = PropType::TX_ACOMP_RELEASE_TIME;
this->PROPD = 0x0004; this->PROPD = 0x0004;
this->RELEASE = release; this->RELEASE = (uint16_t) release;
} }
}; };
@ -978,8 +1104,8 @@ struct PropTxAsqLevelLow : PropBase {
union { union {
uint16_t PROPD; uint16_t PROPD;
struct { struct {
uint16_t IALLTH : 8; // Input Audio Level Low Threshold (-70 to 0 dB) int8_t IALLTH : 8; // Input Audio Level Low Threshold (-70 to 0 dB)
uint16_t : 8; uint8_t : 8;
}; };
}; };
@ -1007,8 +1133,8 @@ struct PropTxAsqLevelHigh : PropBase {
union { union {
uint16_t PROPD; uint16_t PROPD;
struct { struct {
uint16_t IALHTH : 8; // Input Audio Level High Threshold (-70 to 0 dB) int8_t IALHTH : 8; // Input Audio Level High Threshold (-70 to 0 dB)
uint16_t : 8; uint8_t : 8;
}; };
}; };

View file

@ -10,20 +10,36 @@ from .. import (
CONF_SI4713_ID, CONF_SI4713_ID,
Si4713Component, Si4713Component,
si4713_ns, si4713_ns,
CONF_SECTION_PILOT,
CONF_SECTION_COMPRESSOR,
CONF_SECTION_LIMITER,
CONF_SECTION_ASQ,
CONF_SECTION_RDS,
CONF_SECTION_OUTPUT,
CONF_MUTE, CONF_MUTE,
CONF_MONO, CONF_MONO,
CONF_RDS_ENABLE, CONF_ENABLE,
CONF_OVERMOD,
CONF_IALL,
CONF_IALH,
CONF_GPIO1,
CONF_GPIO2,
CONF_GPIO3,
ICON_SINE_WAVE,
ICON_VOLUME_MUTE, ICON_VOLUME_MUTE,
ICON_EAR_HEARING, ICON_EAR_HEARING,
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)
PilotEnableSwitch = si4713_ns.class_("PilotEnableSwitch", switch.Switch)
AcompEnableSwitch = si4713_ns.class_("AcompEnableSwitch", switch.Switch)
LimiterEnableSwitch = si4713_ns.class_("LimiterEnableSwitch", switch.Switch)
AsqOvermodEnableSwitch = si4713_ns.class_("AsqOvermodEnableSwitch", switch.Switch)
AsqIallEnableSwitch = si4713_ns.class_("AsqIallEnableSwitch", switch.Switch)
AsqIalhEnableSwitch = si4713_ns.class_("AsqIalhEnableSwitch", switch.Switch)
RdsEnable = si4713_ns.class_("RdsEnable", switch.Switch)
RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch) RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch)
GPIOSwitch = si4713_ns.class_("GPIOSwitch", switch.Switch) GPIOSwitch = si4713_ns.class_("GPIOSwitch", switch.Switch)
@ -42,12 +58,70 @@ CONFIG_SCHEMA = cv.Schema(
entity_category=ENTITY_CATEGORY_CONFIG, entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_EAR_HEARING, icon=ICON_EAR_HEARING,
), ),
cv.Optional(CONF_RDS_ENABLE): switch.switch_schema( cv.Optional(CONF_SECTION_PILOT): cv.Schema(
{
cv.Optional(CONF_ENABLE): switch.switch_schema(
PilotEnableSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SINE_WAVE,
),
}
),
cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema(
{
cv.Optional(CONF_ENABLE): switch.switch_schema(
AcompEnableSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SINE_WAVE,
),
}
),
cv.Optional(CONF_SECTION_LIMITER): cv.Schema(
{
cv.Optional(CONF_ENABLE): switch.switch_schema(
LimiterEnableSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_SINE_WAVE,
),
}
),
cv.Optional(CONF_SECTION_ASQ): cv.Schema(
{
cv.Optional(CONF_OVERMOD): switch.switch_schema(
AsqOvermodEnableSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
cv.Optional(CONF_IALL): switch.switch_schema(
AsqIallEnableSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
cv.Optional(CONF_IALH): switch.switch_schema(
AsqIalhEnableSwitch,
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
# icon=ICON_,
),
}
),
cv.Optional(CONF_SECTION_RDS): cv.Schema(
{
cv.Optional(CONF_ENABLE): switch.switch_schema(
RDSEnableSwitch, RDSEnableSwitch,
device_class=DEVICE_CLASS_SWITCH, device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG, entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_FORMAT_TEXT, icon=ICON_FORMAT_TEXT,
), ),
}
),
cv.Optional(CONF_SECTION_OUTPUT): cv.Schema(
{
cv.Optional(CONF_GPIO1): switch.switch_schema( cv.Optional(CONF_GPIO1): switch.switch_schema(
GPIOSwitch, GPIOSwitch,
device_class=DEVICE_CLASS_SWITCH, device_class=DEVICE_CLASS_SWITCH,
@ -67,25 +141,39 @@ CONFIG_SCHEMA = cv.Schema(
# icon=, # icon=,
), ),
} }
)
}
) )
async def new_switch(config, id, setter): async def new_switch(parent, config, id, setter):
if c := config.get(id): if c := config.get(id):
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, parent)
cg.add(setter(s)) cg.add(setter(s))
return s return s
async def to_code(config): async def to_code(config):
c = await cg.get_variable(config[CONF_SI4713_ID]) parent = await cg.get_variable(config[CONF_SI4713_ID])
await new_switch(config, CONF_MUTE, c.set_mute_switch) await new_switch(parent, config, CONF_MUTE, parent.set_mute_switch)
await new_switch(config, CONF_MONO, c.set_mono_switch) await new_switch(parent, config, CONF_MONO, parent.set_mono_switch)
await new_switch(config, CONF_RDS_ENABLE, c.set_rds_enable_switch) if pilot_config := config.get(CONF_SECTION_PILOT):
s = await new_switch(config, CONF_GPIO1, c.set_gpio1_switch) await new_switch(parent, pilot_config, CONF_ENABLE, parent.set_pilot_enable_switch)
s.set_pin(1) if compressor_config := config.get(CONF_SECTION_COMPRESSOR):
s = await new_switch(config, CONF_GPIO2, c.set_gpio2_switch) await new_switch(parent, compressor_config, CONF_ENABLE, parent.set_acomp_enable_switch)
s.set_pin(2) if limiter_config := config.get(CONF_SECTION_LIMITER):
s = await new_switch(config, CONF_GPIO3, c.set_gpio3_switch) await new_switch(parent, limiter_config, CONF_ENABLE, parent.set_limiter_enable_switch)
s.set_pin(3) if asq_config := config.get(CONF_SECTION_ASQ):
await new_switch(parent, asq_config, CONF_OVERMOD, parent.set_asq_overmod_enable_switch)
await new_switch(parent, asq_config, CONF_IALL, parent.set_asq_iall_enable_switch)
await new_switch(parent, asq_config, CONF_IALH, parent.set_asq_ialh_enable_switch)
if rds_config := config.get(CONF_SECTION_RDS):
await new_switch(parent, rds_config, CONF_ENABLE, parent.set_rds_enable_switch)
if output_config := config.get(CONF_SECTION_OUTPUT):
gpio1 = await new_switch(parent, output_config, CONF_GPIO1, parent.set_gpio1_switch)
gpio2 = await new_switch(parent, output_config, CONF_GPIO2, parent.set_gpio2_switch)
gpio3 = await new_switch(parent, output_config, CONF_GPIO3, parent.set_gpio3_switch)
cg.add(gpio1.set_pin(1))
cg.add(gpio2.set_pin(2))
cg.add(gpio3.set_pin(3))

View file

@ -0,0 +1,12 @@
#include "acomp_enable_switch.h"
namespace esphome {
namespace si4713 {
void AcompEnableSwitch::write_state(bool value) {
this->publish_state(value);
this->parent_->set_acomp_enable(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/switch/switch.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class AcompEnableSwitch : public switch_::Switch, public Parented<Si4713Component> {
public:
AcompEnableSwitch() = default;
protected:
void write_state(bool value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "limiter_enable_switch.h"
namespace esphome {
namespace si4713 {
void LimiterEnableSwitch::write_state(bool value) {
this->publish_state(value);
this->parent_->set_limiter_enable(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/switch/switch.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class LimiterEnableSwitch : public switch_::Switch, public Parented<Si4713Component> {
public:
LimiterEnableSwitch() = default;
protected:
void write_state(bool value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,12 @@
#include "pilot_enable_switch.h"
namespace esphome {
namespace si4713 {
void PilotEnableSwitch::write_state(bool value) {
this->publish_state(value);
this->parent_->set_pilot_enable(value);
}
} // namespace si4713
} // namespace esphome

View file

@ -0,0 +1,18 @@
#pragma once
#include "esphome/components/switch/switch.h"
#include "../si4713.h"
namespace esphome {
namespace si4713 {
class PilotEnableSwitch : public switch_::Switch, public Parented<Si4713Component> {
public:
PilotEnableSwitch() = default;
protected:
void write_state(bool value) override;
};
} // namespace si4713
} // namespace esphome

View file

@ -18,8 +18,9 @@ from .. import (
CONF_SI4713_ID, CONF_SI4713_ID,
Si4713Component, Si4713Component,
si4713_ns, si4713_ns,
CONF_RDS_STATION, CONF_SECTION_RDS,
CONF_RDS_TEXT, CONF_STATION,
CONF_TEXT,
ICON_FORMAT_TEXT, ICON_FORMAT_TEXT,
) )
@ -123,32 +124,38 @@ async def new_text(
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component), cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
cv.Optional(CONF_RDS_STATION): text_schema( cv.Optional(CONF_SECTION_RDS): cv.Schema(
{
cv.Optional(CONF_STATION): text_schema(
RDSStationText, RDSStationText,
entity_category=ENTITY_CATEGORY_CONFIG, entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_FORMAT_TEXT, icon=ICON_FORMAT_TEXT,
), ),
cv.Optional(CONF_RDS_TEXT): text_schema( cv.Optional(CONF_TEXT): text_schema(
RDSTextText, RDSTextText,
entity_category=ENTITY_CATEGORY_CONFIG, entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_FORMAT_TEXT, icon=ICON_FORMAT_TEXT,
), ),
} }
),
}
) )
async def new_text_simple(config, id, setter, min_length, max_length, *args): async def new_text_simple(parent, config, id, setter, min_length, max_length, *args):
if c := config.get(id): if c := config.get(id):
t = await new_text(c, *args, min_length=min_length, max_length=max_length) t = await new_text(c, *args, min_length=min_length, max_length=max_length)
await cg.register_parented(t, config[CONF_SI4713_ID]) await cg.register_parented(t, parent)
cg.add(setter(t)) cg.add(setter(t))
return t
async def to_code(config): async def to_code(config):
c = await cg.get_variable(config[CONF_SI4713_ID]) parent = await cg.get_variable(config[CONF_SI4713_ID])
if rds_config := config.get(CONF_SECTION_RDS):
await new_text_simple( await new_text_simple(
config, CONF_RDS_STATION, c.set_rds_station_text, 0, si4713_ns.RDS_STATION_MAX parent, rds_config, CONF_STATION, parent.set_rds_station_text, 0, si4713_ns.RDS_STATION_MAX
) )
await new_text_simple( await new_text_simple(
config, CONF_RDS_TEXT, c.set_rds_text_text, 0, si4713_ns.RDS_TEXT_MAX parent, rds_config, CONF_TEXT, parent.set_rds_text_text, 0, si4713_ns.RDS_TEXT_MAX
) )