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:
@@ -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
|
||||
Reference in New Issue
Block a user