a
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
# 状态与流程控制
|
||||
|
||||
<cite>
|
||||
**本文档引用文件**
|
||||
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp)
|
||||
- [HandleProcessor.h](file://h/HandleProcessor.h)
|
||||
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp)
|
||||
- [StateProcessor.h](file://h/StateProcessor.h)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h)
|
||||
- [Constant.h](file://h/Constant.h)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
|
||||
- [DevManager.h](file://h/DevManager.h)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [核心组件协同工作机制](#核心组件协同工作机制)
|
||||
3. [状态机设计模式](#状态机设计模式)
|
||||
4. [消息分发机制](#消息分发机制)
|
||||
5. [数据传输控制机制](#数据传输控制机制)
|
||||
6. [测量任务全链路流程](#测量任务全链路流程)
|
||||
7. [状态同步与异常恢复](#状态同步与异常恢复)
|
||||
8. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
本文档系统化阐述GeomativeStudio项目中HandleProcessor、StateProcessor和TransferCtrl三个核心组件在设备交互中的协同工作机制。这些组件共同构成了系统状态管理、流程控制和数据传输的核心架构,确保了设备连接、就绪、测量、离线等状态的可靠转换,以及底层通信事件向UI层和业务逻辑层的高效分发。
|
||||
|
||||
## 核心组件协同工作机制
|
||||
|
||||
HandleProcessor、StateProcessor和TransferCtrl三个组件在系统中扮演着不同的角色,通过紧密协作实现设备交互的完整控制流程。HandleProcessor负责句柄的生成与解析,将设备ID和类型信息编码到32位DWORD中,实现了高效的对象标识管理。StateProcessor则专注于状态表示的转换,将内部状态值与UI显示状态进行映射。TransferCtrl作为通信控制核心,继承自CTcpClient,负责与设备建立TCP连接,发送控制指令并接收响应数据。
|
||||
|
||||
这三个组件的协同工作始于设备连接:当设备上线时,TransferCtrl接收设备上线通知,通过DevManager获取设备信息,使用HandleProcessor生成设备句柄,然后通过StateProcessor将设备状态转换为UI可识别的形式进行显示。在测量过程中,TransferCtrl发送测量指令,HandleProcessor处理任务相关的句柄信息,StateProcessor管理测量状态的转换。这种分工明确的架构设计确保了系统各层之间的松耦合和高内聚。
|
||||
|
||||
**Section sources**
|
||||
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L26)
|
||||
- [StateProcessor.h](file://h/StateProcessor.h#L12-L19)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L76)
|
||||
|
||||
## 状态机设计模式
|
||||
|
||||
系统采用基于枚举和条件判断的状态机设计模式,管理设备从连接、就绪、测量到离线的完整生命周期。状态转换主要通过TransferCtrl组件中的RecvCommRspMsg方法实现,该方法持续监听通信通道,根据接收到的不同命令字触发相应的状态转换。
|
||||
|
||||
设备状态主要包括:离线(PZ_STATE_OFFLINE)、在线(PZ_STATE_ONLINE)、就绪、测量中等。当设备首次连接时,系统接收到EN_RECV_DEVICE_ONLINE(0x71)命令,设备状态从离线转换为在线。随后通过EN_CTRL_SYN_DEV_PARAM(0x02)命令同步设备参数,完成初始化后进入就绪状态。当用户启动测量任务时,系统发送EN_CTRL_MEASURE_DATA(0x06)命令,设备状态转换为测量中。在测量过程中,系统持续接收实时测量数据,直到任务完成或用户手动停止。
|
||||
|
||||
状态转换的条件主要基于通信协议中的命令字和响应码。例如,当接收到EN_RECV_DEVICE_OFFLINE命令时,无论当前处于何种状态,都会转换为离线状态。这种基于事件驱动的状态机设计确保了状态转换的确定性和可靠性,避免了非法状态的出现。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 离线
|
||||
离线 --> 在线 : 接收到EN_RECV_DEVICE_ONLINE
|
||||
在线 --> 就绪 : 完成设备参数同步
|
||||
就绪 --> 测量中 : 发送EN_CTRL_MEASURE_DATA命令
|
||||
测量中 --> 就绪 : 测量完成或用户停止
|
||||
测量中 --> 离线 : 接收到EN_RECV_DEVICE_OFFLINE
|
||||
就绪 --> 离线 : 接收到EN_RECV_DEVICE_OFFLINE
|
||||
在线 --> 离线 : 接收到EN_RECV_DEVICE_OFFLINE
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [Constant.h](file://h/Constant.h#L132-L134)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L532-L534)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L490)
|
||||
|
||||
## 消息分发机制
|
||||
|
||||
系统采用Windows消息机制和回调函数相结合的方式实现底层通信事件向UI层和业务逻辑层的分发。TransferCtrl组件作为消息的接收端,通过RecvCommRspMsg方法从通信通道接收原始数据包,解析协议头后根据命令字类型决定消息的分发路径。
|
||||
|
||||
对于控制类消息(EN_RECV_CTRL_CMD),系统通过Windows消息机制将其分发到注册的UI窗口。例如,设备上线/下线通知通过WM_MSG_NOTIFY_DEVICE_ON_OR_OFF消息发送到主窗口,触发设备列表的更新。对于实时测量数据(EN_REAL_TIME_TESTING_DATA),系统直接调用注册的回调函数,将数据传递给数据处理模块进行实时显示。
|
||||
|
||||
消息分发的关键在于NetWorkOper组件中的RegeditRealMsgCall和UnRegeditRealMsgCall方法,它们管理着实时消息接收者的注册表。当UI组件需要接收实时数据时,先注册自己的窗口句柄,当不再需要接收时则注销。这种发布-订阅模式确保了消息只发送给当前活跃的接收者,避免了资源浪费和潜在的内存泄漏。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[通信通道] --> B{RecvCommRspMsg}
|
||||
B --> C[解析协议头]
|
||||
C --> D{命令字类型}
|
||||
D --> |EN_RECV_DEVICE_ONLINE| E[发送WM_MSG_NOTIFY_DEVICE_ON_OR_OFF]
|
||||
D --> |EN_CTRL_MEASURE_DATA| F[调用实时数据回调函数]
|
||||
D --> |EN_RECV_PLC_STATUS| G[更新PLC状态显示]
|
||||
D --> |EN_REAL_TIME_TESTING_DATA| H[传递给数据处理模块]
|
||||
E --> I[UI层更新设备列表]
|
||||
F --> J[实时数据显示]
|
||||
G --> K[状态面板更新]
|
||||
H --> L[数据存储与分析]
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L490)
|
||||
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp#L343-L364)
|
||||
- [Constant.h](file://h/Constant.h#L195)
|
||||
|
||||
## 数据传输控制机制
|
||||
|
||||
TransferCtrl组件实现了完整的数据传输控制机制,包括流量控制、进度监控和错误恢复。流量控制通过序列号(m_iSeriNo)和确认机制实现,每个发送的数据包都有唯一的序列号,接收方必须返回相应的确认响应,确保数据的有序传输。
|
||||
|
||||
进度监控主要通过测量任务的状态跟踪实现。系统维护着当前测量点的序号,通过比较已接收数据点和总测量点数来计算进度百分比。在实时测量过程中,系统每接收一个数据包就更新进度显示,让用户了解任务的执行情况。
|
||||
|
||||
错误恢复机制是系统可靠性的关键。当通信超时或数据校验失败时,系统会根据错误类型采取不同的恢复策略。对于临时性错误如通信超时,系统会自动重试发送;对于数据校验失败,则会请求重传;对于严重的连接中断,则会尝试重新连接设备。这种分层的错误处理策略确保了系统在各种异常情况下的稳定运行。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as UI层
|
||||
participant Business as 业务逻辑层
|
||||
participant TransferCtrl as TransferCtrl
|
||||
participant Device as 设备
|
||||
UI->>Business : 启动测量任务
|
||||
Business->>TransferCtrl : 发送EN_CTRL_MEASURE_DATA
|
||||
TransferCtrl->>Device : 发送测量指令
|
||||
Device-->>TransferCtrl : 返回确认响应
|
||||
TransferCtrl-->>Business : 通知测量开始
|
||||
loop 数据接收
|
||||
Device->>TransferCtrl : 发送测量数据
|
||||
TransferCtrl->>TransferCtrl : CRC校验
|
||||
alt 校验成功
|
||||
TransferCtrl-->>Business : 分发测量数据
|
||||
Business-->>UI : 更新进度显示
|
||||
else 校验失败
|
||||
TransferCtrl->>Device : 请求重传
|
||||
end
|
||||
end
|
||||
Device->>TransferCtrl : 发送任务完成通知
|
||||
TransferCtrl-->>Business : 通知测量完成
|
||||
Business-->>UI : 显示完成状态
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L133-L180)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L490)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L515)
|
||||
|
||||
## 测量任务全链路流程
|
||||
|
||||
从任务启动到数据接收完成的全链路流程展示了系统各组件的协同工作。流程始于用户在UI层选择测量任务并点击开始按钮,触发业务逻辑层的测量控制模块。
|
||||
|
||||
首先,系统检查设备连接状态,通过TransferCtrl的GetConnectStatus方法确认通信链路正常。然后,使用HandleProcessor生成任务相关的句柄信息,准备测量参数。接着,通过TransferCtrl发送EN_CTRL_SET_TASK_PARAM命令设置任务参数,等待设备确认。
|
||||
|
||||
设备确认后,系统发送EN_CTRL_MEASURE_DATA命令启动测量。在测量过程中,TransferCtrl持续接收实时数据包,通过RecvCommRspMsg方法解析数据,并使用StateProcessor将测量状态转换为UI可显示的形式。每接收一个有效数据包,系统就更新进度条并存储数据到数据库。
|
||||
|
||||
当设备发送任务完成通知或用户手动停止时,测量流程进入结束阶段。系统发送停止命令,等待设备确认,然后清理资源,更新任务状态为完成。在整个流程中,异常处理机制始终监控着各个环节,确保任何异常都能被及时捕获和处理。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[用户启动测量任务] --> B[检查设备连接状态]
|
||||
B --> C{连接正常?}
|
||||
C --> |是| D[生成任务句柄]
|
||||
C --> |否| Z[显示连接错误]
|
||||
D --> E[设置测量参数]
|
||||
E --> F[发送EN_CTRL_SET_TASK_PARAM]
|
||||
F --> G{设备确认?}
|
||||
G --> |是| H[发送EN_CTRL_MEASURE_DATA]
|
||||
G --> |否| Y[重试或报错]
|
||||
H --> I[开始接收测量数据]
|
||||
I --> J{数据有效?}
|
||||
J --> |是| K[更新进度, 存储数据]
|
||||
J --> |否| L[请求重传]
|
||||
K --> M{任务完成?}
|
||||
L --> M
|
||||
M --> |是| N[发送停止命令]
|
||||
M --> |否| I
|
||||
N --> O[等待设备确认]
|
||||
O --> P[清理资源]
|
||||
P --> Q[更新任务状态]
|
||||
Q --> R[显示完成结果]
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L48-L76)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L133-L180)
|
||||
- [DevManager.h](file://h/DevManager.h#L21-L22)
|
||||
|
||||
## 状态同步与异常恢复
|
||||
|
||||
状态同步和异常恢复是确保系统稳定运行的关键。状态同步主要通过定期的心跳包(EN_REQ_HEART_BEAT_PACKET)和状态查询实现。系统每隔一段时间发送心跳包,确认设备在线状态,同时通过EN_REQ_DOWNLOAD_DEV_INFO命令获取设备最新状态,确保本地状态与设备实际状态一致。
|
||||
|
||||
异常恢复策略分为多个层次:通信层异常通过TCP重连机制处理;数据层异常通过CRC校验和重传机制处理;应用层异常通过状态回滚和任务重启处理。例如,当检测到通信中断时,系统会自动尝试重新连接设备,连接成功后重新同步状态,必要时重启测量任务。
|
||||
|
||||
最佳实践指南建议:在关键操作前始终验证设备状态;对重要数据进行双重校验;设置合理的超时时间避免无限等待;记录详细的日志便于问题排查;提供用户友好的错误提示和恢复选项。这些实践确保了系统在各种异常情况下的可用性和可靠性。
|
||||
|
||||
**Section sources**
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L48-L76)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L492-L522)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L546)
|
||||
|
||||
## 结论
|
||||
HandleProcessor、StateProcessor和TransferCtrl三个组件通过精巧的设计和紧密的协作,构建了GeomativeStudio系统稳定可靠的设备交互基础。HandleProcessor的句柄管理机制实现了高效的对象标识,StateProcessor的状态转换功能确保了UI显示的准确性,而TransferCtrl的通信控制能力则保障了数据传输的可靠性。这三者共同构成了一个完整、健壮的状态与流程控制系统,为地质测量任务的顺利执行提供了坚实的技术支撑。
|
||||
@@ -0,0 +1,269 @@
|
||||
# 网络设备操作
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp)
|
||||
- [NetWorkOper.h](file://h\NetWorkOper.h)
|
||||
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp)
|
||||
- [TcpClient.h](file://h\TcpClient.h)
|
||||
- [TransferCtrl.cpp](file://cpp\Tools\TransferCtrl.cpp)
|
||||
- [TransferCtrl.h](file://h\TransferCtrl.h)
|
||||
- [CtrlProtocolDef.h](file://h\CtrlProtocolDef.h)
|
||||
- [Constant.h](file://h\Constant.h)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概述](#架构概述)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排除指南](#故障排除指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
本文档全面记录了`NetWorkOper.cpp`实现的网络设备交互功能,重点描述了设备发现机制(基于IP广播或组播)、网络连接建立、远程状态查询与控制指令发送流程。详细说明了TCP通信协议的封装方式、连接保持机制及断线重连策略。结合`TcpClient`组件,阐述了异步通信模型、数据包分帧处理和网络异常捕获方法。提供了网络配置参数说明(如端口、超时时间)和性能调优建议,并列举了与GD10设备进行网络通信的典型代码片段,包括设备上线检测和远程固件升级场景。
|
||||
|
||||
## 项目结构
|
||||
项目结构清晰地组织了所有源代码和资源文件,主要分为以下几个部分:
|
||||
- `CACHE`:缓存文件
|
||||
- `DB`:数据库相关文件
|
||||
- `Install`:安装文件和日志
|
||||
- `LOG`:运行日志
|
||||
- `Release`:发布版本文件
|
||||
- `cpp`:C++源代码
|
||||
- `h`:头文件
|
||||
- `res`:资源文件
|
||||
- 根目录下的配置文件和解决方案文件
|
||||
|
||||
**Section sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [NetWorkOper.h](file://h\NetWorkOper.h#L1-L176)
|
||||
|
||||
## 核心组件
|
||||
`NetWorkOper`类是网络设备交互的核心组件,负责管理网络连接、数据传输和设备状态。它通过`TcpClient`组件实现TCP通信,并通过`TransferCtrl`类封装控制信息。`NetWorkOper`类还实现了设备发现、状态查询和控制指令发送等功能。
|
||||
|
||||
**Section sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [NetWorkOper.h](file://h\NetWorkOper.h#L1-L176)
|
||||
|
||||
## 架构概述
|
||||
系统架构采用客户端-服务器模式,通过TCP协议实现网络通信。`NetWorkOper`类作为客户端,负责与服务器建立连接、发送控制指令和接收响应。`TcpClient`类提供了底层的TCP通信功能,包括连接管理、数据发送和接收。`TransferCtrl`类封装了控制信息,确保数据的正确传输。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "客户端"
|
||||
NetWorkOper[NetWorkOper]
|
||||
TransferCtrl[TransferCtrl]
|
||||
TcpClient[TcpClient]
|
||||
end
|
||||
subgraph "服务器"
|
||||
Server[服务器]
|
||||
end
|
||||
NetWorkOper --> TransferCtrl
|
||||
TransferCtrl --> TcpClient
|
||||
TcpClient --> Server
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [TransferCtrl.cpp](file://cpp\Tools\TransferCtrl.cpp#L1-L615)
|
||||
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### NetWorkOper 分析
|
||||
`NetWorkOper`类是网络设备交互的核心,负责管理网络连接和数据传输。它通过`TcpClient`组件实现TCP通信,并通过`TransferCtrl`类封装控制信息。
|
||||
|
||||
#### 类图
|
||||
```mermaid
|
||||
classDiagram
|
||||
class CNetWorkOper {
|
||||
+CTcpClient* m_tcpClient
|
||||
+bool m_bIsRunning
|
||||
+CWinThread* m_pThread
|
||||
+CRITICAL_SECTION m_MutexSec
|
||||
+bool m_bIsTransfer
|
||||
+STSendDataInfo m_stSendCtrlInfo
|
||||
+STRespDataInfo m_stRespDataInfo
|
||||
+bool m_bIsNeedResp
|
||||
+bool m_bIsNeedSend
|
||||
+BYTE m_ucCmd
|
||||
+PNOTIFY_FUNC m_pNotifyFunc
|
||||
+PNOTIFY_DEV_FUNC m_pDevNotifyFunc
|
||||
+LPVOID m_pNotifyParam
|
||||
+char m_chSendBuf[MAX_SND_BUF]
|
||||
+char m_chRcvCtrlBuf[MAX_RCV_CTRLBUF]
|
||||
+LPVOID m_pDevNotfiyParam
|
||||
+bool m_bIsSuspend
|
||||
+bool m_bIsGetDevAddr
|
||||
+CRITICAL_SECTION m_netCs
|
||||
+CRITICAL_SECTION m_realHwndCs
|
||||
+list<HWND> m_listRealHwnd
|
||||
+CNetWorkOper()
|
||||
+~CNetWorkOper()
|
||||
+bool Initialize()
|
||||
+bool StartConnect(CString strDstIP, int iPort)
|
||||
+bool StartWork()
|
||||
+bool TransferOper(BYTE ucCmd, STSendDataInfo* pSendCtrl, bool bIsNeedResp, STRespDataInfo* pRespInfo, PNOTIFY_FUNC pNotifyFunc = NULL, LPVOID lpParam = NULL)
|
||||
+bool GetLinkStatus()
|
||||
+bool SendCtrlMsgDirect(BYTE ucCmd, UINT32 uiDevID, BYTE ucDevType, const char* pData, WORD wDataLen)
|
||||
+int RecvMsgDirect(char* pData, int* pRecvLen, int iMaxRecvLen, int iTimeout)
|
||||
+void RegisterDevNotify(PNOTIFY_DEV_FUNC pNotfiy, LPVOID pWnd)
|
||||
+void SetSuspendForThread(bool bIsSuspend)
|
||||
+bool SendLoginMsgBrocast()
|
||||
+bool ProcPlcStatus(char* pData, int iLen)
|
||||
+void ClearNotfiyFuncInfo()
|
||||
+void PutRequestPacket(const STRequestPacket& clsRequestPacket)
|
||||
+void RegeditRealMsgCall(HWND hWnd)
|
||||
+void UnRegeditRealMsgCall(HWND hWnd)
|
||||
+CRITICAL_SECTION* GetNetCriticalSection()
|
||||
+void ClearSendInfo()
|
||||
+void ReleaseData(void* pData)
|
||||
+void ConsumeDataFromQue(void * pData)
|
||||
+virtual void ThreadFunction()
|
||||
}
|
||||
class CTcpClient {
|
||||
+CString m_strIP
|
||||
+WORD m_wPort
|
||||
+int m_iSndBuf
|
||||
+int m_iRcvBuf
|
||||
+SOCKET m_sockClient
|
||||
+bool m_bIsConnect
|
||||
+bool m_bIsInitialed
|
||||
+char* m_pClearRcvBuf
|
||||
+CTcpClient()
|
||||
+~CTcpClient()
|
||||
+void SetSocketBuf(int iSndBuf, int iRcvBuf)
|
||||
+bool CloseConnect()
|
||||
+bool GetConnectStatus()
|
||||
+bool Disconnect()
|
||||
+bool ClearRecvBuffer()
|
||||
+virtual bool Initialize()
|
||||
+virtual bool ConnectToServer(CString strIP, WORD wPort)
|
||||
+virtual bool ReConnect()
|
||||
+virtual int RecvRspMsg(char* pData, int* pLen, int iMaxLen, int iTimeout)
|
||||
+virtual bool SendCtrlInfo(const char*pCtrlHeader, const char* pData, WORD wDataLen, BYTE DataType = 1)
|
||||
+virtual int RecvCtrlMsg(char* pData, int* pLen, int iMaxLen, int iTimeout)
|
||||
+virtual int GetCurrCtrlCmd()
|
||||
+virtual bool InitialClient()
|
||||
+virtual UINT32 GetPlcAddr()
|
||||
+bool InitailTcp()
|
||||
+bool ConnectServer(CString strAddr, WORD wPort)
|
||||
+int SendData(const char*pData, int iLen)
|
||||
+bool RecvData(char*pData, int iLen, int &iActualLen)
|
||||
}
|
||||
class CTransferCtrl {
|
||||
+BYTE m_ucCmd
|
||||
+bool m_bIsNeedSendCtrMsg
|
||||
+int m_iLastErrNo
|
||||
+int m_iSeriNo
|
||||
+int m_iLastSeriNo
|
||||
+int m_ucDevType
|
||||
+BYTE m_ucCtrlCmd
|
||||
+UINT32 m_uiPlcAddr
|
||||
+CTransferCtrl()
|
||||
+~CTransferCtrl()
|
||||
+bool Initialize()
|
||||
+int RecvRspMsg(char* pData, int* pLen, int iMaxLen, int iTimeout)
|
||||
+int RecvCtrlMsg(char* pData, int* pLen, int iMaxLen, int iTimeout)
|
||||
+bool IsCtrlMsg(BYTE ucCMd)
|
||||
+int GetCurrCtrlCmd()
|
||||
+bool InitialClient()
|
||||
+inline bool IsPlcStatusMsg(BYTE ucCmd, BYTE ucSrcType)
|
||||
+UINT32 GetPlcAddr()
|
||||
+void ClearCtrlInfo()
|
||||
+bool IsNeedSendCtrl()
|
||||
+bool SendCtrlInfoToDev(const STTransCtrlInfo * pTransInfo, const char* pData, WORD wDataLen, BYTE ucDataType = 1)
|
||||
+bool SendCtrlInfo(const char*pCtrlHeader, const char* pData, WORD wDataLen, BYTE DataType = 1)
|
||||
+bool RecvEnoughMsg(char* pData, int iLen, int iTimeOut)
|
||||
+int RecvCommRspMsg(char* pRcvData, int* pRcvLen, int iMaxRcvLen, int iRcvTimeout, bool bIsRcvCtrl = false)
|
||||
}
|
||||
CNetWorkOper --> CTcpClient : "uses"
|
||||
CNetWorkOper --> CTransferCtrl : "uses"
|
||||
CTransferCtrl --> CTcpClient : "extends"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [NetWorkOper.h](file://h\NetWorkOper.h#L1-L176)
|
||||
- [TransferCtrl.cpp](file://cpp\Tools\TransferCtrl.cpp#L1-L615)
|
||||
- [TransferCtrl.h](file://h\TransferCtrl.h#L1-L79)
|
||||
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
|
||||
- [TcpClient.h](file://h\TcpClient.h#L1-L76)
|
||||
|
||||
### 设备发现与连接建立
|
||||
`NetWorkOper`类通过广播登录消息实现设备发现。`SendLoginMsgBrocast`方法发送广播消息,服务器接收到后会响应设备上线通知。`StartConnect`方法用于建立与服务器的TCP连接。
|
||||
|
||||
#### 序列图
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Server as "服务器"
|
||||
Client->>Client : SendLoginMsgBrocast()
|
||||
Client->>Server : 发送广播登录消息
|
||||
Server->>Client : 响应设备上线通知
|
||||
Client->>Client : 处理设备上线通知
|
||||
Client->>Server : StartConnect(IP, Port)
|
||||
Server->>Client : 连接成功
|
||||
Client->>Client : 初始化网络操作
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L241-L248)
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L74-L97)
|
||||
|
||||
### 数据传输与控制指令
|
||||
`NetWorkOper`类通过`TransferOper`方法发送控制指令,并通过`RecvMsgDirect`方法接收响应。`TransferCtrl`类封装了控制信息,确保数据的正确传输。
|
||||
|
||||
#### 序列图
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Server as "服务器"
|
||||
Client->>Client : TransferOper(ucCmd, pSendCtrl, bIsNeedResp, pRespInfo)
|
||||
Client->>Client : 封装控制信息
|
||||
Client->>Server : 发送控制指令
|
||||
Server->>Client : 响应控制指令
|
||||
Client->>Client : 解析响应数据
|
||||
Client->>Client : 调用回调函数
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L128-L155)
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L206-L217)
|
||||
|
||||
## 依赖分析
|
||||
`NetWorkOper`类依赖于`TcpClient`和`TransferCtrl`类,`TransferCtrl`类继承自`TcpClient`类。`TcpClient`类提供了底层的TCP通信功能,`TransferCtrl`类封装了控制信息,`NetWorkOper`类负责管理网络连接和数据传输。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
NetWorkOper[NetWorkOper] --> TransferCtrl[TransferCtrl]
|
||||
TransferCtrl --> TcpClient[TcpClient]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [TransferCtrl.cpp](file://cpp\Tools\TransferCtrl.cpp#L1-L615)
|
||||
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
|
||||
|
||||
## 性能考虑
|
||||
为了提高性能,`NetWorkOper`类采用了异步通信模型,通过多线程处理数据传输。`TcpClient`类设置了较大的接收和发送缓冲区,以减少网络延迟。`TransferCtrl`类通过序列号和CRC校验确保数据的完整性和正确性。
|
||||
|
||||
**Section sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
|
||||
- [TransferCtrl.cpp](file://cpp\Tools\TransferCtrl.cpp#L1-L615)
|
||||
|
||||
## 故障排除指南
|
||||
常见的网络问题包括连接失败、数据传输错误和设备离线。可以通过检查日志文件、验证网络配置和重启设备来解决这些问题。`NetWorkOper`类提供了详细的日志记录功能,有助于诊断和解决问题。
|
||||
|
||||
**Section sources**
|
||||
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
|
||||
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
|
||||
- [FileOperTools.cpp](file://cpp\Tools\FileOperTools.cpp#L1-L420)
|
||||
|
||||
## 结论
|
||||
`NetWorkOper`类实现了完整的网络设备交互功能,通过`TcpClient`和`TransferCtrl`类提供了可靠的TCP通信和数据传输。系统架构清晰,组件职责明确,性能优化得当,能够满足复杂的网络通信需求。
|
||||
@@ -0,0 +1,286 @@
|
||||
# 设备交互工具
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [GD10OperCmd.h](file://h/GD10OperCmd.h)
|
||||
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp)
|
||||
- [NetWorkOper.h](file://h/NetWorkOper.h)
|
||||
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp)
|
||||
- [OperPLC.h](file://h/OperPLC.h)
|
||||
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp)
|
||||
- [HandleProcessor.h](file://h/HandleProcessor.h)
|
||||
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp)
|
||||
- [StateProcessor.h](file://h/StateProcessor.h)
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
|
||||
- [Constant.h](file://h/Constant.h)
|
||||
- [TcpClient.h](file://h/TcpClient.h)
|
||||
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [GD10设备通信指令集](#gd10设备通信指令集)
|
||||
3. [网络设备发现与远程控制](#网络设备发现与远程控制)
|
||||
4. [PLC设备读写操作](#plc设备读写操作)
|
||||
5. [设备状态机与消息处理](#设备状态机与消息处理)
|
||||
6. [数据传输控制](#数据传输控制)
|
||||
7. [典型交互流程](#典型交互流程)
|
||||
8. [最佳实践](#最佳实践)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
GeomativeStudio系统通过一系列工具组件实现与外部设备的交互,包括GD10主机、PLC控制器和网络设备。本文档系统化记录了这些工具组件的设计与实现,重点分析GD10设备通信指令集、网络设备发现与控制、PLC设备读写操作,以及设备状态管理、消息分发和数据传输控制机制。这些组件共同构成了系统与外部设备通信的核心基础设施。
|
||||
|
||||
## GD10设备通信指令集
|
||||
|
||||
`GD10OperCmd`组件定义了与GD10设备交互的完整指令集,通过模拟微机操作来管理设备上的文件和配置。该组件采用单例模式,确保全局唯一实例。
|
||||
|
||||
指令集主要包括:
|
||||
- **工程管理**:`project_add`和`project_delete`方法用于在GD10设备上创建和删除工程,通过操作`localhost.xml`和MAC地址对应的XML文件来维护工程目录映射。
|
||||
- **测区管理**:`testzone_add`和`testzone_delete`方法用于管理测区,创建相应的目录并在`project.xml`中添加或删除测区记录。
|
||||
- **脚本管理**:`script_add`和`script_delete`方法用于管理测量脚本,支持VES、ERI、ERT等不同类型,操作`scripts.xml`文件和脚本文件。
|
||||
- **任务管理**:`meas_delete`方法用于删除测量任务,同时清理XML配置和相关数据文件。
|
||||
- **参数配置**:`set_param`方法用于设置设备参数,解析以分号分隔的参数字符串,并更新`equipment.xml`文件中的相应节点。
|
||||
- **设备注册管理**:`unregister_user`方法用于注销用户,删除对应的用户配置文件。
|
||||
|
||||
所有操作都包含详细的错误处理和日志记录,确保操作的可靠性和可追溯性。
|
||||
|
||||
**Section sources**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L53-L1213)
|
||||
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L18-L52)
|
||||
|
||||
## 网络设备发现与远程控制
|
||||
|
||||
`NetWorkOper`组件实现了网络设备的发现、状态查询和远程控制功能。该组件基于TCP通信,通过`CTransferCtrl`进行底层数据传输。
|
||||
|
||||
主要功能包括:
|
||||
- **连接管理**:`StartConnect`方法建立与服务器的TCP连接,`StartWork`方法启动数据处理线程。
|
||||
- **设备发现**:通过监听特定控制命令(如`EN_RECV_NOTIFY_DEVICE_ONLINE`)来发现网络上的设备,并通过`CDetcGD10Dev`管理器注册设备。
|
||||
- **状态查询**:`TransferOper`方法用于发送状态查询命令,支持同步和异步模式,通过回调函数通知结果。
|
||||
- **远程控制**:`SendCtrlMsgDirect`方法用于发送控制命令,`RecvMsgDirect`方法用于接收响应。
|
||||
- **实时数据处理**:通过`RegeditRealMsgCall`注册实时数据接收窗口,当接收到实时测量数据时,通过Windows消息机制通知注册的窗口。
|
||||
|
||||
该组件采用生产者-消费者模式,通过临界区保护共享数据,确保多线程环境下的数据一致性。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant NetWorkOper as "NetWorkOper"
|
||||
participant TransferCtrl as "TransferCtrl"
|
||||
participant Server as "服务器"
|
||||
Client->>NetWorkOper : StartConnect(IP, Port)
|
||||
NetWorkOper->>TransferCtrl : ConnectToServer()
|
||||
TransferCtrl->>Server : TCP连接
|
||||
Server-->>TransferCtrl : 连接成功
|
||||
TransferCtrl-->>NetWorkOper : 连接状态
|
||||
NetWorkOper->>NetWorkOper : StartWork()
|
||||
NetWorkOper->>NetWorkOper : ThreadFunction()
|
||||
loop 消息循环
|
||||
NetWorkOper->>TransferCtrl : RecvCtrlMsg()
|
||||
alt 设备上线通知
|
||||
TransferCtrl-->>NetWorkOper : EN_RECV_NOTIFY_DEVICE_ONLINE
|
||||
NetWorkOper->>DevManager : AddRemoteDevice()
|
||||
NetWorkOper->>MainFrm : WM_MSG_NOTIFY_DEVICE_ON_OR_OFF
|
||||
else PLC状态
|
||||
TransferCtrl-->>NetWorkOper : EN_RECV_PLC_STATUS
|
||||
NetWorkOper->>TaskDataOper : InsertPlcStatusData()
|
||||
else 实时测量数据
|
||||
TransferCtrl-->>NetWorkOper : EN_REAL_TIME_TESTING_DATA
|
||||
NetWorkOper->>RealWnd : WM_NET_RECV_REAL_TIME_DATA
|
||||
else 控制命令
|
||||
TransferCtrl-->>NetWorkOper : EN_RECV_CTRL_CMD
|
||||
NetWorkOper->>DevNotify : 回调通知
|
||||
end
|
||||
alt 需要发送命令
|
||||
NetWorkOper->>TransferCtrl : SendCtrlInfo()
|
||||
TransferCtrl->>Server : 发送控制命令
|
||||
TransferCtrl->>TransferCtrl : RecvRspMsg()
|
||||
TransferCtrl-->>NetWorkOper : 响应数据
|
||||
NetWorkOper->>NotifyFunc : 回调通知
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp#L26-L706)
|
||||
- [NetWorkOper.h](file://h/NetWorkOper.h#L107-L173)
|
||||
|
||||
**Section sources**
|
||||
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp#L26-L706)
|
||||
- [NetWorkOper.h](file://h/NetWorkOper.h#L107-L173)
|
||||
|
||||
## PLC设备读写操作
|
||||
|
||||
`OperPLC`组件封装了对PLC设备的读写操作,提供了一个简洁的接口来控制PLC的电源状态。
|
||||
|
||||
主要功能包括:
|
||||
- **命令生成**:`GetPlcCmdInfo`方法根据命令类型生成相应的PLC控制数据包,支持`EN_PLC_POWER_ON`和`EN_PLC_POWER_OFF`命令。
|
||||
- **响应解析**:`ParsePlcOperResInfo`方法解析PLC返回的状态信息,验证数据长度并提取操作结果。
|
||||
- **具体命令实现**:`GetPowerOnCmd`和`GetPowerOffCmd`方法构建具体的控制数据包,设置相应的控制位。
|
||||
|
||||
该组件通过`STRemPlcDataInfo`结构体定义PLC数据格式,确保与设备的通信协议一致。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class COperPLC {
|
||||
+GetInstance() COperPLC*
|
||||
+GetPlcCmdInfo(BYTE, char*, int&, int) void
|
||||
+ParsePlcOperResInfo(char*, int) int
|
||||
-GetPowerOnCmd(char*, int&) void
|
||||
-GetPowerOffCmd(char*, int&) void
|
||||
-m_pOperPlc COperPLC*
|
||||
}
|
||||
class STRemPlcDataInfo {
|
||||
+ucPacketIndex BYTE
|
||||
+ucCtrlK1 BYTE
|
||||
+ucCtrlK2 BYTE
|
||||
+ucCtrlK3 BYTE
|
||||
+ucCtrlK4 BYTE
|
||||
+ucCtrlK5 BYTE
|
||||
+ucCtrlK6 BYTE
|
||||
+ucResult BYTE
|
||||
}
|
||||
COperPLC --> STRemPlcDataInfo : "使用"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L18-L121)
|
||||
- [OperPLC.h](file://h/OperPLC.h#L24-L39)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
|
||||
|
||||
**Section sources**
|
||||
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L18-L121)
|
||||
- [OperPLC.h](file://h/OperPLC.h#L24-L39)
|
||||
|
||||
## 设备状态机与消息处理
|
||||
|
||||
`HandleProcessor`和`StateProcessor`组件在设备状态机管理、消息分发和事件处理中扮演关键角色。
|
||||
|
||||
`HandleProcessor`负责句柄的生成和解析,将ID和类型信息编码到32位DWORD中:
|
||||
- **句柄生成**:`GenerateHandle`方法将27位ID和5位类型组合成一个唯一的句柄。
|
||||
- **句柄解析**:`AnalyseHandle`、`GetIDFromHandle`和`GetStyleFromHandle`方法从句柄中提取ID和类型信息。
|
||||
|
||||
`StateProcessor`负责状态与图像索引之间的转换:
|
||||
- **状态转换**:`ChangeToImageState`和`ChangeToItemState`方法在树控件的状态图像索引和内部状态值之间进行转换。
|
||||
|
||||
这些组件为系统提供了统一的标识和状态管理机制,简化了设备和对象的管理和显示。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class CHandleProcessor {
|
||||
+GenerateHandle(DWORD, UINT) DWORD
|
||||
+GenerateNewHandle(DWORD, UINT) DWORD
|
||||
+AnalyseHandle(DWORD, DWORD&, UINT&) void
|
||||
+GetIDFromHandle(DWORD) DWORD
|
||||
+GetStyleFromHandle(DWORD) UINT
|
||||
}
|
||||
class CStateProcessor {
|
||||
+ChangeToImageState(UINT) UINT
|
||||
+ChangeToItemState(UINT) UINT
|
||||
}
|
||||
CHandleProcessor : HANDLE_OFFSET = 27
|
||||
CStateProcessor : STATE_OFFSET = 12
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L19-L96)
|
||||
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L28)
|
||||
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L19-L41)
|
||||
- [StateProcessor.h](file://h/StateProcessor.h#L12-L22)
|
||||
- [Constant.h](file://h/Constant.h)
|
||||
|
||||
**Section sources**
|
||||
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L19-L96)
|
||||
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L28)
|
||||
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L19-L41)
|
||||
- [StateProcessor.h](file://h/StateProcessor.h#L12-L22)
|
||||
|
||||
## 数据传输控制
|
||||
|
||||
`TransferCtrl`组件负责数据传输过程的流量控制与状态监控,继承自`CTcpClient`,实现了协议特定的通信逻辑。
|
||||
|
||||
主要功能包括:
|
||||
- **协议封装**:`SendCtrlInfoToDev`方法构建符合`STCtrlProtoHeader`格式的数据包,包含ID码、源/目的地址、命令码、序列号和CRC校验。
|
||||
- **数据接收**:`RecvCommRspMsg`方法处理接收的数据,包括查找协议头、长度校验、CRC校验和命令类型识别。
|
||||
- **状态管理**:维护当前命令、设备类型、序列号等状态信息,用于响应匹配和错误检测。
|
||||
- **错误处理**:实现超时、数据错序、CRC错误等多种错误处理机制。
|
||||
|
||||
该组件通过`RecvEnoughMsg`确保完整接收数据包,并通过`IsCtrlMsg`和`IsPlcStatusMsg`识别特殊类型的控制消息。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始发送] --> B[构建STCtrlProtoHeader]
|
||||
B --> C[计算总长度]
|
||||
C --> D[复制数据内容]
|
||||
D --> E[计算CRC校验]
|
||||
E --> F[发送数据]
|
||||
F --> G{发送成功?}
|
||||
G --> |是| H[更新状态信息]
|
||||
G --> |否| I[记录错误日志]
|
||||
H --> J[结束]
|
||||
I --> J
|
||||
K[开始接收] --> L[接收协议头]
|
||||
L --> M{找到ID码?}
|
||||
M --> |否| N[跳过字节]
|
||||
N --> O{超过最大跳过字节?}
|
||||
O --> |是| P[返回错误]
|
||||
O --> |否| L
|
||||
M --> |是| Q[校验长度]
|
||||
Q --> R{长度有效?}
|
||||
R --> |否| P
|
||||
R --> |是| S[接收剩余数据]
|
||||
S --> T[校验CRC]
|
||||
T --> U{CRC正确?}
|
||||
U --> |否| P
|
||||
U --> |是| V[解析命令类型]
|
||||
V --> W[返回结果]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L27-L615)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L78)
|
||||
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
|
||||
|
||||
**Section sources**
|
||||
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L27-L615)
|
||||
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L78)
|
||||
|
||||
## 典型交互流程
|
||||
|
||||
### 设备连接初始化
|
||||
1. 调用`NetWorkOper::StartConnect`建立TCP连接
|
||||
2. 调用`NetWorkOper::StartWork`启动消息处理线程
|
||||
3. 系统自动发现在线设备并更新设备列表
|
||||
|
||||
### 参数配置
|
||||
1. 调用`GD10OperCmd::set_param`设置参数
|
||||
2. 构造参数字符串(如`"gain,2;range,1"`)
|
||||
3. 方法解析参数并更新`equipment.xml`
|
||||
|
||||
### 实时监控
|
||||
1. 调用`NetWorkOper::RegeditRealMsgCall`注册实时数据窗口
|
||||
2. 当接收到实时测量数据时,系统发送`WM_NET_RECV_REAL_TIME_DATA`消息
|
||||
3. 注册窗口处理消息并更新显示
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 超时处理
|
||||
- 所有网络操作都应设置合理的超时时间
|
||||
- 使用`STRespDataInfo`中的`iTimeout`字段配置超时
|
||||
- 超时后应进行重试或错误处理
|
||||
|
||||
### 指令重发
|
||||
- 对于关键操作,实现自动重试机制
|
||||
- 使用序列号跟踪命令,避免重复执行
|
||||
- 在`TransferCtrl`中维护命令状态,确保可靠性
|
||||
|
||||
### 状态同步
|
||||
- 通过`NetWorkOper`的设备上线/下线通知保持状态同步
|
||||
- 使用`HandleProcessor`确保对象标识的一致性
|
||||
- 定期查询设备状态,验证同步状态
|
||||
|
||||
## 结论
|
||||
GeomativeStudio的设备交互工具组件提供了一个完整、可靠的外部设备通信框架。通过`GD10OperCmd`、`NetWorkOper`、`OperPLC`等组件的协同工作,系统能够有效地管理GD10设备、网络设备和PLC控制器。`HandleProcessor`和`StateProcessor`提供了统一的状态和标识管理,而`TransferCtrl`确保了数据传输的可靠性和效率。这些组件的设计体现了良好的分层架构和关注点分离原则,为系统的稳定运行提供了坚实的基础。
|
||||
@@ -0,0 +1,353 @@
|
||||
# 设备指令系统
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [GD10OperCmd.h](file://h/GD10OperCmd.h)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
|
||||
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
|
||||
- [DevManager.h](file://h/DevManager.h)
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
- [IOManager.h](file://h/IOManager.h)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
- [FileOperTools.h](file://h/FileOperTools.h)
|
||||
- [Markup.h](file://h/Markup.h)
|
||||
- [Constant.h](file://h/Constant.h)
|
||||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
|
||||
- [Crc16.h](file://h/Crc16.h)
|
||||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
|
||||
- [Crc32.h](file://h/Crc32.h)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概述](#架构概述)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排除指南](#故障排除指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
本文档深入解析了GD10设备指令系统的实现,重点分析了`GD10OperCmd.cpp`文件中的设备指令系统。文档详细说明了GD10设备通信协议的命令格式、参数编码规则与响应解析机制,涵盖了指令分类(如设备配置、数据采集、状态查询等)、命令帧结构、校验机制(CRC16/CRC32)及超时重传策略。通过代码示例展示了典型指令的构造与解析流程,如启动测量任务、读取设备参数等。同时,文档解释了与DevManager、IOManager等模块的集成方式,以及在不同设备状态下的指令调度逻辑,并提供了常见通信异常的诊断方法和处理建议。
|
||||
|
||||
## 项目结构
|
||||
GeomativeStudio项目是一个用于地质勘探设备管理的软件系统,其核心功能围绕GD10设备的通信、配置和数据管理展开。项目结构清晰地分为多个模块,每个模块负责特定的功能领域。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "核心模块"
|
||||
DevManager["设备管理器<br>(Managers/DevManager.cpp)"]
|
||||
IOManager["输入输出管理器<br>(Managers/IOManager.cpp)"]
|
||||
GD10OperCmd["GD10操作命令<br>(Tools/GD10OperCmd.cpp)"]
|
||||
end
|
||||
subgraph "工具与支持模块"
|
||||
DetcGD10Dev["GD10设备检测<br>(Operator/DetcGD10Dev.cpp)"]
|
||||
FileOperTools["文件操作工具<br>(Tools/FileOperTools.cpp)"]
|
||||
Markup["XML解析工具<br>(Tools/Markup.cpp)"]
|
||||
Crc16["CRC16校验<br>(Tools/Crc16.cpp)"]
|
||||
Crc32["CRC32校验<br>(Tools/Crc32.cpp)"]
|
||||
end
|
||||
subgraph "常量与头文件"
|
||||
Constant["常量定义<br>(h/Constant.h)"]
|
||||
Headers["头文件<br>(h/*.h)"]
|
||||
end
|
||||
GD10OperCmd --> DevManager
|
||||
GD10OperCmd --> IOManager
|
||||
GD10OperCmd --> DetcGD10Dev
|
||||
GD10OperCmd --> FileOperTools
|
||||
GD10OperCmd --> Markup
|
||||
GD10OperCmd --> Crc16
|
||||
GD10OperCmd --> Crc32
|
||||
DetcGD10Dev --> FileOperTools
|
||||
DevManager --> Headers
|
||||
IOManager --> Headers
|
||||
Constant --> Headers
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
- [Markup.h](file://h/Markup.h)
|
||||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
|
||||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
|
||||
- [Constant.h](file://h/Constant.h)
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
- [Constant.h](file://h/Constant.h)
|
||||
|
||||
## 核心组件
|
||||
`GD10OperCmd`类是实现GD10设备指令系统的核心组件,它通过模拟微机操作来管理连接到Geomative Studio的GD10设备。该类提供了对设备上文件系统的操作接口,包括工程、测区、脚本和测量任务的增删改查。所有操作都依赖于`DetcGD10Dev`类来检测和确认设备的连接状态,并使用`Markup`类来解析和修改设备上的XML配置文件。`FileOperTools`类则提供了底层的文件和目录操作功能,确保了操作的原子性和日志记录。
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L1213)
|
||||
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L1-L55)
|
||||
|
||||
## 架构概述
|
||||
GD10设备指令系统的架构是一个典型的分层设计,从上层应用逻辑到底层硬件交互,各层职责分明。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户界面] --> B[GD10OperCmd]
|
||||
B --> C[DetcGD10Dev]
|
||||
B --> D[FileOperTools]
|
||||
B --> E[Markup]
|
||||
C --> F[USB设备]
|
||||
D --> G[文件系统]
|
||||
E --> H[XML文件]
|
||||
B --> I[Crc16/Crc32]
|
||||
subgraph "应用层"
|
||||
A
|
||||
B
|
||||
end
|
||||
subgraph "服务层"
|
||||
C
|
||||
D
|
||||
E
|
||||
I
|
||||
end
|
||||
subgraph "数据层"
|
||||
F
|
||||
G
|
||||
H
|
||||
end
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
- [Markup.h](file://h/Markup.h)
|
||||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
|
||||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### GD10操作命令分析
|
||||
`CGD10OperCmd`类是整个指令系统的核心,它封装了所有与GD10设备交互的命令。
|
||||
|
||||
#### 类结构与关系
|
||||
```mermaid
|
||||
classDiagram
|
||||
class CGD10OperCmd {
|
||||
+static CGD10OperCmd* m_pGD10Oper
|
||||
+CGD10OperCmd()
|
||||
+~CGD10OperCmd()
|
||||
+static CGD10OperCmd* GetInstance()
|
||||
+int project_add(const char *mac, const char *projectcn)
|
||||
+bool project_delete(const char *mac, const char *projectcn)
|
||||
+int testzone_add(const char *projectcn, const char *testzonecn, const char *type)
|
||||
+int testzone_delete(const char *projectcn, const char *testzonecn)
|
||||
+int script_add(const char *scriptcn, const char *scriptname, const char *mudiumid)
|
||||
+bool script_delete(const char *scriptcn)
|
||||
+bool meas_delete(const char *projectcn, const char *testzonecn, const char *measuringcn)
|
||||
+bool set_param(const CString& strParam)
|
||||
+bool unregister_user(CString strMacAddr)
|
||||
+bool loadDeviceMarkDataFromGD()
|
||||
+static UINT LoadDevMarkDataFormGDThread(LPVOID lParam)
|
||||
}
|
||||
class CDetcGD10Dev {
|
||||
+static CDetcGD10Dev* m_pDetcDev
|
||||
+bool m_bGD10DevIsCon
|
||||
+CString m_strDevAddr
|
||||
+CDetcGD10Dev()
|
||||
+~CDetcGD10Dev()
|
||||
+static CDetcGD10Dev* GetInstance()
|
||||
+bool IsGD10DevConnect()
|
||||
+CString GetGD10DevAddr()
|
||||
+void DetectGD10Dev()
|
||||
}
|
||||
class CFileOperTools {
|
||||
+static CFileOperTools* m_pFileOper
|
||||
+FILE* m_pComLog
|
||||
+CRITICAL_SECTION *m_pWriteLogSection
|
||||
+CFileOperTools()
|
||||
+~CFileOperTools()
|
||||
+static CFileOperTools* GetInstance()
|
||||
+bool CopyFolder(CString strSrcPath, CString strDstPath)
|
||||
+bool IsFileExist(CString strFileInfo)
|
||||
+bool WriteComLog(const CString& strInfo)
|
||||
+bool DeleteDirectory(CString strDirPath)
|
||||
+bool DeleteFileDirect(CString strFilePath)
|
||||
}
|
||||
class CMarkup {
|
||||
+CMarkup()
|
||||
+~CMarkup()
|
||||
+bool Load(const char* szFileName)
|
||||
+bool Save(const char* szFileName)
|
||||
+bool FindChildElem(const char* szName)
|
||||
+bool IntoElem()
|
||||
+bool AddChildElem(const char* szName, const char* szData)
|
||||
+bool RemoveChildElem()
|
||||
+CString GetChildData()
|
||||
+bool SetChildData(const char* szData)
|
||||
+void ResetPos()
|
||||
}
|
||||
CGD10OperCmd --> CDetcGD10Dev : "使用"
|
||||
CGD10OperCmd --> CFileOperTools : "使用"
|
||||
CGD10OperCmd --> CMarkup : "使用"
|
||||
CDetcGD10Dev --> CFileOperTools : "使用"
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L1-L55)
|
||||
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L1-L38)
|
||||
- [FileOperTools.h](file://h/FileOperTools.h#L1-L42)
|
||||
- [Markup.h](file://h/Markup.h#L1-L266)
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L1213)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
|
||||
|
||||
#### 指令执行流程
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as "用户界面"
|
||||
participant GD10Cmd as "CGD10OperCmd"
|
||||
participant DetDev as "CDetcGD10Dev"
|
||||
participant FileTools as "CFileOperTools"
|
||||
participant Markup as "CMarkup"
|
||||
UI->>GD10Cmd : project_add(mac, projectcn)
|
||||
GD10Cmd->>DetDev : IsGD10DevConnect()
|
||||
alt 设备未连接
|
||||
GD10Cmd-->>UI : 显示错误消息
|
||||
return
|
||||
end
|
||||
GD10Cmd->>DetDev : GetGD10DevAddr()
|
||||
GD10Cmd->>FileTools : MakeSureDirectoryPathExists()
|
||||
alt 创建目录失败
|
||||
GD10Cmd-->>UI : 显示错误消息
|
||||
return
|
||||
end
|
||||
GD10Cmd->>Markup : 加载 localhost.xml
|
||||
GD10Cmd->>Markup : 在 path_dictionary 中添加 path 元素
|
||||
GD10Cmd->>Markup : 保存 localhost.xml
|
||||
GD10Cmd->>Markup : 加载 mac.xml
|
||||
GD10Cmd->>Markup : 在 path_dictionary 中添加 path 元素
|
||||
GD10Cmd->>Markup : 保存 mac.xml
|
||||
GD10Cmd-->>UI : 返回成功 (1)
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L53-L105)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L61-L68)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L261-L324)
|
||||
- [Markup.h](file://h/Markup.h)
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L53-L105)
|
||||
|
||||
### 设备检测与管理分析
|
||||
`CDetcGD10Dev`类负责检测和管理GD10设备的连接状态,为上层指令系统提供设备可用性保障。
|
||||
|
||||
#### 设备检测流程
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始检测设备]) --> GetDrives["获取所有逻辑驱动器"]
|
||||
GetDrives --> CheckDrive["遍历每个驱动器"]
|
||||
CheckDrive --> IsRemovable{"是否为可移动驱动器?"}
|
||||
IsRemovable --> |是| GetVolName["获取卷标名称"]
|
||||
IsRemovable --> |否| NextDrive["下一个驱动器"]
|
||||
GetVolName --> CompareName{"卷标是否为 'GD10' 或 'GD20'?"}
|
||||
CompareName --> |是| SetAddr["设置设备地址"]
|
||||
CompareName --> |否| CheckDir["检查是否存在 \\SD\\equipment 目录"]
|
||||
CheckDir --> |存在| SetAddr
|
||||
CheckDir --> |不存在| NextDrive
|
||||
SetAddr --> SetConnected["设置连接状态为 true"]
|
||||
SetConnected --> End([设备检测完成])
|
||||
NextDrive --> CheckDrive
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L100-L174)
|
||||
|
||||
**节源**
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L61-L68)
|
||||
|
||||
## 依赖分析
|
||||
GD10设备指令系统依赖于多个核心组件和工具类,这些依赖关系确保了系统的稳定性和功能完整性。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
GD10OperCmd --> DetcGD10Dev
|
||||
GD10OperCmd --> FileOperTools
|
||||
GD10OperCmd --> Markup
|
||||
GD10OperCmd --> Crc16
|
||||
GD10OperCmd --> Crc32
|
||||
DetcGD10Dev --> FileOperTools
|
||||
DevManager --> GD10OperCmd
|
||||
IOManager --> GD10OperCmd
|
||||
subgraph "GD10指令系统"
|
||||
GD10OperCmd
|
||||
DetcGD10Dev
|
||||
end
|
||||
subgraph "工具类"
|
||||
FileOperTools
|
||||
Markup
|
||||
Crc16
|
||||
Crc32
|
||||
end
|
||||
subgraph "其他管理器"
|
||||
DevManager
|
||||
IOManager
|
||||
end
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
- [Markup.h](file://h/Markup.h)
|
||||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
|
||||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
|
||||
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
|
||||
## 性能考虑
|
||||
在设计和实现GD10设备指令系统时,性能是一个重要的考量因素。系统通过以下方式优化性能:
|
||||
1. **单例模式**:`CGD10OperCmd`和`CDetcGD10Dev`类都采用了单例模式,避免了重复创建对象的开销。
|
||||
2. **线程安全**:`CFileOperTools`类在写日志时使用了临界区(CRITICAL_SECTION)来保证线程安全,防止多线程并发写入导致的日志混乱。
|
||||
3. **异步操作**:`loadDeviceMarkDataFromGD`方法通过创建独立线程来执行文件复制和删除操作,避免了阻塞主线程,提高了用户体验。
|
||||
4. **错误重试**:在删除文件或复制文件时,系统会进行多次重试(最多3次),以应对可能的文件占用或I/O错误,提高了操作的鲁棒性。
|
||||
|
||||
## 故障排除指南
|
||||
当GD10设备指令系统出现通信异常时,可以按照以下步骤进行诊断和处理:
|
||||
|
||||
**节源**
|
||||
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
|
||||
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
|
||||
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
|
||||
|
||||
### 常见问题与解决方案
|
||||
| 问题现象 | 可能原因 | 解决方案 |
|
||||
| :--- | :--- | :--- |
|
||||
| "请确保主机设备连上Geomative Studio!" | GD10设备未正确连接或未被识别 | 1. 检查USB线缆连接是否牢固。<br>2. 确认设备卷标是否为'GD10'或'GD20'。<br>3. 检查`LOG\detect_gd20_log.txt`日志文件以获取详细检测信息。 |
|
||||
| "添加工程到本机失败" | `localhost.xml`文件损坏或权限不足 | 1. 检查`sd\users\localhost.xml`文件是否存在且可写。<br>2. 查看`LOG\general\`目录下的日志文件,确认具体的错误代码。 |
|
||||
| "创建工程失败" | SD卡空间不足或文件系统错误 | 1. 检查GD10设备的SD卡剩余空间。<br>2. 尝试格式化SD卡(注意备份数据)。 |
|
||||
| "删除文件失败" | 文件被其他进程占用 | 1. 确保没有其他程序正在访问GD10设备的文件。<br>2. 系统会自动重试3次,若仍失败,重启软件或设备后重试。 |
|
||||
| "解析输入参数错误" | `set_param`方法的输入字符串格式不正确 | 1. 确认输入参数为逗号分隔的键值对,如`"key1,value1;key2,value2"`。<br>2. 检查键名是否存在于`equipment.xml`文件中。 |
|
||||
|
||||
## 结论
|
||||
通过对`GD10OperCmd.cpp`及其相关组件的深入分析,我们全面理解了GD10设备指令系统的工作原理。该系统通过一个清晰的分层架构,将设备检测、文件操作、XML解析和指令执行等功能解耦,实现了对GD10设备的高效管理和控制。系统设计考虑了单例模式、线程安全和异步操作等性能优化策略,并通过详细的日志记录和错误处理机制保证了系统的稳定性。对于开发者而言,理解这些核心组件的交互方式和设计模式,对于维护和扩展系统功能至关重要。
|
||||
Reference in New Issue
Block a user