mrDarker
2025-09-12 8d55ed4a167d9b09d65e4a26ece287c6e37a9c84
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#pragma once
 
#include "CCLinkIEControl.h"
 
#include <thread>
#include <atomic>
#include <functional>
#include <vector>
 
using OutValuesArray = std::array<double, 4>;
using Callback = std::function<void()>;
using AnalyzeCallback = std::function<OutValuesArray()>;
using LogCallback = std::function<void(const CString& strContent, int type)>;
 
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);
 
    /**
     * @brief ¶ÁÈ¡ PLC ÄÚ²¿µÄ²úÆ· ID£¨×Ö·û´®ÐÎʽ£©¡£
     *
     * @param strProductID  Êä³ö²ÎÊý£¬´æ´¢¶ÁÈ¡µ½µÄ²úÆ· ID¡£
     * @return true         ¶ÁÈ¡³É¹¦¡£
     * @return false        ¶Áȡʧ°Ü¡£
     */
    bool ReadProductID(std::string& strProductID);
 
private:
    /**
     * @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  ÐÄÌøÓб仯£¨PLC Õý³£ÔÚÏߣ©¡£
     * @return false ÐÄÌøÎޱ仯£¨¿ÉÄÜÀëÏߣ©¡£
     */
    bool CheckHeartbeat();
 
    /**
     * @brief ¼à¿Ø PLC ÐÄÌøÊÇ·ñÖжϣ¬²¢×Ô¶¯¼Ç¼״̬¡£
     *
     * @return true  PLC ÔÚÏß»òÔÚÔÊÐíµÄδÏìÓ¦´ÎÊýÄÚ¡£
     * @return false PLC ÐÄÌøÖжϣ¬³¬¹ýÔÊÐíãÐÖµ¡£
     */
    bool MonitorHeartbeat();
 
    /**
     * @brief Æô¶¯ÐÄÌø¼à¿ØỊ̈߳¨¶ÀÁ¢ÓÚÐźżàÌýỊ̈߳©¡£
     */
    void StartHeartbeatMonitor();
 
    /**
     * @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 ¹ÜÀí ACK ÏìÓ¦µÄÉúÃüÖÜÆÚ£¬³¬Ê±×Ô¶¯Çå³ý¡£
     *
     * @param i                ¿ØÖÆÎ»Ë÷Òý£¨0=Start£¬1=Stop£©¡£
     * @param bCurrTriggerBit  µ±Ç°´Ó PLC ¶ÁÈ¡µ½µÄ´¥·¢Î»×´Ì¬¡£
     */
    void HandleAckLife(int i, bool bCurrTriggerBit);
 
    /**
     * @brief Ö÷¼àÌýÏß³ÌÂß¼­£¬Ñ­»·¶ÁÈ¡ PLC ¿ØÖÆÐźŲ¢´¦Àí´¥·¢¡£
     */
    void ThreadProc();
 
private:
    // === PLC Í¨ÐźËÐĶÔÏó ===
    std::unique_ptr<CCCLinkIEControl> m_pPlc; // PLC Í¨ÐÅ¿ØÖÆÆ÷
    StationIdentifier m_station;              // PLC Õ¾ºÅ
    std::atomic<bool> m_bConnected{ false };  // ÊÇ·ñ³É¹¦Á¬½Ó
 
    // === ¿ØÖƲÎÊý ===
    int m_nIntervalMs = 200;                  // ÂÖѯÖÜÆÚ£¨ms£©
 
    // === ÃüÁî´¥·¢×´Ì¬»º´æ ===
    std::vector<bool> m_vecPrevBits;          // ÉÏÒ»ÖÜÆÚµÄÃüÁîλ״̬£¨ÓÃÓÚ¼ì²âÉÏÉýÑØ£©
 
    // === »Øµ÷º¯Êý£¨¿ØÖÆ/¼ÆËã/ÈÕÖ¾£©===
    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;                     // Ö÷¼àÌýÏ̶߳ÔÏó
 
    // === 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 µôÏߣ©
};