Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 70ae1ae6cf | |||
| f2ffb45ca6 |
@@ -2775,8 +2775,12 @@ CONFIG_DALI_TIMER_RESOLUTION_HZ=3000000
|
|||||||
CONFIG_DALI_CUSTOM_HALF_BIT_TIME_X100_US=0
|
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=25
|
CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS=20
|
||||||
CONFIG_DALI_DOUBLE_SEND_DELAY_MS=12
|
CONFIG_DALI_DOUBLE_SEND_DELAY_MS=12
|
||||||
|
CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS=25
|
||||||
|
CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS=5
|
||||||
|
CONFIG_DALI_FORWARD_MAX_WAIT_MS=50
|
||||||
|
CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS=9
|
||||||
CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS=500
|
CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS=500
|
||||||
CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS=3000
|
CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS=3000
|
||||||
# CONFIG_DALI_LOG_LEVEL_NONE is not set
|
# CONFIG_DALI_LOG_LEVEL_NONE is not set
|
||||||
|
|||||||
@@ -2775,8 +2775,12 @@ CONFIG_DALI_TIMER_RESOLUTION_HZ=3000000
|
|||||||
CONFIG_DALI_CUSTOM_HALF_BIT_TIME_X100_US=0
|
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=25
|
CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS=12
|
||||||
CONFIG_DALI_DOUBLE_SEND_DELAY_MS=12
|
CONFIG_DALI_DOUBLE_SEND_DELAY_MS=12
|
||||||
|
CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS=25
|
||||||
|
CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS=5
|
||||||
|
CONFIG_DALI_FORWARD_MAX_WAIT_MS=50
|
||||||
|
CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS=9
|
||||||
CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS=500
|
CONFIG_DALI_BUS_POWER_CHECK_INTERVAL_MS=500
|
||||||
CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS=3000
|
CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS=3000
|
||||||
# CONFIG_DALI_LOG_LEVEL_NONE is not set
|
# CONFIG_DALI_LOG_LEVEL_NONE is not set
|
||||||
@@ -2795,7 +2799,7 @@ CONFIG_DALI_TX_QUEUE_LEN=4
|
|||||||
CONFIG_DALI_TX_REPLY_QUEUE_LEN=4
|
CONFIG_DALI_TX_REPLY_QUEUE_LEN=4
|
||||||
CONFIG_DALI_RX_QUEUE_LEN=50
|
CONFIG_DALI_RX_QUEUE_LEN=50
|
||||||
CONFIG_DALI_DEBUG_QUEUE_LEN=100
|
CONFIG_DALI_DEBUG_QUEUE_LEN=100
|
||||||
# CONFIG_DALI_ENABLE_DEBUG_TASK is not set
|
CONFIG_DALI_ENABLE_DEBUG_TASK=y
|
||||||
CONFIG_DALI_DALI_TASK_STACK_SIZE=8192
|
CONFIG_DALI_DALI_TASK_STACK_SIZE=8192
|
||||||
CONFIG_DALI_DALI_TASK_PRIORITY=2
|
CONFIG_DALI_DALI_TASK_PRIORITY=2
|
||||||
CONFIG_DALI_DEBUG_TASK_STACK_SIZE=2048
|
CONFIG_DALI_DEBUG_TASK_STACK_SIZE=2048
|
||||||
|
|||||||
@@ -66,6 +66,40 @@ config DALI_DOUBLE_SEND_DELAY_MS
|
|||||||
Delay between the two frames sent by dali_send_double(), measured after
|
Delay between the two frames sent by dali_send_double(), measured after
|
||||||
the first frame has completed. Exposed for development tuning.
|
the first frame has completed. Exposed for development tuning.
|
||||||
|
|
||||||
|
config DALI_FORWARD_ACTIVITY_WAIT_MS
|
||||||
|
int "Forward-frame wait after bus activity ms"
|
||||||
|
range 0 1000
|
||||||
|
default 25
|
||||||
|
help
|
||||||
|
Minimum delay before sending a 2- to 4-byte forward frame after normal
|
||||||
|
bus activity. This is the native queue anti-collision wait.
|
||||||
|
|
||||||
|
config DALI_FORWARD_AFTER_BACKWARD_WAIT_MS
|
||||||
|
int "Forward-frame wait after backward frame ms"
|
||||||
|
range 0 1000
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
Minimum delay before sending a 2- to 4-byte forward frame after the last
|
||||||
|
valid 1-byte backward frame received by the native bus.
|
||||||
|
|
||||||
|
config DALI_FORWARD_MAX_WAIT_MS
|
||||||
|
int "Forward-frame maximum queue wait ms"
|
||||||
|
range 0 5000
|
||||||
|
default 50
|
||||||
|
help
|
||||||
|
Maximum time the native queue waits for a forward-frame send window. If
|
||||||
|
no valid send window is reached before this timeout, the frame is
|
||||||
|
dropped with an error status.
|
||||||
|
|
||||||
|
config DALI_BACKWARD_IDLE_TIMEOUT_MS
|
||||||
|
int "Backward-frame idle wait timeout ms"
|
||||||
|
range 0 1000
|
||||||
|
default 9
|
||||||
|
help
|
||||||
|
Time a 1-byte backward frame waits for an idle bus before being sent
|
||||||
|
anyway. Backward frame sends are not echo-verified because collisions
|
||||||
|
during addressing responses are valid DALI behavior.
|
||||||
|
|
||||||
config DALI_BUS_POWER_CHECK_INTERVAL_MS
|
config DALI_BUS_POWER_CHECK_INTERVAL_MS
|
||||||
int "Bus power-down check interval ms"
|
int "Bus power-down check interval ms"
|
||||||
range 10 5000
|
range 10 5000
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ Use `menuconfig` under `DALI Component` to configure:
|
|||||||
|
|
||||||
- Bus count and default baudrate.
|
- Bus count and default baudrate.
|
||||||
- Native timing values for development, including timer resolution, half-bit period,
|
- Native timing values for development, including timer resolution, half-bit period,
|
||||||
TX/RX stop conditions, query response timeout, and double-send delay.
|
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.
|
- 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 and legacy `FF FD` bus-abnormal raw-frame reporting intervals.
|
||||||
- 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.
|
||||||
@@ -61,6 +62,13 @@ can override the half-bit period for development; keep it at 0 for baudrate-deri
|
|||||||
Query no-response timeout defaults to 25 ms, which covers the 5.5-10.5 ms backward-frame
|
Query no-response timeout defaults to 25 ms, which covers the 5.5-10.5 ms backward-frame
|
||||||
start window plus the approximately 9.95 ms backward frame duration.
|
start window plus the approximately 9.95 ms backward frame duration.
|
||||||
|
|
||||||
|
Native TX queue arbitration uses frame length as the frame type signal. Two- to four-byte
|
||||||
|
forward frames wait up to `CONFIG_DALI_FORWARD_MAX_WAIT_MS` for a valid send window,
|
||||||
|
using `CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS` after normal bus activity and
|
||||||
|
`CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS` after a valid backward frame. One-byte
|
||||||
|
backward frames wait up to `CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS` for idle, then are
|
||||||
|
sent without echo verification because addressing-phase collisions are valid.
|
||||||
|
|
||||||
## API Note
|
## API Note
|
||||||
|
|
||||||
The global TX response queue symbol was renamed:
|
The global TX response queue symbol was renamed:
|
||||||
|
|||||||
@@ -87,6 +87,22 @@
|
|||||||
#define CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS 1000
|
#define CONFIG_DALI_BUS_ABNORMAL_REPORT_INTERVAL_MS 1000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS
|
||||||
|
#define CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS 25
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS
|
||||||
|
#define CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_DALI_FORWARD_MAX_WAIT_MS
|
||||||
|
#define CONFIG_DALI_FORWARD_MAX_WAIT_MS 50
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS
|
||||||
|
#define CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS 9
|
||||||
|
#endif
|
||||||
|
|
||||||
#define WITHIN_RANGE(x, min, max) ((x) > (min) && (x) < (max))
|
#define WITHIN_RANGE(x, min, max) ((x) > (min) && (x) < (max))
|
||||||
#define MAX_DELTA_RELOAD_TIME 600000000 // 600s - max u32: 4,294,967,295~4,294s
|
#define MAX_DELTA_RELOAD_TIME 600000000 // 600s - max u32: 4,294,967,295~4,294s
|
||||||
|
|
||||||
@@ -138,6 +154,11 @@ typedef struct {
|
|||||||
uint64_t bus_abnormal_report_time;
|
uint64_t bus_abnormal_report_time;
|
||||||
|
|
||||||
Dali_msg_t tx_data;
|
Dali_msg_t tx_data;
|
||||||
|
bool bus_activity_seen;
|
||||||
|
uint64_t rx_last_frame_time;
|
||||||
|
uint8_t rx_last_frame_length;
|
||||||
|
uint8_t rx_last_frame_status;
|
||||||
|
volatile bool force_backward_tx;
|
||||||
Dali_msg_t rx_data;
|
Dali_msg_t rx_data;
|
||||||
|
|
||||||
uint8_t tx_half_bit_counter;
|
uint8_t tx_half_bit_counter;
|
||||||
@@ -391,6 +412,115 @@ static uint32_t tx_completion_timeout_ms(const Dali_msg_t *msg)
|
|||||||
return timeout_ms;
|
return timeout_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool IRAM_ATTR is_backward_tx_msg(const Dali_msg_t *msg)
|
||||||
|
{
|
||||||
|
return msg != NULL && msg->length == 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_forward_tx_msg(const Dali_msg_t *msg)
|
||||||
|
{
|
||||||
|
return msg != NULL && msg->length >= 16 && msg->length <= 32 && (msg->length % 8) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UBaseType_t queue_waiting(QueueHandle_t queue);
|
||||||
|
|
||||||
|
static uint64_t bus_last_activity_time_us(const dali_bus_ctx_t *bus)
|
||||||
|
{
|
||||||
|
if (bus == NULL || !bus->bus_activity_seen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return bus->rx_last_edge_time > bus->tx_last_edge_time ? bus->rx_last_edge_time
|
||||||
|
: bus->tx_last_edge_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bus_idle_for_tx(const dali_bus_ctx_t *bus)
|
||||||
|
{
|
||||||
|
return bus != NULL && bus->bus_state == DALI_BUS_READY && bus->tx_state == TX_STATE_IDLE &&
|
||||||
|
bus->rx_state == RX_STATE_IDLE && bus->rx_level == 1 && queue_waiting(bus->tx_queue) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool last_activity_was_backward_frame(const dali_bus_ctx_t *bus, uint64_t last_activity)
|
||||||
|
{
|
||||||
|
return bus != NULL && bus->rx_last_frame_status == DALI_FRAME_OK &&
|
||||||
|
bus->rx_last_frame_length == 8 && bus->rx_last_frame_time != 0 &&
|
||||||
|
bus->rx_last_frame_time >= last_activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TickType_t tx_wait_poll_ticks(void)
|
||||||
|
{
|
||||||
|
TickType_t ticks = pdMS_TO_TICKS(1);
|
||||||
|
return ticks == 0 ? 1 : ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wait_for_forward_tx_window(dali_bus_ctx_t *bus, const Dali_msg_t *msg)
|
||||||
|
{
|
||||||
|
if (bus == NULL || !is_forward_tx_msg(msg)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t started = esp_timer_get_time();
|
||||||
|
const uint64_t max_wait_us = (uint64_t)CONFIG_DALI_FORWARD_MAX_WAIT_MS * 1000ULL;
|
||||||
|
const TickType_t poll_ticks = tx_wait_poll_ticks();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (bus->bus_state == DALI_BUS_POWER_DOWN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t now = esp_timer_get_time();
|
||||||
|
if (bus_idle_for_tx(bus)) {
|
||||||
|
const uint64_t last_activity = bus_last_activity_time_us(bus);
|
||||||
|
if (last_activity == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const uint32_t wait_ms = last_activity_was_backward_frame(bus, last_activity)
|
||||||
|
? CONFIG_DALI_FORWARD_AFTER_BACKWARD_WAIT_MS
|
||||||
|
: CONFIG_DALI_FORWARD_ACTIVITY_WAIT_MS;
|
||||||
|
if (wait_ms == 0 || (now - last_activity) >= ((uint64_t)wait_ms * 1000ULL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_wait_us == 0 || (now - started) >= max_wait_us) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vTaskDelay(poll_ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wait_for_backward_tx_window(dali_bus_ctx_t *bus, const Dali_msg_t *msg,
|
||||||
|
bool *force_start)
|
||||||
|
{
|
||||||
|
if (force_start != NULL) {
|
||||||
|
*force_start = false;
|
||||||
|
}
|
||||||
|
if (bus == NULL || !is_backward_tx_msg(msg)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t started = esp_timer_get_time();
|
||||||
|
const uint64_t timeout_us = (uint64_t)CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS * 1000ULL;
|
||||||
|
const TickType_t poll_ticks = tx_wait_poll_ticks();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (bus->bus_state == DALI_BUS_POWER_DOWN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bus_idle_for_tx(bus)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t now = esp_timer_get_time();
|
||||||
|
if (timeout_us == 0 || (now - started) >= timeout_us) {
|
||||||
|
if (force_start != NULL) {
|
||||||
|
*force_start = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
vTaskDelay(poll_ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static UBaseType_t queue_waiting(QueueHandle_t queue)
|
static UBaseType_t queue_waiting(QueueHandle_t queue)
|
||||||
{
|
{
|
||||||
return queue ? uxQueueMessagesWaiting(queue) : 0;
|
return queue ? uxQueueMessagesWaiting(queue) : 0;
|
||||||
@@ -537,6 +667,16 @@ static inline void publish_rx_frame_from_isr(Dali_msg_t *msg, QueueHandle_t queu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void IRAM_ATTR note_rx_frame_from_isr(dali_bus_ctx_t *bus)
|
||||||
|
{
|
||||||
|
if (bus == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bus->rx_last_frame_time = bus->rx_last_edge_time;
|
||||||
|
bus->rx_last_frame_length = bus->rx_data.length;
|
||||||
|
bus->rx_last_frame_status = bus->rx_data.status;
|
||||||
|
}
|
||||||
|
|
||||||
static void IRAM_ATTR complete_tx_from_isr(dali_bus_ctx_t *bus, BaseType_t *yield)
|
static void IRAM_ATTR complete_tx_from_isr(dali_bus_ctx_t *bus, BaseType_t *yield)
|
||||||
{
|
{
|
||||||
if (bus == NULL) {
|
if (bus == NULL) {
|
||||||
@@ -544,7 +684,7 @@ static void IRAM_ATTR complete_tx_from_isr(dali_bus_ctx_t *bus, BaseType_t *yiel
|
|||||||
}
|
}
|
||||||
|
|
||||||
bus->tx_data.status = DALI_FRAME_OK;
|
bus->tx_data.status = DALI_FRAME_OK;
|
||||||
if (bus->tx_reply_queue) {
|
if (!is_backward_tx_msg(&bus->tx_data) && bus->tx_reply_queue) {
|
||||||
if (xQueueSendToBackFromISR(bus->tx_reply_queue, &bus->tx_data, yield) != pdTRUE) {
|
if (xQueueSendToBackFromISR(bus->tx_reply_queue, &bus->tx_data, yield) != pdTRUE) {
|
||||||
Dali_msg_t dropped = {0};
|
Dali_msg_t dropped = {0};
|
||||||
xQueueReceiveFromISR(bus->tx_reply_queue, &dropped, yield);
|
xQueueReceiveFromISR(bus->tx_reply_queue, &dropped, yield);
|
||||||
@@ -586,6 +726,7 @@ static void IRAM_ATTR rx_gpio_isr_handler(void* arg)
|
|||||||
|
|
||||||
// rx_level = 1 if and only if DALI bus is really high, idle
|
// rx_level = 1 if and only if DALI bus is really high, idle
|
||||||
bus->rx_level = DALI_GET_BUS_LEVEL(bus); // get level of RX pin - not depend on hw: 0 - low, 1 - high
|
bus->rx_level = DALI_GET_BUS_LEVEL(bus); // get level of RX pin - not depend on hw: 0 - low, 1 - high
|
||||||
|
bus->bus_activity_seen = true;
|
||||||
|
|
||||||
bus->rx_pulse_width = rx_current_edge_time - bus->rx_last_edge_time; // time from last edge
|
bus->rx_pulse_width = rx_current_edge_time - bus->rx_last_edge_time; // time from last edge
|
||||||
bus->rx_tx_delta = rx_current_edge_time - bus->tx_last_edge_time; // time from last edge
|
bus->rx_tx_delta = rx_current_edge_time - bus->tx_last_edge_time; // time from last edge
|
||||||
@@ -693,6 +834,7 @@ static void IRAM_ATTR rx_gpio_isr_handler(void* arg)
|
|||||||
|
|
||||||
// if collision detected: we are too late after bit was transmitted
|
// if collision detected: we are too late after bit was transmitted
|
||||||
else if (bus->bus_state == DALI_BUS_TRANSMITTING && bus->tx_state != TX_STATE_STOP &&
|
else if (bus->bus_state == DALI_BUS_TRANSMITTING && bus->tx_state != TX_STATE_STOP &&
|
||||||
|
!is_backward_tx_msg(&bus->tx_data) &&
|
||||||
bus->rx_tx_delta > s_timing.collision_txrx_delta)
|
bus->rx_tx_delta > s_timing.collision_txrx_delta)
|
||||||
{
|
{
|
||||||
// we need now to start collision recovery with time break: 101.9.2.4
|
// we need now to start collision recovery with time break: 101.9.2.4
|
||||||
@@ -803,20 +945,40 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start transmitting
|
// start transmitting
|
||||||
else if(bus->bus_state == DALI_BUS_READY && bus->tx_state == TX_STATE_IDLE && bus->tx_queue && xQueueReceiveFromISR(bus->tx_queue, &bus->tx_data, NULL) == pdTRUE)
|
else if(bus->tx_state == TX_STATE_IDLE && bus->tx_queue)
|
||||||
{
|
{
|
||||||
bus->tx_data.status = DALI_FRAME_ERROR; // error status - will be set ok on success
|
Dali_msg_t pending = {0};
|
||||||
bus->bus_state = DALI_BUS_TRANSMITTING; // bus is transmitting
|
bool can_start = bus->bus_state == DALI_BUS_READY;
|
||||||
bus->tx_state = TX_STATE_START; // start transmitting
|
bool force_backward = false;
|
||||||
bus->tx_half_bit_counter = 0;
|
if (!can_start && bus->force_backward_tx &&
|
||||||
bus->tx_data_bit_counter = 0; // actually sent bits count
|
xQueuePeekFromISR(bus->tx_queue, &pending) == pdTRUE) {
|
||||||
bus->tx_last_edge_time = esp_timer_get_time(); // get time in us
|
if (is_backward_tx_msg(&pending) && bus->bus_state != DALI_BUS_POWER_DOWN) {
|
||||||
DALI_SET_BUS_LOW(bus); // start bit first half
|
can_start = true;
|
||||||
|
force_backward = true;
|
||||||
|
} else {
|
||||||
|
bus->force_backward_tx = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_start && xQueueReceiveFromISR(bus->tx_queue, &bus->tx_data, &yield) == pdTRUE) {
|
||||||
|
bus->force_backward_tx = false;
|
||||||
|
if (force_backward) {
|
||||||
|
bus->rx_state = RX_STATE_IDLE;
|
||||||
|
}
|
||||||
|
bus->tx_data.status = DALI_FRAME_ERROR; // error status - will be set ok on success
|
||||||
|
bus->bus_activity_seen = true;
|
||||||
|
bus->bus_state = DALI_BUS_TRANSMITTING; // bus is transmitting
|
||||||
|
bus->tx_state = TX_STATE_START; // start transmitting
|
||||||
|
bus->tx_half_bit_counter = 0;
|
||||||
|
bus->tx_data_bit_counter = 0; // actually sent bits count
|
||||||
|
bus->tx_last_edge_time = esp_timer_get_time(); // get time in us
|
||||||
|
DALI_SET_BUS_LOW(bus); // start bit first half
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(bus->bus_state == DALI_BUS_TRANSMITTING)
|
else if(bus->bus_state == DALI_BUS_TRANSMITTING)
|
||||||
{
|
{
|
||||||
uint8_t bus_level = DALI_GET_BUS_LEVEL(bus);
|
uint8_t bus_level = DALI_GET_BUS_LEVEL(bus);
|
||||||
if(bus->tx_state != TX_STATE_STOP && tx_delta > s_timing.collision_txrx_delta &&
|
if(bus->tx_state != TX_STATE_STOP && !is_backward_tx_msg(&bus->tx_data) &&
|
||||||
|
tx_delta > s_timing.collision_txrx_delta &&
|
||||||
bus_level != DALI_GET_TX_LEVEL(bus)) {
|
bus_level != DALI_GET_TX_LEVEL(bus)) {
|
||||||
bus->rx_level = bus_level;
|
bus->rx_level = bus_level;
|
||||||
bus->rx_tx_delta = tx_delta;
|
bus->rx_tx_delta = tx_delta;
|
||||||
@@ -859,7 +1021,7 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now)
|
|||||||
else if(bus->bus_state == DALI_BUS_READY && bus->tx_state > TX_STATE_IDLE)
|
else if(bus->bus_state == DALI_BUS_READY && bus->tx_state > TX_STATE_IDLE)
|
||||||
{
|
{
|
||||||
// we are not transmitting but we have data - reply to queue and let error state in tx_data.status
|
// we are not transmitting but we have data - reply to queue and let error state in tx_data.status
|
||||||
if (bus->tx_reply_queue) {
|
if (bus->tx_reply_queue && !is_backward_tx_msg(&bus->tx_data)) {
|
||||||
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
|
||||||
@@ -875,6 +1037,7 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now)
|
|||||||
// rx_data.status = DALI_FRAME_ERROR; // should be set inside ISR
|
// rx_data.status = DALI_FRAME_ERROR; // should be set inside ISR
|
||||||
bus->rx_data.length = bus->rx_data_bit_counter; // set length of data
|
bus->rx_data.length = bus->rx_data_bit_counter; // set length of data
|
||||||
// rx_data.data[0] = 0xAA; // debug
|
// rx_data.data[0] = 0xAA; // debug
|
||||||
|
note_rx_frame_from_isr(bus);
|
||||||
publish_rx_frame_from_isr(&bus->rx_data, bus->rx_queue, &yield); // send data to queue
|
publish_rx_frame_from_isr(&bus->rx_data, bus->rx_queue, &yield); // send data to queue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -886,6 +1049,7 @@ static bool IRAM_ATTR handle_bus_timer(dali_bus_ctx_t *bus, uint64_t time_now)
|
|||||||
bus->rx_data.status = DALI_FRAME_OK; // frame is OK
|
bus->rx_data.status = DALI_FRAME_OK; // frame is OK
|
||||||
bus->rx_data.length = bus->rx_data_bit_counter; // set length of data
|
bus->rx_data.length = bus->rx_data_bit_counter; // set length of data
|
||||||
// rx_data.data[0] = 0xBB; // debug
|
// rx_data.data[0] = 0xBB; // debug
|
||||||
|
note_rx_frame_from_isr(bus);
|
||||||
publish_rx_frame_from_isr(&bus->rx_data, bus->rx_queue, &yield); // send data to queue
|
publish_rx_frame_from_isr(&bus->rx_data, bus->rx_queue, &yield); // send data to queue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1117,6 +1281,11 @@ static esp_err_t init_bus(uint8_t bus_id, uint8_t tx_pin, uint8_t 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_abnormal_report_time = 0;
|
bus->bus_abnormal_report_time = 0;
|
||||||
|
bus->bus_activity_seen = false;
|
||||||
|
bus->rx_last_frame_time = 0;
|
||||||
|
bus->rx_last_frame_length = 0;
|
||||||
|
bus->rx_last_frame_status = DALI_FRAME_UNKNOWN;
|
||||||
|
bus->force_backward_tx = false;
|
||||||
|
|
||||||
err = ensure_isr_service();
|
err = ensure_isr_service();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
@@ -1169,13 +1338,37 @@ static int dali_tx_bus(dali_bus_ctx_t *bus, Dali_msg_t *dali_msg)
|
|||||||
bus->bus_id, dali_msg->length, dali_msg->data[0], dali_msg->data[1],
|
bus->bus_id, dali_msg->length, dali_msg->data[0], dali_msg->data[1],
|
||||||
dali_msg->data[2], dali_msg->data[3], (unsigned long)timeout_ms);
|
dali_msg->data[2], dali_msg->data[3], (unsigned long)timeout_ms);
|
||||||
|
|
||||||
if(xQueueSendToBack(bus->tx_queue, dali_msg, timeout_ticks) == pdFALSE) {
|
if (is_forward_tx_msg(dali_msg) && !wait_for_forward_tx_window(bus, dali_msg)) {
|
||||||
|
dali_msg->status = DALI_FRAME_ERROR;
|
||||||
|
log_tx_message("native TX wait timeout", bus, dali_msg,
|
||||||
|
CONFIG_DALI_FORWARD_MAX_WAIT_MS);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool force_backward = false;
|
||||||
|
if (is_backward_tx_msg(dali_msg) &&
|
||||||
|
!wait_for_backward_tx_window(bus, dali_msg, &force_backward)) {
|
||||||
|
dali_msg->status = DALI_FRAME_ERROR;
|
||||||
|
log_tx_message("native backward TX wait timeout", bus, dali_msg,
|
||||||
|
CONFIG_DALI_BACKWARD_IDLE_TIMEOUT_MS);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus->force_backward_tx = force_backward;
|
||||||
|
if(xQueueSendToBack(bus->tx_queue, dali_msg, 0) == pdFALSE) {
|
||||||
|
bus->force_backward_tx = false;
|
||||||
log_tx_message("native TX queue full", bus, dali_msg, timeout_ms);
|
log_tx_message("native TX queue full", bus, dali_msg, timeout_ms);
|
||||||
if (bus->tx_state == TX_STATE_IDLE) {
|
if (bus->tx_state == TX_STATE_IDLE) {
|
||||||
xQueueReset(bus->tx_queue);
|
xQueueReset(bus->tx_queue);
|
||||||
}
|
}
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_backward_tx_msg(dali_msg)) {
|
||||||
|
dali_msg->status = DALI_FRAME_OK;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if(xQueueReceive(bus->tx_reply_queue, dali_msg, timeout_ticks) == pdFALSE) {
|
if(xQueueReceive(bus->tx_reply_queue, dali_msg, timeout_ticks) == pdFALSE) {
|
||||||
if (bus->tx_state == TX_STATE_IDLE && queue_waiting(bus->tx_queue) == 0) {
|
if (bus->tx_state == TX_STATE_IDLE && queue_waiting(bus->tx_queue) == 0) {
|
||||||
*dali_msg = bus->tx_data;
|
*dali_msg = bus->tx_data;
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#ifndef CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS
|
||||||
|
#define CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS 25
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace gateway {
|
namespace gateway {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -17,6 +21,48 @@ namespace {
|
|||||||
constexpr const char* kTag = "dali_domain";
|
constexpr const char* kTag = "dali_domain";
|
||||||
constexpr size_t kSerialRxPacketMaxBytes = 8;
|
constexpr size_t kSerialRxPacketMaxBytes = 8;
|
||||||
constexpr UBaseType_t kSerialRxQueueDepth = 8;
|
constexpr UBaseType_t kSerialRxQueueDepth = 8;
|
||||||
|
constexpr uint32_t kHardwareQueryRawSuppressMs = CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS + 10;
|
||||||
|
|
||||||
|
portMUX_TYPE s_query_raw_suppress_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
TickType_t s_query_raw_suppress_until[DALI_PHY_COUNT] = {};
|
||||||
|
|
||||||
|
void BeginHardwareQueryRawSuppress(uint8_t bus_id) {
|
||||||
|
if (bus_id >= DALI_PHY_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const TickType_t until = xTaskGetTickCount() + pdMS_TO_TICKS(kHardwareQueryRawSuppressMs);
|
||||||
|
portENTER_CRITICAL(&s_query_raw_suppress_lock);
|
||||||
|
s_query_raw_suppress_until[bus_id] = until;
|
||||||
|
portEXIT_CRITICAL(&s_query_raw_suppress_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TakeHardwareQueryRawSuppress(uint8_t bus_id) {
|
||||||
|
if (bus_id >= DALI_PHY_COUNT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool suppress = false;
|
||||||
|
const TickType_t now = xTaskGetTickCount();
|
||||||
|
portENTER_CRITICAL(&s_query_raw_suppress_lock);
|
||||||
|
const TickType_t until = s_query_raw_suppress_until[bus_id];
|
||||||
|
if (until != 0 && now <= until) {
|
||||||
|
suppress = true;
|
||||||
|
s_query_raw_suppress_until[bus_id] = 0;
|
||||||
|
} else if (until != 0) {
|
||||||
|
s_query_raw_suppress_until[bus_id] = 0;
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&s_query_raw_suppress_lock);
|
||||||
|
return suppress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearHardwareQueryRawSuppress(uint8_t bus_id) {
|
||||||
|
if (bus_id >= DALI_PHY_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
portENTER_CRITICAL(&s_query_raw_suppress_lock);
|
||||||
|
s_query_raw_suppress_until[bus_id] = 0;
|
||||||
|
portEXIT_CRITICAL(&s_query_raw_suppress_lock);
|
||||||
|
}
|
||||||
|
|
||||||
DaliDomainSnapshot MakeSnapshot(uint8_t gateway_id, int address, const char* kind) {
|
DaliDomainSnapshot MakeSnapshot(uint8_t gateway_id, int address, const char* kind) {
|
||||||
DaliDomainSnapshot snapshot;
|
DaliDomainSnapshot snapshot;
|
||||||
@@ -113,12 +159,15 @@ std::vector<uint8_t> TransactHardwareFrame(uint8_t bus_id, const uint8_t* data,
|
|||||||
Dali_msg_t tx = dali_msg_new(data[1], data[2]);
|
Dali_msg_t tx = dali_msg_new(data[1], data[2]);
|
||||||
tx.id = bus_id;
|
tx.id = bus_id;
|
||||||
Dali_msg_t rx = {};
|
Dali_msg_t rx = {};
|
||||||
|
BeginHardwareQueryRawSuppress(bus_id);
|
||||||
if (dali_query(&tx, &rx) == pdTRUE) {
|
if (dali_query(&tx, &rx) == pdTRUE) {
|
||||||
if (rx.status != DALI_FRAME_OK || rx.length != 8) {
|
if (rx.status != DALI_FRAME_OK || rx.length != 8) {
|
||||||
|
ClearHardwareQueryRawSuppress(bus_id);
|
||||||
return LegacyQueryResponse(0xFD);
|
return LegacyQueryResponse(0xFD);
|
||||||
}
|
}
|
||||||
return {0xFF, rx.data[0]};
|
return {0xFF, rx.data[0]};
|
||||||
}
|
}
|
||||||
|
ClearHardwareQueryRawSuppress(bus_id);
|
||||||
return LegacyQueryResponse(0xFE);
|
return LegacyQueryResponse(0xFE);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1250,6 +1299,12 @@ void DaliDomainService::rawFrameTaskLoop() {
|
|||||||
if (byte_count > DALI_MAX_BYTES) {
|
if (byte_count > DALI_MAX_BYTES) {
|
||||||
byte_count = DALI_MAX_BYTES;
|
byte_count = DALI_MAX_BYTES;
|
||||||
}
|
}
|
||||||
|
if (byte_count == 1 && TakeHardwareQueryRawSuppress(message.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (byte_count != 1 && byte_count != 2 && byte_count != 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
DaliRawFrame frame;
|
DaliRawFrame frame;
|
||||||
frame.channel_index = channel->config.channel_index;
|
frame.channel_index = channel->config.channel_index;
|
||||||
frame.gateway_id = channel->config.gateway_id;
|
frame.gateway_id = channel->config.gateway_id;
|
||||||
|
|||||||
@@ -141,6 +141,13 @@ void RegisterGatt(struct ble_gatt_register_ctxt* ctxt, void* arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> LegacyRawPayload(const std::vector<uint8_t>& data) {
|
||||||
|
if (data.size() == 1) {
|
||||||
|
return {0xBE, data[0]};
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
const struct ble_gatt_svc_def kGattServices[] = {
|
const struct ble_gatt_svc_def kGattServices[] = {
|
||||||
{
|
{
|
||||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||||
@@ -377,7 +384,7 @@ void GatewayBleBridge::handleDaliRawFrame(const DaliRawFrame& frame) {
|
|||||||
if (!enabled_ || conn_handle_ == kInvalidConnectionHandle || frame.data.empty()) {
|
if (!enabled_ || conn_handle_ == kInvalidConnectionHandle || frame.data.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notifyCharacteristic(frame.channel_index, frame.data);
|
notifyCharacteristic(frame.channel_index, LegacyRawPayload(frame.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GatewayBleBridge::handleRawWrite(size_t channel_index, const std::vector<uint8_t>& payload) {
|
void GatewayBleBridge::handleRawWrite(size_t channel_index, const std::vector<uint8_t>& payload) {
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ namespace gateway {
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr const char* kTag = "gateway_usb";
|
constexpr const char* kTag = "gateway_usb";
|
||||||
constexpr size_t kCommandFrameMinLen = 7;
|
constexpr size_t kCommandFrameMinLen = 7;
|
||||||
|
|
||||||
|
std::vector<uint8_t> LegacyRawPayload(const std::vector<uint8_t>& data) {
|
||||||
|
if (data.size() == 1) {
|
||||||
|
return {0xBE, data[0]};
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GatewayUsbSetupBridge::GatewayUsbSetupBridge(GatewayController& controller,
|
GatewayUsbSetupBridge::GatewayUsbSetupBridge(GatewayController& controller,
|
||||||
@@ -106,11 +113,12 @@ void GatewayUsbSetupBridge::handleRawFrame(const DaliRawFrame& frame) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int written = usb_serial_jtag_write_bytes(frame.data.data(), frame.data.size(),
|
const auto payload = LegacyRawPayload(frame.data);
|
||||||
|
const int written = usb_serial_jtag_write_bytes(payload.data(), payload.size(),
|
||||||
pdMS_TO_TICKS(config_.write_timeout_ms));
|
pdMS_TO_TICKS(config_.write_timeout_ms));
|
||||||
if (written < 0 || static_cast<size_t>(written) != frame.data.size()) {
|
if (written < 0 || static_cast<size_t>(written) != payload.size()) {
|
||||||
ESP_LOGW(kTag, "failed to forward USB raw setup frame channel=%u len=%u", frame.channel_index,
|
ESP_LOGW(kTag, "failed to forward USB raw setup frame channel=%u len=%u", frame.channel_index,
|
||||||
static_cast<unsigned>(frame.data.size()));
|
static_cast<unsigned>(payload.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user