From 3fca7161fcb76ad196d4b79fec7528f3eb444c18 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 16 Jun 2026 06:07:06 +0800 Subject: [PATCH] fix: update DALI double send delay and increase SPIRAM malloc reserve size This commit fix the crash risk when bus abnormal. Signed-off-by: Tony --- apps/gateway/main/app_main.cpp | 5 + apps/gateway/sdkconfig | 2 +- apps/gateway/sdkconfig.old | 8 +- components/dali/Kconfig | 22 +- components/dali/README.md | 13 +- components/dali/src/dali_hal_idf5.c | 265 ++++++++++++++++-- components/dali/src/include/dali_hal.h | 2 +- .../dali_domain/include/dali_domain.hpp | 1 + components/dali_domain/src/dali_domain.cpp | 17 +- .../include/gateway_usb_setup.hpp | 3 +- .../src/gateway_usb_setup.cpp | 18 +- 11 files changed, 321 insertions(+), 35 deletions(-) diff --git a/apps/gateway/main/app_main.cpp b/apps/gateway/main/app_main.cpp index e6cc38a..ed41098 100644 --- a/apps/gateway/main/app_main.cpp +++ b/apps/gateway/main/app_main.cpp @@ -73,6 +73,10 @@ #define CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS 20 #endif +#ifndef CONFIG_DALI_BUS_RESET_PULSE_MS +#define CONFIG_DALI_BUS_RESET_PULSE_MS 10 +#endif + #ifndef CONFIG_GATEWAY_485_CONTROL_BAUDRATE #define CONFIG_GATEWAY_485_CONTROL_BAUDRATE 9600 #endif @@ -1284,6 +1288,7 @@ extern "C" void app_main(void) { usb_config.rx_buffer_size = static_cast(CONFIG_GATEWAY_USB_SETUP_RX_BUFFER); usb_config.tx_buffer_size = static_cast(CONFIG_GATEWAY_USB_SETUP_TX_BUFFER); usb_config.read_timeout_ms = static_cast(CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS); + usb_config.reset_pulse_ms = static_cast(CONFIG_DALI_BUS_RESET_PULSE_MS); s_usb_setup_bridge = std::make_unique(*s_controller, *s_dali_domain, usb_config); diff --git a/apps/gateway/sdkconfig b/apps/gateway/sdkconfig index aa1609b..ec94005 100644 --- a/apps/gateway/sdkconfig +++ b/apps/gateway/sdkconfig @@ -2919,7 +2919,7 @@ CONFIG_DALI_CUSTOM_HALF_BIT_TIME_X100_US=0 CONFIG_DALI_TX_STOP_CONDITION_US=0 CONFIG_DALI_RX_STOP_CONDITION_US=0 CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS=30 -CONFIG_DALI_DOUBLE_SEND_DELAY_MS=20 +CONFIG_DALI_DOUBLE_SEND_DELAY_MS=30 CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS=20 CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS=10 CONFIG_DALI_FORWARD_MAX_WAIT_MS=50 diff --git a/apps/gateway/sdkconfig.old b/apps/gateway/sdkconfig.old index a43d70e..68484da 100644 --- a/apps/gateway/sdkconfig.old +++ b/apps/gateway/sdkconfig.old @@ -1861,7 +1861,7 @@ CONFIG_SPIRAM_USE_MALLOC=y CONFIG_SPIRAM_MEMTEST=y CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y -CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65535 # CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set # CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set # end of SPI RAM config @@ -2480,9 +2480,9 @@ CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y # # mbedTLS # -CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set # CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set -# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 @@ -2646,7 +2646,7 @@ CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND=y # CONFIG_NVS_ENCRYPTION is not set # CONFIG_NVS_ASSERT_ERROR_CHECK is not set # CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set -# CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM is not set +CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM=y # end of NVS # diff --git a/components/dali/Kconfig b/components/dali/Kconfig index 05747ca..0242f1a 100644 --- a/components/dali/Kconfig +++ b/components/dali/Kconfig @@ -109,13 +109,31 @@ config DALI_BUS_POWER_CHECK_INTERVAL_MS power-down. This lets the HAL recover when the bus was already powered before gateway startup and no RX edge is generated. +config DALI_BUS_FAIL_EVENT_DELAY_MS + int "Bus fail event delay ms" + range 1 60000 + default 45 + help + Continuous low-bus duration required before publishing the legacy FF FD + bus-abnormal raw frame for the first time. Repeat reports are controlled + separately by DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS. + config DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS int "Legacy bus abnormal report interval ms" range 0 60000 default 3000 help - Interval for publishing the legacy two-byte FF FD bus-abnormal raw frame - while the native DALI bus is power-down. Set to 0 to disable the report. + Repeat interval for publishing the legacy two-byte FF FD bus-abnormal raw + frame while the native DALI bus remains failed. Set to 0 to disable both + the first and repeated reports. + +config DALI_BUS_RESET_PULSE_MS + int "Bus reset low pulse ms" + range 1 1000 + default 10 + help + Default duration for the native physical DALI bus reset pulse. The USB + setup bridge uses this value for short command 01 00 00. choice DALI_LOG_LEVEL_CHOICE prompt "DALI log level" diff --git a/components/dali/README.md b/components/dali/README.md index 3fe4a41..6041da1 100644 --- a/components/dali/README.md +++ b/components/dali/README.md @@ -45,16 +45,21 @@ Use `menuconfig` under `DALI Component` to configure: TX/RX stop conditions, query response timeout, double-send delay, and TX queue arbitration waits. - TX/RX active polarity. The native gateway default is TX active low and RX active high. -- Native bus power-down polling and legacy `FF FD` bus-abnormal raw-frame reporting intervals. +- Native bus power-down polling, first bus-fail event delay, legacy `FF FD` + bus-abnormal raw-frame repeat interval, and physical bus reset pulse duration. - Native DALI HAL log level for the `dali_hal` ESP-IDF log tag. - Queue sizes. - Task stack sizes and priorities. - Optional debug task. The native bus monitor uses `CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS` to resample RX while -power-down and `CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS` to publish legacy `FF FD` -raw frames while down. The report interval defaults to 3000 ms; set it to 0 to disable the -compatibility report. +power-down, `CONFIG_DALI_BUS_FAIL_EVENT_DELAY_MS` to publish the first legacy `FF FD` +raw frame after a continuous low-bus failure, and +`CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS` for repeat reports while the bus remains +failed. The first delay defaults to 45 ms and the repeat interval defaults to 3000 ms; +set the repeat interval to 0 to disable the compatibility report. USB setup command +`01 00 00` uses `CONFIG_DALI_BUS_RESET_PULSE_MS` to drive the bus low intentionally for +a physical reset pulse, defaulting to 10 ms. Native timing defaults target standard 1200 bps DALI: a 416.67 us half-bit period is generated by the default 3.636363 MHz timer. `CONFIG_DALI_CUSTOM_HALF_BIT_TIME_X100_US` diff --git a/components/dali/src/dali_hal_idf5.c b/components/dali/src/dali_hal_idf5.c index d79137a..d2f1746 100644 --- a/components/dali/src/dali_hal_idf5.c +++ b/components/dali/src/dali_hal_idf5.c @@ -83,10 +83,18 @@ #define CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS 500 #endif +#ifndef CONFIG_DALI_BUS_FAIL_EVENT_DELAY_MS +#define CONFIG_DALI_BUS_FAIL_EVENT_DELAY_MS 45 +#endif + #ifndef CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS #define CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS 3000 #endif +#ifndef CONFIG_DALI_BUS_RESET_PULSE_MS +#define CONFIG_DALI_BUS_RESET_PULSE_MS 10 +#endif + #ifndef CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS #define CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS 20 #endif @@ -109,6 +117,7 @@ #define DALI_BAUDRATE_MIN 400U #define DALI_BAUDRATE_MAX 2400U #define DALI_BUS_POWER_CHECK_INTERVAL_US ((uint64_t)CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS * 1000ULL) +#define DALI_BUS_FAIL_EVENT_DELAY_US ((uint64_t)CONFIG_DALI_BUS_FAIL_EVENT_DELAY_MS * 1000ULL) #define DALI_BUS_ABNORMAL_REPORT_INTERVAL_US ((uint64_t)CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS * 1000ULL) typedef struct { @@ -151,7 +160,10 @@ typedef struct { uint8_t tx_level; uint64_t bus_level_check_time; + uint64_t bus_low_since_time; uint64_t bus_abnormal_report_time; + uint64_t bus_abnormal_suppress_until; + bool bus_fail_reported; Dali_msg_t tx_data; bool bus_activity_seen; @@ -526,6 +538,48 @@ static UBaseType_t queue_waiting(QueueHandle_t queue) return queue ? uxQueueMessagesWaiting(queue) : 0; } +static void IRAM_ATTR reset_rx_state_from_isr(dali_bus_ctx_t *bus) +{ + if (bus == NULL) { + return; + } + bus->rx_state = RX_STATE_IDLE; + bus->rx_half_bit_counter = 0; + bus->rx_data_bit_counter = 0; + bus->rx_data.status = DALI_FRAME_UNKNOWN; + bus->rx_data.length = 0; +} + +static void IRAM_ATTR reset_tx_counters_from_isr(dali_bus_ctx_t *bus) +{ + if (bus == NULL) { + return; + } + bus->tx_half_bit_counter = 0; + bus->tx_data_bit_counter = 0; +} + +static void reset_rx_state(dali_bus_ctx_t *bus) +{ + if (bus == NULL) { + return; + } + bus->rx_state = RX_STATE_IDLE; + bus->rx_half_bit_counter = 0; + bus->rx_data_bit_counter = 0; + bus->rx_data.status = DALI_FRAME_UNKNOWN; + bus->rx_data.length = 0; +} + +static void reset_tx_counters(dali_bus_ctx_t *bus) +{ + if (bus == NULL) { + return; + } + bus->tx_half_bit_counter = 0; + bus->tx_data_bit_counter = 0; +} + static void log_tx_message(const char *prefix, const dali_bus_ctx_t *bus, const Dali_msg_t *msg, uint32_t timeout_ms) { @@ -576,11 +630,8 @@ static void recover_tx_timeout(dali_bus_ctx_t *bus) bus->tx_data.status = DALI_FRAME_ERROR; bus->tx_state = TX_STATE_IDLE; - bus->rx_state = RX_STATE_IDLE; - bus->tx_half_bit_counter = 0; - bus->tx_data_bit_counter = 0; - bus->rx_half_bit_counter = 0; - bus->rx_data_bit_counter = 0; + reset_rx_state(bus); + reset_tx_counters(bus); if (bus->bus_state == DALI_BUS_TRANSMITTING || bus->bus_state == DALI_BUS_TIME_BREAK || bus->bus_state == DALI_BUS_RECOVERY) { bus->tx_last_edge_time = esp_timer_get_time(); @@ -620,22 +671,82 @@ static void IRAM_ATTR publish_bus_abnormal_from_isr(dali_bus_ctx_t *bus, BaseTyp } } -static void IRAM_ATTR maybe_report_bus_abnormal_from_isr(dali_bus_ctx_t *bus, uint64_t time_now, - BaseType_t *yield) +static void IRAM_ATTR update_bus_low_tracking_from_isr(dali_bus_ctx_t *bus, + uint64_t time_now, + uint8_t current_level) { - if (bus == NULL || DALI_BUS_ABNORMAL_REPORT_INTERVAL_US == 0) { + if (bus == NULL) { return; } - if (!interval_elapsed_us(time_now, bus->bus_abnormal_report_time, - DALI_BUS_ABNORMAL_REPORT_INTERVAL_US)) { + if (current_level == 0) { + if (bus->bus_low_since_time == 0) { + bus->bus_low_since_time = time_now; + } return; } - publish_bus_abnormal_from_isr(bus, yield); - bus->bus_abnormal_report_time = time_now; + bus->bus_low_since_time = 0; + bus->bus_fail_reported = false; + bus->bus_abnormal_report_time = 0; + bus->bus_abnormal_suppress_until = 0; } -static void IRAM_ATTR poll_power_down_bus_from_isr(dali_bus_ctx_t *bus, uint64_t time_now, - BaseType_t *yield) +static void IRAM_ATTR maybe_report_low_bus_abnormal_from_isr(dali_bus_ctx_t *bus, + uint64_t time_now, + uint8_t current_level, + BaseType_t *yield) +{ + if (bus == NULL || DALI_BUS_ABNORMAL_REPORT_INTERVAL_US == 0 || current_level != 0 || + bus->bus_low_since_time == 0) { + return; + } + if (bus->bus_abnormal_suppress_until != 0 && time_now < bus->bus_abnormal_suppress_until) { + return; + } + if ((time_now - bus->bus_low_since_time) < DALI_BUS_FAIL_EVENT_DELAY_US) { + return; + } + + if (!bus->bus_fail_reported) { + publish_bus_abnormal_from_isr(bus, yield); + bus->bus_fail_reported = true; + bus->bus_abnormal_report_time = time_now; + return; + } + + if (interval_elapsed_us(time_now, bus->bus_abnormal_report_time, + DALI_BUS_ABNORMAL_REPORT_INTERVAL_US)) { + publish_bus_abnormal_from_isr(bus, yield); + bus->bus_abnormal_report_time = time_now; + } +} + +static void IRAM_ATTR resample_stale_bus_level_from_isr(dali_bus_ctx_t *bus, + uint64_t time_now, + uint32_t rx_delta, + uint8_t current_level) +{ + if (bus == NULL || current_level == bus->rx_level) { + return; + } + + bool should_resample = bus->bus_state == DALI_BUS_POWER_DOWN || + bus->bus_state <= DALI_BUS_ERROR || + (bus->bus_state == DALI_BUS_READY && + (bus->rx_state != RX_STATE_IDLE || bus->rx_level == 0) && + rx_delta > s_timing.rx_hb_max) || + (bus->bus_state == DALI_BUS_RECEIVING && + bus->rx_state == RX_STATE_START && + rx_delta > s_timing.rx_hb_max); + if (!should_resample) { + return; + } + + bus->rx_level = current_level; + bus->rx_last_edge_time = time_now; + bus->bus_activity_seen = true; +} + +static void IRAM_ATTR poll_power_down_bus_from_isr(dali_bus_ctx_t *bus, uint64_t time_now) { if (bus == NULL || bus->bus_state != DALI_BUS_POWER_DOWN) { return; @@ -650,8 +761,6 @@ static void IRAM_ATTR poll_power_down_bus_from_isr(dali_bus_ctx_t *bus, uint64_t bus->rx_last_edge_time = time_now; } } - - maybe_report_bus_abnormal_from_isr(bus, time_now, yield); } static inline void publish_rx_frame_from_isr(Dali_msg_t *msg, QueueHandle_t queue, BaseType_t *yield) @@ -884,9 +993,20 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now) bus->tx_last_edge_time = time_now - MAX_DELTA_RELOAD_TIME/2; // half of max time } - poll_power_down_bus_from_isr(bus, time_now, &yield); + uint8_t current_level = DALI_GET_BUS_LEVEL(bus); + update_bus_low_tracking_from_isr(bus, time_now, current_level); + resample_stale_bus_level_from_isr(bus, time_now, rx_delta, current_level); + poll_power_down_bus_from_isr(bus, time_now); rx_delta = time_now - bus->rx_last_edge_time; tx_delta = time_now - bus->tx_last_edge_time; + current_level = DALI_GET_BUS_LEVEL(bus); + update_bus_low_tracking_from_isr(bus, time_now, current_level); + maybe_report_low_bus_abnormal_from_isr(bus, time_now, current_level, &yield); + + if (bus->bus_state == DALI_BUS_READY && bus->rx_state != RX_STATE_IDLE && + rx_delta > s_timing.rx_hb_max) { + reset_rx_state_from_isr(bus); + } if (bus->bus_state == DALI_BUS_TRANSMITTING && bus->tx_state == TX_STATE_STOP && DALI_GET_TX_LEVEL(bus) == 1 && @@ -901,18 +1021,21 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now) { // 101.8.2.4 - startup BUS after 2.4ms if(bus->rx_level==1 && rx_delta > s_timing.rx_stop_cond) { + DALI_SET_BUS_HIGH(bus); + reset_rx_state_from_isr(bus); + reset_tx_counters_from_isr(bus); bus->bus_state = DALI_BUS_READY; // bus is ready } } // if bus power down - if bus is low for more then 45ms - if(bus->rx_level==0 && rx_delta > s_timing.time_bus_down) + if(current_level == 0 && bus->bus_low_since_time != 0 && + (time_now - bus->bus_low_since_time) > s_timing.time_bus_down) { // power lost bool entered_power_down = bus->bus_state != DALI_BUS_POWER_DOWN; bus->bus_state = DALI_BUS_POWER_DOWN; // bus is power down - recovery see previous if DALI_SET_BUS_HIGH(bus); // make sure TX is high if (entered_power_down) { bus->bus_level_check_time = time_now; - bus->bus_abnormal_report_time = time_now; } } @@ -940,6 +1063,8 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now) } else if(bus->bus_state == DALI_BUS_RECOVERY && rx_delta > s_timing.time_recovery_min) { + reset_rx_state_from_isr(bus); + reset_tx_counters_from_isr(bus); bus->bus_state = DALI_BUS_READY; // bus is ready // immediately start transmitting if we have data } @@ -1025,6 +1150,7 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now) xQueueSendToBackFromISR(bus->tx_reply_queue, &bus->tx_data, &yield); // send data to queue } bus->tx_state = TX_STATE_IDLE; // clear state + reset_tx_counters_from_isr(bus); } // recover receiving @@ -1280,7 +1406,10 @@ static esp_err_t init_bus(uint8_t bus_id, uint8_t tx_pin, uint8_t rx_pin) bus->rx_level = DALI_GET_BUS_LEVEL(bus); // get level of RX pin bus->tx_last_edge_time = bus->rx_last_edge_time; bus->bus_level_check_time = bus->rx_last_edge_time; + bus->bus_low_since_time = bus->rx_level == 0 ? bus->rx_last_edge_time : 0; bus->bus_abnormal_report_time = 0; + bus->bus_abnormal_suppress_until = 0; + bus->bus_fail_reported = false; bus->bus_activity_seen = false; bus->rx_last_frame_time = 0; bus->rx_last_frame_length = 0; @@ -1513,6 +1642,104 @@ esp_err_t dali_hal_get_bus_info(uint8_t bus_id, dali_hal_bus_info_t *info) return ESP_OK; } +esp_err_t dali_hal_pulse_bus_low(uint8_t bus_id, uint32_t duration_ms) +{ + if (bus_id >= DALI_PHY_COUNT) { + return ESP_ERR_INVALID_ARG; + } + if (duration_ms == 0) { + duration_ms = CONFIG_DALI_BUS_RESET_PULSE_MS; + } + + dali_hal_lock(); + esp_err_t err = ensure_timing_ready_locked(); + if (err != ESP_OK) { + dali_hal_unlock(); + return err; + } + dali_bus_ctx_t *bus = &s_bus[bus_id]; + if (!bus->inited) { + dali_hal_unlock(); + return ESP_ERR_INVALID_STATE; + } + + const uint64_t start_time = esp_timer_get_time(); + const uint64_t duration_us = (uint64_t)duration_ms * 1000ULL; + const bool had_tx = bus->tx_state > TX_STATE_IDLE || queue_waiting(bus->tx_queue) > 0; + Dali_msg_t failed_tx = bus->tx_data; + failed_tx.status = DALI_FRAME_ERROR; + + err = gpio_intr_disable(bus->rx_pin); + if (err != ESP_OK) { + dali_hal_unlock(); + return err; + } + + if (bus->tx_queue) { + xQueueReset(bus->tx_queue); + } + if (bus->tx_reply_queue) { + xQueueReset(bus->tx_reply_queue); + if (had_tx && !is_backward_tx_msg(&failed_tx)) { + xQueueSendToBack(bus->tx_reply_queue, &failed_tx, 0); + } + } + + bus->force_backward_tx = false; + bus->tx_state = TX_STATE_IDLE; + bus->tx_data.status = DALI_FRAME_ERROR; + reset_rx_state(bus); + reset_tx_counters(bus); + bus->bus_activity_seen = true; + bus->bus_state = DALI_BUS_POWER_DOWN; + bus->bus_level_check_time = start_time; + bus->bus_abnormal_report_time = 0; + bus->bus_fail_reported = false; + bus->bus_abnormal_suppress_until = + start_time + duration_us + DALI_BUS_FAIL_EVENT_DELAY_US + s_timing.rx_stop_cond; + + DALI_SET_BUS_LOW(bus); + bus->rx_level = DALI_GET_BUS_LEVEL(bus); + bus->rx_last_edge_time = start_time; + bus->tx_last_edge_time = start_time; + bus->bus_low_since_time = bus->rx_level == 0 ? start_time : 0; + dali_hal_unlock(); + + TickType_t delay_ticks = pdMS_TO_TICKS(duration_ms); + if (delay_ticks == 0) { + delay_ticks = 1; + } + vTaskDelay(delay_ticks); + + dali_hal_lock(); + const uint64_t end_time = esp_timer_get_time(); + DALI_SET_BUS_HIGH(bus); + bus->rx_level = DALI_GET_BUS_LEVEL(bus); + bus->rx_last_edge_time = end_time; + bus->tx_last_edge_time = end_time; + bus->bus_level_check_time = end_time; + bus->bus_low_since_time = bus->rx_level == 0 ? end_time : 0; + bus->bus_abnormal_report_time = 0; + bus->bus_fail_reported = false; + if (bus->rx_level == 1) { + bus->bus_abnormal_suppress_until = 0; + bus->bus_state = DALI_BUS_READY; + } else { + bus->bus_abnormal_suppress_until = + end_time + DALI_BUS_FAIL_EVENT_DELAY_US + s_timing.rx_stop_cond; + bus->bus_state = DALI_BUS_POWER_DOWN; + } + bus->tx_state = TX_STATE_IDLE; + reset_rx_state(bus); + reset_tx_counters(bus); + gpio_intr_enable(bus->rx_pin); + dali_hal_unlock(); + + ESP_LOGI(TAG, "bus=%u physical reset pulse complete durationMs=%lu", bus_id, + (unsigned long)duration_ms); + return ESP_OK; +} + QueueHandle_t dali_hal_raw_receive_queue(void) { ensure_common_queues(); diff --git a/components/dali/src/include/dali_hal.h b/components/dali/src/include/dali_hal.h index ddcc75a..6affa0c 100644 --- a/components/dali/src/include/dali_hal.h +++ b/components/dali/src/include/dali_hal.h @@ -238,10 +238,10 @@ esp_err_t dali_hal_set_baudrate(uint32_t baudrate); uint32_t dali_hal_get_baudrate(void); size_t dali_hal_get_inited_buses(uint8_t *ids, size_t max_ids); esp_err_t dali_hal_get_bus_info(uint8_t bus_id, dali_hal_bus_info_t *info); +esp_err_t dali_hal_pulse_bus_low(uint8_t bus_id, uint32_t duration_ms); QueueHandle_t dali_hal_raw_receive_queue(void); void dali_task(void *pvParameters); #ifdef __cplusplus } #endif - diff --git a/components/dali_domain/include/dali_domain.hpp b/components/dali_domain/include/dali_domain.hpp index 7648c89..3fd738b 100644 --- a/components/dali_domain/include/dali_domain.hpp +++ b/components/dali_domain/include/dali_domain.hpp @@ -129,6 +129,7 @@ class DaliDomainService { void addRawFrameSink(std::function sink); bool resetBus(uint8_t gateway_id) const; + bool pulseBusLow(uint8_t gateway_id, uint32_t duration_ms) const; bool isBusIdle(uint8_t gateway_id, uint32_t quiet_ms) const; void markHostActivity(uint8_t gateway_id) const; void markHostCommandFrame(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const; diff --git a/components/dali_domain/src/dali_domain.cpp b/components/dali_domain/src/dali_domain.cpp index 165e81f..63eeace 100644 --- a/components/dali_domain/src/dali_domain.cpp +++ b/components/dali_domain/src/dali_domain.cpp @@ -305,6 +305,7 @@ std::vector TransactHardwareFrame(uint8_t bus_id, const uint8_t* data, switch (data[0]) { case 0x00: ESP_LOGD(TAG, "received reset for bus=%u", bus_id); + return {1}; case 0x01: return {1}; case 0x10: @@ -650,8 +651,11 @@ std::vector DaliDomainService::channelInfo() const { std::vector info; info.reserve(channels_.size()); for (const auto& channel : channels_) { - DaliChannelInfo item{channel->config.channel_index, channel->config.gateway_id, - channel->phy_kind, channel->config.name}; + DaliChannelInfo item; + item.channel_index = channel->config.channel_index; + item.gateway_id = channel->config.gateway_id; + item.phy_kind = channel->phy_kind; + item.name = channel->config.name; if (channel->hardware_bus.has_value()) { item.native_bus_id = channel->hardware_bus->bus_id; } @@ -707,6 +711,15 @@ bool DaliDomainService::resetBus(uint8_t gateway_id) const { return channel->comm->resetBus(); } +bool DaliDomainService::pulseBusLow(uint8_t gateway_id, uint32_t duration_ms) const { + const auto* channel = findChannelByGateway(gateway_id); + if (channel == nullptr || !channel->hardware_bus.has_value()) { + return false; + } + markBusActivity(gateway_id); + return dali_hal_pulse_bus_low(channel->hardware_bus->bus_id, duration_ms) == ESP_OK; +} + bool DaliDomainService::isBusIdle(uint8_t gateway_id, uint32_t quiet_ms) const { TickType_t last_activity = 0; if (bus_activity_lock_ != nullptr) { diff --git a/components/gateway_usb_setup/include/gateway_usb_setup.hpp b/components/gateway_usb_setup/include/gateway_usb_setup.hpp index b0f5a25..77bfec2 100644 --- a/components/gateway_usb_setup/include/gateway_usb_setup.hpp +++ b/components/gateway_usb_setup/include/gateway_usb_setup.hpp @@ -20,6 +20,7 @@ struct GatewayUsbSetupBridgeConfig { size_t tx_buffer_size{256}; uint32_t read_timeout_ms{20}; uint32_t write_timeout_ms{20}; + uint32_t reset_pulse_ms{10}; uint32_t task_stack_size{4096}; UBaseType_t task_priority{4}; }; @@ -45,4 +46,4 @@ class GatewayUsbSetupBridge { bool started_{false}; }; -} // namespace gateway \ No newline at end of file +} // namespace gateway diff --git a/components/gateway_usb_setup/src/gateway_usb_setup.cpp b/components/gateway_usb_setup/src/gateway_usb_setup.cpp index e2200fa..6d485a0 100644 --- a/components/gateway_usb_setup/src/gateway_usb_setup.cpp +++ b/components/gateway_usb_setup/src/gateway_usb_setup.cpp @@ -89,6 +89,22 @@ void GatewayUsbSetupBridge::handleBytes(const uint8_t* data, size_t len) { } const uint8_t gateway_id = setupGatewayId(); + if (len == 3 && data[0] == 0x01 && data[1] == 0x00 && data[2] == 0x00) { + const bool ok = dali_domain_.pulseBusLow(gateway_id, config_.reset_pulse_ms); + const uint8_t response[2] = {static_cast(ok ? 0x01 : 0xFD), 0x00}; + const int written = usb_serial_jtag_write_bytes(response, sizeof(response), + pdMS_TO_TICKS(config_.write_timeout_ms)); + if (written < 0 || static_cast(written) != sizeof(response)) { + ESP_LOGW(kTag, "failed to write USB bus reset response channel=%u ok=%u", + config_.channel_index, ok ? 1 : 0); + } + if (!ok) { + ESP_LOGW(kTag, "failed to pulse DALI bus low for USB reset channel=%u gateway=%u", + config_.channel_index, gateway_id); + } + return; + } + if (data[0] == 0x12) { const auto response = dali_domain_.transactBridgeFrame(gateway_id, data, len); if (!response.empty()) { @@ -131,4 +147,4 @@ uint8_t GatewayUsbSetupBridge::setupGatewayId() const { return config_.channel_index; } -} // namespace gateway \ No newline at end of file +} // namespace gateway