feat: implement raw frame dispatch and handling in DaliDomainService

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-06-14 21:20:42 +08:00
parent 4d2cfa3cb3
commit 9598147dd5
3 changed files with 122 additions and 11 deletions
@@ -13,6 +13,7 @@
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
@@ -220,9 +221,13 @@ class DaliDomainService {
esp_err_t startSerialRxTask(DaliChannel& channel);
static void SerialRxTaskEntry(void* arg);
void serialRxTaskLoop(DaliChannel* channel);
esp_err_t startRawFrameDispatchTask();
static void RawFrameDispatchTaskEntry(void* arg);
void rawFrameDispatchTaskLoop();
esp_err_t startRawFrameTask();
static void RawFrameTaskEntry(void* arg);
void rawFrameTaskLoop();
void queueRawFrame(const DaliChannel& channel, const uint8_t* data, size_t len);
void notifyRawFrameSinks(const DaliRawFrame& frame);
void markBusActivity(uint8_t gateway_id) const;
@@ -234,6 +239,8 @@ class DaliDomainService {
mutable SemaphoreHandle_t host_activity_lock_{nullptr};
mutable std::map<uint8_t, TickType_t> last_host_activity_ticks_;
mutable std::map<uint8_t, RecentHostCommandFrame> recent_host_command_frames_;
QueueHandle_t raw_frame_dispatch_queue_{nullptr};
TaskHandle_t raw_frame_dispatch_task_handle_{nullptr};
TaskHandle_t raw_frame_task_handle_{nullptr};
};
+111 -11
View File
@@ -16,6 +16,18 @@
#define CONFIG_DALI_QUERY_RESPONSE_TIMEOUT_MS 25
#endif
#ifndef CONFIG_DALI_DOMAIN_RAW_RX_TASK_STACK_SIZE
#define CONFIG_DALI_DOMAIN_RAW_RX_TASK_STACK_SIZE 4096
#endif
#ifndef CONFIG_DALI_DOMAIN_RAW_DISPATCH_TASK_STACK_SIZE
#define CONFIG_DALI_DOMAIN_RAW_DISPATCH_TASK_STACK_SIZE 12288
#endif
#ifndef CONFIG_DALI_DOMAIN_RAW_DISPATCH_QUEUE_LEN
#define CONFIG_DALI_DOMAIN_RAW_DISPATCH_QUEUE_LEN 16
#endif
static const char *TAG = "dali_domain";
namespace gateway {
@@ -24,6 +36,11 @@ namespace {
constexpr size_t kSerialRxPacketMaxBytes = 8;
constexpr UBaseType_t kSerialRxQueueDepth = 8;
constexpr size_t kRawFrameMaxBytes = DALI_MAX_BYTES;
constexpr UBaseType_t kRawFrameDispatchQueueDepth = CONFIG_DALI_DOMAIN_RAW_DISPATCH_QUEUE_LEN;
constexpr uint32_t kRawFrameRxTaskStackSize = CONFIG_DALI_DOMAIN_RAW_RX_TASK_STACK_SIZE;
constexpr uint32_t kRawFrameDispatchTaskStackSize =
CONFIG_DALI_DOMAIN_RAW_DISPATCH_TASK_STACK_SIZE;
constexpr uint32_t kHardwareQueryRawPostSuppressMs = 10;
constexpr uint8_t kControlDeviceSendOpcode = 0x60;
constexpr uint8_t kControlDeviceSendTwiceOpcode = 0x61;
@@ -145,6 +162,14 @@ struct SerialRxPacket {
uint8_t data[kSerialRxPacketMaxBytes]{};
};
struct RawFrameEvent {
uint8_t channel_index{0};
uint8_t gateway_id{0};
DaliPhyKind phy_kind{DaliPhyKind::kCustom};
size_t len{0};
uint8_t data[kRawFrameMaxBytes]{};
};
std::vector<uint8_t> LegacyQueryResponse(uint8_t status, uint8_t value = 0x00) {
return {status, value};
}
@@ -1723,6 +1748,10 @@ esp_err_t DaliDomainService::startSerialRxTask(DaliChannel& channel) {
if (!channel.serial_bus.has_value() || channel.serial_rx_queue == nullptr) {
return ESP_ERR_INVALID_STATE;
}
const esp_err_t dispatch_err = startRawFrameDispatchTask();
if (dispatch_err != ESP_OK) {
ESP_LOGW(TAG, "serial raw frame dispatch disabled: %s", esp_err_to_name(dispatch_err));
}
const BaseType_t created = xTaskCreate(&DaliDomainService::SerialRxTaskEntry,
"dali_uart_rx", 4096, &channel, 4,
&channel.serial_rx_task_handle);
@@ -1765,11 +1794,52 @@ void DaliDomainService::serialRxTaskLoop(DaliChannel* channel) {
if (packet.len != 2 && packet.len != 3) {
continue;
}
queueRawFrame(*channel, packet.data, packet.len);
}
}
esp_err_t DaliDomainService::startRawFrameDispatchTask() {
if (raw_frame_dispatch_task_handle_ != nullptr) {
return ESP_OK;
}
if (raw_frame_dispatch_queue_ == nullptr) {
raw_frame_dispatch_queue_ =
xQueueCreate(kRawFrameDispatchQueueDepth, sizeof(RawFrameEvent));
if (raw_frame_dispatch_queue_ == nullptr) {
return ESP_ERR_NO_MEM;
}
}
const BaseType_t created =
xTaskCreate(&DaliDomainService::RawFrameDispatchTaskEntry, "dali_raw_dispatch",
kRawFrameDispatchTaskStackSize, this, 4,
&raw_frame_dispatch_task_handle_);
if (created != pdPASS) {
raw_frame_dispatch_task_handle_ = nullptr;
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
void DaliDomainService::RawFrameDispatchTaskEntry(void* arg) {
static_cast<DaliDomainService*>(arg)->rawFrameDispatchTaskLoop();
}
void DaliDomainService::rawFrameDispatchTaskLoop() {
RawFrameEvent event;
while (true) {
if (raw_frame_dispatch_queue_ == nullptr) {
vTaskDelay(pdMS_TO_TICKS(10));
continue;
}
if (xQueueReceive(raw_frame_dispatch_queue_, &event, portMAX_DELAY) != pdTRUE) {
continue;
}
DaliRawFrame frame;
frame.channel_index = channel->config.channel_index;
frame.gateway_id = channel->config.gateway_id;
frame.phy_kind = channel->phy_kind;
frame.data.assign(packet.data, packet.data + packet.len);
frame.channel_index = event.channel_index;
frame.gateway_id = event.gateway_id;
frame.phy_kind = event.phy_kind;
frame.data.assign(event.data, event.data + event.len);
notifyRawFrameSinks(frame);
}
}
@@ -1778,12 +1848,16 @@ esp_err_t DaliDomainService::startRawFrameTask() {
if (raw_frame_task_handle_ != nullptr) {
return ESP_OK;
}
esp_err_t err = startRawFrameDispatchTask();
if (err != ESP_OK) {
return err;
}
QueueHandle_t queue = dali_hal_raw_receive_queue();
if (queue == nullptr) {
return ESP_ERR_INVALID_STATE;
}
const BaseType_t created = xTaskCreate(&DaliDomainService::RawFrameTaskEntry,
"dali_raw_rx", 4096, this, 4,
"dali_raw_rx", kRawFrameRxTaskStackSize, this, 4,
&raw_frame_task_handle_);
if (created != pdPASS) {
raw_frame_task_handle_ = nullptr;
@@ -1825,15 +1899,41 @@ void DaliDomainService::rawFrameTaskLoop() {
if (byte_count != 1 && byte_count != 2 && byte_count != 3) {
continue;
}
DaliRawFrame frame;
frame.channel_index = channel->config.channel_index;
frame.gateway_id = channel->config.gateway_id;
frame.phy_kind = channel->phy_kind;
frame.data.assign(message.data, message.data + byte_count);
notifyRawFrameSinks(frame);
queueRawFrame(*channel, message.data, byte_count);
}
}
void DaliDomainService::queueRawFrame(const DaliChannel& channel, const uint8_t* data,
size_t len) {
if (data == nullptr || len == 0) {
return;
}
if (len > kRawFrameMaxBytes) {
len = kRawFrameMaxBytes;
}
markBusActivity(channel.config.gateway_id);
if (raw_frame_dispatch_queue_ == nullptr) {
return;
}
RawFrameEvent event;
event.channel_index = channel.config.channel_index;
event.gateway_id = channel.config.gateway_id;
event.phy_kind = channel.phy_kind;
event.len = len;
std::copy(data, data + len, event.data);
if (xQueueSendToBack(raw_frame_dispatch_queue_, &event, 0) == pdTRUE) {
return;
}
RawFrameEvent dropped;
xQueueReceive(raw_frame_dispatch_queue_, &dropped, 0);
xQueueSendToBack(raw_frame_dispatch_queue_, &event, 0);
}
void DaliDomainService::notifyRawFrameSinks(const DaliRawFrame& frame) {
markBusActivity(frame.gateway_id);
if (raw_frame_sink_lock_ != nullptr) {
@@ -408,6 +408,10 @@ void GatewayBleBridge::handleDaliRawFrame(const DaliRawFrame& frame) {
if (!controller_.rawReportingEnabled(frame.gateway_id)) {
return;
}
// Forward/control events are already published on FFF3 as structured 0x22 frames.
if (notify_enabled_[kGatewayCharacteristicIndex] && frame.data.size() != 1) {
return;
}
notifyCharacteristic(frame.channel_index, LegacyRawPayload(frame.data));
}