diff --git a/esphome/components/dfu/__init__.py b/esphome/components/dfu/__init__.py index bef8a35ff7..a2ddcd41ba 100644 --- a/esphome/components/dfu/__init__.py +++ b/esphome/components/dfu/__init__.py @@ -1,16 +1,23 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome.components import output from esphome.const import ( CONF_ID, ) +from esphome.core import CORE +from esphome.components.nrf52 import add_zephyr_prj_conf_option + dfu_ns = cg.esphome_ns.namespace("dfu") DeviceFirmwareUpdate = dfu_ns.class_("DeviceFirmwareUpdate", cg.Component) +CONF_RESET_OUTPUT = "reset_output" + CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(DeviceFirmwareUpdate), + cv.Required(CONF_RESET_OUTPUT): cv.use_id(output.BinaryOutput), } ).extend(cv.COMPONENT_SCHEMA), cv.only_on_nrf52, @@ -19,6 +26,11 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - # week symbol do not work for some reason so use wrap instaed - cg.add_build_flag("-Wl,--wrap=tud_cdc_line_state_cb") + reset_output = await cg.get_variable(config[CONF_RESET_OUTPUT]) + cg.add(var.set_reset_output(reset_output)) + if CORE.using_arduino: + # week symbol do not work for some reason so use wrap instaed + cg.add_build_flag("-Wl,--wrap=tud_cdc_line_state_cb") + elif CORE.using_zephyr: + add_zephyr_prj_conf_option("CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT", True) await cg.register_component(var, config) diff --git a/esphome/components/dfu/dfu.cpp b/esphome/components/dfu/dfu.cpp index d62a11b145..af18e54081 100644 --- a/esphome/components/dfu/dfu.cpp +++ b/esphome/components/dfu/dfu.cpp @@ -1,10 +1,57 @@ #include "dfu.h" +#ifdef USE_NRF52 +#include +#include +#include +#endif +#ifdef USE_ARRUINO #include -#include // for Serial +#include +#endif -extern "C" { +namespace esphome { +namespace dfu { volatile bool goto_dfu = false; + +#define DFU_DBL_RESET_MEM 0x20007F7C +#define DFU_DBL_RESET_MAGIC 0x5A1AD5 // SALADS +uint32_t *dbl_reset_mem = ((uint32_t *) DFU_DBL_RESET_MEM); + +#ifdef USE_NRF52 +#define DEVICE_AND_COMMA(node_id) DEVICE_DT_GET(node_id), + +const struct device *cdc_dev[] = {DT_FOREACH_STATUS_OKAY(zephyr_cdc_acm_uart, DEVICE_AND_COMMA)}; + +static void cdc_dte_rate_callback(const struct device *, uint32_t rate){ + if (rate == 1200) { + goto_dfu = true; + } +} +#endif + +void DeviceFirmwareUpdate::setup() { +#ifdef USE_NRF52 + for (int idx = 0; idx < ARRAY_SIZE(cdc_dev); idx++) { + cdc_acm_dte_rate_callback_set(cdc_dev[idx], cdc_dte_rate_callback); + } +#endif +} + +void DeviceFirmwareUpdate::loop() { + if (goto_dfu) { + goto_dfu = false; + (*dbl_reset_mem) = DFU_DBL_RESET_MAGIC; + reset_output_->set_state(true); + } +} + +} // namespace dfu +} // namespace esphome + +#ifdef USE_ARRUINO +extern "C" { + void __wrap_tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { (void) rts; @@ -22,28 +69,4 @@ void __wrap_tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { } } } - -namespace esphome { -namespace dfu { - -#define DFU_DBL_RESET_MEM 0x20007F7C -#define DFU_DBL_RESET_MAGIC 0x5A1AD5 // SALADS -uint32_t *dbl_reset_mem = ((uint32_t *) DFU_DBL_RESET_MEM); - -void DeviceFirmwareUpdate::loop() { - if (goto_dfu) { - goto_dfu = false; - (*dbl_reset_mem) = DFU_DBL_RESET_MAGIC; - pinMode(14, OUTPUT); - pinMode(16, OUTPUT); - digitalWrite(14, 1); - digitalWrite(16, 1); - - delay(50); - digitalWrite(14, 0); - digitalWrite(16, 0); - } -} - -} // namespace dfu -} // namespace esphome +#endif diff --git a/esphome/components/dfu/dfu.h b/esphome/components/dfu/dfu.h index 221406773c..5589a58b55 100644 --- a/esphome/components/dfu/dfu.h +++ b/esphome/components/dfu/dfu.h @@ -1,10 +1,23 @@ #pragma once +#include "esphome/core/defines.h" #include "esphome/core/component.h" +#ifdef USE_OUTPUT +#include "esphome/components/output/binary_output.h" +#endif namespace esphome { namespace dfu { class DeviceFirmwareUpdate : public Component { - void loop() override; + public: + void setup() override; + void loop() override; +#ifdef USE_OUTPUT + void set_reset_output(output::BinaryOutput *reset_output) { this->reset_output_ = reset_output; } +#endif + protected: +#ifdef USE_OUTPUT + output::BinaryOutput *reset_output_; +#endif }; } }