From 2a3049cc9f1b63bc5105814c7cec13088179cd5f Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Sun, 14 May 2023 19:07:14 -0400 Subject: [PATCH 01/12] Initial TemperBridge implementation --- esphome/components/temperbridge/__init__.py | 191 +++++ .../temperbridge/radio_config_Si4463.h | 688 ++++++++++++++++++ esphome/components/temperbridge/si446x.cpp | 80 ++ esphome/components/temperbridge/si446x.h | 61 ++ .../components/temperbridge/temperbridge.cpp | 561 ++++++++++++++ .../components/temperbridge/temperbridge.h | 144 ++++ 6 files changed, 1725 insertions(+) create mode 100644 esphome/components/temperbridge/__init__.py create mode 100644 esphome/components/temperbridge/radio_config_Si4463.h create mode 100644 esphome/components/temperbridge/si446x.cpp create mode 100644 esphome/components/temperbridge/si446x.h create mode 100644 esphome/components/temperbridge/temperbridge.cpp create mode 100644 esphome/components/temperbridge/temperbridge.h diff --git a/esphome/components/temperbridge/__init__.py b/esphome/components/temperbridge/__init__.py new file mode 100644 index 000000000000..1b47a2e56e1b --- /dev/null +++ b/esphome/components/temperbridge/__init__.py @@ -0,0 +1,191 @@ +from esphome import pins, automation +from esphome.automation import maybe_simple_id +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi +from esphome.const import CONF_ID, CONF_INTERRUPT_PIN + +CONF_SDN_PIN = "sdn_pin" + +CONF_CHANNEL = "channel" +CONF_CMD = "cmd" +CONF_TARGET = "target" +CONF_LEVEL = "level" + +DEPENDENCIES = ["spi"] + +temperbridge_ns = cg.esphome_ns.namespace("temperbridge") +TemperBridge = temperbridge_ns.class_( + "TemperBridgeComponent", cg.Component, spi.SPIDevice +) + +temperbridge_simple_command_ns = temperbridge_ns.enum("SimpleCommand", is_class=True) + +SIMPLE_COMMANDS = { + "flat": temperbridge_simple_command_ns.PRESET_FLAT, + "mode_1": temperbridge_simple_command_ns.PRESET_MODE1, + "mode_2": temperbridge_simple_command_ns.PRESET_MODE2, + "mode_3": temperbridge_simple_command_ns.PRESET_MODE3, + "mode_4": temperbridge_simple_command_ns.PRESET_MODE4, + "save_preset_mode1": temperbridge_simple_command_ns.SAVE_PRESET_MODE1, + "save_preset_mode2": temperbridge_simple_command_ns.SAVE_PRESET_MODE2, + "save_preset_mode3": temperbridge_simple_command_ns.SAVE_PRESET_MODE3, + "save_preset_mode4": temperbridge_simple_command_ns.SAVE_PRESET_MODE4, + "stop": temperbridge_simple_command_ns.STOP, + "massage_mode_1": temperbridge_simple_command_ns.MASSAGE_PRESET_MODE1, + "massage_mode_2": temperbridge_simple_command_ns.MASSAGE_PRESET_MODE2, + "massage_mode_3": temperbridge_simple_command_ns.MASSAGE_PRESET_MODE3, + "massage_mode_4": temperbridge_simple_command_ns.MASSAGE_PRESET_MODE4, +} + +validate_simple_command = cv.enum(SIMPLE_COMMANDS, lower=True) + +temperbridge_position_command_ns = temperbridge_ns.enum( + "PositionCommand", is_class=True +) + +POSITION_COMMANDS = { + "raise_head": temperbridge_position_command_ns.RAISE_HEAD, + "raise_legs": temperbridge_position_command_ns.RAISE_LEGS, + "lower_head": temperbridge_position_command_ns.LOWER_HEAD, + "lower_legs": temperbridge_position_command_ns.LOWER_LEGS, +} + +validate_position_command = cv.enum(POSITION_COMMANDS, lower=True) + +temperbridge_massage_target_enum = temperbridge_ns.enum("MassageTarget", is_class=True) + +MASSAGE_TARGET = { + "head": temperbridge_massage_target_enum.HEAD, + "legs": temperbridge_massage_target_enum.LEGS, + "lumbar": temperbridge_massage_target_enum.LUMBAR, +} + +validate_massage_target = cv.enum(MASSAGE_TARGET, lower=True) + +ExecuteSimpleCommandAction = temperbridge_ns.class_( + "ExecuteSimpleCommandAction", automation.Action +) + +PositionCommandAction = temperbridge_ns.class_( + "PositionCommandAction", automation.Action +) + +SetMassageIntensityAction = temperbridge_ns.class_( + "SetMassageIntensityAction", automation.Action +) + +SetChannelAction = temperbridge_ns.class_("SetChannelAction", automation.Action) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(TemperBridge), + cv.Required(CONF_SDN_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_INTERRUPT_PIN): cv.All( + pins.internal_gpio_input_pin_schema + ), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(spi.spi_device_schema(cs_pin_required=True)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + + interrupt_pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) + cg.add(var.set_interrupt_pin(interrupt_pin)) + + sdn_pin = await cg.gpio_pin_expression(config[CONF_SDN_PIN]) + cg.add(var.set_sdn_pin(sdn_pin)) + + +@automation.register_action( + "temperbridge.position_command_2", + PositionCommandAction, + maybe_simple_id( + { + cv.GenerateID(): cv.use_id(TemperBridge), + cv.Required(CONF_CMD): cv.templatable(validate_position_command), + }, + ), +) +async def temperbridge_start_position_command_to_code( + config, action_id, template_arg, args +): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + cg.add(var.set_cmd(config[CONF_CMD])) + return var + + +@automation.register_action( + "temperbridge.execute_simple_command", + ExecuteSimpleCommandAction, + maybe_simple_id( + { + cv.GenerateID(): cv.use_id(TemperBridge), + cv.Required(CONF_CMD): cv.templatable(validate_simple_command), + }, + ), +) +async def temperbridge_execute_simple_command_to_code( + config, action_id, template_arg, args +): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + cg.add(var.set_cmd(config[CONF_CMD])) + return var + + +validate_channel = cv.All(cv.int_range(min=0, max=9999)) + + +@automation.register_action( + "temperbridge.set_channel", + SetChannelAction, + cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(TemperBridge), + cv.Required(CONF_CHANNEL): cv.templatable(validate_channel), + }, + key=CONF_CHANNEL, + ), +) +async def temperbridge_set_channel_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_CHANNEL], args, cg.uint16) + cg.add(var.set_channel(template_)) + return var + + +validate_massage_level = cv.All(cv.int_range(min=0, max=10)) + + +@automation.register_action( + "temperbridge.set_massage_intensity", + SetMassageIntensityAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(TemperBridge), + cv.Required(CONF_TARGET): cv.templatable(validate_massage_target), + cv.Required(CONF_LEVEL): cv.templatable(validate_massage_level), + } + ), +) +async def temperbridge_set_massage_intensity_to_code( + config, action_id, template_arg, args +): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_TARGET], args, validate_massage_target) + cg.add(var.set_target(template_)) + + template_ = await cg.templatable(config[CONF_LEVEL], args, cg.uint8) + cg.add(var.set_level(template_)) + return var diff --git a/esphome/components/temperbridge/radio_config_Si4463.h b/esphome/components/temperbridge/radio_config_Si4463.h new file mode 100644 index 000000000000..15d820956f53 --- /dev/null +++ b/esphome/components/temperbridge/radio_config_Si4463.h @@ -0,0 +1,688 @@ +/*! @file radio_config.h + * @brief This file contains the automatically generated + * configurations. + * + * @n WDS GUI Version: 3.2.11.0 + * @n Device: Si4463 Rev.: C2 + * + * @b COPYRIGHT + * @n Silicon Laboratories Confidential + * @n Copyright 2017 Silicon Laboratories, Inc. + * @n http://www.silabs.com + */ + +#ifndef RADIO_CONFIG_H_ +#define RADIO_CONFIG_H_ + +// USER DEFINED PARAMETERS +// Define your own parameters here + +// INPUT DATA +/* +// Crys_freq(Hz): 30000000 Crys_tol(ppm): 10 IF_mode: 2 High_perf_Ch_Fil: 1 OSRtune: 0 Ch_Fil_Bw_AFC: 0 +ANT_DIV: 0 PM_pattern: 0 +// MOD_type: 3 Rsymb(sps): 12800 Fdev(Hz): 25000 RXBW(Hz): 150000 Manchester: 0 AFC_en: 0 Rsymb_error: +0.0 Chip-Version: 2 +// RF Freq.(MHz): 434.09547 API_TC: 29 fhst: 0 inputBW: 0 BERT: 0 RAW_dout: 0 D_source: 0 Hi_pfm_div: +1 +// API_ARR_Det_en: 0 Fdev_error: 0 API_ETSI: 0 +// +// # RX IF frequency is -468750 Hz +// # WB filter 1 (BW = 76.31 kHz); NB-filter 1 (BW = 76.31 kHz) +// +// Modulation index: 3.906 +*/ + +// CONFIGURATION PARAMETERS +#define RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ 30000000L +#define RADIO_CONFIGURATION_DATA_CHANNEL_NUMBER 0x00 +#define RADIO_CONFIGURATION_DATA_RADIO_PACKET_LENGTH 0x07 +#define RADIO_CONFIGURATION_DATA_RADIO_STATE_AFTER_POWER_UP 0x03 +#define RADIO_CONFIGURATION_DATA_RADIO_DELAY_CNT_AFTER_RESET 0xF000 + +// CONFIGURATION COMMANDS + +/* +// Command: RF_POWER_UP +// Description: Command to power-up the device and select the operational mode and functionality. +*/ +#define RF_POWER_UP 0x02, 0x01, 0x00, 0x01, 0xC9, 0xC3, 0x80 + +/* +// Command: RF_GPIO_PIN_CFG +// Description: Configures the GPIO pins. +*/ +#define RF_GPIO_PIN_CFG 0x13, 0x00, 0x00, 0x21, 0x20, 39, 0x00, 0x00 + +/* +// Set properties: RF_GLOBAL_XO_TUNE_2 +// Number of properties: 2 +// Group ID: 0x00 +// Start ID: 0x00 +// Default values: 0x40, 0x00, +// Descriptions: +// GLOBAL_XO_TUNE - Configure the internal capacitor frequency tuning bank for the crystal oscillator. +// GLOBAL_CLK_CFG - Clock configuration options. +*/ +#define RF_GLOBAL_XO_TUNE_2 0x11, 0x00, 0x02, 0x00, 0x62, 0x00 + +/* +// Set properties: RF_GLOBAL_CONFIG_1 +// Number of properties: 1 +// Group ID: 0x00 +// Start ID: 0x03 +// Default values: 0x20, +// Descriptions: +// GLOBAL_CONFIG - Global configuration settings. +*/ +#define RF_GLOBAL_CONFIG_1 0x11, 0x00, 0x01, 0x03, 0x20 + +/* +// Set properties: RF_INT_CTL_ENABLE_2 +// Number of properties: 2 +// Group ID: 0x01 +// Start ID: 0x00 +// Default values: 0x04, 0x00, +// Descriptions: +// INT_CTL_ENABLE - This property provides for global enabling of the three interrupt groups (Chip, Modem and Packet +Handler) in order to generate HW interrupts at the NIRQ pin. +// INT_CTL_PH_ENABLE - Enable individual interrupt sources within the Packet Handler Interrupt Group to generate a HW +interrupt on the NIRQ output pin. +*/ +#define RF_INT_CTL_ENABLE_2 0x11, 0x01, 0x02, 0x00, 0x01, 0x20 + +/* +// Set properties: RF_FRR_CTL_A_MODE_4 +// Number of properties: 4 +// Group ID: 0x02 +// Start ID: 0x00 +// Default values: 0x01, 0x02, 0x09, 0x00, +// Descriptions: +// FRR_CTL_A_MODE - Fast Response Register A Configuration. +// FRR_CTL_B_MODE - Fast Response Register B Configuration. +// FRR_CTL_C_MODE - Fast Response Register C Configuration. +// FRR_CTL_D_MODE - Fast Response Register D Configuration. +*/ +#define RF_FRR_CTL_A_MODE_4 0x11, 0x02, 0x04, 0x00, 0x02, 0x04, 0x06, 0x08 + +/* +// Set properties: RF_PREAMBLE_TX_LENGTH_9 +// Number of properties: 9 +// Group ID: 0x10 +// Start ID: 0x00 +// Default values: 0x08, 0x14, 0x00, 0x0F, 0x21, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// PREAMBLE_TX_LENGTH - Configure length of TX Preamble. +// PREAMBLE_CONFIG_STD_1 - Configuration of reception of a packet with a Standard Preamble pattern. +// PREAMBLE_CONFIG_NSTD - Configuration of transmission/reception of a packet with a Non-Standard Preamble pattern. +// PREAMBLE_CONFIG_STD_2 - Configuration of timeout periods during reception of a packet with Standard Preamble +pattern. +// PREAMBLE_CONFIG - General configuration bits for the Preamble field. +// PREAMBLE_PATTERN_31_24 - Configuration of the bit values describing a Non-Standard Preamble pattern. +// PREAMBLE_PATTERN_23_16 - Configuration of the bit values describing a Non-Standard Preamble pattern. +// PREAMBLE_PATTERN_15_8 - Configuration of the bit values describing a Non-Standard Preamble pattern. +// PREAMBLE_PATTERN_7_0 - Configuration of the bit values describing a Non-Standard Preamble pattern. +*/ +#define RF_PREAMBLE_TX_LENGTH_9 0x11, 0x10, 0x09, 0x00, 0x05, 0x0A, 0x00, 0x0F, 0x31, 0x00, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_SYNC_CONFIG_6 +// Number of properties: 6 +// Group ID: 0x11 +// Start ID: 0x00 +// Default values: 0x01, 0x2D, 0xD4, 0x2D, 0xD4, 0x00, +// Descriptions: +// SYNC_CONFIG - Sync Word configuration bits. +// SYNC_BITS_31_24 - Sync word. +// SYNC_BITS_23_16 - Sync word. +// SYNC_BITS_15_8 - Sync word. +// SYNC_BITS_7_0 - Sync word. +// SYNC_CONFIG2 - Sync Word configuration bits. +*/ +#define RF_SYNC_CONFIG_6 0x11, 0x11, 0x06, 0x00, 0x31, 0xB4, 0x2B, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_PKT_CRC_CONFIG_12 +// Number of properties: 12 +// Group ID: 0x12 +// Start ID: 0x00 +// Default values: 0x00, 0x01, 0x08, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +// Descriptions: +// PKT_CRC_CONFIG - Select a CRC polynomial and seed. +// PKT_WHT_POLY_15_8 - 16-bit polynomial value for the PN Generator (e.g., for Data Whitening) +// PKT_WHT_POLY_7_0 - 16-bit polynomial value for the PN Generator (e.g., for Data Whitening) +// PKT_WHT_SEED_15_8 - 16-bit seed value for the PN Generator (e.g., for Data Whitening) +// PKT_WHT_SEED_7_0 - 16-bit seed value for the PN Generator (e.g., for Data Whitening) +// PKT_WHT_BIT_NUM - Selects which bit of the LFSR (used to generate the PN / data whitening sequence) is used as the +output bit for data scrambling. +// PKT_CONFIG1 - General configuration bits for transmission or reception of a packet. +// PKT_CONFIG2 - General packet configuration bits. +// PKT_LEN - Configuration bits for reception of a variable length packet. +// PKT_LEN_FIELD_SOURCE - Field number containing the received packet length byte(s). +// PKT_LEN_ADJUST - Provides for adjustment/offset of the received packet length value (in order to accommodate a +variety of methods of defining total packet length). +// PKT_TX_THRESHOLD - TX FIFO almost empty threshold. +*/ +#define RF_PKT_CRC_CONFIG_12 \ + 0x11, 0x12, 0x0C, 0x00, 0x04, 0x01, 0x08, 0xFF, 0xFF, 0x20, 0x12, 0x00, 0x2A, 0x01, 0x00, 0x30 + +/* +// Set properties: RF_PKT_RX_THRESHOLD_12 +// Number of properties: 12 +// Group ID: 0x12 +// Start ID: 0x0C +// Default values: 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// PKT_RX_THRESHOLD - RX FIFO Almost Full threshold. +// PKT_FIELD_1_LENGTH_12_8 - Unsigned 13-bit Field 1 length value. +// PKT_FIELD_1_LENGTH_7_0 - Unsigned 13-bit Field 1 length value. +// PKT_FIELD_1_CONFIG - General data processing and packet configuration bits for Field 1. +// PKT_FIELD_1_CRC_CONFIG - Configuration of CRC control bits across Field 1. +// PKT_FIELD_2_LENGTH_12_8 - Unsigned 13-bit Field 2 length value. +// PKT_FIELD_2_LENGTH_7_0 - Unsigned 13-bit Field 2 length value. +// PKT_FIELD_2_CONFIG - General data processing and packet configuration bits for Field 2. +// PKT_FIELD_2_CRC_CONFIG - Configuration of CRC control bits across Field 2. +// PKT_FIELD_3_LENGTH_12_8 - Unsigned 13-bit Field 3 length value. +// PKT_FIELD_3_LENGTH_7_0 - Unsigned 13-bit Field 3 length value. +// PKT_FIELD_3_CONFIG - General data processing and packet configuration bits for Field 3. +*/ +#define RF_PKT_RX_THRESHOLD_12 \ + 0x11, 0x12, 0x0C, 0x0C, 0x30, 0x00, 0x01, 0x00, 0x82, 0x00, 0x07, 0x00, 0x2A, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_PKT_FIELD_3_CRC_CONFIG_12 +// Number of properties: 12 +// Group ID: 0x12 +// Start ID: 0x18 +// Default values: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// PKT_FIELD_3_CRC_CONFIG - Configuration of CRC control bits across Field 3. +// PKT_FIELD_4_LENGTH_12_8 - Unsigned 13-bit Field 4 length value. +// PKT_FIELD_4_LENGTH_7_0 - Unsigned 13-bit Field 4 length value. +// PKT_FIELD_4_CONFIG - General data processing and packet configuration bits for Field 4. +// PKT_FIELD_4_CRC_CONFIG - Configuration of CRC control bits across Field 4. +// PKT_FIELD_5_LENGTH_12_8 - Unsigned 13-bit Field 5 length value. +// PKT_FIELD_5_LENGTH_7_0 - Unsigned 13-bit Field 5 length value. +// PKT_FIELD_5_CONFIG - General data processing and packet configuration bits for Field 5. +// PKT_FIELD_5_CRC_CONFIG - Configuration of CRC control bits across Field 5. +// PKT_RX_FIELD_1_LENGTH_12_8 - Unsigned 13-bit RX Field 1 length value. +// PKT_RX_FIELD_1_LENGTH_7_0 - Unsigned 13-bit RX Field 1 length value. +// PKT_RX_FIELD_1_CONFIG - General data processing and packet configuration bits for RX Field 1. +*/ +#define RF_PKT_FIELD_3_CRC_CONFIG_12 \ + 0x11, 0x12, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_PKT_RX_FIELD_1_CRC_CONFIG_12 +// Number of properties: 12 +// Group ID: 0x12 +// Start ID: 0x24 +// Default values: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// PKT_RX_FIELD_1_CRC_CONFIG - Configuration of CRC control bits across RX Field 1. +// PKT_RX_FIELD_2_LENGTH_12_8 - Unsigned 13-bit RX Field 2 length value. +// PKT_RX_FIELD_2_LENGTH_7_0 - Unsigned 13-bit RX Field 2 length value. +// PKT_RX_FIELD_2_CONFIG - General data processing and packet configuration bits for RX Field 2. +// PKT_RX_FIELD_2_CRC_CONFIG - Configuration of CRC control bits across RX Field 2. +// PKT_RX_FIELD_3_LENGTH_12_8 - Unsigned 13-bit RX Field 3 length value. +// PKT_RX_FIELD_3_LENGTH_7_0 - Unsigned 13-bit RX Field 3 length value. +// PKT_RX_FIELD_3_CONFIG - General data processing and packet configuration bits for RX Field 3. +// PKT_RX_FIELD_3_CRC_CONFIG - Configuration of CRC control bits across RX Field 3. +// PKT_RX_FIELD_4_LENGTH_12_8 - Unsigned 13-bit RX Field 4 length value. +// PKT_RX_FIELD_4_LENGTH_7_0 - Unsigned 13-bit RX Field 4 length value. +// PKT_RX_FIELD_4_CONFIG - General data processing and packet configuration bits for RX Field 4. +*/ +#define RF_PKT_RX_FIELD_1_CRC_CONFIG_12 \ + 0x11, 0x12, 0x0C, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_PKT_RX_FIELD_4_CRC_CONFIG_5 +// Number of properties: 5 +// Group ID: 0x12 +// Start ID: 0x30 +// Default values: 0x00, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// PKT_RX_FIELD_4_CRC_CONFIG - Configuration of CRC control bits across RX Field 4. +// PKT_RX_FIELD_5_LENGTH_12_8 - Unsigned 13-bit RX Field 5 length value. +// PKT_RX_FIELD_5_LENGTH_7_0 - Unsigned 13-bit RX Field 5 length value. +// PKT_RX_FIELD_5_CONFIG - General data processing and packet configuration bits for RX Field 5. +// PKT_RX_FIELD_5_CRC_CONFIG - Configuration of CRC control bits across RX Field 5. +*/ +#define RF_PKT_RX_FIELD_4_CRC_CONFIG_5 0x11, 0x12, 0x05, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_PKT_CRC_SEED_31_24_4 +// Number of properties: 4 +// Group ID: 0x12 +// Start ID: 0x36 +// Default values: 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// PKT_CRC_SEED_31_24 - 32-bit seed value for the 32-bit CRC engine +// PKT_CRC_SEED_23_16 - 32-bit seed value for the 32-bit CRC engine +// PKT_CRC_SEED_15_8 - 32-bit seed value for the 32-bit CRC engine +// PKT_CRC_SEED_7_0 - 32-bit seed value for the 32-bit CRC engine +*/ +#define RF_PKT_CRC_SEED_31_24_4 0x11, 0x12, 0x04, 0x36, 0x00, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_MODEM_MOD_TYPE_12 +// Number of properties: 12 +// Group ID: 0x20 +// Start ID: 0x00 +// Default values: 0x02, 0x80, 0x07, 0x0F, 0x42, 0x40, 0x01, 0xC9, 0xC3, 0x80, 0x00, 0x06, +// Descriptions: +// MODEM_MOD_TYPE - Selects the type of modulation. In TX mode, additionally selects the source of the modulation. +// MODEM_MAP_CONTROL - Controls polarity and mapping of transmit and receive bits. +// MODEM_DSM_CTRL - Miscellaneous control bits for the Delta-Sigma Modulator (DSM) in the PLL Synthesizer. +// MODEM_DATA_RATE_2 - Unsigned 24-bit value used to determine the TX data rate +// MODEM_DATA_RATE_1 - Unsigned 24-bit value used to determine the TX data rate +// MODEM_DATA_RATE_0 - Unsigned 24-bit value used to determine the TX data rate +// MODEM_TX_NCO_MODE_3 - TX Gaussian filter oversampling ratio and Byte 3 of unsigned 26-bit TX Numerically Controlled +Oscillator (NCO) modulus. +// MODEM_TX_NCO_MODE_2 - TX Gaussian filter oversampling ratio and Byte 3 of unsigned 26-bit TX Numerically Controlled +Oscillator (NCO) modulus. +// MODEM_TX_NCO_MODE_1 - TX Gaussian filter oversampling ratio and Byte 3 of unsigned 26-bit TX Numerically Controlled +Oscillator (NCO) modulus. +// MODEM_TX_NCO_MODE_0 - TX Gaussian filter oversampling ratio and Byte 3 of unsigned 26-bit TX Numerically Controlled +Oscillator (NCO) modulus. +// MODEM_FREQ_DEV_2 - 17-bit unsigned TX frequency deviation word. +// MODEM_FREQ_DEV_1 - 17-bit unsigned TX frequency deviation word. +*/ +#define RF_MODEM_MOD_TYPE_12 \ + 0x11, 0x20, 0x0C, 0x00, 0x03, 0x00, 0x07, 0x07, 0xD0, 0x00, 0x05, 0xC9, 0xC3, 0x80, 0x00, 0x06 + +/* +// Set properties: RF_MODEM_FREQ_DEV_0_1 +// Number of properties: 1 +// Group ID: 0x20 +// Start ID: 0x0C +// Default values: 0xD3, +// Descriptions: +// MODEM_FREQ_DEV_0 - 17-bit unsigned TX frequency deviation word. +*/ +#define RF_MODEM_FREQ_DEV_0_1 0x11, 0x20, 0x01, 0x0C, 0xD4 + +/* +// Set properties: RF_MODEM_TX_RAMP_DELAY_12 +// Number of properties: 12 +// Group ID: 0x20 +// Start ID: 0x18 +// Default values: 0x01, 0x00, 0x08, 0x03, 0xC0, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x4B, +// Descriptions: +// MODEM_TX_RAMP_DELAY - TX ramp-down delay setting. +// MODEM_MDM_CTRL - MDM control. +// MODEM_IF_CONTROL - Selects Fixed-IF, Scaled-IF, or Zero-IF mode of RX Modem operation. +// MODEM_IF_FREQ_2 - the IF frequency setting (an 18-bit signed number). +// MODEM_IF_FREQ_1 - the IF frequency setting (an 18-bit signed number). +// MODEM_IF_FREQ_0 - the IF frequency setting (an 18-bit signed number). +// MODEM_DECIMATION_CFG1 - Specifies three decimator ratios for the Cascaded Integrator Comb (CIC) filter. +// MODEM_DECIMATION_CFG0 - Specifies miscellaneous parameters and decimator ratios for the Cascaded Integrator Comb +(CIC) filter. +// MODEM_DECIMATION_CFG2 - Specifies miscellaneous decimator filter selections. +// MODEM_IFPKD_THRESHOLDS - +// MODEM_BCR_OSR_1 - RX BCR/Slicer oversampling rate (12-bit unsigned number). +// MODEM_BCR_OSR_0 - RX BCR/Slicer oversampling rate (12-bit unsigned number). +*/ +#define RF_MODEM_TX_RAMP_DELAY_12 \ + 0x11, 0x20, 0x0C, 0x18, 0x01, 0x80, 0x08, 0x03, 0x80, 0x00, 0x20, 0x10, 0x00, 0xE8, 0x00, 0xC3 + +/* +// Set properties: RF_MODEM_BCR_NCO_OFFSET_2_12 +// Number of properties: 12 +// Group ID: 0x20 +// Start ID: 0x24 +// Default values: 0x06, 0xD3, 0xA0, 0x06, 0xD3, 0x02, 0xC0, 0x00, 0x00, 0x23, 0x83, 0x69, +// Descriptions: +// MODEM_BCR_NCO_OFFSET_2 - RX BCR NCO offset value (an unsigned 22-bit number). +// MODEM_BCR_NCO_OFFSET_1 - RX BCR NCO offset value (an unsigned 22-bit number). +// MODEM_BCR_NCO_OFFSET_0 - RX BCR NCO offset value (an unsigned 22-bit number). +// MODEM_BCR_GAIN_1 - The unsigned 11-bit RX BCR loop gain value. +// MODEM_BCR_GAIN_0 - The unsigned 11-bit RX BCR loop gain value. +// MODEM_BCR_GEAR - RX BCR loop gear control. +// MODEM_BCR_MISC1 - Miscellaneous control bits for the RX BCR loop. +// MODEM_BCR_MISC0 - Miscellaneous RX BCR loop controls. +// MODEM_AFC_GEAR - RX AFC loop gear control. +// MODEM_AFC_WAIT - RX AFC loop wait time control. +// MODEM_AFC_GAIN_1 - Sets the gain of the PLL-based AFC acquisition loop, and provides miscellaneous control bits for +AFC functionality. +// MODEM_AFC_GAIN_0 - Sets the gain of the PLL-based AFC acquisition loop, and provides miscellaneous control bits for +AFC functionality. +*/ +#define RF_MODEM_BCR_NCO_OFFSET_2_12 \ + 0x11, 0x20, 0x0C, 0x24, 0x02, 0x9F, 0x17, 0x01, 0x50, 0x02, 0xC2, 0x00, 0x04, 0x23, 0x80, 0x25 + +/* +// Set properties: RF_MODEM_AFC_LIMITER_1_3 +// Number of properties: 3 +// Group ID: 0x20 +// Start ID: 0x30 +// Default values: 0x00, 0x40, 0xA0, +// Descriptions: +// MODEM_AFC_LIMITER_1 - Set the AFC limiter value. +// MODEM_AFC_LIMITER_0 - Set the AFC limiter value. +// MODEM_AFC_MISC - Specifies miscellaneous AFC control bits. +*/ +#define RF_MODEM_AFC_LIMITER_1_3 0x11, 0x20, 0x03, 0x30, 0x0B, 0x9A, 0x80 + +/* +// Set properties: RF_MODEM_AGC_CONTROL_1 +// Number of properties: 1 +// Group ID: 0x20 +// Start ID: 0x35 +// Default values: 0xE0, +// Descriptions: +// MODEM_AGC_CONTROL - Miscellaneous control bits for the Automatic Gain Control (AGC) function in the RX Chain. +*/ +#define RF_MODEM_AGC_CONTROL_1 0x11, 0x20, 0x01, 0x35, 0xE0 + +/* +// Set properties: RF_MODEM_AGC_WINDOW_SIZE_12 +// Number of properties: 12 +// Group ID: 0x20 +// Start ID: 0x38 +// Default values: 0x11, 0x10, 0x10, 0x0B, 0x1C, 0x40, 0x00, 0x00, 0x2B, 0x0C, 0xA4, 0x03, +// Descriptions: +// MODEM_AGC_WINDOW_SIZE - Specifies the size of the measurement and settling windows for the AGC algorithm. +// MODEM_AGC_RFPD_DECAY - Sets the decay time of the RF peak detectors. +// MODEM_AGC_IFPD_DECAY - Sets the decay time of the IF peak detectors. +// MODEM_FSK4_GAIN1 - Specifies the gain factor of the secondary branch in 4(G)FSK ISI-suppression. +// MODEM_FSK4_GAIN0 - Specifies the gain factor of the primary branch in 4(G)FSK ISI-suppression. +// MODEM_FSK4_TH1 - 16 bit 4(G)FSK slicer threshold. +// MODEM_FSK4_TH0 - 16 bit 4(G)FSK slicer threshold. +// MODEM_FSK4_MAP - 4(G)FSK symbol mapping code. +// MODEM_OOK_PDTC - Configures the attack and decay times of the OOK Peak Detector. +// MODEM_OOK_BLOPK - Configures the slicing reference level of the OOK Peak Detector. +// MODEM_OOK_CNT1 - OOK control. +// MODEM_OOK_MISC - Selects the detector(s) used for demodulation of an OOK signal, or for demodulation of a (G)FSK +signal when using the asynchronous demodulator. +*/ +#define RF_MODEM_AGC_WINDOW_SIZE_12 \ + 0x11, 0x20, 0x0C, 0x38, 0x11, 0x2B, 0x2B, 0x80, 0x1A, 0xFA, 0x00, 0x00, 0x29, 0x0C, 0xA4, 0x22 + +/* +// Set properties: RF_MODEM_RAW_CONTROL_10 +// Number of properties: 10 +// Group ID: 0x20 +// Start ID: 0x45 +// Default values: 0x02, 0x00, 0xA3, 0x02, 0x80, 0xFF, 0x0C, 0x01, 0x00, 0x40, +// Descriptions: +// MODEM_RAW_CONTROL - Defines gain and enable controls for raw / nonstandard mode. +// MODEM_RAW_EYE_1 - 11 bit eye-open detector threshold. +// MODEM_RAW_EYE_0 - 11 bit eye-open detector threshold. +// MODEM_ANT_DIV_MODE - Antenna diversity mode settings. +// MODEM_ANT_DIV_CONTROL - Specifies controls for the Antenna Diversity algorithm. +// MODEM_RSSI_THRESH - Configures the RSSI threshold. +// MODEM_RSSI_JUMP_THRESH - Configures the RSSI Jump Detection threshold. +// MODEM_RSSI_CONTROL - Control of the averaging modes and latching time for reporting RSSI value(s). +// MODEM_RSSI_CONTROL2 - RSSI Jump Detection control. +// MODEM_RSSI_COMP - RSSI compensation value. +*/ +#define RF_MODEM_RAW_CONTROL_10 0x11, 0x20, 0x0A, 0x45, 0x83, 0x01, 0x9F, 0x01, 0x00, 0xFF, 0x06, 0x00, 0x18, 0x40 + +/* +// Set properties: RF_MODEM_RAW_SEARCH2_2 +// Number of properties: 2 +// Group ID: 0x20 +// Start ID: 0x50 +// Default values: 0x00, 0x08, +// Descriptions: +// MODEM_RAW_SEARCH2 - Defines and controls the search period length for the Moving Average and Min-Max detectors. +// MODEM_CLKGEN_BAND - Select PLL Synthesizer output divider ratio as a function of frequency band. +*/ +#define RF_MODEM_RAW_SEARCH2_2 0x11, 0x20, 0x02, 0x50, 0x84, 0x0A + +/* +// Set properties: RF_MODEM_SPIKE_DET_2 +// Number of properties: 2 +// Group ID: 0x20 +// Start ID: 0x54 +// Default values: 0x00, 0x00, +// Descriptions: +// MODEM_SPIKE_DET - Configures the threshold for (G)FSK Spike Detection. +// MODEM_ONE_SHOT_AFC - Configures parameters for th e One Shot AFC function and for BCR timing/acquisition. +*/ +#define RF_MODEM_SPIKE_DET_2 0x11, 0x20, 0x02, 0x54, 0x05, 0x07 + +/* +// Set properties: RF_MODEM_RSSI_MUTE_1 +// Number of properties: 1 +// Group ID: 0x20 +// Start ID: 0x57 +// Default values: 0x00, +// Descriptions: +// MODEM_RSSI_MUTE - Configures muting of the RSSI to avoid false RSSI interrupts. +*/ +#define RF_MODEM_RSSI_MUTE_1 0x11, 0x20, 0x01, 0x57, 0x00 + +/* +// Set properties: RF_MODEM_DSA_CTRL1_5 +// Number of properties: 5 +// Group ID: 0x20 +// Start ID: 0x5B +// Default values: 0x00, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// MODEM_DSA_CTRL1 - Configures parameters for the Signal Arrival Detection circuit block and algorithm. +// MODEM_DSA_CTRL2 - Configures parameters for the Signal Arrival Detection circuit block and algorithm. +// MODEM_DSA_QUAL - Configures parameters for the Eye Opening qualification m ethod of the Signal Arrival Detection +algorithm. +// MODEM_DSA_RSSI - Signal Arrival Detect RSSI Qualifier Config +// MODEM_DSA_MISC - Miscellaneous detection of signal arrival bits. +*/ +#define RF_MODEM_DSA_CTRL1_5 0x11, 0x20, 0x05, 0x5B, 0x40, 0x04, 0x0C, 0x78, 0x20 + +/* +// Set properties: RF_MODEM_CHFLT_RX1_CHFLT_COE13_7_0_12 +// Number of properties: 12 +// Group ID: 0x21 +// Start ID: 0x00 +// Default values: 0xFF, 0xBA, 0x0F, 0x51, 0xCF, 0xA9, 0xC9, 0xFC, 0x1B, 0x1E, 0x0F, 0x01, +// Descriptions: +// MODEM_CHFLT_RX1_CHFLT_COE13_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE12_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE11_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE10_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE9_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE8_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE7_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE6_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE5_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE4_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE3_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE2_7_0 - Filter coefficients for the first set of RX filter coefficients. +*/ +#define RF_MODEM_CHFLT_RX1_CHFLT_COE13_7_0_12 \ + 0x11, 0x21, 0x0C, 0x00, 0xFF, 0xBA, 0x0F, 0x51, 0xCF, 0xA9, 0xC9, 0xFC, 0x1B, 0x1E, 0x0F, 0x01 + +/* +// Set properties: RF_MODEM_CHFLT_RX1_CHFLT_COE1_7_0_12 +// Number of properties: 12 +// Group ID: 0x21 +// Start ID: 0x0C +// Default values: 0xFC, 0xFD, 0x15, 0xFF, 0x00, 0x0F, 0xFF, 0xC4, 0x30, 0x7F, 0xF5, 0xB5, +// Descriptions: +// MODEM_CHFLT_RX1_CHFLT_COE1_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COE0_7_0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COEM0 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COEM1 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COEM2 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX1_CHFLT_COEM3 - Filter coefficients for the first set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE13_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE12_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE11_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE10_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE9_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE8_7_0 - Filter coefficients for the second set of RX filter coefficients. +*/ +#define RF_MODEM_CHFLT_RX1_CHFLT_COE1_7_0_12 \ + 0x11, 0x21, 0x0C, 0x0C, 0xFC, 0xFD, 0x15, 0xFF, 0x00, 0x0F, 0xFF, 0xBA, 0x0F, 0x51, 0xCF, 0xA9 + +/* +// Set properties: RF_MODEM_CHFLT_RX2_CHFLT_COE7_7_0_12 +// Number of properties: 12 +// Group ID: 0x21 +// Start ID: 0x18 +// Default values: 0xB8, 0xDE, 0x05, 0x17, 0x16, 0x0C, 0x03, 0x00, 0x15, 0xFF, 0x00, 0x00, +// Descriptions: +// MODEM_CHFLT_RX2_CHFLT_COE7_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE6_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE5_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE4_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE3_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE2_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE1_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COE0_7_0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COEM0 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COEM1 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COEM2 - Filter coefficients for the second set of RX filter coefficients. +// MODEM_CHFLT_RX2_CHFLT_COEM3 - Filter coefficients for the second set of RX filter coefficients. +*/ +#define RF_MODEM_CHFLT_RX2_CHFLT_COE7_7_0_12 \ + 0x11, 0x21, 0x0C, 0x18, 0xC9, 0xFC, 0x1B, 0x1E, 0x0F, 0x01, 0xFC, 0xFD, 0x15, 0xFF, 0x00, 0x0F + +/* +// Set properties: RF_PA_MODE_4 +// Number of properties: 4 +// Group ID: 0x22 +// Start ID: 0x00 +// Default values: 0x08, 0x7F, 0x00, 0x5D, +// Descriptions: +// PA_MODE - Selects the PA operating mode, and selects resolution of PA power adjustment (i.e., step size). +// PA_PWR_LVL - Configuration of PA output power level. +// PA_BIAS_CLKDUTY - Configuration of the PA Bias and duty cycle of the TX clock source. +// PA_TC - Configuration of PA ramping parameters. +*/ +#define RF_PA_MODE_4 0x11, 0x22, 0x04, 0x00, 0x08, 0x7F, 0x00, 0x1D + +/* +// Set properties: RF_SYNTH_PFDCP_CPFF_7 +// Number of properties: 7 +// Group ID: 0x23 +// Start ID: 0x00 +// Default values: 0x2C, 0x0E, 0x0B, 0x04, 0x0C, 0x73, 0x03, +// Descriptions: +// SYNTH_PFDCP_CPFF - Feed forward charge pump current selection. +// SYNTH_PFDCP_CPINT - Integration charge pump current selection. +// SYNTH_VCO_KV - Gain scaling factors (Kv) for the VCO tuning varactors on both the integrated-path and feed forward +path. +// SYNTH_LPFILT3 - Value of resistor R2 in feed-forward path of loop filter. +// SYNTH_LPFILT2 - Value of capacitor C2 in feed-forward path of loop filter. +// SYNTH_LPFILT1 - Value of capacitors C1 and C3 in feed-forward path of loop filter. +// SYNTH_LPFILT0 - Bias current of the active amplifier in the feed-forward loop filter. +*/ +#define RF_SYNTH_PFDCP_CPFF_7 0x11, 0x23, 0x07, 0x00, 0x2C, 0x0E, 0x0B, 0x04, 0x0C, 0x73, 0x03 + +/* +// Set properties: RF_MATCH_VALUE_1_12 +// Number of properties: 12 +// Group ID: 0x30 +// Start ID: 0x00 +// Default values: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// Descriptions: +// MATCH_VALUE_1 - Match value to be compared with the result of logically AND-ing (bit-wise) the Mask 1 value with +the received Match 1 byte. +// MATCH_MASK_1 - Mask value to be logically AND-ed (bit-wise) with the Match 1 byte. +// MATCH_CTRL_1 - Enable for Packet Match functionality, and configuration of Match Byte 1. +// MATCH_VALUE_2 - Match value to be compared with the result of logically AND-ing (bit-wise) the Mask 2 value with +the received Match 2 byte. +// MATCH_MASK_2 - Mask value to be logically AND-ed (bit-wise) with the Match 2 byte. +// MATCH_CTRL_2 - Configuration of Match Byte 2. +// MATCH_VALUE_3 - Match value to be compared with the result of logically AND-ing (bit-wise) the Mask 3 value with +the received Match 3 byte. +// MATCH_MASK_3 - Mask value to be logically AND-ed (bit-wise) with the Match 3 byte. +// MATCH_CTRL_3 - Configuration of Match Byte 3. +// MATCH_VALUE_4 - Match value to be compared with the result of logically AND-ing (bit-wise) the Mask 4 value with +the received Match 4 byte. +// MATCH_MASK_4 - Mask value to be logically AND-ed (bit-wise) with the Match 4 byte. +// MATCH_CTRL_4 - Configuration of Match Byte 4. +*/ +#define RF_MATCH_VALUE_1_12 \ + 0x11, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +/* +// Set properties: RF_FREQ_CONTROL_INTE_8 +// Number of properties: 8 +// Group ID: 0x40 +// Start ID: 0x00 +// Default values: 0x3C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, +// Descriptions: +// FREQ_CONTROL_INTE - Frac-N PLL Synthesizer integer divide number. +// FREQ_CONTROL_FRAC_2 - Frac-N PLL fraction number. +// FREQ_CONTROL_FRAC_1 - Frac-N PLL fraction number. +// FREQ_CONTROL_FRAC_0 - Frac-N PLL fraction number. +// FREQ_CONTROL_CHANNEL_STEP_SIZE_1 - EZ Frequency Programming channel step size. +// FREQ_CONTROL_CHANNEL_STEP_SIZE_0 - EZ Frequency Programming channel step size. +// FREQ_CONTROL_W_SIZE - Set window gating period (in number of crystal reference clock cycles) for counting VCO +frequency during calibration. +// FREQ_CONTROL_VCOCNT_RX_ADJ - Adjust target count for VCO calibration in RX mode. +*/ +#define RF_FREQ_CONTROL_INTE_8 0x11, 0x40, 0x08, 0x00, 0x38, 0x0E, 0x61, 0x12, 0x00, 0x00, 0x20, 0xFE + +// AUTOMATICALLY GENERATED CODE! +// DO NOT EDIT/MODIFY BELOW THIS LINE! +// -------------------------------------------- + +#ifndef FIRMWARE_LOAD_COMPILE +#define RADIO_CONFIGURATION_DATA_ARRAY \ + { \ + 0x07, RF_POWER_UP, 0x08, RF_GPIO_PIN_CFG, 0x06, RF_GLOBAL_XO_TUNE_2, 0x05, RF_GLOBAL_CONFIG_1, 0x06, \ + RF_INT_CTL_ENABLE_2, 0x08, RF_FRR_CTL_A_MODE_4, 0x0D, RF_PREAMBLE_TX_LENGTH_9, 0x0A, RF_SYNC_CONFIG_6, 0x10, \ + RF_PKT_CRC_CONFIG_12, 0x10, RF_PKT_RX_THRESHOLD_12, 0x10, RF_PKT_FIELD_3_CRC_CONFIG_12, 0x10, \ + RF_PKT_RX_FIELD_1_CRC_CONFIG_12, 0x09, RF_PKT_RX_FIELD_4_CRC_CONFIG_5, 0x08, RF_PKT_CRC_SEED_31_24_4, 0x10, \ + RF_MODEM_MOD_TYPE_12, 0x05, RF_MODEM_FREQ_DEV_0_1, 0x10, RF_MODEM_TX_RAMP_DELAY_12, 0x10, \ + RF_MODEM_BCR_NCO_OFFSET_2_12, 0x07, RF_MODEM_AFC_LIMITER_1_3, 0x05, RF_MODEM_AGC_CONTROL_1, 0x10, \ + RF_MODEM_AGC_WINDOW_SIZE_12, 0x0E, RF_MODEM_RAW_CONTROL_10, 0x06, RF_MODEM_RAW_SEARCH2_2, 0x06, \ + RF_MODEM_SPIKE_DET_2, 0x05, RF_MODEM_RSSI_MUTE_1, 0x09, RF_MODEM_DSA_CTRL1_5, 0x10, \ + RF_MODEM_CHFLT_RX1_CHFLT_COE13_7_0_12, 0x10, RF_MODEM_CHFLT_RX1_CHFLT_COE1_7_0_12, 0x10, \ + RF_MODEM_CHFLT_RX2_CHFLT_COE7_7_0_12, 0x08, RF_PA_MODE_4, 0x0B, RF_SYNTH_PFDCP_CPFF_7, 0x10, \ + RF_MATCH_VALUE_1_12, 0x0C, RF_FREQ_CONTROL_INTE_8, 0x00 \ + } +#else +#define RADIO_CONFIGURATION_DATA_ARRAY \ + { 0 } +#endif + +// DEFAULT VALUES FOR CONFIGURATION PARAMETERS +#define RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ_DEFAULT 30000000L +#define RADIO_CONFIGURATION_DATA_CHANNEL_NUMBER_DEFAULT 0x00 +#define RADIO_CONFIGURATION_DATA_RADIO_PACKET_LENGTH_DEFAULT 0x10 +#define RADIO_CONFIGURATION_DATA_RADIO_STATE_AFTER_POWER_UP_DEFAULT 0x01 +#define RADIO_CONFIGURATION_DATA_RADIO_DELAY_CNT_AFTER_RESET_DEFAULT 0x1000 + +#define RADIO_CONFIGURATION_DATA_RADIO_PATCH_INCLUDED 0x00 +#define RADIO_CONFIGURATION_DATA_RADIO_PATCH_SIZE 0x00 +#define RADIO_CONFIGURATION_DATA_RADIO_PATCH \ + {} + +#ifndef RADIO_CONFIGURATION_DATA_ARRAY +#error "This property must be defined!" +#endif + +#ifndef RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ +#define RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ_DEFAULT +#endif + +#ifndef RADIO_CONFIGURATION_DATA_CHANNEL_NUMBER +#define RADIO_CONFIGURATION_DATA_CHANNEL_NUMBER RADIO_CONFIGURATION_DATA_CHANNEL_NUMBER_DEFAULT +#endif + +#ifndef RADIO_CONFIGURATION_DATA_RADIO_PACKET_LENGTH +#define RADIO_CONFIGURATION_DATA_RADIO_PACKET_LENGTH RADIO_CONFIGURATION_DATA_RADIO_PACKET_LENGTH_DEFAULT +#endif + +#ifndef RADIO_CONFIGURATION_DATA_RADIO_STATE_AFTER_POWER_UP +#define RADIO_CONFIGURATION_DATA_RADIO_STATE_AFTER_POWER_UP RADIO_CONFIGURATION_DATA_RADIO_STATE_AFTER_POWER_UP_DEFAULT +#endif + +#ifndef RADIO_CONFIGURATION_DATA_RADIO_DELAY_CNT_AFTER_RESET +#define RADIO_CONFIGURATION_DATA_RADIO_DELAY_CNT_AFTER_RESET \ + RADIO_CONFIGURATION_DATA_RADIO_DELAY_CNT_AFTER_RESET_DEFAULT +#endif + +#define RADIO_CONFIGURATION_DATA \ + { \ + Radio_Configuration_Data_Array, RADIO_CONFIGURATION_DATA_CHANNEL_NUMBER, \ + RADIO_CONFIGURATION_DATA_RADIO_PACKET_LENGTH, RADIO_CONFIGURATION_DATA_RADIO_STATE_AFTER_POWER_UP, \ + RADIO_CONFIGURATION_DATA_RADIO_DELAY_CNT_AFTER_RESET \ + } + +#endif /* RADIO_CONFIG_H_ */ diff --git a/esphome/components/temperbridge/si446x.cpp b/esphome/components/temperbridge/si446x.cpp new file mode 100644 index 000000000000..970ed489d608 --- /dev/null +++ b/esphome/components/temperbridge/si446x.cpp @@ -0,0 +1,80 @@ +#include "si446x.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace temperbridge { + +static const char *const TAG = "temperbridge"; + +void Si446xGetIntStatusResp::print() { + if (this->int_pend != 0) { + ESP_LOGI(TAG, "interrupt pend:"); + if (this->int_pend & (1 << 2)) + ESP_LOGI(TAG, "\tCHIP_INT_PEND"); + if (this->int_pend & (1 << 1)) + ESP_LOGI(TAG, "\tMODEM_INT_PEND"); + if (this->int_pend & (1 << 0)) + ESP_LOGI(TAG, "\tPH_INT_PEND"); + } + + if (this->ph_pend != 0) { + ESP_LOGI(TAG, "packet pend:"); + if (this->ph_pend & (1 << 7)) + ESP_LOGI(TAG, "\tFILTER_MATCH_PEND"); + if (this->ph_pend & (1 << 6)) + ESP_LOGI(TAG, "\tFILTER_MISS_PEND"); + if (this->ph_pend & (1 << 5)) + ESP_LOGI(TAG, "\tPACKET_SENT_PEND"); + if (this->ph_pend & (1 << 4)) + ESP_LOGI(TAG, "\tPACKET_RX_PEND"); + if (this->ph_pend & (1 << 3)) + ESP_LOGI(TAG, "\tCRC_ERROR_PEND"); + if (this->ph_pend & (1 << 2)) + ESP_LOGI(TAG, "\tALT_CRC_ERROR_PEND"); + if (this->ph_pend & (1 << 1)) + ESP_LOGI(TAG, "\tTX_FIFO_ALMOST_EMPTY_PEND"); + if (this->ph_pend & (1 << 0)) + ESP_LOGI(TAG, "\tRX_FIFO_ALMOST_FULL_PEND"); + } + + if (this->modem_pend != 0) { + ESP_LOGI(TAG, "modem pend:"); + if (this->modem_pend & (1 << 7)) + ESP_LOGI(TAG, "\tRSSI_LATCH_PEND"); + if (this->modem_pend & (1 << 6)) + ESP_LOGI(TAG, "\tPOSTAMBLE_DETECT_PEND"); + if (this->modem_pend & (1 << 5)) + ESP_LOGI(TAG, "\tINVALID_SYNC_PEND"); + if (this->modem_pend & (1 << 4)) + ESP_LOGI(TAG, "\tRSSI_JUMP_PEND"); + if (this->modem_pend & (1 << 3)) + ESP_LOGI(TAG, "\tRSSI_PEND"); + if (this->modem_pend & (1 << 2)) + ESP_LOGI(TAG, "\tINVALID_PREAMBLE_PEND"); + if (this->modem_pend & (1 << 1)) + ESP_LOGI(TAG, "\tPREAMBLE_DETECT_PEND"); + if (this->modem_pend & (1 << 0)) + ESP_LOGI(TAG, "\tSYNC_DETECT_PEND"); + } + + if (this->chip_pend != 0) { + ESP_LOGI(TAG, "chip pend:"); + if (this->chip_pend & (1 << 6)) + ESP_LOGI(TAG, "\tCAL_PEND"); + if (this->chip_pend & (1 << 5)) + ESP_LOGI(TAG, "\tFIFO_UNDERFLOW_OVERFLOW_ERROR_PEND"); + if (this->chip_pend & (1 << 4)) + ESP_LOGI(TAG, "\tSTATE_CHANGE_PEND"); + if (this->chip_pend & (1 << 3)) + ESP_LOGI(TAG, "\t>>> CMD_ERROR_PEND <<<"); + if (this->chip_pend & (1 << 2)) + ESP_LOGI(TAG, "\tCHIP_READY_PEND"); + if (this->chip_pend & (1 << 1)) + ESP_LOGI(TAG, "\tLOW_BATT_PEND"); + if (this->chip_pend & (1 << 0)) + ESP_LOGI(TAG, "\tWUT_PEND"); + } +} + +} // namespace temperbridge +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/temperbridge/si446x.h b/esphome/components/temperbridge/si446x.h new file mode 100644 index 000000000000..6dabd2af9bbe --- /dev/null +++ b/esphome/components/temperbridge/si446x.h @@ -0,0 +1,61 @@ +#ifndef TEMPERF_BRIDGE_ALEXA_SI446X_H +#define TEMPERF_BRIDGE_ALEXA_SI446X_H + +#include + +#define SI446X_CMD_PART_INFO 0x01 +#define SI446X_CMD_SET_PROPERTY 0x11 +#define SI446X_CMD_GET_PROPERTY 0x12 +#define SI446X_CMD_FIFO_INFO 0x15 +#define SI446X_CMD_GET_INT_STATUS 0x20 +#define SI446X_CMD_START_TX 0x31 +#define SI446X_CMD_WRITE_TX_FIFO 0x66 +#define SI446X_CMD_READ_CMD_BUFF 0x44 +#define SI446X_CMD_FRR_A_READ 0x50 + +namespace esphome { +namespace temperbridge { + +struct Si446xChipInfoResp { + uint8_t chiprev; + uint16_t part; + uint8_t prbuild; + uint16_t id; + uint8_t customer; + uint8_t romid; +} __attribute__((packed)); + +struct Si446xGetIntStatusResp { + uint8_t int_pend; + uint8_t int_status; + uint8_t ph_pend; + uint8_t ph_status; + uint8_t modem_pend; + uint8_t modem_status; + uint8_t chip_pend; + uint8_t chip_status; + + void print(); +} __attribute__((packed)); + +struct Si446xFifoInfoResp { + uint8_t rx_fifo_count; + uint8_t tx_fifo_space; +} __attribute__((packed)); + +struct Si446xGetPropertyArgs { + uint8_t group; + uint8_t num_props; + uint8_t start_prop; +} __attribute__((packed)); + +struct Si446xSetPropertyArgs { + uint8_t group; + uint8_t num_props; + uint8_t start_prop; +} __attribute__((packed)); + +} // namespace temperbridge +} // namespace esphome + +#endif // TEMPERF_BRIDGE_ALEXA_SI446X_H diff --git a/esphome/components/temperbridge/temperbridge.cpp b/esphome/components/temperbridge/temperbridge.cpp new file mode 100644 index 000000000000..9bc4bc557bf8 --- /dev/null +++ b/esphome/components/temperbridge/temperbridge.cpp @@ -0,0 +1,561 @@ +#include +#include + +#include "esphome/core/helpers.h" +#include "si446x.h" +#include "radio_config_Si4463.h" + +#include "temperbridge.h" + +namespace esphome { +namespace temperbridge { + +static const char *const TAG = "temperbridge"; + +const uint8_t SI4463_RADIO_CONFIGURATION_DATA_ARRAY[] = RADIO_CONFIGURATION_DATA_ARRAY; + +void TemperBridgeComponent::setup() { + this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT); + this->interrupt_pin_->setup(); + + // this->store_.pin = this->interrupt_pin_->to_isr(); + + this->sdn_pin_->pin_mode(gpio::FLAG_OUTPUT); + this->sdn_pin_->setup(); + + this->spi_setup(); + + Component::setup(); + + this->sdn_pin_->digital_write(true); + delay(10); + this->sdn_pin_->digital_write(false); + delay(20); + + const Si446xChipInfoResp resp = si446x_part_info_(); + ESP_LOGCONFIG(TAG, "part %x", resp.part); + ESP_LOGCONFIG(TAG, "rev %x", resp.chiprev); + // https://community.silabs.com/s/article/using-part-info-command-to-identify-ezradio-pro-part-number?language=en_US + ESP_LOGCONFIG(TAG, "romid %x", resp.romid); + ESP_LOGCONFIG(TAG, "prbuild %x", resp.prbuild); + + si446x_configuration_init_(SI4463_RADIO_CONFIGURATION_DATA_ARRAY); + + Si446xGetIntStatusResp int_status; + si446x_get_int_status(&int_status, true); + int_status.print(); + + this->initialized_ = true; + + this->tune_channel_(this->channel_); +} + +void TemperBridgeComponent::si446x_raw_command_(const uint8_t *tx_data, size_t tx_data_bytes, uint8_t *resp, + size_t resp_bytes) { + // Wait for CTS + while (true) { + this->enable(); + this->write_byte(SI446X_CMD_READ_CMD_BUFF); + const uint8_t cts = this->read_byte(); + this->disable(); + if (cts == 0xFF) { + break; + } + delay(20); + } + + this->enable(); + this->write_array(tx_data, tx_data_bytes); + this->disable(); + + // TODO timeout + if (resp) { + while (true) { + this->enable(); + this->write_byte(SI446X_CMD_READ_CMD_BUFF); + const uint8_t cts = this->read_byte(); + if (cts != 0xFF) { + this->disable(); + delay(20); + continue; + } + + this->read_array(resp, resp_bytes); + this->disable(); + break; + } + } +} + +Si446xChipInfoResp TemperBridgeComponent::si446x_part_info_() { + static_assert(sizeof(Si446xChipInfoResp) == 8, "size wrong"); + Si446xChipInfoResp ret; + + this->si446x_execute_command_(SI446X_CMD_PART_INFO, nullptr, 0, (uint8_t *) &ret, sizeof(Si446xChipInfoResp)); + ret.part = convert_big_endian(ret.part); + ret.id = convert_big_endian(ret.id); + + return ret; +} +void TemperBridgeComponent::si446x_execute_command_(uint8_t command, const uint8_t *args, size_t arg_bytes, + uint8_t *data, size_t data_bytes) { + assert(data != nullptr); + + uint8_t tx_data[arg_bytes + 1]; + tx_data[0] = command; + if (arg_bytes > 0) { + assert(args != nullptr); + memcpy(tx_data + 1, args, arg_bytes); + } + + this->si446x_raw_command_(tx_data, arg_bytes + 1, data, data_bytes); +} +void TemperBridgeComponent::si446x_configuration_init_(const uint8_t *data) { + while (*data != 0) { + const size_t size_bytes = *data++; + assert(size_bytes <= 16); + + uint8_t command[size_bytes]; + memcpy(command, data, size_bytes); + ESP_LOGI(TAG, "Processing command %x with # bytes: %d", command[0], size_bytes); + data += size_bytes; + si446x_raw_command_(command, size_bytes, nullptr, 0); + } +} + +void TemperBridgeComponent::si446x_get_int_status(Si446xGetIntStatusResp *ret, bool clear_pending) { + static_assert(sizeof(Si446xGetIntStatusResp) == 8, "wrong size"); + if (clear_pending) { + si446x_execute_command_(SI446X_CMD_GET_INT_STATUS, nullptr, 0, (uint8_t *) ret, sizeof(Si446xGetIntStatusResp)); + } else { + const uint8_t args[] = { + static_cast(0xFF), + static_cast(0xFF), + static_cast(0x7F), + }; + + si446x_execute_command_(SI446X_CMD_GET_INT_STATUS, args, sizeof(args), (uint8_t *) ret, + sizeof(Si446xGetIntStatusResp)); + } +} + +void TemperBridgeComponent::read_irq_pend_frr() { + this->enable(); + this->write_byte(SI446X_CMD_FRR_A_READ); + const uint8_t a = this->read_byte(); + const uint8_t b = this->read_byte(); + const uint8_t c = this->read_byte(); + const uint8_t d = this->read_byte(); + ESP_LOGI(TAG, "a: %x, b: %x, c: %x, d: %x", a, b, c, d); + + this->disable(); +} + +enum class TemperCommand : uint32_t { + HEAD_UP = 0X96530005, + HEAD_DOWN = 0X96540005, + FLAT = 0X965C0400, + LEG_UP = 0X96510100, + LEG_DOWN = 0X96520100, + MEM_1 = 0X965C0000, + MEM_2 = 0X965C0100, + MEM_3 = 0X965C0200, + MEM_4 = 0X965C0300, + SET_MEM_1 = 0x965B0000, + SET_MEM_2 = 0x965B0100, + SET_MEM_3 = 0x965B0200, + SET_MEM_4 = 0x965B0300, + STOP = 0X96860000, + MASSAGE_MODE_1 = 0X968D0078, + MASSAGE_MODE_2 = 0X968D0178, + MASSAGE_MODE_3 = 0X968D0278, + MASSAGE_MODE_4 = 0X968D0378 +}; + +#define TEMPER_CMD_BROADCAST_CH 0x96000000 + +// CRC table generated from http://www.sunshine2k.de/coding/javascript/crc/crc_js.html +// The parameters were reversed using http://reveng.sourceforge.net/ +// Poly: 0x8D, initial: 0xFF +const uint8_t TEMPER_CRC_TABLE[] = { + 0x00, 0x8D, 0x97, 0x1A, 0xA3, 0x2E, 0x34, 0xB9, 0xCB, 0x46, 0x5C, 0xD1, 0x68, 0xE5, 0xFF, 0x72, 0x1B, 0x96, 0x8C, + 0x01, 0xB8, 0x35, 0x2F, 0xA2, 0xD0, 0x5D, 0x47, 0xCA, 0x73, 0xFE, 0xE4, 0x69, 0x36, 0xBB, 0xA1, 0x2C, 0x95, 0x18, + 0x02, 0x8F, 0xFD, 0x70, 0x6A, 0xE7, 0x5E, 0xD3, 0xC9, 0x44, 0x2D, 0xA0, 0xBA, 0x37, 0x8E, 0x03, 0x19, 0x94, 0xE6, + 0x6B, 0x71, 0xFC, 0x45, 0xC8, 0xD2, 0x5F, 0x6C, 0xE1, 0xFB, 0x76, 0xCF, 0x42, 0x58, 0xD5, 0xA7, 0x2A, 0x30, 0xBD, + 0x04, 0x89, 0x93, 0x1E, 0x77, 0xFA, 0xE0, 0x6D, 0xD4, 0x59, 0x43, 0xCE, 0xBC, 0x31, 0x2B, 0xA6, 0x1F, 0x92, 0x88, + 0x05, 0x5A, 0xD7, 0xCD, 0x40, 0xF9, 0x74, 0x6E, 0xE3, 0x91, 0x1C, 0x06, 0x8B, 0x32, 0xBF, 0xA5, 0x28, 0x41, 0xCC, + 0xD6, 0x5B, 0xE2, 0x6F, 0x75, 0xF8, 0x8A, 0x07, 0x1D, 0x90, 0x29, 0xA4, 0xBE, 0x33, 0xD8, 0x55, 0x4F, 0xC2, 0x7B, + 0xF6, 0xEC, 0x61, 0x13, 0x9E, 0x84, 0x09, 0xB0, 0x3D, 0x27, 0xAA, 0xC3, 0x4E, 0x54, 0xD9, 0x60, 0xED, 0xF7, 0x7A, + 0x08, 0x85, 0x9F, 0x12, 0xAB, 0x26, 0x3C, 0xB1, 0xEE, 0x63, 0x79, 0xF4, 0x4D, 0xC0, 0xDA, 0x57, 0x25, 0xA8, 0xB2, + 0x3F, 0x86, 0x0B, 0x11, 0x9C, 0xF5, 0x78, 0x62, 0xEF, 0x56, 0xDB, 0xC1, 0x4C, 0x3E, 0xB3, 0xA9, 0x24, 0x9D, 0x10, + 0x0A, 0x87, 0xB4, 0x39, 0x23, 0xAE, 0x17, 0x9A, 0x80, 0x0D, 0x7F, 0xF2, 0xE8, 0x65, 0xDC, 0x51, 0x4B, 0xC6, 0xAF, + 0x22, 0x38, 0xB5, 0x0C, 0x81, 0x9B, 0x16, 0x64, 0xE9, 0xF3, 0x7E, 0xC7, 0x4A, 0x50, 0xDD, 0x82, 0x0F, 0x15, 0x98, + 0x21, 0xAC, 0xB6, 0x3B, 0x49, 0xC4, 0xDE, 0x53, 0xEA, 0x67, 0x7D, 0xF0, 0x99, 0x14, 0x0E, 0x83, 0x3A, 0xB7, 0xAD, + 0x20, 0x52, 0xDF, 0xC5, 0x48, 0xF1, 0x7C, 0x66, 0xEB, +}; + +uint8_t temper_crc(const uint8_t data[], size_t len) { + // Compute CRC using table lookup method + uint8_t ret = 0xFF; + for (size_t i = 0; i < len; i++) { + const uint8_t byte = data[i] ^ ret; + ret = TEMPER_CRC_TABLE[byte]; + } + + return ret; +} + +void TemperBridgeComponent::start_positioning(PositionCommand cmd) { + TemperCommand command; + switch (cmd) { + case PositionCommand::LOWER_HEAD: + command = TemperCommand::HEAD_DOWN; + break; + case PositionCommand::LOWER_LEGS: + command = TemperCommand::LEG_DOWN; + break; + case PositionCommand::RAISE_HEAD: + command = TemperCommand::HEAD_UP; + break; + case PositionCommand::RAISE_LEGS: + command = TemperCommand::LEG_UP; + break; + } + + for (int i = 0; i < 5; i++) { + const uint32_t tx_start = micros(); + this->transmit_command_(static_cast(command)); + this->si446x_start_tx_(); + + const uint32_t start_time = millis(); + while (this->interrupt_pin_->digital_read()) { + if (millis() - start_time > 50) { + break; + } + } + + Si446xGetIntStatusResp int_status; + si446x_get_int_status(&int_status, true); + int_status.print(); + + uint32_t tx_diff = micros() - tx_start; + ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); + + while (tx_diff < 100000) { + delay(10); + tx_diff = micros() - tx_start; + } + + ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); + } +} + +void TemperBridgeComponent::execute_simple_command(SimpleCommand cmd) { + ESP_LOGI(TAG, "OK buddy!"); + + TemperCommand command; + switch (cmd) { + case SimpleCommand::PRESET_FLAT: + command = TemperCommand::FLAT; + break; + case SimpleCommand::PRESET_MODE1: + command = TemperCommand::MEM_1; + break; + case SimpleCommand::PRESET_MODE2: + command = TemperCommand::MEM_2; + break; + case SimpleCommand::PRESET_MODE3: + command = TemperCommand::MEM_3; + break; + case SimpleCommand::PRESET_MODE4: + command = TemperCommand::MEM_4; + break; + case SimpleCommand::SAVE_PRESET_MODE1: + command = TemperCommand::SET_MEM_1; + break; + case SimpleCommand::SAVE_PRESET_MODE2: + command = TemperCommand::SET_MEM_2; + break; + case SimpleCommand::SAVE_PRESET_MODE3: + command = TemperCommand::SET_MEM_3; + break; + case SimpleCommand::SAVE_PRESET_MODE4: + command = TemperCommand::SET_MEM_4; + break; + case SimpleCommand::STOP: + command = TemperCommand::STOP; + this->massage_head_intensity_ = 0; + this->massage_leg_intensity_ = 0; + this->massage_lumbar_intensity_ = 0; + this->massage_command_mode_ = MassageCommandMode::CUSTOM; + break; + case SimpleCommand::MASSAGE_PRESET_MODE1: + command = TemperCommand::MASSAGE_MODE_1; + this->massage_head_intensity_ = 5; + this->massage_leg_intensity_ = 5; + this->massage_lumbar_intensity_ = 5; + this->massage_command_mode_ = MassageCommandMode::BUILTIN; + break; + case SimpleCommand::MASSAGE_PRESET_MODE2: + command = TemperCommand::MASSAGE_MODE_2; + this->massage_command_mode_ = MassageCommandMode::BUILTIN; + break; + case SimpleCommand::MASSAGE_PRESET_MODE3: + command = TemperCommand::MASSAGE_MODE_3; + this->massage_command_mode_ = MassageCommandMode::BUILTIN; + break; + case SimpleCommand::MASSAGE_PRESET_MODE4: + command = TemperCommand::MASSAGE_MODE_4; + this->massage_command_mode_ = MassageCommandMode::BUILTIN; + break; + } + + ESP_LOGI(TAG, "TX"); + + for (int i = 0; i < 3; i++) { + const uint32_t tx_start = micros(); + this->transmit_command_(static_cast(command)); + this->si446x_start_tx_(); + + const uint32_t start_time = millis(); + while (this->interrupt_pin_->digital_read()) { + ESP_LOGE(TAG, "interrupt timeout!"); + if (millis() - start_time > 50) { + break; + } + } + + Si446xGetIntStatusResp int_status; + si446x_get_int_status(&int_status, true); + int_status.print(); + + uint32_t tx_diff = micros() - tx_start; + ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); + + while (tx_diff < 100000) { + delay(10); + tx_diff = micros() - tx_start; + } + + ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); + } + + ESP_LOGI(TAG, "done waiting"); +} + +void TemperBridgeComponent::transmit_command_(uint32_t command) { + // This command doesn't need to wait for CTS + uint8_t packet_bytes[9] = {0}; + static_assert(sizeof(TemperPacket) == 7, "wrong size"); + packet_bytes[0] = SI446X_CMD_WRITE_TX_FIFO; + packet_bytes[1] = sizeof(TemperPacket); + + TemperPacket packet = {.cmd = convert_big_endian(command), .channel = convert_big_endian(this->channel_)}; + packet.crc = temper_crc((uint8_t *) &packet, 6); + memcpy(packet_bytes + 2, &packet, sizeof(TemperPacket)); + + this->enable(); + this->write_array(packet_bytes, sizeof(packet_bytes)); + this->disable(); +} + +void TemperBridgeComponent::loop() { + if (!this->interrupt_pin_->digital_read()) { + Si446xGetIntStatusResp int_status; + si446x_get_int_status(&int_status, true); + int_status.print(); + } +} + +void TemperBridgeComponent::set_channel(uint16_t channel) { + this->channel_ = channel; + if (this->initialized_) { + this->tune_channel_(channel); + } +} + +void TemperBridgeComponent::si446x_fifo_info_(Si446xFifoInfoResp *ret, bool clear_rx, bool clear_tx) { + static_assert(sizeof(Si446xFifoInfoResp) == 2, ""); + uint8_t const arg = (clear_tx ? (1 << 0) : 0) | (clear_rx ? (1 << 1) : 0); + si446x_execute_command_(SI446X_CMD_FIFO_INFO, &arg, 1, (uint8_t *) ret, sizeof(Si446xFifoInfoResp)); +} + +void TemperBridgeComponent::si446x_start_tx_() { + uint8_t start_ret[1]; + uint8_t tx_args[] = { + 0x0, // channel + 0, // condition + }; + si446x_execute_command_(SI446X_CMD_START_TX, tx_args, sizeof(tx_args), start_ret, sizeof(start_ret)); +} + +inline float temper_frequency_for_channel(uint16_t channel) { + // compute fc (from original Si4432 implementation) + const uint16_t fc = channel > 8862 ? ((2 * channel) + 10658) : channel + 19520; + return 10.0f * (19 + 24 + (fc / 64000.0f)); +} + +// TODO these methods should go in the si446x file +void temper_calculate_freq_control(uint16_t channel, uint8_t *freq_control_inte, uint32_t *freq_control_frac) { + assert(channel >= 1); + assert(channel <= 10111); + assert(freq_control_inte != nullptr); + assert(freq_control_frac != nullptr); + + // TODO compiler warnings + // oscillator frequency in Hz + const float freq_xo = 0x01C9C380; + + const float freq_mhz = temper_frequency_for_channel(channel); + const float freq_hz = pow10f(6) * freq_mhz; + + const float N = freq_hz / ((2 * freq_xo) / 8); + + float integ; + float frac = modff(N, &integ); + + integ--; + frac++; + assert(frac >= 1 && frac <= 2); + + *freq_control_frac = frac * powf(2, 19); + *freq_control_inte = integ; +} + +void TemperBridgeComponent::si446x_set_freq_control_properties_(uint8_t freq_control_inte, uint32_t freq_control_frac) { + Si446xSetPropertyArgs args = { + .group = 0x40, // TODO don't hardcode + .num_props = 4, + .start_prop = 0x00 // TODO don't hardcode + }; + + uint8_t data[] = {freq_control_inte, static_cast((freq_control_frac & 0xFFFF00) >> 16), + static_cast((freq_control_frac & 0xFF00) >> 8), + static_cast(freq_control_frac & 0xFF)}; + si446x_set_property_(&args, data); +} + +void TemperBridgeComponent::si446x_set_property_(Si446xSetPropertyArgs *args, uint8_t *data) { + static_assert(sizeof(Si446xSetPropertyArgs) == 3, "wrong size"); + uint8_t cts; + uint8_t full_args[sizeof(Si446xSetPropertyArgs) + args->num_props]; + memcpy(full_args, (uint8_t *) args, sizeof(Si446xSetPropertyArgs)); + memcpy(full_args + sizeof(Si446xSetPropertyArgs), data, args->num_props); + + si446x_execute_command_(SI446X_CMD_SET_PROPERTY, full_args, sizeof(full_args), &cts, 1); +} + +void TemperBridgeComponent::si446x_get_property_(Si446xGetPropertyArgs *args, uint8_t *props) { + static_assert(sizeof(Si446xGetPropertyArgs) == 3, "wrong size"); + uint8_t resp[args->num_props + 1]; + si446x_execute_command_(SI446X_CMD_GET_PROPERTY, (uint8_t *) args, sizeof(Si446xGetPropertyArgs), (uint8_t *) resp, + args->num_props + 1); + memcpy(props, resp + 1, args->num_props); +} + +void TemperBridgeComponent::si446x_get_freq_control_properties_(uint8_t *freq_control_inte, + uint32_t *freq_control_frac) { + Si446xGetPropertyArgs args = { + .group = 0x40, // TODO don't hardcode + .num_props = 4, + .start_prop = 0x00 // TODO don't hardcode + }; + + uint8_t freq_props[4] = {0}; + si446x_get_property_(&args, freq_props); + + *freq_control_inte = freq_props[0]; + *freq_control_frac = freq_props[3] | (freq_props[2] << 8) | (freq_props[1] << 16); +} + +void TemperBridgeComponent::tune_channel_(uint16_t channel) { + uint8_t calc_inte; + uint32_t calc_frac; + temper_calculate_freq_control(channel, &calc_inte, &calc_frac); + + ESP_LOGI(TAG, "calculated frac: %08" PRIx32, calc_frac); + ESP_LOGI(TAG, "calculated inte: %x", calc_inte); + + si446x_set_freq_control_properties_(calc_inte, calc_frac); + + delay(50); + + uint32_t read_frac; + uint8_t read_inte; + si446x_get_freq_control_properties_(&read_inte, &read_frac); + ESP_LOGI(TAG, "read frac: %08" PRIx32, read_frac); + ESP_LOGI(TAG, "read inte: %x", read_inte); +} + +// This one seems to be used when making adjustments to built-in modes +#define TEMPER_MASSAGE_MAGIC_1 0x968E0000 +#define TEMPER_MASSAGE_MAGIC_2 0x96850000 + +#define TEMPER_MASSAGE_TYPE_HEAD 0X00000000 +#define TEMPER_MASSAGE_TYPE_LUMBAR 0X00000100 +#define TEMPER_MASSAGE_TYPE_LEG 0X00000200 + +#define TEMPER_MASSAGE_LEVEL_STEP 0x18 + +void TemperBridgeComponent::set_massage_level(MassageTarget target, uint8_t level) { + uint32_t command = + this->massage_command_mode_ == MassageCommandMode::BUILTIN ? TEMPER_MASSAGE_MAGIC_1 : TEMPER_MASSAGE_MAGIC_2; + + switch (target) { + case MassageTarget::HEAD: + if (this->massage_head_intensity_ == level) { + return; + } + this->massage_head_intensity_ = level; + command |= TEMPER_MASSAGE_TYPE_HEAD; + break; + case MassageTarget::LEGS: + if (this->massage_leg_intensity_ == level) { + return; + } + this->massage_leg_intensity_ = level; + command |= TEMPER_MASSAGE_TYPE_LEG; + break; + case MassageTarget::LUMBAR: + if (this->massage_lumbar_intensity_ == level) { + return; + } + this->massage_lumbar_intensity_ = level; + command |= TEMPER_MASSAGE_TYPE_LUMBAR; + break; + } + + command |= TEMPER_MASSAGE_LEVEL_STEP * level; + + // TODO: De-dupe + for (int i = 0; i < 3; i++) { + const uint32_t tx_start = micros(); + this->transmit_command_(static_cast(command)); + this->si446x_start_tx_(); + + const uint32_t start_time = millis(); + while (this->interrupt_pin_->digital_read()) { + ESP_LOGE(TAG, "interrupt timeout!"); + if (millis() - start_time > 50) { + break; + } + } + + Si446xGetIntStatusResp int_status; + si446x_get_int_status(&int_status, true); + int_status.print(); + + uint32_t tx_diff = micros() - tx_start; + ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); + + while (tx_diff < 100000) { + delay(10); + tx_diff = micros() - tx_start; + } + + ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); + } +} + +} // namespace temperbridge +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/temperbridge/temperbridge.h b/esphome/components/temperbridge/temperbridge.h new file mode 100644 index 000000000000..91396c463ad8 --- /dev/null +++ b/esphome/components/temperbridge/temperbridge.h @@ -0,0 +1,144 @@ +#include "esphome/core/component.h" +#include "esphome/components/spi/spi.h" +#include "esphome/core/log.h" +#include "esphome/core/automation.h" + +#ifndef ESPHOME_TEMPERBRIDGE_H +#define ESPHOME_TEMPERBRIDGE_H + +namespace esphome { +namespace temperbridge { + +enum class SimpleCommand { + PRESET_FLAT, + PRESET_MODE1, + PRESET_MODE2, + PRESET_MODE3, + PRESET_MODE4, + SAVE_PRESET_MODE1, + SAVE_PRESET_MODE2, + SAVE_PRESET_MODE3, + SAVE_PRESET_MODE4, + STOP, + MASSAGE_PRESET_MODE1, + MASSAGE_PRESET_MODE2, + MASSAGE_PRESET_MODE3, + MASSAGE_PRESET_MODE4, +}; + +enum class PositionCommand { + RAISE_HEAD, + RAISE_LEGS, + LOWER_HEAD, + LOWER_LEGS, +}; + +enum class MassageTarget { + HEAD, + LEGS, + LUMBAR, +}; + +enum class MassageCommandMode { + BUILTIN, + CUSTOM, +}; + +struct TemperPacket { + uint32_t cmd; + uint16_t channel; + uint8_t crc; +} PACKED; + +class TemperBridgeComponent : public Component, + public spi::SPIDevice { + public: + void setup() override; + void loop() override; + + void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } + + void set_sdn_pin(GPIOPin *pin) { this->sdn_pin_ = pin; } + + void execute_simple_command(SimpleCommand cmd); + + void start_positioning(PositionCommand cmd); + + void set_channel(uint16_t channel); + + void set_massage_level(MassageTarget target, uint8_t level); + + void si446x_get_int_status(Si446xGetIntStatusResp *ret, bool clear_pending); + + protected: + void si446x_raw_command_(const uint8_t *tx_data, size_t tx_data_bytes, uint8_t *resp, size_t resp_bytes); + void si446x_execute_command_(uint8_t command, const uint8_t *args, size_t arg_bytes, uint8_t *data, size_t data_bytes); + Si446xChipInfoResp si446x_part_info_(); + void si446x_configuration_init_(const uint8_t *data); + void si446x_fifo_info_(Si446xFifoInfoResp *ret, bool clear_rx, bool clear_tx); + void si446x_start_tx_(); + void si446x_set_freq_control_properties_(uint8_t freq_control_inte, uint32_t freq_control_frac); + void si446x_set_property_(Si446xSetPropertyArgs *args, uint8_t *data); + void si446x_get_freq_control_properties_(uint8_t *freq_control_inte, uint32_t *freq_control_frac); + void si446x_get_property_(Si446xGetPropertyArgs *args, uint8_t *props); + + void transmit_command_(uint32_t command); + + void read_irq_pend_frr(); + + void tune_channel_(uint16_t channel); + + bool initialized_ = false; + + uint16_t channel_; + InternalGPIOPin *interrupt_pin_; + GPIOPin *sdn_pin_; + + uint8_t massage_leg_intensity_ = 0; + uint8_t massage_head_intensity_ = 0; + uint8_t massage_lumbar_intensity_ = 0; + MassageCommandMode massage_command_mode_ = MassageCommandMode::CUSTOM; +}; + +template class ExecuteSimpleCommandAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(SimpleCommand, cmd); + + void play(Ts... x) override { this->parent_->execute_simple_command(this->cmd_.value(x...)); } +}; + +template class PositionCommandAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(PositionCommand, cmd); + + void play(Ts... x) override { this->parent_->start_positioning(this->cmd_.value(x...)); } +}; + +template class SetChannelAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(uint16_t, channel) + + void play(Ts... x) override { + auto channel = this->channel_.value(x...); + ESP_LOGI("temperbridge", "channel: %d", channel); + this->parent_->set_channel(channel); + } +}; + +template class SetMassageIntensityAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(MassageTarget, target) + TEMPLATABLE_VALUE(uint8_t, level) + + void play(Ts... x) override { + auto target = this->target_.value(x...); + auto level = this->level_.value(x...); + this->parent_->set_massage_level(target, level); + } +}; + +} // namespace temperbridge +} // namespace esphome + +#endif // ESPHOME_TEMPERBRIDGE_H From 54c504241ee6fd7111edc729f68e1da8ad898543 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Sun, 15 Jan 2023 15:59:38 -0500 Subject: [PATCH 02/12] cleanup massage --- .../components/temperbridge/temperbridge.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/esphome/components/temperbridge/temperbridge.cpp b/esphome/components/temperbridge/temperbridge.cpp index 9bc4bc557bf8..757f2cb368e0 100644 --- a/esphome/components/temperbridge/temperbridge.cpp +++ b/esphome/components/temperbridge/temperbridge.cpp @@ -97,6 +97,7 @@ Si446xChipInfoResp TemperBridgeComponent::si446x_part_info_() { return ret; } + void TemperBridgeComponent::si446x_execute_command_(uint8_t command, const uint8_t *args, size_t arg_bytes, uint8_t *data, size_t data_bytes) { assert(data != nullptr); @@ -110,6 +111,7 @@ void TemperBridgeComponent::si446x_execute_command_(uint8_t command, const uint8 this->si446x_raw_command_(tx_data, arg_bytes + 1, data, data_bytes); } + void TemperBridgeComponent::si446x_configuration_init_(const uint8_t *data) { while (*data != 0) { const size_t size_bytes = *data++; @@ -291,25 +293,26 @@ void TemperBridgeComponent::execute_simple_command(SimpleCommand cmd) { break; case SimpleCommand::MASSAGE_PRESET_MODE1: command = TemperCommand::MASSAGE_MODE_1; - this->massage_head_intensity_ = 5; - this->massage_leg_intensity_ = 5; - this->massage_lumbar_intensity_ = 5; - this->massage_command_mode_ = MassageCommandMode::BUILTIN; break; case SimpleCommand::MASSAGE_PRESET_MODE2: command = TemperCommand::MASSAGE_MODE_2; - this->massage_command_mode_ = MassageCommandMode::BUILTIN; break; case SimpleCommand::MASSAGE_PRESET_MODE3: command = TemperCommand::MASSAGE_MODE_3; - this->massage_command_mode_ = MassageCommandMode::BUILTIN; break; case SimpleCommand::MASSAGE_PRESET_MODE4: command = TemperCommand::MASSAGE_MODE_4; - this->massage_command_mode_ = MassageCommandMode::BUILTIN; break; } + if (cmd == SimpleCommand::MASSAGE_PRESET_MODE1 || cmd == SimpleCommand::MASSAGE_PRESET_MODE2 || + cmd == SimpleCommand::MASSAGE_PRESET_MODE3 || cmd == SimpleCommand::MASSAGE_PRESET_MODE4) { + this->massage_head_intensity_ = 5; + this->massage_leg_intensity_ = 5; + this->massage_lumbar_intensity_ = 5; + this->massage_command_mode_ = MassageCommandMode::BUILTIN; + } + ESP_LOGI(TAG, "TX"); for (int i = 0; i < 3; i++) { From 7755bcd568c1e1e770da82c20c92761399a7f084 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Sun, 22 Jan 2023 22:40:15 -0500 Subject: [PATCH 03/12] fix --- esphome/components/temperbridge/temperbridge.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/esphome/components/temperbridge/temperbridge.cpp b/esphome/components/temperbridge/temperbridge.cpp index 757f2cb368e0..b961509c6d21 100644 --- a/esphome/components/temperbridge/temperbridge.cpp +++ b/esphome/components/temperbridge/temperbridge.cpp @@ -100,8 +100,6 @@ Si446xChipInfoResp TemperBridgeComponent::si446x_part_info_() { void TemperBridgeComponent::si446x_execute_command_(uint8_t command, const uint8_t *args, size_t arg_bytes, uint8_t *data, size_t data_bytes) { - assert(data != nullptr); - uint8_t tx_data[arg_bytes + 1]; tx_data[0] = command; if (arg_bytes > 0) { @@ -384,12 +382,11 @@ void TemperBridgeComponent::si446x_fifo_info_(Si446xFifoInfoResp *ret, bool clea } void TemperBridgeComponent::si446x_start_tx_() { - uint8_t start_ret[1]; uint8_t tx_args[] = { 0x0, // channel 0, // condition }; - si446x_execute_command_(SI446X_CMD_START_TX, tx_args, sizeof(tx_args), start_ret, sizeof(start_ret)); + si446x_execute_command_(SI446X_CMD_START_TX, tx_args, sizeof(tx_args), nullptr, 0); } inline float temper_frequency_for_channel(uint16_t channel) { @@ -450,10 +447,10 @@ void TemperBridgeComponent::si446x_set_property_(Si446xSetPropertyArgs *args, ui void TemperBridgeComponent::si446x_get_property_(Si446xGetPropertyArgs *args, uint8_t *props) { static_assert(sizeof(Si446xGetPropertyArgs) == 3, "wrong size"); - uint8_t resp[args->num_props + 1]; + uint8_t resp[args->num_props]; si446x_execute_command_(SI446X_CMD_GET_PROPERTY, (uint8_t *) args, sizeof(Si446xGetPropertyArgs), (uint8_t *) resp, - args->num_props + 1); - memcpy(props, resp + 1, args->num_props); + args->num_props); + memcpy(props, resp, args->num_props); } void TemperBridgeComponent::si446x_get_freq_control_properties_(uint8_t *freq_control_inte, From c6f1cb75931a469e79ecb0699c309260e1c40917 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Mon, 23 Jan 2023 21:49:43 -0500 Subject: [PATCH 04/12] slow down the SPI bus --- esphome/components/temperbridge/temperbridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/temperbridge/temperbridge.h b/esphome/components/temperbridge/temperbridge.h index 91396c463ad8..a6bada28cbb8 100644 --- a/esphome/components/temperbridge/temperbridge.h +++ b/esphome/components/temperbridge/temperbridge.h @@ -52,7 +52,7 @@ struct TemperPacket { class TemperBridgeComponent : public Component, public spi::SPIDevice { + spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_4MHZ> { public: void setup() override; void loop() override; From 5241165000727d5d4a47a5eec2de412ae86faf96 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Fri, 27 Jan 2023 16:31:10 -0500 Subject: [PATCH 05/12] deduplicate code --- .../components/temperbridge/temperbridge.cpp | 98 +++++-------------- 1 file changed, 26 insertions(+), 72 deletions(-) diff --git a/esphome/components/temperbridge/temperbridge.cpp b/esphome/components/temperbridge/temperbridge.cpp index b961509c6d21..be4ff8d4dccf 100644 --- a/esphome/components/temperbridge/temperbridge.cpp +++ b/esphome/components/temperbridge/temperbridge.cpp @@ -43,7 +43,7 @@ void TemperBridgeComponent::setup() { Si446xGetIntStatusResp int_status; si446x_get_int_status(&int_status, true); - int_status.print(); + //int_status.print(); this->initialized_ = true; @@ -223,30 +223,7 @@ void TemperBridgeComponent::start_positioning(PositionCommand cmd) { } for (int i = 0; i < 5; i++) { - const uint32_t tx_start = micros(); this->transmit_command_(static_cast(command)); - this->si446x_start_tx_(); - - const uint32_t start_time = millis(); - while (this->interrupt_pin_->digital_read()) { - if (millis() - start_time > 50) { - break; - } - } - - Si446xGetIntStatusResp int_status; - si446x_get_int_status(&int_status, true); - int_status.print(); - - uint32_t tx_diff = micros() - tx_start; - ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); - - while (tx_diff < 100000) { - delay(10); - tx_diff = micros() - tx_start; - } - - ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); } } @@ -314,37 +291,15 @@ void TemperBridgeComponent::execute_simple_command(SimpleCommand cmd) { ESP_LOGI(TAG, "TX"); for (int i = 0; i < 3; i++) { - const uint32_t tx_start = micros(); this->transmit_command_(static_cast(command)); - this->si446x_start_tx_(); - - const uint32_t start_time = millis(); - while (this->interrupt_pin_->digital_read()) { - ESP_LOGE(TAG, "interrupt timeout!"); - if (millis() - start_time > 50) { - break; - } - } - - Si446xGetIntStatusResp int_status; - si446x_get_int_status(&int_status, true); - int_status.print(); - - uint32_t tx_diff = micros() - tx_start; - ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); - - while (tx_diff < 100000) { - delay(10); - tx_diff = micros() - tx_start; - } - - ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); } ESP_LOGI(TAG, "done waiting"); } void TemperBridgeComponent::transmit_command_(uint32_t command) { + const uint32_t tx_start = micros(); + // This command doesn't need to wait for CTS uint8_t packet_bytes[9] = {0}; static_assert(sizeof(TemperPacket) == 7, "wrong size"); @@ -358,6 +313,29 @@ void TemperBridgeComponent::transmit_command_(uint32_t command) { this->enable(); this->write_array(packet_bytes, sizeof(packet_bytes)); this->disable(); + + this->si446x_start_tx_(); + + const uint32_t start_time = millis(); + while (this->interrupt_pin_->digital_read()) { + if (millis() - start_time > 50) { + break; + } + } + + Si446xGetIntStatusResp int_status; + si446x_get_int_status(&int_status, true); + //int_status.print(); + + uint32_t tx_diff = micros() - tx_start; + ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); + + while (tx_diff < 100000) { + delay(10); + tx_diff = micros() - tx_start; + } + + ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); } void TemperBridgeComponent::loop() { @@ -529,31 +507,7 @@ void TemperBridgeComponent::set_massage_level(MassageTarget target, uint8_t leve // TODO: De-dupe for (int i = 0; i < 3; i++) { - const uint32_t tx_start = micros(); this->transmit_command_(static_cast(command)); - this->si446x_start_tx_(); - - const uint32_t start_time = millis(); - while (this->interrupt_pin_->digital_read()) { - ESP_LOGE(TAG, "interrupt timeout!"); - if (millis() - start_time > 50) { - break; - } - } - - Si446xGetIntStatusResp int_status; - si446x_get_int_status(&int_status, true); - int_status.print(); - - uint32_t tx_diff = micros() - tx_start; - ESP_LOGI(TAG, "took %u us to TX one packet", tx_diff); - - while (tx_diff < 100000) { - delay(10); - tx_diff = micros() - tx_start; - } - - ESP_LOGI(TAG, "after delay: took %u us to TX one packet", tx_diff); } } From 711b433a963540cbf02c235bd2c84146f88a9896 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Fri, 27 Jan 2023 16:34:10 -0500 Subject: [PATCH 06/12] remove more debug logging --- esphome/components/temperbridge/temperbridge.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/esphome/components/temperbridge/temperbridge.cpp b/esphome/components/temperbridge/temperbridge.cpp index be4ff8d4dccf..6b3a26310a56 100644 --- a/esphome/components/temperbridge/temperbridge.cpp +++ b/esphome/components/temperbridge/temperbridge.cpp @@ -228,8 +228,6 @@ void TemperBridgeComponent::start_positioning(PositionCommand cmd) { } void TemperBridgeComponent::execute_simple_command(SimpleCommand cmd) { - ESP_LOGI(TAG, "OK buddy!"); - TemperCommand command; switch (cmd) { case SimpleCommand::PRESET_FLAT: @@ -288,13 +286,9 @@ void TemperBridgeComponent::execute_simple_command(SimpleCommand cmd) { this->massage_command_mode_ = MassageCommandMode::BUILTIN; } - ESP_LOGI(TAG, "TX"); - for (int i = 0; i < 3; i++) { this->transmit_command_(static_cast(command)); } - - ESP_LOGI(TAG, "done waiting"); } void TemperBridgeComponent::transmit_command_(uint32_t command) { From e667be2227a1ae0133b1b32a60e08d6e87674d62 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Fri, 27 Jan 2023 20:16:44 -0500 Subject: [PATCH 07/12] add js to fix dumb range sliders in web server --- temperbridge.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 temperbridge.js diff --git a/temperbridge.js b/temperbridge.js new file mode 100644 index 000000000000..0ea9d9422623 --- /dev/null +++ b/temperbridge.js @@ -0,0 +1,7 @@ +let style = document.createElement("style"); + +style.textContent = `input[type="range"] { + width: auto !important; +}` + +document.getElementsByTagName("esp-app")[0].shadowRoot.querySelector("esp-entity-table").shadowRoot.appendChild(style); \ No newline at end of file From bb9714034afbd49719a12c8fc098511cfa642403 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Sun, 16 Apr 2023 21:11:41 -0400 Subject: [PATCH 08/12] gitignore secrets.yaml --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 71b66b249987..6a613af78cdf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +secrets.yaml + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -129,4 +131,4 @@ tests/.esphome/ sdkconfig.* !sdkconfig.defaults -.tests/ \ No newline at end of file +.tests/ From b7a0829fd822ba31a31f88263d58b26655321325 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Sun, 16 Apr 2023 21:12:08 -0400 Subject: [PATCH 09/12] add temperbridge.yaml config --- temperbridge.yaml | 370 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 temperbridge.yaml diff --git a/temperbridge.yaml b/temperbridge.yaml new file mode 100644 index 000000000000..6e1c0f64f7bd --- /dev/null +++ b/temperbridge.yaml @@ -0,0 +1,370 @@ +substitutions: + devicename: bedroom1 + upper_devicename: Bedroom1 + +esphome: + name: temperbridge + name_add_mac_suffix: true + +esp32: + board: esp32dev + framework: + type: arduino + +# Enable Home Assistant API +api: + encryption: + key: !secret encryption_key + +ota: + password: !secret password + +wifi: + # Enable fallback hotspot (captive portal) in case wifi connection fails + ap: + ssid: "TemperBridge Wifi Config" + password: !secret password + +# Enable logging +logger: + +captive_portal: + +# Uncomment below lines to enable the web server. +#web_server: +# js_include: "temperbridge.js" +# auth: +# username: "temper" +# password: !secret password + +esp32_improv: + authorizer: other_button + +improv_serial: + +binary_sensor: + - platform: gpio + id: other_button + name: ${upper_devicename} Physical Reset Button + pin: + number: GPIO0 + mode: + input: true + pullup: true + inverted: true + on_click: + min_length: 10000ms + then: + - button.press: ${devicename}_factory_reset + +temperbridge: + id: ${devicename}_bed + cs_pin: 5 + sdn_pin: 14 + interrupt_pin: 27 + +spi: + clk_pin: 18 + miso_pin: 19 + mosi_pin: 23 + +# Red LED +status_led: + pin: GPIO2 + +# Green LED +output: + - platform: ledc + pin: GPIO16 + id: ${devicename}_status_led_output + +light: + - platform: monochromatic + output: ${devicename}_status_led_output + name: "${upper_devicename} Green LED" + +time: + - platform: homeassistant + id: homeassistant_time + +button: + - platform: factory_reset + id: ${devicename}_factory_reset + name: ${upper_devicename} Restart with Factory Default Settings + - platform: template + name: ${upper_devicename} Flat + + # Optional variables: + icon: "mdi:seat-flat" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "flat" + - platform: template + name: ${upper_devicename} Preset 1 + + icon: "mdi:numeric-1-box" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "mode_1" + - platform: template + name: ${upper_devicename} Preset 2 + + icon: "mdi:numeric-2-box" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "mode_2" + - platform: template + name: ${upper_devicename} Preset 3 + + icon: "mdi:numeric-3-box" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "mode_3" + - platform: template + name: ${upper_devicename} Preset 4 + + icon: "mdi:numeric-4-box" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "mode_4" + - platform: template + name: ${upper_devicename} Save Preset 1 + + icon: "mdi:content-save-settings-outline" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "save_preset_mode1" + + - platform: template + name: ${upper_devicename} Save Preset 2 + + icon: "mdi:content-save-settings-outline" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "save_preset_mode2" + + - platform: template + name: ${upper_devicename} Save Preset 3 + + icon: "mdi:content-save-settings-outline" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "save_preset_mode3" + + - platform: template + name: ${upper_devicename} Save Preset 4 + + icon: "mdi:content-save-settings-outline" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "save_preset_mode4" + + - platform: template + name: ${upper_devicename} Massage Mode 1 + + icon: "mdi:wave" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "massage_mode_1" + - lambda: |- + auto call = id(${devicename}_head_massage_intensity).make_call(); + call.set_value(5); + call.perform(); + + auto call2 = id(${devicename}_lumbar_massage_intensity).make_call(); + call2.set_value(5); + call2.perform(); + + auto call3 = id(${devicename}_legs_massage_intensity).make_call(); + call3.set_value(5); + call3.perform(); + + - platform: template + name: ${upper_devicename} Massage Mode 2 + + icon: "mdi:sine-wave" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "massage_mode_2" + - lambda: |- + auto call = id(${devicename}_head_massage_intensity).make_call(); + call.set_value(5); + call.perform(); + + auto call2 = id(${devicename}_lumbar_massage_intensity).make_call(); + call2.set_value(5); + call2.perform(); + + auto call3 = id(${devicename}_legs_massage_intensity).make_call(); + call3.set_value(5); + call3.perform(); + + - platform: template + name: ${upper_devicename} Massage Mode 3 + + icon: "mdi:waves" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "massage_mode_3" + - lambda: |- + auto call = id(${devicename}_head_massage_intensity).make_call(); + call.set_value(5); + call.perform(); + + auto call2 = id(${devicename}_lumbar_massage_intensity).make_call(); + call2.set_value(5); + call2.perform(); + + auto call3 = id(${devicename}_legs_massage_intensity).make_call(); + call3.set_value(5); + call3.perform(); + + - platform: template + name: ${upper_devicename} Massage Mode 4 + + icon: "mdi:reorder-vertical" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "massage_mode_4" + - lambda: |- + auto call = id(${devicename}_head_massage_intensity).make_call(); + call.set_value(5); + call.perform(); + + auto call2 = id(${devicename}_lumbar_massage_intensity).make_call(); + call2.set_value(5); + call2.perform(); + + auto call3 = id(${devicename}_legs_massage_intensity).make_call(); + call3.set_value(5); + call3.perform(); + + - platform: template + name: ${upper_devicename} Stop + + icon: "mdi:stop" + on_press: + - temperbridge.execute_simple_command: + id: ${devicename}_bed + cmd: "stop" + - lambda: |- + auto call = id(${devicename}_head_massage_intensity).make_call(); + call.set_value(0); + call.perform(); + + auto call2 = id(${devicename}_lumbar_massage_intensity).make_call(); + call2.set_value(0); + call2.perform(); + + auto call3 = id(${devicename}_legs_massage_intensity).make_call(); + call3.set_value(0); + call3.perform(); + + - platform: template + name: ${upper_devicename} Head Up + + icon: "mdi:seat-flat-angled" + on_press: + - temperbridge.position_command_2: + id: ${devicename}_bed + cmd: "raise_head" + - platform: template + name: ${upper_devicename} Head Down + + icon: "mdi:seat-flat-angled" + on_press: + - temperbridge.position_command_2: + id: ${devicename}_bed + cmd: "lower_head" + - platform: template + name: ${upper_devicename} Legs Up + + icon: "mdi:seat-legroom-extra" + on_press: + - temperbridge.position_command_2: + id: ${devicename}_bed + cmd: "raise_legs" + - platform: template + name: ${upper_devicename} Legs Down + + icon: "mdi:seat-legroom-normal" + on_press: + - temperbridge.position_command_2: + id: ${devicename}_bed + cmd: "lower_legs" +number: + - platform: template + # Example number configuration + name: ${upper_devicename} Channel + + # Optional variables: + icon: "mdi:counter" + + min_value: 1 + max_value: 9999 + step: 1 + optimistic: true + restore_value: true + mode: box + + on_value: + then: + - temperbridge.set_channel: + id: ${devicename}_bed + channel: !lambda "return x;" + + - platform: template + name: ${upper_devicename} Head Massage Intensity + id: ${devicename}_head_massage_intensity + icon: "mdi:head-dots-horizontal" + min_value: 0 + max_value: 10 + step: 1 + optimistic: true + on_value: + then: + temperbridge.set_massage_intensity: + id: ${devicename}_bed + target: head + level: !lambda "return x;" + + - platform: template + name: ${upper_devicename} Lumbar Massage Intensity + id: ${devicename}_lumbar_massage_intensity + min_value: 0 + max_value: 10 + step: 1 + optimistic: true + on_value: + then: + temperbridge.set_massage_intensity: + id: ${devicename}_bed + target: lumbar + level: !lambda "return x;" + + - platform: template + name: ${upper_devicename} Leg Massage Intensity + id: ${devicename}_legs_massage_intensity + min_value: 0 + max_value: 10 + step: 1 + optimistic: true + on_value: + then: + temperbridge.set_massage_intensity: + id: ${devicename}_bed + target: legs + level: !lambda "return x;" From dde2a1090e1a089cb1b4feeadfc69c4bf7fa2510 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Wed, 17 May 2023 21:10:56 -0400 Subject: [PATCH 10/12] fix factory reset button --- temperbridge.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/temperbridge.yaml b/temperbridge.yaml index 6e1c0f64f7bd..38661a74204c 100644 --- a/temperbridge.yaml +++ b/temperbridge.yaml @@ -54,6 +54,7 @@ binary_sensor: inverted: true on_click: min_length: 10000ms + max_length: 30000ms then: - button.press: ${devicename}_factory_reset From 3152c7aabadf76304f785af8c617cd27ce477d8a Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Wed, 17 May 2023 21:11:22 -0400 Subject: [PATCH 11/12] tweak name of Factory Button --- temperbridge.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temperbridge.yaml b/temperbridge.yaml index 38661a74204c..15da57e6e562 100644 --- a/temperbridge.yaml +++ b/temperbridge.yaml @@ -45,7 +45,7 @@ improv_serial: binary_sensor: - platform: gpio id: other_button - name: ${upper_devicename} Physical Reset Button + name: ${upper_devicename} Factory Button pin: number: GPIO0 mode: From 43fb43c368976ddaf2f52ff1d2802eb8b88653dc Mon Sep 17 00:00:00 2001 From: esphomebot Date: Thu, 16 Nov 2023 06:49:53 +0000 Subject: [PATCH 12/12] Synchronise Device Classes from Home Assistant --- esphome/components/button/__init__.py | 2 ++ esphome/components/number/__init__.py | 6 ++++++ esphome/components/sensor/__init__.py | 4 ++++ esphome/const.py | 3 +++ 4 files changed, 15 insertions(+) diff --git a/esphome/components/button/__init__.py b/esphome/components/button/__init__.py index 55f2fe794a67..a999c6d91e6c 100644 --- a/esphome/components/button/__init__.py +++ b/esphome/components/button/__init__.py @@ -12,6 +12,7 @@ CONF_TRIGGER_ID, CONF_MQTT_ID, DEVICE_CLASS_EMPTY, + DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, DEVICE_CLASS_UPDATE, ) @@ -24,6 +25,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_EMPTY, + DEVICE_CLASS_IDENTIFY, DEVICE_CLASS_RESTART, DEVICE_CLASS_UPDATE, ] diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index f532f4e405f9..e6ad545d7029 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -28,6 +28,7 @@ DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY_STORAGE, @@ -42,6 +43,7 @@ DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, @@ -57,6 +59,7 @@ DEVICE_CLASS_SULPHUR_DIOXIDE, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, @@ -80,6 +83,7 @@ DEVICE_CLASS_DATA_RATE, DEVICE_CLASS_DATA_SIZE, DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, DEVICE_CLASS_ENERGY_STORAGE, @@ -94,6 +98,7 @@ DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, @@ -109,6 +114,7 @@ DEVICE_CLASS_SULPHUR_DIOXIDE, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index f0a58d908c11..41d02901e3b6 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -57,6 +57,7 @@ DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, @@ -73,6 +74,7 @@ DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, @@ -113,6 +115,7 @@ DEVICE_CLASS_NITROGEN_MONOXIDE, DEVICE_CLASS_NITROUS_OXIDE, DEVICE_CLASS_OZONE, + DEVICE_CLASS_PH, DEVICE_CLASS_PM1, DEVICE_CLASS_PM10, DEVICE_CLASS_PM25, @@ -129,6 +132,7 @@ DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, DEVICE_CLASS_VOLUME_STORAGE, diff --git a/esphome/const.py b/esphome/const.py index 7525c7acfbd7..2b9233bf06d1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -955,6 +955,7 @@ DEVICE_CLASS_GATE = "gate" DEVICE_CLASS_HEAT = "heat" DEVICE_CLASS_HUMIDITY = "humidity" +DEVICE_CLASS_IDENTIFY = "identify" DEVICE_CLASS_ILLUMINANCE = "illuminance" DEVICE_CLASS_IRRADIANCE = "irradiance" DEVICE_CLASS_LIGHT = "light" @@ -970,6 +971,7 @@ DEVICE_CLASS_OPENING = "opening" DEVICE_CLASS_OUTLET = "outlet" DEVICE_CLASS_OZONE = "ozone" +DEVICE_CLASS_PH = "ph" DEVICE_CLASS_PLUG = "plug" DEVICE_CLASS_PM1 = "pm1" DEVICE_CLASS_PM10 = "pm10" @@ -1000,6 +1002,7 @@ DEVICE_CLASS_UPDATE = "update" DEVICE_CLASS_VIBRATION = "vibration" DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" +DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS = "volatile_organic_compounds_parts" DEVICE_CLASS_VOLTAGE = "voltage" DEVICE_CLASS_VOLUME = "volume" DEVICE_CLASS_VOLUME_STORAGE = "volume_storage"