#pragma once #include "services/plc_discovery_gateway.h" #include #include #include #include #include #include #include #include class QModbusReply; class QModbusRtuSerialMaster; // 使用独立 Qt Modbus RTU 主站逐项探测串口参数,不污染正式 PLC 连接状态 class PlcDiscoveryService final : public QObject, public PlcDiscoveryGateway { public: /** * @brief 创建独立的 PLC 自动搜索服务 * @param parent Qt 父对象 */ explicit PlcDiscoveryService(QObject *parent = nullptr); ~PlcDiscoveryService() override; /** * @brief 枚举串口和候选参数,并异步逐项探测 PLC * @param preferred 优先尝试的串口参数 * @return 搜索启动结果,最终搜索结果通过回调返回 */ PlcCommunicationResult startDiscovery( const PlcSerialConfiguration &preferred) override; // 取消当前自动搜索并释放探测串口 void cancelDiscovery() override; // 返回当前是否正在自动搜索 bool isDiscovering() const override; /** * @brief 设置搜索进度和最终结果回调 * @param progress_changed 每次候选参数或进度变化时调用 * @param discovery_finished 搜索结束、取消或失败时调用 */ void setCallbacks( std::function progress_changed, std::function discovery_finished) override; private: enum class Phase { Idle, // 等待尝试候选参数 Connecting, // 正在异步打开候选串口 Probing, // 已打开串口,正在读取 D0 Disconnecting // 正在释放当前候选串口 }; // 尝试当前候选参数并等待串口异步打开 void tryCurrentCandidate(); // 串口打开后发送只读 D0 探测请求 void sendProbe(); /** * @brief 处理当前 D0 探测结果 * @param reply 当前候选串口的异步 Modbus 回复 * @param attempt_generation 发起请求时的尝试代次,用于丢弃过期回复 */ void handleProbeFinished(QModbusReply *reply, std::uint64_t attempt_generation); /** * @brief 释放当前串口,释放完成后进入下一个候选或报告结果 * @param found 当前候选参数是否已经探测到 PLC */ void disconnectCurrent(bool found); // 当前串口完全释放后完成状态迁移 void continueAfterDisconnect(); /** * @brief 报告最终结果并清理搜索状态 * @param outcome 要交给调用方的最终搜索结果 */ void finishDiscovery(const PlcDiscoveryOutcome &outcome); /** * @brief 处理 Qt Modbus 主站连接状态变化 * @param state Qt Modbus 主站的新连接状态 */ void handleDeviceStateChanged(QModbusDevice::State state); std::unique_ptr master_; // 独立的探测主站对象 std::vector candidates_; // 待依次尝试的串口参数 std::size_t current_candidate_ = 0; // 当前候选参数下标 QPointer pending_reply_; // 当前未完成的 D0 探测回复 Phase phase_ = Phase::Idle; // 当前搜索阶段 bool discovering_ = false; // 是否正在执行搜索 bool cancel_requested_ = false; // 是否已收到取消请求 bool found_pending_ = false; // 当前候选是否探测到 PLC std::uint64_t attempt_generation_ = 0; // 尝试代次,用于丢弃旧异步回复 std::function progress_changed_callback_; // 搜索进度回调 std::function discovery_finished_callback_; // 搜索结束回调 };