| | |
| | | #pragma once |
| | | #pragma once |
| | | |
| | | #include "CCLinkIEControl.h" |
| | | |
| | |
| | | class CPLCSignalListener |
| | | { |
| | | public: |
| | | CPLCSignalListener(); |
| | | ~CPLCSignalListener(); |
| | | |
| | | /** |
| | | * @brief 初始化 PLC 信号监听器。 |
| | | * |
| | | * @param station 目标 PLC 的站号标识符。 |
| | | * @param nIntervalMs 轮询周期(单位:毫秒),默认 200ms。 |
| | | * @return true 初始化成功。 |
| | | * @return false 初始化失败。 |
| | | */ |
| | | bool Initialize(StationIdentifier station, int nIntervalMs = 200); |
| | | |
| | | /** |
| | | * @brief 设置开始命令的回调函数(对应 PLC 的 Start 信号)。 |
| | | * |
| | | * @param cb 用户自定义的开始回调函数。 |
| | | */ |
| | | void SetStartCallback(Callback cb); |
| | | |
| | | /** |
| | | * @brief 设置停止命令的回调函数(对应 PLC 的 Stop 信号)。 |
| | | * |
| | | * @param cb 用户自定义的停止回调函数。 |
| | | */ |
| | | void SetStopCallback(Callback cb); |
| | | |
| | | /** |
| | | * @brief 设置分析计算回调函数,在接收到停止命令后调用。 |
| | | * |
| | | * @param cb 返回计算结果数组(OUT1~OUT4)的函数。 |
| | | */ |
| | | void SetAnalyzeCallback(AnalyzeCallback cb); |
| | | |
| | | /** |
| | | * @brief 设置日志输出回调函数。 |
| | | * |
| | | * @param cb 用户提供的日志输出接口(包含日志内容和日志类型)。 |
| | | */ |
| | | void SetLogCallback(LogCallback cb); |
| | | |
| | | /** |
| | | * @brief 启动信号监听线程。 |
| | | * |
| | | * @return true 启动成功。 |
| | | * @return false 启动失败(可能已运行或未初始化)。 |
| | | */ |
| | | bool Start(); |
| | | |
| | | /** |
| | | * @brief 停止信号监听线程。 |
| | | */ |
| | | void Stop(); |
| | | |
| | | /** |
| | | * @brief 向 PLC 写入分析结果值(通常为 OUT1 ~ OUT4)。 |
| | | * |
| | | * @param values 包含四个 double 类型的结果值,将转换为整数后写入 PLC。 |
| | | * @return true 写入成功。 |
| | | * @return false 写入失败。 |
| | | */ |
| | | bool WriteOutValues(const OutValuesArray& values); |
| | | CPLCSignalListener(); |
| | | ~CPLCSignalListener(); |
| | | |
| | | /** |
| | | * @brief 读取 PLC 内部的产品 ID(字符串形式)。 |
| | | * @brief 初始化 PLC 信号监听器。 |
| | | * |
| | | * @param strProductID 输出参数,存储读取到的产品 ID。 |
| | | * @return true 读取成功。 |
| | | * @return false 读取失败。 |
| | | * @param station 目标 PLC 的站号标识符。 |
| | | * @param nIntervalMs 轮询周期(单位:毫秒),默认 200ms。 |
| | | * @return true 初始化成功。 |
| | | * @return false 初始化失败。 |
| | | */ |
| | | bool ReadProductID(std::string& strProductID); |
| | | bool Initialize(StationIdentifier station, int nIntervalMs = 200); |
| | | |
| | | /** |
| | | * @brief 设置开始命令的回调函数(对应 PLC 的 Start 信号)。 |
| | | * |
| | | * @param cb 用户自定义的开始回调函数。 |
| | | */ |
| | | void SetStartCallback(Callback cb); |
| | | |
| | | /** |
| | | * @brief 设置停止命令的回调函数(对应 PLC 的 Stop 信号)。 |
| | | * |
| | | * @param cb 用户自定义的停止回调函数。 |
| | | */ |
| | | void SetStopCallback(Callback cb); |
| | | |
| | | /** |
| | | * @brief 设置分析计算回调函数,在接收到停止命令后调用。 |
| | | * |
| | | * @param cb 返回计算结果数组(OUT1~OUT4)的函数。 |
| | | */ |
| | | void SetAnalyzeCallback(AnalyzeCallback cb); |
| | | |
| | | /** |
| | | * @brief 设置日志输出回调函数。 |
| | | * |
| | | * @param cb 用户提供的日志输出接口(包含日志内容和日志类型)。 |
| | | */ |
| | | void SetLogCallback(LogCallback cb); |
| | | |
| | | /** |
| | | * @brief 启动信号监听线程。 |
| | | * |
| | | * @return true 启动成功。 |
| | | * @return false 启动失败(可能已运行或未初始化)。 |
| | | */ |
| | | bool Start(); |
| | | |
| | | /** |
| | | * @brief 停止信号监听线程。 |
| | | */ |
| | | void Stop(); |
| | | |
| | | /** |
| | | * @brief 向 PLC 写入分析结果值(通常为 OUT1 ~ OUT4)。 |
| | | * |
| | | * @param values 包含四个 double 类型的结果值,将转换为整数后写入 PLC。 |
| | | * @return true 写入成功。 |
| | | * @return false 写入失败。 |
| | | */ |
| | | bool WriteOutValues(const OutValuesArray& values); |
| | | |
| | | /** |
| | | * @brief 读取 PLC 内部的产品 ID(字符串形式)。 |
| | | * |
| | | * @param strProductID 输出参数,存储读取到的产品 ID。 |
| | | * @return true 读取成功。 |
| | | * @return false 读取失败。 |
| | | */ |
| | | bool ReadProductID(std::string& strProductID); |
| | | |
| | | /** |
| | | * @brief 将产品 ID(字符串形式)写入 PLC 内部。 |
| | | * |
| | | * @param strProductID 输入参数,要写入的产品 ID。 |
| | | * 字符串会按字节对齐,每两个字节组成一个 Word, |
| | | * 写入 PLC 的指定寄存器区域,不足时自动补零。 |
| | | * @return true 写入成功。 |
| | | * @return false 写入失败。 |
| | | */ |
| | | bool WriteProductID(const std::string& strProductID); |
| | | |
| | | private: |
| | | /** |
| | | * @brief 输出日志信息(封装日志回调)。 |
| | | * |
| | | * @param strText 日志内容文本。 |
| | | * @param nType 日志类型(LOG_TYPE_NORMAL / ERROR / WARNING 等)。 |
| | | */ |
| | | void LogInfo(const CString& strText, int nType); |
| | | /** |
| | | * @brief 输出日志信息(封装日志回调)。 |
| | | * |
| | | * @param strText 日志内容文本。 |
| | | * @param nType 日志类型(LOG_TYPE_NORMAL / ERROR / WARNING 等)。 |
| | | */ |
| | | void LogInfo(const CString& strText, int nType); |
| | | |
| | | /** |
| | | * @brief 向 PLC 写入心跳信号(交替位)。 |
| | | * |
| | | * @return true 写入成功。 |
| | | * @return false 写入失败(如未连接)。 |
| | | */ |
| | | bool SendHeartbeat(); |
| | | /** |
| | | * @brief 向 PLC 写入心跳信号(交替位)。 |
| | | * |
| | | * @return true 写入成功。 |
| | | * @return false 写入失败(如未连接)。 |
| | | */ |
| | | bool SendHeartbeat(); |
| | | |
| | | /** |
| | | * @brief 检查从 PLC 读取到的心跳信号是否发生变化。 |
| | | * |
| | | * @return true 心跳有变化(PLC 正常在线)。 |
| | | * @return false 心跳无变化(可能离线)。 |
| | | */ |
| | | bool CheckHeartbeat(); |
| | | /** |
| | | * @brief 检查从 PLC 读取到的心跳信号是否发生变化。 |
| | | * |
| | | * @return true 心跳有变化(PLC 正常在线)。 |
| | | * @return false 心跳无变化(可能离线)。 |
| | | */ |
| | | bool CheckHeartbeat(); |
| | | |
| | | /** |
| | | * @brief 监控 PLC 心跳是否中断,并自动记录状态。 |
| | | * |
| | | * @return true PLC 在线或在允许的未响应次数内。 |
| | | * @return false PLC 心跳中断,超过允许阈值。 |
| | | */ |
| | | bool MonitorHeartbeat(); |
| | | /** |
| | | * @brief 监控 PLC 心跳是否中断,并自动记录状态。 |
| | | * |
| | | * @return true PLC 在线或在允许的未响应次数内。 |
| | | * @return false PLC 心跳中断,超过允许阈值。 |
| | | */ |
| | | bool MonitorHeartbeat(); |
| | | |
| | | /** |
| | | * @brief 启动心跳监控线程(独立于信号监听线程)。 |
| | | */ |
| | | void StartHeartbeatMonitor(); |
| | | /** |
| | | * @brief 启动心跳监控线程(独立于信号监听线程)。 |
| | | */ |
| | | void StartHeartbeatMonitor(); |
| | | |
| | | /** |
| | | * @brief 停止心跳监控线程。 |
| | | */ |
| | | void StopHeartbeatMonitor(); |
| | | /** |
| | | * @brief 停止心跳监控线程。 |
| | | */ |
| | | void StopHeartbeatMonitor(); |
| | | |
| | | /** |
| | | * @brief 向指定软元件位写入一个脉冲(先写1,延时后自动写0)。 |
| | | * |
| | | * @param eDevType 位软元件类型(如 M/B)。 |
| | | * @param nBitNo 位地址编号。 |
| | | * @param nDelayMs 脉冲持续时间,默认50毫秒。 |
| | | */ |
| | | void PulseBitDevice(DeviceType eDevType, long nBitNo, int nDelayMs = 50); |
| | | /** |
| | | * @brief 向指定软元件位写入一个脉冲(先写1,延时后自动写0)。 |
| | | * |
| | | * @param eDevType 位软元件类型(如 M/B)。 |
| | | * @param nBitNo 位地址编号。 |
| | | * @param nDelayMs 脉冲持续时间,默认50毫秒。 |
| | | */ |
| | | void PulseBitDevice(DeviceType eDevType, long nBitNo, int nDelayMs = 50); |
| | | |
| | | /** |
| | | * @brief 管理 ACK 响应的生命周期,超时自动清除。 |
| | | * |
| | | * @param i 控制位索引(0=Start,1=Stop)。 |
| | | * @param bCurrTriggerBit 当前从 PLC 读取到的触发位状态。 |
| | | */ |
| | | void HandleAckLife(int i, bool bCurrTriggerBit); |
| | | /** |
| | | * @brief 管理 ACK 响应的生命周期,超时自动清除。 |
| | | * |
| | | * @param i 控制位索引(0=Start,1=Stop)。 |
| | | * @param bCurrTriggerBit 当前从 PLC 读取到的触发位状态。 |
| | | */ |
| | | void HandleAckLife(int i, bool bCurrTriggerBit); |
| | | |
| | | /** |
| | | * @brief 主监听线程逻辑,循环读取 PLC 控制信号并处理触发。 |
| | | */ |
| | | void ThreadProc(); |
| | | /** |
| | | * @brief 主监听线程逻辑,循环读取 PLC 控制信号并处理触发。 |
| | | */ |
| | | void ThreadProc(); |
| | | |
| | | private: |
| | | // === PLC 通信核心对象 === |
| | | std::unique_ptr<CCCLinkIEControl> m_pPlc; // PLC 通信控制器 |
| | | StationIdentifier m_station; // PLC 站号 |
| | | std::atomic<bool> m_bConnected{ false }; // 是否成功连接 |
| | | // === PLC 通信核心对象 === |
| | | std::unique_ptr<CCCLinkIEControl> m_pPlc; // PLC 通信控制器 |
| | | StationIdentifier m_station; // PLC 站号 |
| | | std::atomic<bool> m_bConnected{ false }; // 是否成功连接 |
| | | |
| | | // === 控制参数 === |
| | | int m_nIntervalMs = 200; // 轮询周期(ms) |
| | | // === 控制参数 === |
| | | int m_nIntervalMs = 200; // 轮询周期(ms) |
| | | |
| | | // === 命令触发状态缓存 === |
| | | std::vector<bool> m_vecPrevBits; // 上一周期的命令位状态(用于检测上升沿) |
| | | // === 命令触发状态缓存 === |
| | | std::vector<bool> m_vecPrevBits; // 上一周期的命令位状态(用于检测上升沿) |
| | | |
| | | // === 回调函数(控制/计算/日志)=== |
| | | Callback m_cbStart; // Start 命令回调 |
| | | Callback m_cbStop; // Stop 命令回调 |
| | | AnalyzeCallback m_cbAnalyze; // Analyze 计算回调(返回 OUT1~OUT4) |
| | | LogCallback m_cbLog; // 日志输出回调 |
| | | // === 回调函数(控制/计算/日志)=== |
| | | Callback m_cbStart; // Start 命令回调 |
| | | Callback m_cbStop; // Stop 命令回调 |
| | | AnalyzeCallback m_cbAnalyze; // Analyze 计算回调(返回 OUT1~OUT4) |
| | | LogCallback m_cbLog; // 日志输出回调 |
| | | |
| | | // === 主线程控制 === |
| | | std::atomic<bool> m_bRunning{ false }; // 主监听线程是否运行 |
| | | std::thread m_thread; // 主监听线程对象 |
| | | // === 主线程控制 === |
| | | std::atomic<bool> m_bRunning{ false }; // 主监听线程是否运行 |
| | | std::thread m_thread; // 主监听线程对象 |
| | | |
| | | // === ACK 信号状态 === |
| | | std::array<bool, 2> m_vecAckSent = { false, false }; // 是否已发送应答信号(B10/B11) |
| | | std::array<int, 2> m_vecAckCounter = { 0, 0 }; // 对应应答信号的生命周期计数器 |
| | | // === ACK 信号状态 === |
| | | std::array<bool, 2> m_vecAckSent = { false, false }; // 是否已发送应答信号(B10/B11) |
| | | std::array<int, 2> m_vecAckCounter = { 0, 0 }; // 对应应答信号的生命周期计数器 |
| | | |
| | | // === 心跳检测相关 === |
| | | std::thread m_heartbeatThread; // 心跳检测线程对象 |
| | | std::atomic<bool> m_bHeartbeatRunning = false; // 心跳线程运行标志 |
| | | std::atomic<bool> m_bHeartbeatLost = false; // 心跳丢失标志 |
| | | int m_nMissedHeartbeatCount = 0; // 心跳未变化次数(用于检测 PLC 掉线) |
| | | // === 心跳检测相关 === |
| | | std::thread m_heartbeatThread; // 心跳检测线程对象 |
| | | std::atomic<bool> m_bHeartbeatRunning = false; // 心跳线程运行标志 |
| | | std::atomic<bool> m_bHeartbeatLost = false; // 心跳丢失标志 |
| | | int m_nMissedHeartbeatCount = 0; // 心跳未变化次数(用于检测 PLC 掉线) |
| | | }; |
| | | |