feat(gateway): Update SDK configuration and add 485 control bridge

- Changed flash size configuration from 16MB to 4MB and updated partition table filename.
- Introduced two gateway channels with UART configurations for communication.
- Added support for gateway cache and startup services including BLE and Wi-Fi.
- Enabled SPI RAM and configured its parameters for better memory management.
- Enhanced the gateway bridge service to handle generated Modbus points more efficiently.
- Refactored the gateway Modbus component to improve point management and added new methods for point description and generation.
- Implemented a new Gateway485ControlBridge for handling 485 control communication with UART.
- Added necessary files for the 485 control bridge including configuration and implementation.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-06 00:39:58 +08:00
parent 34d2d9caa0
commit 029785ff1d
13 changed files with 925 additions and 181 deletions
@@ -0,0 +1,7 @@
idf_component_register(
SRCS "src/gateway_485_control.cpp"
INCLUDE_DIRS "include"
REQUIRES esp_driver_uart freertos gateway_controller log
)
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
@@ -0,0 +1,47 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <vector>
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
namespace gateway {
class GatewayController;
struct Gateway485ControlBridgeConfig {
bool enabled{false};
int tx_pin{-1};
int rx_pin{-1};
uint32_t baudrate{9600};
size_t rx_buffer_size{256};
size_t tx_buffer_size{256};
uint32_t read_timeout_ms{20};
uint32_t write_timeout_ms{20};
uint32_t task_stack_size{4096};
UBaseType_t task_priority{4};
};
class Gateway485ControlBridge {
public:
Gateway485ControlBridge(GatewayController& controller,
Gateway485ControlBridgeConfig config = {});
esp_err_t start();
private:
static void TaskEntry(void* arg);
void taskLoop();
void handleBytes(const uint8_t* data, size_t len);
void handleGatewayNotification(const std::vector<uint8_t>& frame);
GatewayController& controller_;
Gateway485ControlBridgeConfig config_;
TaskHandle_t task_handle_{nullptr};
bool started_{false};
};
} // namespace gateway
@@ -0,0 +1,134 @@
#include "gateway_485_control.hpp"
#include "gateway_controller.hpp"
#include "driver/uart.h"
#include "esp_log.h"
#include <algorithm>
namespace gateway {
namespace {
constexpr const char* kTag = "gateway_485";
constexpr uart_port_t kControlUart = UART_NUM_0;
constexpr size_t kCommandFrameMinLen = 7;
int EffectivePin(int pin) {
return pin >= 0 ? pin : UART_PIN_NO_CHANGE;
}
} // namespace
Gateway485ControlBridge::Gateway485ControlBridge(GatewayController& controller,
Gateway485ControlBridgeConfig config)
: controller_(controller), config_(config) {}
esp_err_t Gateway485ControlBridge::start() {
if (started_) {
return ESP_OK;
}
if (!config_.enabled) {
ESP_LOGI(kTag, "UART0 control bridge disabled");
return ESP_OK;
}
if (uart_is_driver_installed(kControlUart)) {
ESP_LOGE(kTag, "UART0 driver already installed; move console or other users off UART0");
return ESP_ERR_INVALID_STATE;
}
uart_config_t uart_config{};
uart_config.baud_rate = static_cast<int>(config_.baudrate);
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_DEFAULT;
esp_err_t err = uart_param_config(kControlUart, &uart_config);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to configure UART0: %s", esp_err_to_name(err));
return err;
}
err = uart_set_pin(kControlUart, EffectivePin(config_.tx_pin), EffectivePin(config_.rx_pin),
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to set UART0 pins: %s", esp_err_to_name(err));
return err;
}
err = uart_driver_install(kControlUart, static_cast<int>(config_.rx_buffer_size),
static_cast<int>(config_.tx_buffer_size), 0, nullptr, 0);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to install UART0 driver: %s", esp_err_to_name(err));
return err;
}
controller_.addNotificationSink(
[this](const std::vector<uint8_t>& frame) { handleGatewayNotification(frame); });
const BaseType_t created = xTaskCreate(&Gateway485ControlBridge::TaskEntry,
"gateway_485_ctrl",
static_cast<uint32_t>(config_.task_stack_size), this,
config_.task_priority, &task_handle_);
if (created != pdPASS) {
uart_driver_delete(kControlUart);
task_handle_ = nullptr;
ESP_LOGE(kTag, "failed to create 485 control task");
return ESP_ERR_NO_MEM;
}
started_ = true;
ESP_LOGI(kTag, "485 control bridge started baud=%lu", static_cast<unsigned long>(config_.baudrate));
return ESP_OK;
}
void Gateway485ControlBridge::TaskEntry(void* arg) {
static_cast<Gateway485ControlBridge*>(arg)->taskLoop();
}
void Gateway485ControlBridge::taskLoop() {
std::vector<uint8_t> read_buffer(std::max<size_t>(config_.rx_buffer_size, 64));
std::vector<uint8_t> pending;
pending.reserve(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 = uart_read_bytes(kControlUart, read_buffer.data(), read_buffer.size(), timeout);
if (read_len > 0) {
pending.insert(pending.end(), read_buffer.begin(), read_buffer.begin() + read_len);
continue;
}
if (!pending.empty()) {
handleBytes(pending.data(), pending.size());
pending.clear();
}
}
}
void Gateway485ControlBridge::handleBytes(const uint8_t* data, size_t len) {
if (data == nullptr || len < kCommandFrameMinLen) {
return;
}
if (data[0] != 0x28 || data[1] != 0x01) {
ESP_LOGD(kTag, "ignored non-gateway UART0 burst len=%u", static_cast<unsigned>(len));
return;
}
controller_.enqueueCommandFrame(std::vector<uint8_t>(data, data + len));
}
void Gateway485ControlBridge::handleGatewayNotification(const std::vector<uint8_t>& frame) {
if (!started_ || frame.empty()) {
return;
}
const int written = uart_write_bytes(kControlUart, frame.data(), frame.size());
if (written < 0 || static_cast<size_t>(written) != frame.size()) {
ESP_LOGW(kTag, "failed to write UART0 notification len=%u", static_cast<unsigned>(frame.size()));
return;
}
if (uart_wait_tx_done(kControlUart, pdMS_TO_TICKS(config_.write_timeout_ms)) != ESP_OK) {
ESP_LOGW(kTag, "timed out flushing UART0 notification len=%u", static_cast<unsigned>(frame.size()));
}
}
} // namespace gateway