#pragma once #include "services/plc_communication_gateway.h" #include "domain/register_repository.h" #include #include #include #include #include #include #include class PlcRegisterRepository; class QModbusReply; class QModbusRtuSerialMaster; struct PlcCommunicationFailure; class PlcCommunicationService final : public QObject, public PlcCommunicationGateway { Q_OBJECT public: explicit PlcCommunicationService( PlcRegisterRepository &repository, QObject *parent = nullptr); ~PlcCommunicationService() override; PlcCommunicationResult connectDevice( const PlcSerialConfiguration &configuration) override; void disconnectDevice() override; PlcCommunicationResult setPollAddresses( const std::vector &addresses) override; PlcConnectionState state() const override; bool initialReadCompleted() const override; PlcCommunicationError lastErrorType() const override; const std::string &lastError() const override; const PlcSerialConfiguration &configuration() const; void setCallbacks( std::function state_changed, std::function initial_read_changed, std::function cache_updated, std::function error_reported) override; signals: void stateChanged(); void initialReadCompletedChanged(bool completed); void cacheUpdated(); void communicationError(const QString &message); private: struct PollBlock { RegisterArea area = RegisterArea::M; int startAddress = 0; int count = 1; }; void rebuildPollBlocks(); void applyPollAddresses(const std::vector &addresses); void pollNextBlock(); void probeRecovery(); void handleRecoveryProbeFailure(QModbusDevice::Error error); void restoreCommunication(); void handleReadFinished(QModbusReply *reply, PollBlock block); RegisterWriteResult sendBitWrite(const RegisterAddress &address, bool value); RegisterWriteResult sendWordWrite( const RegisterAddress &address, std::int16_t value); void updateInitialReadCompleted(bool completed, bool force_notification = false); void handleUnexpectedDisconnect(); void handleModbusError(QModbusDevice::Error error); void closeSerialSession(); void setState(PlcConnectionState state); void setError(const PlcCommunicationFailure &failure); PlcRegisterRepository &repository_; std::unique_ptr master_; QTimer poll_timer_; QTimer recovery_timer_; PlcSerialConfiguration configuration_; std::vector poll_addresses_; std::vector pending_poll_addresses_; std::vector poll_blocks_; std::size_t next_poll_block_ = 0; QModbusReply *pending_reply_ = nullptr; QModbusReply *pending_write_reply_ = nullptr; bool poll_update_pending_ = false; bool disconnecting_ = false; bool serial_session_opened_ = false; bool received_valid_response_ = false; std::uint64_t connection_generation_ = 0; PlcConnectionState state_ = PlcConnectionState::Disconnected; bool initial_read_completed_ = false; std::vector initial_blocks_read_; PlcCommunicationError last_error_type_ = PlcCommunicationError::None; std::string last_error_; std::function state_changed_callback_; std::function initial_read_changed_callback_; std::function cache_updated_callback_; std::function error_reported_callback_; };