Add serial configuration support to Gateway Modbus
- Introduced GatewayModbusSerialConfig structure to encapsulate serial communication settings. - Added clamping functions for integer and size values to ensure valid configuration ranges. - Updated GatewayModbusConfigFromValue to parse serial configuration from JSON input. - Implemented transport type checking functions for TCP, RTU, ASCII, and Serial. - Enhanced GatewayModbusConfigToValue to include serial configuration in output. Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -18,14 +18,43 @@ constexpr uint16_t kGatewayModbusMaxReadBits = 2000;
|
||||
constexpr uint16_t kGatewayModbusMaxReadRegisters = 125;
|
||||
constexpr uint16_t kGatewayModbusMaxWriteBits = 1968;
|
||||
constexpr uint16_t kGatewayModbusMaxWriteRegisters = 123;
|
||||
constexpr uint32_t kGatewayModbusDefaultSerialBaudrate = 9600;
|
||||
constexpr uint32_t kGatewayModbusDefaultSerialResponseTimeoutMs = 20;
|
||||
constexpr uint32_t kGatewayModbusDefaultSerialInterFrameGapUs = 4000;
|
||||
|
||||
struct GatewayModbusRs485Config {
|
||||
bool enabled{false};
|
||||
int de_pin{-1};
|
||||
};
|
||||
|
||||
struct GatewayModbusSerialConfig {
|
||||
int uart_port{1};
|
||||
int tx_pin{-1};
|
||||
int rx_pin{-1};
|
||||
uint32_t baudrate{kGatewayModbusDefaultSerialBaudrate};
|
||||
int data_bits{8};
|
||||
std::string parity{"none"};
|
||||
int stop_bits{1};
|
||||
size_t rx_buffer_size{512};
|
||||
size_t tx_buffer_size{512};
|
||||
uint32_t response_timeout_ms{kGatewayModbusDefaultSerialResponseTimeoutMs};
|
||||
uint32_t inter_frame_gap_us{kGatewayModbusDefaultSerialInterFrameGapUs};
|
||||
GatewayModbusRs485Config rs485;
|
||||
};
|
||||
|
||||
struct GatewayModbusConfig {
|
||||
std::string transport{"tcp-server"};
|
||||
std::string host;
|
||||
uint16_t port{kGatewayModbusDefaultTcpPort};
|
||||
uint8_t unit_id{1};
|
||||
GatewayModbusSerialConfig serial;
|
||||
};
|
||||
|
||||
bool GatewayModbusTransportIsTcp(const std::string& transport);
|
||||
bool GatewayModbusTransportIsRtu(const std::string& transport);
|
||||
bool GatewayModbusTransportIsAscii(const std::string& transport);
|
||||
bool GatewayModbusTransportIsSerial(const std::string& transport);
|
||||
|
||||
enum class GatewayModbusSpace : uint8_t {
|
||||
kCoil = 1,
|
||||
kDiscreteInput = 2,
|
||||
|
||||
@@ -396,8 +396,44 @@ GatewayModbusPointBinding toBinding(const GatewayModbusPoint& point) {
|
||||
point.diagnostic_device_type};
|
||||
}
|
||||
|
||||
int clampedInt(const DaliValue::Object& json, const std::string& key, int fallback,
|
||||
int min_value, int max_value) {
|
||||
const int value = getObjectInt(json, key).value_or(fallback);
|
||||
return std::clamp(value, min_value, max_value);
|
||||
}
|
||||
|
||||
uint32_t clampedU32(const DaliValue::Object& json, const std::string& key, uint32_t fallback,
|
||||
uint32_t min_value, uint32_t max_value) {
|
||||
const int value = getObjectInt(json, key).value_or(static_cast<int>(fallback));
|
||||
return static_cast<uint32_t>(std::clamp(value, static_cast<int>(min_value),
|
||||
static_cast<int>(max_value)));
|
||||
}
|
||||
|
||||
size_t clampedSize(const DaliValue::Object& json, const std::string& key, size_t fallback,
|
||||
size_t min_value, size_t max_value) {
|
||||
const int value = getObjectInt(json, key).value_or(static_cast<int>(fallback));
|
||||
return static_cast<size_t>(std::clamp(value, static_cast<int>(min_value),
|
||||
static_cast<int>(max_value)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GatewayModbusTransportIsTcp(const std::string& transport) {
|
||||
return transport.empty() || transport == "tcp" || transport == "tcp-server";
|
||||
}
|
||||
|
||||
bool GatewayModbusTransportIsRtu(const std::string& transport) {
|
||||
return transport == "rtu" || transport == "rtu-server" || transport == "modbus-rtu";
|
||||
}
|
||||
|
||||
bool GatewayModbusTransportIsAscii(const std::string& transport) {
|
||||
return transport == "ascii" || transport == "ascii-server" || transport == "modbus-ascii";
|
||||
}
|
||||
|
||||
bool GatewayModbusTransportIsSerial(const std::string& transport) {
|
||||
return GatewayModbusTransportIsRtu(transport) || GatewayModbusTransportIsAscii(transport);
|
||||
}
|
||||
|
||||
std::optional<GatewayModbusConfig> GatewayModbusConfigFromValue(const DaliValue* value) {
|
||||
if (value == nullptr || value->asObject() == nullptr) {
|
||||
return std::nullopt;
|
||||
@@ -410,6 +446,35 @@ std::optional<GatewayModbusConfig> GatewayModbusConfigFromValue(const DaliValue*
|
||||
getObjectInt(json, "port").value_or(kGatewayModbusDefaultTcpPort));
|
||||
config.unit_id = static_cast<uint8_t>(getObjectInt(json, "unitID").value_or(
|
||||
getObjectInt(json, "unitId").value_or(getObjectInt(json, "unit_id").value_or(1))));
|
||||
if (const auto* serial_value = getObjectValue(json, "serial")) {
|
||||
if (const auto* serial = serial_value->asObject()) {
|
||||
config.serial.uart_port = clampedInt(*serial, "uartPort", config.serial.uart_port, 0, 2);
|
||||
config.serial.tx_pin = clampedInt(*serial, "txPin", config.serial.tx_pin, -1, 48);
|
||||
config.serial.rx_pin = clampedInt(*serial, "rxPin", config.serial.rx_pin, -1, 48);
|
||||
config.serial.baudrate = clampedU32(*serial, "baudrate", config.serial.baudrate,
|
||||
1200, 921600);
|
||||
config.serial.data_bits = clampedInt(*serial, "dataBits", config.serial.data_bits, 7, 8);
|
||||
config.serial.parity = getObjectString(*serial, "parity").value_or(config.serial.parity);
|
||||
config.serial.stop_bits = clampedInt(*serial, "stopBits", config.serial.stop_bits, 1, 2);
|
||||
config.serial.rx_buffer_size = clampedSize(*serial, "rxBufferBytes",
|
||||
config.serial.rx_buffer_size, 128, 4096);
|
||||
config.serial.tx_buffer_size = clampedSize(*serial, "txBufferBytes",
|
||||
config.serial.tx_buffer_size, 0, 4096);
|
||||
config.serial.response_timeout_ms = clampedU32(*serial, "responseTimeoutMs",
|
||||
config.serial.response_timeout_ms, 1, 1000);
|
||||
config.serial.inter_frame_gap_us = clampedU32(*serial, "interFrameGapUs",
|
||||
config.serial.inter_frame_gap_us, 1000,
|
||||
100000);
|
||||
if (const auto* rs485_value = getObjectValue(*serial, "rs485")) {
|
||||
if (const auto* rs485 = rs485_value->asObject()) {
|
||||
config.serial.rs485.enabled = getObjectBool(*rs485, "enabled")
|
||||
.value_or(config.serial.rs485.enabled);
|
||||
config.serial.rs485.de_pin = clampedInt(*rs485, "dePin",
|
||||
config.serial.rs485.de_pin, -1, 48);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -419,6 +484,23 @@ DaliValue GatewayModbusConfigToValue(const GatewayModbusConfig& config) {
|
||||
out["host"] = config.host;
|
||||
out["port"] = static_cast<int>(config.port);
|
||||
out["unitID"] = static_cast<int>(config.unit_id);
|
||||
DaliValue::Object serial;
|
||||
serial["uartPort"] = config.serial.uart_port;
|
||||
serial["txPin"] = config.serial.tx_pin;
|
||||
serial["rxPin"] = config.serial.rx_pin;
|
||||
serial["baudrate"] = static_cast<int>(config.serial.baudrate);
|
||||
serial["dataBits"] = config.serial.data_bits;
|
||||
serial["parity"] = config.serial.parity;
|
||||
serial["stopBits"] = config.serial.stop_bits;
|
||||
serial["rxBufferBytes"] = static_cast<int>(config.serial.rx_buffer_size);
|
||||
serial["txBufferBytes"] = static_cast<int>(config.serial.tx_buffer_size);
|
||||
serial["responseTimeoutMs"] = static_cast<int>(config.serial.response_timeout_ms);
|
||||
serial["interFrameGapUs"] = static_cast<int>(config.serial.inter_frame_gap_us);
|
||||
DaliValue::Object rs485;
|
||||
rs485["enabled"] = config.serial.rs485.enabled;
|
||||
rs485["dePin"] = config.serial.rs485.de_pin;
|
||||
serial["rs485"] = std::move(rs485);
|
||||
out["serial"] = std::move(serial);
|
||||
return DaliValue(std::move(out));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user