#pragma once #include "domain/register_address.h" #include "domain/project_limits.h" #include #include #include #include #include struct PlcSerialConfiguration { std::string portName; int serverAddress = 1; int baudRate = 9600; int dataBits = 8; int parity = 2; int stopBits = 1; int responseTimeoutMs = 1000; int retries = 2; int pollIntervalMs = 200; }; enum class PlcConnectionState { Disconnected, Connecting, Connected, Recovering, Faulted }; enum class PlcCommunicationError { None, SerialPortOpenFailed, PlcNotResponding, UsbSerialAdapterRemoved, SerialConnectionLost, CommunicationTimeout, ProtocolError, ReadFailed, WriteFailed, ConfigurationError, RequestAborted, Unknown }; struct PlcCommunicationResult { bool succeeded = false; std::string message; }; inline PlcCommunicationResult validatePlcSerialConfiguration( const PlcSerialConfiguration &configuration) { const bool has_port_name = std::any_of( configuration.portName.cbegin(), configuration.portName.cend(), [](unsigned char character) { return std::isspace(character) == 0; }); if (!has_port_name) { return {false, "必须填写串口端口"}; } if (configuration.serverAddress < ProjectLimits::kMinimumPlcServerAddress || configuration.serverAddress > ProjectLimits::kMaximumPlcServerAddress) { return {false, "PLC 站号必须在 1~247 范围内"}; } if (configuration.baudRate != 9600 && configuration.baudRate != 19200 && configuration.baudRate != 38400 && configuration.baudRate != 57600 && configuration.baudRate != 115200) { return {false, "波特率只支持 9600、19200、38400、57600 或 115200"}; } if (configuration.dataBits != 7 && configuration.dataBits != 8) { return {false, "数据位只支持 7 或 8"}; } if (configuration.parity != 0 && configuration.parity != 2 && configuration.parity != 3) { return {false, "校验方式只支持无校验、偶校验或奇校验"}; } if (configuration.stopBits != 1 && configuration.stopBits != 2) { return {false, "停止位只支持 1 或 2"}; } if (configuration.responseTimeoutMs < ProjectLimits::kMinimumResponseTimeoutMs || configuration.responseTimeoutMs > ProjectLimits::kMaximumResponseTimeoutMs) { return {false, "PLC 响应超时必须在 100~30000 ms 范围内"}; } if (configuration.retries < ProjectLimits::kMinimumRetries || configuration.retries > ProjectLimits::kMaximumRetries) { return {false, "PLC 失败重试次数必须在 0~5 范围内"}; } if (configuration.pollIntervalMs < ProjectLimits::kMinimumPollIntervalMs || configuration.pollIntervalMs > ProjectLimits::kMaximumPollIntervalMs) { return {false, "PLC 轮询周期必须在 50~10000 ms 范围内"}; } return {true, {}}; } class PlcCommunicationGateway { public: virtual ~PlcCommunicationGateway() = default; virtual PlcCommunicationResult connectDevice( const PlcSerialConfiguration &configuration) = 0; virtual void disconnectDevice() = 0; virtual PlcCommunicationResult setPollAddresses( const std::vector &addresses) = 0; virtual PlcConnectionState state() const = 0; virtual bool initialReadCompleted() const = 0; virtual PlcCommunicationError lastErrorType() const = 0; virtual const std::string &lastError() const = 0; virtual void setCallbacks( std::function state_changed, std::function initial_read_changed, std::function cache_updated, std::function error_reported) = 0; };