Files
gateway/components/gateway_usb_setup/src/gateway_usb_setup.cpp
T
Tony 4ce3513dd2 feat: Add DALI raw frame handling and USB setup bridge
- Introduced DaliRawFrame structure to encapsulate raw frame data.
- Enhanced DaliDomainService to manage raw frame sinks and processing.
- Implemented raw frame task for asynchronous handling of incoming DALI frames.
- Integrated raw frame handling in GatewayBleBridge and GatewayNetworkService.
- Added GatewayUsbSetupBridge to facilitate USB Serial/JTAG communication with DALI.
- Configured ESP-NOW for wireless communication and setup management.
- Updated GatewayRuntime to support clearing wireless credentials on boot button long press.
- Enhanced CMakeLists to include new components and dependencies.

Co-authored-by: Copilot <copilot@github.com>
2026-04-30 04:15:05 +08:00

113 lines
3.7 KiB
C++

#include "gateway_usb_setup.hpp"
#include "gateway_controller.hpp"
#include "driver/usb_serial_jtag.h"
#include "esp_log.h"
#include <algorithm>
namespace gateway {
namespace {
constexpr const char* kTag = "gateway_usb";
constexpr size_t kCommandFrameMinLen = 7;
}
GatewayUsbSetupBridge::GatewayUsbSetupBridge(GatewayController& controller,
DaliDomainService& dali_domain,
GatewayUsbSetupBridgeConfig config)
: controller_(controller), dali_domain_(dali_domain), config_(config) {}
esp_err_t GatewayUsbSetupBridge::start() {
if (started_) {
return ESP_OK;
}
if (!config_.enabled) {
ESP_LOGI(kTag, "USB Serial/JTAG setup bridge disabled; USB remains available for debug");
return ESP_OK;
}
if (!usb_serial_jtag_is_driver_installed()) {
usb_serial_jtag_driver_config_t driver_config = {};
driver_config.rx_buffer_size = static_cast<int>(config_.rx_buffer_size);
driver_config.tx_buffer_size = static_cast<int>(config_.tx_buffer_size);
esp_err_t err = usb_serial_jtag_driver_install(&driver_config);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to install USB Serial/JTAG driver: %s", esp_err_to_name(err));
return err;
}
}
dali_domain_.addRawFrameSink([this](const DaliRawFrame& frame) { handleRawFrame(frame); });
const BaseType_t ok = xTaskCreate(&GatewayUsbSetupBridge::TaskEntry, "gateway_usb_setup",
static_cast<uint32_t>(config_.task_stack_size), this,
config_.task_priority, &task_handle_);
if (ok != pdPASS) {
ESP_LOGE(kTag, "failed to create USB setup task");
return ESP_ERR_NO_MEM;
}
started_ = true;
ESP_LOGI(kTag, "USB Serial/JTAG setup bridge started channel=%u", config_.channel_index);
return ESP_OK;
}
void GatewayUsbSetupBridge::TaskEntry(void* arg) {
auto* self = static_cast<GatewayUsbSetupBridge*>(arg);
self->taskLoop();
}
void GatewayUsbSetupBridge::taskLoop() {
std::vector<uint8_t> buffer(std::max<size_t>(config_.rx_buffer_size, 64));
const TickType_t timeout = pdMS_TO_TICKS(config_.read_timeout_ms);
while (true) {
const int read_len = usb_serial_jtag_read_bytes(buffer.data(), buffer.size(), timeout);
if (read_len > 0) {
handleBytes(buffer.data(), static_cast<size_t>(read_len));
}
}
}
void GatewayUsbSetupBridge::handleBytes(const uint8_t* data, size_t len) {
if (data == nullptr || len == 0) {
return;
}
if (len >= kCommandFrameMinLen) {
controller_.enqueueCommandFrame(std::vector<uint8_t>(data, data + len));
return;
}
const uint8_t gateway_id = setupGatewayId();
if (!dali_domain_.writeBridgeFrame(gateway_id, data, len)) {
ESP_LOGW(kTag, "failed to write USB raw setup frame channel=%u len=%u", config_.channel_index,
static_cast<unsigned>(len));
}
}
void GatewayUsbSetupBridge::handleRawFrame(const DaliRawFrame& frame) {
if (!config_.enabled || frame.channel_index != config_.channel_index || frame.data.empty()) {
return;
}
const int written = usb_serial_jtag_write_bytes(frame.data.data(), frame.data.size(),
pdMS_TO_TICKS(config_.write_timeout_ms));
if (written < 0 || static_cast<size_t>(written) != frame.data.size()) {
ESP_LOGW(kTag, "failed to forward USB raw setup frame channel=%u len=%u", frame.channel_index,
static_cast<unsigned>(frame.data.size()));
}
}
uint8_t GatewayUsbSetupBridge::setupGatewayId() const {
for (const auto& channel : dali_domain_.channelInfo()) {
if (channel.channel_index == config_.channel_index) {
return channel.gateway_id;
}
}
return config_.channel_index;
}
} // namespace gateway