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 <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-06-16 06:07:06 +08:00
parent 49dcd8785b
commit 3fca7161fc
11 changed files with 321 additions and 35 deletions
+5
View File
@@ -73,6 +73,10 @@
#define CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS 20 #define CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS 20
#endif #endif
#ifndef CONFIG_DALI_BUS_RESET_PULSE_MS
#define CONFIG_DALI_BUS_RESET_PULSE_MS 10
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_BAUDRATE #ifndef CONFIG_GATEWAY_485_CONTROL_BAUDRATE
#define CONFIG_GATEWAY_485_CONTROL_BAUDRATE 9600 #define CONFIG_GATEWAY_485_CONTROL_BAUDRATE 9600
#endif #endif
@@ -1284,6 +1288,7 @@ extern "C" void app_main(void) {
usb_config.rx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_USB_SETUP_RX_BUFFER); usb_config.rx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_USB_SETUP_RX_BUFFER);
usb_config.tx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_USB_SETUP_TX_BUFFER); usb_config.tx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_USB_SETUP_TX_BUFFER);
usb_config.read_timeout_ms = static_cast<uint32_t>(CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS); usb_config.read_timeout_ms = static_cast<uint32_t>(CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS);
usb_config.reset_pulse_ms = static_cast<uint32_t>(CONFIG_DALI_BUS_RESET_PULSE_MS);
s_usb_setup_bridge = std::make_unique<gateway::GatewayUsbSetupBridge>(*s_controller, s_usb_setup_bridge = std::make_unique<gateway::GatewayUsbSetupBridge>(*s_controller,
*s_dali_domain, *s_dali_domain,
usb_config); usb_config);
+1 -1
View File
@@ -2919,7 +2919,7 @@ CONFIG_DALI_CUSTOM_HALF_BIT_TIME_X100_US=0
CONFIG_DALI_TX_STOP_CONDITION_US=0 CONFIG_DALI_TX_STOP_CONDITION_US=0
CONFIG_DALI_RX_STOP_CONDITION_US=0 CONFIG_DALI_RX_STOP_CONDITION_US=0
CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS=30 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_ACTIVITY_WAIT_MS=20
CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS=10 CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS=10
CONFIG_DALI_FORWARD_MAX_WAIT_MS=50 CONFIG_DALI_FORWARD_MAX_WAIT_MS=50
+4 -4
View File
@@ -1861,7 +1861,7 @@ CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MEMTEST=y CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y 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_BSS_SEG_EXTERNAL_MEMORY is not set
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set # CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config # end of SPI RAM config
@@ -2480,9 +2480,9 @@ CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y
# #
# mbedTLS # 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_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_CUSTOM_MEM_ALLOC is not set
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 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_ENCRYPTION is not set
# CONFIG_NVS_ASSERT_ERROR_CHECK is not set # CONFIG_NVS_ASSERT_ERROR_CHECK is not set
# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY 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 # end of NVS
# #
+20 -2
View File
@@ -109,13 +109,31 @@ config DALI_BUS_POWER_CHECK_INTERVAL_MS
power-down. This lets the HAL recover when the bus was already powered power-down. This lets the HAL recover when the bus was already powered
before gateway startup and no RX edge is generated. 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 config DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS
int "Legacy bus abnormal report interval ms" int "Legacy bus abnormal report interval ms"
range 0 60000 range 0 60000
default 3000 default 3000
help help
Interval for publishing the legacy two-byte FF FD bus-abnormal raw frame Repeat interval for publishing the legacy two-byte FF FD bus-abnormal raw
while the native DALI bus is power-down. Set to 0 to disable the report. 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 choice DALI_LOG_LEVEL_CHOICE
prompt "DALI log level" prompt "DALI log level"
+9 -4
View File
@@ -45,16 +45,21 @@ Use `menuconfig` under `DALI Component` to configure:
TX/RX stop conditions, query response timeout, double-send delay, and TX queue TX/RX stop conditions, query response timeout, double-send delay, and TX queue
arbitration waits. arbitration waits.
- TX/RX active polarity. The native gateway default is TX active low and RX active high. - 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. - Native DALI HAL log level for the `dali_hal` ESP-IDF log tag.
- Queue sizes. - Queue sizes.
- Task stack sizes and priorities. - Task stack sizes and priorities.
- Optional debug task. - Optional debug task.
The native bus monitor uses `CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS` to resample RX while 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` power-down, `CONFIG_DALI_BUS_FAIL_EVENT_DELAY_MS` to publish the first legacy `FF FD`
raw frames while down. The report interval defaults to 3000 ms; set it to 0 to disable the raw frame after a continuous low-bus failure, and
compatibility report. `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 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` generated by the default 3.636363 MHz timer. `CONFIG_DALI_CUSTOM_HALF_BIT_TIME_X100_US`
+246 -19
View File
@@ -83,10 +83,18 @@
#define CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS 500 #define CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS 500
#endif #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 #ifndef CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS
#define CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS 3000 #define CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS 3000
#endif #endif
#ifndef CONFIG_DALI_BUS_RESET_PULSE_MS
#define CONFIG_DALI_BUS_RESET_PULSE_MS 10
#endif
#ifndef CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS #ifndef CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS
#define CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS 20 #define CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS 20
#endif #endif
@@ -109,6 +117,7 @@
#define DALI_BAUDRATE_MIN 400U #define DALI_BAUDRATE_MIN 400U
#define DALI_BAUDRATE_MAX 2400U #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_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) #define DALI_BUS_ABNORMAL_REPORT_INTERVAL_US ((uint64_t)CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS * 1000ULL)
typedef struct { typedef struct {
@@ -151,7 +160,10 @@ typedef struct {
uint8_t tx_level; uint8_t tx_level;
uint64_t bus_level_check_time; uint64_t bus_level_check_time;
uint64_t bus_low_since_time;
uint64_t bus_abnormal_report_time; uint64_t bus_abnormal_report_time;
uint64_t bus_abnormal_suppress_until;
bool bus_fail_reported;
Dali_msg_t tx_data; Dali_msg_t tx_data;
bool bus_activity_seen; bool bus_activity_seen;
@@ -526,6 +538,48 @@ static UBaseType_t queue_waiting(QueueHandle_t queue)
return queue ? uxQueueMessagesWaiting(queue) : 0; 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, static void log_tx_message(const char *prefix, const dali_bus_ctx_t *bus,
const Dali_msg_t *msg, uint32_t timeout_ms) 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_data.status = DALI_FRAME_ERROR;
bus->tx_state = TX_STATE_IDLE; bus->tx_state = TX_STATE_IDLE;
bus->rx_state = RX_STATE_IDLE; reset_rx_state(bus);
bus->tx_half_bit_counter = 0; reset_tx_counters(bus);
bus->tx_data_bit_counter = 0;
bus->rx_half_bit_counter = 0;
bus->rx_data_bit_counter = 0;
if (bus->bus_state == DALI_BUS_TRANSMITTING || bus->bus_state == DALI_BUS_TIME_BREAK || if (bus->bus_state == DALI_BUS_TRANSMITTING || bus->bus_state == DALI_BUS_TIME_BREAK ||
bus->bus_state == DALI_BUS_RECOVERY) { bus->bus_state == DALI_BUS_RECOVERY) {
bus->tx_last_edge_time = esp_timer_get_time(); 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, static void IRAM_ATTR update_bus_low_tracking_from_isr(dali_bus_ctx_t *bus,
BaseType_t *yield) uint64_t time_now,
uint8_t current_level)
{ {
if (bus == NULL || DALI_BUS_ABNORMAL_REPORT_INTERVAL_US == 0) { if (bus == NULL) {
return; return;
} }
if (!interval_elapsed_us(time_now, bus->bus_abnormal_report_time, if (current_level == 0) {
DALI_BUS_ABNORMAL_REPORT_INTERVAL_US)) { if (bus->bus_low_since_time == 0) {
bus->bus_low_since_time = time_now;
}
return; return;
} }
publish_bus_abnormal_from_isr(bus, yield); bus->bus_low_since_time = 0;
bus->bus_abnormal_report_time = time_now; 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, static void IRAM_ATTR maybe_report_low_bus_abnormal_from_isr(dali_bus_ctx_t *bus,
BaseType_t *yield) 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) { if (bus == NULL || bus->bus_state != DALI_BUS_POWER_DOWN) {
return; 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; 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) 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 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; rx_delta = time_now - bus->rx_last_edge_time;
tx_delta = time_now - bus->tx_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 && if (bus->bus_state == DALI_BUS_TRANSMITTING && bus->tx_state == TX_STATE_STOP &&
DALI_GET_TX_LEVEL(bus) == 1 && 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 { // 101.8.2.4 - startup BUS after 2.4ms
if(bus->rx_level==1 && rx_delta > s_timing.rx_stop_cond) 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 bus->bus_state = DALI_BUS_READY; // bus is ready
} }
} }
// if bus power down - if bus is low for more then 45ms // 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 { // power lost
bool entered_power_down = bus->bus_state != DALI_BUS_POWER_DOWN; 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 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 DALI_SET_BUS_HIGH(bus); // make sure TX is high
if (entered_power_down) { if (entered_power_down) {
bus->bus_level_check_time = time_now; 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) 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 bus->bus_state = DALI_BUS_READY; // bus is ready
// immediately start transmitting if we have data // 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 xQueueSendToBackFromISR(bus->tx_reply_queue, &bus->tx_data, &yield); // send data to queue
} }
bus->tx_state = TX_STATE_IDLE; // clear state bus->tx_state = TX_STATE_IDLE; // clear state
reset_tx_counters_from_isr(bus);
} }
// recover receiving // 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->rx_level = DALI_GET_BUS_LEVEL(bus); // get level of RX pin
bus->tx_last_edge_time = bus->rx_last_edge_time; bus->tx_last_edge_time = bus->rx_last_edge_time;
bus->bus_level_check_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_report_time = 0;
bus->bus_abnormal_suppress_until = 0;
bus->bus_fail_reported = false;
bus->bus_activity_seen = false; bus->bus_activity_seen = false;
bus->rx_last_frame_time = 0; bus->rx_last_frame_time = 0;
bus->rx_last_frame_length = 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; 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) QueueHandle_t dali_hal_raw_receive_queue(void)
{ {
ensure_common_queues(); ensure_common_queues();
+1 -1
View File
@@ -238,10 +238,10 @@ esp_err_t dali_hal_set_baudrate(uint32_t baudrate);
uint32_t dali_hal_get_baudrate(void); uint32_t dali_hal_get_baudrate(void);
size_t dali_hal_get_inited_buses(uint8_t *ids, size_t max_ids); 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_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); QueueHandle_t dali_hal_raw_receive_queue(void);
void dali_task(void *pvParameters); void dali_task(void *pvParameters);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -129,6 +129,7 @@ class DaliDomainService {
void addRawFrameSink(std::function<void(const DaliRawFrame& frame)> sink); void addRawFrameSink(std::function<void(const DaliRawFrame& frame)> sink);
bool resetBus(uint8_t gateway_id) const; 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; bool isBusIdle(uint8_t gateway_id, uint32_t quiet_ms) const;
void markHostActivity(uint8_t gateway_id) const; void markHostActivity(uint8_t gateway_id) const;
void markHostCommandFrame(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const; void markHostCommandFrame(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
+15 -2
View File
@@ -305,6 +305,7 @@ std::vector<uint8_t> TransactHardwareFrame(uint8_t bus_id, const uint8_t* data,
switch (data[0]) { switch (data[0]) {
case 0x00: case 0x00:
ESP_LOGD(TAG, "received reset for bus=%u", bus_id); ESP_LOGD(TAG, "received reset for bus=%u", bus_id);
return {1};
case 0x01: case 0x01:
return {1}; return {1};
case 0x10: case 0x10:
@@ -650,8 +651,11 @@ std::vector<DaliChannelInfo> DaliDomainService::channelInfo() const {
std::vector<DaliChannelInfo> info; std::vector<DaliChannelInfo> info;
info.reserve(channels_.size()); info.reserve(channels_.size());
for (const auto& channel : channels_) { for (const auto& channel : channels_) {
DaliChannelInfo item{channel->config.channel_index, channel->config.gateway_id, DaliChannelInfo item;
channel->phy_kind, channel->config.name}; 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()) { if (channel->hardware_bus.has_value()) {
item.native_bus_id = channel->hardware_bus->bus_id; 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(); 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 { bool DaliDomainService::isBusIdle(uint8_t gateway_id, uint32_t quiet_ms) const {
TickType_t last_activity = 0; TickType_t last_activity = 0;
if (bus_activity_lock_ != nullptr) { if (bus_activity_lock_ != nullptr) {
@@ -20,6 +20,7 @@ struct GatewayUsbSetupBridgeConfig {
size_t tx_buffer_size{256}; size_t tx_buffer_size{256};
uint32_t read_timeout_ms{20}; uint32_t read_timeout_ms{20};
uint32_t write_timeout_ms{20}; uint32_t write_timeout_ms{20};
uint32_t reset_pulse_ms{10};
uint32_t task_stack_size{4096}; uint32_t task_stack_size{4096};
UBaseType_t task_priority{4}; UBaseType_t task_priority{4};
}; };
@@ -89,6 +89,22 @@ void GatewayUsbSetupBridge::handleBytes(const uint8_t* data, size_t len) {
} }
const uint8_t gateway_id = setupGatewayId(); 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<uint8_t>(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<size_t>(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) { if (data[0] == 0x12) {
const auto response = dali_domain_.transactBridgeFrame(gateway_id, data, len); const auto response = dali_domain_.transactBridgeFrame(gateway_id, data, len);
if (!response.empty()) { if (!response.empty()) {