This commit is contained in:
coco
2026-07-03 16:05:30 +08:00
commit df489d5640
1101 changed files with 779140 additions and 0 deletions
@@ -0,0 +1,339 @@
# 开发工具与实用程序
<cite>
**本文档引用的文件**
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp)
- [SComPort.h](file://h\SComPort.h)
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp)
- [TcpClient.h](file://h\TcpClient.h)
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp)
- [Zmodem.h](file://h\Zmodem.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)
- [FileOperTools.cpp](file://cpp\Tools\FileOperTools.cpp)
- [FileOperTools.h](file://h\FileOperTools.h)
- [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)
- [GUCodeCreator.cpp](file://cpp\Tools\GUCodeCreator.cpp)
- [GUCodeCreator.h](file://h\GUCodeCreator.h)
- [excel.cpp](file://cpp\Tools\excel.cpp)
- [excel.h](file://h\excel.h)
- [checkupdate.cpp](file://cpp\Tools\checkupdate.cpp)
- [checkupdate.h](file://h\checkupdate.h)
</cite>
## 目录
1. [通信相关工具](#通信相关工具)
2. [数据处理工具](#数据处理工具)
3. [设备交互工具](#设备交互工具)
4. [辅助工具](#辅助工具)
5. [调用示例与最佳实践](#调用示例与最佳实践)
## 通信相关工具
### SComPort.cpp - 串口通信
`SComPort.cpp` 文件实现了 `CSComPort` 类,用于处理串口通信。该类提供了串口的打开、关闭、数据发送和接收等基本功能。主要功能包括:
- **串口管理**:通过 `OpenComm``CloseComm` 方法管理串口的打开和关闭。
- **数据传输**:提供 `SendDataDirectly``ReceiveDataDirectly` 方法进行数据的直接发送和接收。
- **事件处理**:支持通过 `SetOwnerWnd``SetCommID` 设置所有者窗口和通信ID,以便在串口事件发生时进行通知。
**Section sources**
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L1-L1199)
- [SComPort.h](file://h\SComPort.h#L1-L74)
### TcpClient.cpp - TCP网络通信
`TcpClient.cpp` 文件实现了 `CTcpClient` 类,用于处理TCP网络通信。该类提供了TCP连接的初始化、连接、断开连接、数据发送和接收等功能。主要功能包括:
- **连接管理**:通过 `InitailTcp``ConnectToServer` 方法初始化和建立TCP连接。
- **数据传输**:提供 `SendData``RecvData` 方法进行数据的发送和接收。
- **连接状态检查**:通过 `GetConnectStatus` 方法检查连接状态,确保通信的可靠性。
**Section sources**
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
- [TcpClient.h](file://h\TcpClient.h#L1-L76)
### Zmodem.cpp - Zmodem协议文件传输
`Zmodem.cpp` 文件实现了 `Zmodem` 类,用于实现Zmodem协议的文件传输。该类提供了文件的发送和接收功能,支持断点续传。主要功能包括:
- **文件发送**:通过 `Send` 方法发送文件,支持批量文件传输。
- **文件接收**:通过 `Receive` 方法接收文件,支持断点续传。
- **协议处理**:内部实现了Zmodem协议的各种帧类型处理,如 `ZRQINIT``ZRINIT``ZFILE` 等。
**Section sources**
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L1-L1940)
- [Zmodem.h](file://h\Zmodem.h#L1-L143)
## 数据处理工具
### Crc16.cpp 和 Crc32.cpp - 数据校验
`Crc16.cpp``Crc32.cpp` 文件分别实现了 `Crc16``Crc32` 类,用于提供数据校验功能。这些类通过计算CRC(循环冗余校验)值来确保数据的完整性。主要功能包括:
- **CRC16**`Crc16` 类提供16位CRC校验,适用于较小的数据块。
- **CRC32**`Crc32` 类提供32位CRC校验,适用于较大的数据块。
**Section sources**
- [Crc16.cpp](file://cpp\Tools\Crc16.cpp#L1-L54)
- [Crc16.h](file://h\Crc16.h#L1-L37)
- [Crc32.cpp](file://cpp\Tools\Crc32.cpp#L1-L51)
- [Crc32.h](file://h\Crc32.h#L1-L37)
### FileOperTools.cpp - 文件操作封装
`FileOperTools.cpp` 文件实现了 `CFileOperTools` 类,提供了一系列文件操作的封装方法。主要功能包括:
- **文件复制**:通过 `CopyFolder` 方法复制整个文件夹。
- **文件删除**:通过 `DeleteFileDirect``DeleteDirectory` 方法删除文件和目录。
- **日志记录**:通过 `WriteComLog` 方法记录通信日志,支持多线程安全。
**Section sources**
- [FileOperTools.cpp](file://cpp\Tools\FileOperTools.cpp#L1-L420)
- [FileOperTools.h](file://h\FileOperTools.h#L1-L37)
## 设备交互工具
### GD10OperCmd.cpp - GD10设备通信指令
`GD10OperCmd.cpp` 文件实现了 `CGD10OperCmd` 类,定义了与GD10设备的通信指令。主要功能包括:
- **工程管理**:通过 `project_add``project_delete` 方法添加和删除工程。
- **测区管理**:通过 `testzone_add``testzone_delete` 方法添加和删除测区。
- **脚本管理**:通过 `script_add``script_delete` 方法添加和删除脚本。
**Section sources**
- [GD10OperCmd.cpp](file://cpp\Tools\GD10OperCmd.cpp#L1-L1213)
- [GD10OperCmd.h](file://h\GD10OperCmd.h#L1-L37)
### NetWorkOper.cpp - 网络操作
`NetWorkOper.cpp` 文件实现了 `CNetWorkOper` 类,处理网络操作。主要功能包括:
- **连接管理**:通过 `StartConnect` 方法建立与服务器的连接。
- **数据传输**:通过 `TransferOper` 方法进行数据的转发。
- **实时数据接收**:通过 `ThreadFunction` 方法在后台线程中接收实时数据。
**Section sources**
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
- [NetWorkOper.h](file://h\NetWorkOper.h#L1-L37)
## 辅助工具
### GUCodeCreator.cpp - GU码生成
`GUCodeCreator.cpp` 文件实现了 `CGUCodeCreator` 类,用于生成GU码。主要功能包括:
- **MAC地址获取**:通过 `GetMacAddress` 方法获取本机的MAC地址。
- **时间戳生成**:通过 `GetTotalSecond` 方法获取当前时间的总秒数。
- **GU码生成**:通过 `GenerateGUCode` 方法生成GU码,结合MAC地址和时间戳。
**Section sources**
- [GUCodeCreator.cpp](file://cpp\Tools\GUCodeCreator.cpp#L1-L395)
- [GUCodeCreator.h](file://h\GUCodeCreator.h#L1-L37)
### excel.cpp - Excel文件导出
`excel.cpp` 文件实现了与Excel文件的交互,主要用于数据导出。主要功能包括:
- **Excel操作**:通过 `_Application` 类提供的方法进行Excel文件的创建、打开、保存等操作。
- **数据写入**:通过 `Range``Cells` 方法将数据写入Excel文件。
**Section sources**
- [excel.cpp](file://cpp\Tools\excel.cpp#L1-L7130)
- [excel.h](file://h\excel.h#L1-L37)
### checkupdate.cpp - 版本检查
`checkupdate.cpp` 文件实现了 `Ccheckupdate` 类,用于版本检查和更新。主要功能包括:
- **版本检查**:通过 `checkGeoMaive` 方法检查当前版本是否需要更新。
- **文件下载**:通过 `RequestFileContent` 方法从服务器下载文件内容。
- **更新操作**:通过 `UpdateAppToDev``UpdateGD10Dev` 方法执行更新操作。
**Section sources**
- [checkupdate.cpp](file://cpp\Tools\checkupdate.cpp#L1-L1523)
- [checkupdate.h](file://h\checkupdate.h#L1-L37)
## 调用示例与最佳实践
### 通信相关工具调用示例
#### 串口通信
```cpp
CSComPort comPort;
if (comPort.OpenComm("COM1")) {
char sendData[] = "Hello, World!";
comPort.SendDataDirectly(sendData, strlen(sendData));
char receiveData[1024];
int receiveSize;
if (comPort.ReceiveDataDirectly(receiveData, &receiveSize)) {
// 处理接收到的数据
}
comPort.CloseComm();
}
```
#### TCP网络通信
```cpp
CTcpClient tcpClient;
if (tcpClient.InitailTcp()) {
if (tcpClient.ConnectToServer("192.168.1.1", 8080)) {
char sendData[] = "Hello, Server!";
tcpClient.SendData(sendData, strlen(sendData));
char receiveData[1024];
int actualLen;
if (tcpClient.RecvData(receiveData, 1024, actualLen)) {
// 处理接收到的数据
}
tcpClient.CloseConnect();
}
}
```
#### Zmodem协议文件传输
```cpp
CSComPort comPort;
Zmodem zmodem(&comPort);
if (comPort.OpenComm("COM1")) {
char *files[] = {"file1.txt", "file2.txt", NULL};
if (zmodem.Send(files)) {
// 文件发送成功
}
if (zmodem.Receive("C:\\ReceivedFiles\\")) {
// 文件接收成功
}
comPort.CloseComm();
}
```
### 数据处理工具调用示例
#### CRC16和CRC32校验
```cpp
Crc16 crc16(0);
Crc32 crc32(0xFFFFFFFFL);
char data[] = "Hello, World!";
for (int i = 0; i < strlen(data); i++) {
crc16.update(data[i]);
crc32.update(data[i]);
}
unsigned short crc16Value = crc16.value();
unsigned long crc32Value = crc32.value();
```
#### 文件操作
```cpp
CFileOperTools fileTools;
if (fileTools.CopyFolder("C:\\SourceFolder", "D:\\DestinationFolder")) {
// 文件夹复制成功
}
if (fileTools.DeleteDirectory("D:\\OldFolder")) {
// 文件夹删除成功
}
CString logMessage = "This is a log message.";
fileTools.WriteComLog(logMessage);
```
### 设备交互工具调用示例
#### GD10设备通信
```cpp
CGD10OperCmd gd10Cmd;
if (gd10Cmd.project_add("00:11:22:33:44:55", "MyProject")) {
// 工程添加成功
}
if (gd10Cmd.testzone_add("MyProject", "MyTestZone", "Type1")) {
// 测区添加成功
}
if (gd10Cmd.script_add("VES123", "Script1", "0")) {
// 脚本添加成功
}
```
#### 网络操作
```cpp
CNetWorkOper netOper;
if (netOper.Initialize()) {
if (netOper.StartConnect("192.168.1.1", 8080)) {
if (netOper.StartWork()) {
// 网络操作开始
}
}
}
```
### 辅助工具调用示例
#### GU码生成
```cpp
CGUCodeCreator guCodeCreator;
CString guCode = guCodeCreator.GenerateGUCode();
```
#### Excel文件导出
```cpp
_Application excelApp;
excelApp.CreateDispatch("Excel.Application");
excelApp.SetVisible(TRUE);
_Workbook workbook = excelApp.GetWorkbooks().Add();
_Worksheet worksheet = workbook.GetWorksheets().GetItem(1);
Range range = worksheet.GetRange("A1");
range.SetValue2("Hello, Excel!");
workbook.SaveAs("C:\\ExportedFile.xlsx");
workbook.Close();
excelApp.Quit();
```
#### 版本检查
```cpp
Ccheckupdate checkUpdate;
if (checkUpdate.checkGeoMaive()) {
// 需要更新
if (checkUpdate.DownLoadFileList()) {
if (checkUpdate.UpdateGD10Dev()) {
// 更新成功
}
}
}
```
**Section sources**
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L1-L1199)
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L1-L449)
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L1-L1940)
- [Crc16.cpp](file://cpp\Tools\Crc16.cpp#L1-L54)
- [Crc32.cpp](file://cpp\Tools\Crc32.cpp#L1-L51)
- [FileOperTools.cpp](file://cpp\Tools\FileOperTools.cpp#L1-L420)
- [GD10OperCmd.cpp](file://cpp\Tools\GD10OperCmd.cpp#L1-L1213)
- [NetWorkOper.cpp](file://cpp\Tools\NetWorkOper.cpp#L1-L706)
- [GUCodeCreator.cpp](file://cpp\Tools\GUCodeCreator.cpp#L1-L395)
- [excel.cpp](file://cpp\Tools\excel.cpp#L1-L7130)
- [checkupdate.cpp](file://cpp\Tools\checkupdate.cpp#L1-L1523)
@@ -0,0 +1,179 @@
# 数据处理工具
<cite>
**Referenced Files in This Document**
- [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)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
- [FileOperTools.h](file://h/FileOperTools.h)
- [Markup.cpp](file://cpp/Tools/Markup.cpp)
- [Markup.h](file://h/Markup.h)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperTxtFile.h](file://h/OperTxtFile.h)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [OperUrfFile.h](file://h/OperUrfFile.h)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp)
- [Res3DDatFile.h](file://h/Res3DDatFile.h)
</cite>
## 目录
1. [引言](#引言)
2. [数据完整性校验工具](#数据完整性校验工具)
3. [文件操作工具](#文件操作工具)
4. [XML配置文件处理](#xml配置文件处理)
5. [特定格式数据文件处理](#特定格式数据文件处理)
6. [三维测量结果数据处理](#三维测量结果数据处理)
7. [应用场景与使用示例](#应用场景与使用示例)
8. [内存管理与性能优化](#内存管理与性能优化)
9. [错误恢复策略](#错误恢复策略)
10. [结论](#结论)
## 引言
GeomativeStudio中的数据处理工具集为地质勘探数据的完整性校验、文件操作、配置管理及数据存储提供了全面的解决方案。这些工具在项目配置保存、测量数据导出和缓存管理等关键场景中发挥着重要作用。本文档将深入解析Crc16.cpp和Crc32.cpp实现的数据完整性校验机制,FileOperTools.cpp封装的文件操作接口,Markup.cpp对XML配置文件的解析与生成逻辑,以及OperTxtFile.cpp、OperUrfFile.cpp和Res3DDatFile.cpp对特定格式数据文件的读写实现。
## 数据完整性校验工具
### CRC16校验实现
Crc16类实现了基于查表法的CRC16校验算法,通过预计算的256项查找表优化性能。该类采用静态成员变量`table`存储预计算的校验值,并使用`initialized`标志确保表只初始化一次。构造函数接收初始值,通过位运算和多项式0x1021进行校验计算。`update`方法对每个输入字节进行处理,利用查表法快速更新校验值,避免了重复的多项式除法运算。
**Section sources**
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L28-L54)
- [Crc16.h](file://h/Crc16.h#L12-L37)
### CRC32校验实现
Crc32类实现了CRC32校验算法,同样采用查表优化技术。与CRC16类似,它使用静态`table`数组存储预计算值,并通过`initialized`标志控制初始化。构造函数使用多项式0xEDB88320L进行表的生成,该多项式是CRC32标准算法的核心。`update`方法通过查表和位移操作高效更新校验值,确保数据完整性验证的高性能。
**Section sources**
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L28-L51)
- [Crc32.h](file://h/Crc32.h#L12-L37)
## 文件操作工具
### 文件操作接口封装
CFileOperTools类封装了常用的文件操作功能,提供了一个单例模式的全局访问点。该类实现了目录复制、文件存在性检查、文件删除、日志写入等核心功能。`CopyFolder`方法递归复制目录及其内容,`DeleteDirectory`方法递归删除目录树,确保了文件系统操作的完整性和可靠性。
**Section sources**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L58-L124)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L261-L323)
- [FileOperTools.h](file://h/FileOperTools.h#L12-L42)
### 文件锁定与日志机制
该工具类实现了线程安全的日志写入机制,使用临界区(CRITICAL_SECTION)保护日志文件的并发访问。`WriteComLog`方法在写入日志前获取临界区锁,确保多线程环境下的数据一致性。同时,类提供了`CloseComLog`方法正确释放资源,防止内存泄漏。`DealGeneralLogFunc`方法创建后台线程定期清理过期日志文件,实现了自动化的日志管理。
**Section sources**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L21-L37)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L150-L197)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L345-L398)
## XML配置文件处理
### XML解析与生成逻辑
CMarkup类提供了完整的XML文档处理能力,支持文档加载、元素查找、属性读取、内容修改等操作。该类采用内部状态机解析XML文档,通过`FindElem`方法定位元素,`GetAttrib``GetData`方法提取属性和内容。`AddElem``SetData`方法允许动态修改文档结构,支持创建和更新XML配置文件。
**Section sources**
- [Markup.cpp](file://cpp/Tools/Markup.cpp#L265-L291)
- [Markup.h](file://h/Markup.h#L276-L305)
### 编码转换与字符处理
CMarkup类内置了强大的编码转换功能,支持UTF-8、UTF-16、UTF-32等多种编码格式的相互转换。通过`TextEncoding`结构体和相关方法,实现了跨平台的字符集处理。`x_GetEncodingCodePage`函数使用哈希表快速查找编码对应的代码页,`PerformConversion`方法执行实际的编码转换,确保XML文档在不同环境下的正确读写。
**Section sources**
- [Markup.cpp](file://cpp/Tools/Markup.cpp#L183-L764)
- [Markup.h](file://h/Markup.h#L387-L394)
## 特定格式数据文件处理
### 文本文件操作
COperTxtFile类专门处理文本文件的读写操作,提供了参数化宽度的文本写入功能。`SetParamWidth`方法设置输出字段宽度,`WriteFileContent`方法将字符串数组按指定宽度格式化写入文件,不足部分用空格填充。该类还实现了错误检查和日志记录,确保文件操作的可靠性和可追溯性。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L39-L57)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L104-L158)
- [OperTxtFile.h](file://h/OperTxtFile.h#L12-L32)
### URF文件处理
COperUrfFile类负责URFUniversal Resistivity data File)格式文件的生成,支持多种电极阵列配置。该类提供了`WriteElecByAR`系列方法,根据不同的装置类型(如温纳-施伦贝格尔、跨孔等)生成相应的电极坐标信息。`WriteUrfHeadInfo`方法创建文件头,包含格式说明和单位信息,确保文件的标准化和可读性。
**Section sources**
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L64-L77)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L506-L538)
- [OperUrfFile.h](file://h/OperUrfFile.h#L12-L52)
## 三维测量结果数据处理
### 三维数据文件结构
CRes3DDatFile类处理三维测量结果数据的结构化存储,采用特定的二进制文件格式。该类定义了文件头、记录和文件尾三部分结构,通过`WriteHead``WriteRecord``WriteTail`方法分别写入。文件头包含标题、网格尺寸、间距和介质类型等元数据,记录部分存储具体的测量点数据。
**Section sources**
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L189-L257)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L260-L322)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L325-L351)
- [Res3DDatFile.h](file://h/Res3DDatFile.h#L28-L31)
### 数据记录管理
该类使用CPtrArray管理测量记录,通过`AddRecord`方法添加新的测量点,`DelRecord``ClearAllRecord`方法删除记录。`Generate`方法协调整个文件生成过程,先创建文件,然后依次写入头部、记录和尾部信息。`SetMedium`方法将用户友好的介质代码转换为内部表示,确保数据的一致性和正确性。
**Section sources**
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L100-L165)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L353-L386)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L168-L187)
## 应用场景与使用示例
### 项目配置保存
在项目配置保存场景中,Markup类用于序列化应用程序设置到XML文件。通过`SetDoc`方法加载现有配置或创建新文档,使用`AddElem``AddAttrib`方法添加配置项,最后调用`Save`方法持久化到磁盘。这种机制确保了配置数据的结构化存储和跨会话持久性。
**Section sources**
- [Markup.cpp](file://cpp/Tools/Markup.cpp#L344-L346)
- [Markup.cpp](file://cpp/Tools/Markup.cpp#L346-L348)
### 测量数据导出
测量数据导出功能结合使用OperTxtFile和OperUrfFile类,将采集的测量结果转换为标准格式。对于文本报告,使用OperTxtFile按固定宽度格式化输出;对于专业分析,使用OperUrfFile生成URF格式文件,包含电极配置和测量数据。这种多格式支持满足了不同用户和软件的需求。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L104-L158)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L506-L538)
### 缓存管理
缓存管理利用FileOperTools类的目录操作功能,实现缓存文件的自动清理。`DealGeneralLogThread`方法扫描日志目录,识别并删除两天前的旧文件,防止磁盘空间耗尽。`CopyFolder``DeleteDirectory`方法支持缓存的备份和重置,确保系统稳定运行。
**Section sources**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L346-L398)
## 内存管理与性能优化
### 查表法优化
CRC校验算法采用查表法进行性能优化,将复杂的多项式除法运算转换为简单的查表操作。Crc16和Crc32类在首次使用时预计算256个可能的余数,存储在静态数组中。后续计算只需一次查表和几次位运算,大大提高了处理速度,特别适合处理大量数据的场景。
**Section sources**
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L38-L50)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L38-L47)
### 资源管理
所有文件操作类都实现了正确的资源管理,确保文件句柄和内存的及时释放。析构函数中调用`CloseFile``CloseComLog`关闭文件,`ClearAllRecord`方法释放动态分配的记录对象。这种RAII(资源获取即初始化)模式防止了资源泄漏,提高了系统的稳定性和可靠性。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L27-L35)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L26-L29)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp#L35-L36)
## 错误恢复策略
### 异常处理与日志记录
数据处理工具集实现了全面的错误检测和恢复机制。每个关键操作都包含输入验证和边界检查,如`OpenFileforWrite`检查文件名是否为空。操作失败时,通过`WriteComLog`记录详细的错误信息,包括错误码和上下文,便于问题诊断和恢复。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L69-L97)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L150-L197)
### 事务性操作
对于复杂的文件操作,如目录复制和删除,采用事务性设计原则。操作过程中持续检查状态,一旦发现错误立即停止并记录,避免部分完成的状态。`CopyFolder`方法在复制每个文件前检查源和目标路径,`DeleteDirectory`方法在删除每个子项前验证其存在性,确保操作的原子性和一致性。
**Section sources**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L58-L124)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L261-L323)
## 结论
GeomativeStudio的数据处理工具集通过精心设计的类和方法,提供了高效、可靠的数据完整性校验、文件操作和数据存储功能。CRC校验工具采用查表法优化性能,文件操作工具确保线程安全和资源正确管理,XML处理工具支持复杂的配置管理,特定格式文件处理工具满足专业数据交换需求。这些工具协同工作,为地质勘探应用提供了坚实的数据处理基础,确保了数据的完整性、一致性和可追溯性。
@@ -0,0 +1,204 @@
# 数据校验工具
<cite>
**本文档引用的文件**
- [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)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档深入解析GeomativeStudio中实现的数据完整性校验机制,重点分析CRC16和CRC32算法的具体实现方式。文档详细说明了标准多项式选择、查表法优化策略、字节序处理及内存对齐优化等关键技术,并阐述这些校验工具在设备通信协议数据包、配置文件传输和测量数据存储中的应用场景。
## 项目结构
GeomativeStudio项目中的CRC校验工具位于cpp/Tools目录下,包含Crc16.cpp和Crc32.cpp两个核心实现文件,以及对应的头文件Crc16.h和Crc32.h。这些工具被集成在Zmodem文件传输协议中,用于确保数据传输的完整性。
```mermaid
graph TD
A[CRC校验工具] --> B[Crc16.cpp]
A --> C[Crc32.cpp]
A --> D[Crc16.h]
A --> E[Crc32.h]
B --> F[Zmodem.cpp]
C --> F
F --> G[文件传输]
F --> H[数据通信]
```
**图示来源**
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1-L1940)
**章节来源**
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
## 核心组件
CRC16和CRC32类实现了数据完整性校验的核心功能。Crc16类使用16位循环冗余校验,而Crc32类使用32位循环冗余校验。两个类都采用了查表法优化策略,通过预计算的CRC表来提高计算效率。
**章节来源**
- [Crc16.h](file://h/Crc16.h#L1-L37)
- [Crc32.h](file://h/Crc32.h#L1-L37)
## 架构概述
CRC校验工具的架构设计采用了静态查表法,通过预计算的CRC表来加速校验计算过程。初始化时生成CRC表,后续计算直接查表获取结果,大大提高了计算效率。该架构被设计为轻量级工具类,可被多个模块复用。
```mermaid
classDiagram
class Crc16 {
+static unsigned short table[256]
+static int initialized
-unsigned short crc
+Crc16(unsigned short init_value)
+void update(int c)
+unsigned short value()
}
class Crc32 {
+static unsigned long table[256]
+static int initialized
-unsigned long crc
+Crc32(unsigned long init_value)
+void update(int c)
+unsigned long value()
}
Crc16 <|-- Crc32 : 继承自
```
**图示来源**
- [Crc16.h](file://h/Crc16.h#L12-L27)
- [Crc32.h](file://h/Crc32.h#L12-L28)
## 详细组件分析
### CRC16组件分析
CRC16类实现了16位循环冗余校验算法,采用CCITT标准多项式x^16 + x^12 + x^5 + 10x1021)。该实现使用查表法优化,通过预计算256个字节的CRC值来加速计算过程。
#### CRC16类图
```mermaid
classDiagram
class Crc16 {
+static unsigned short table[256]
+static int initialized
-unsigned short crc
+Crc16(unsigned short init_value)
+void update(int c)
+unsigned short value()
}
```
**图示来源**
- [Crc16.h](file://h/Crc16.h#L12-L27)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L28-L54)
### CRC32组件分析
CRC32类实现了32位循环冗余校验算法,采用IEEE 802.3标准多项式x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 10xEDB88320)。与CRC16类似,也采用了查表法优化策略。
#### CRC32类图
```mermaid
classDiagram
class Crc32 {
+static unsigned long table[256]
+static int initialized
-unsigned long crc
+Crc32(unsigned long init_value)
+void update(int c)
+unsigned long value()
}
```
**图示来源**
- [Crc32.h](file://h/Crc32.h#L12-L28)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L28-L51)
### 实际应用分析
CRC校验工具在Zmodem文件传输协议中得到了广泛应用,用于确保数据传输的完整性。在文件传输过程中,发送方计算数据的CRC值并随数据一起发送,接收方重新计算CRC值进行比对,以检测传输过程中的任何数据损坏。
#### Zmodem协议中的CRC使用流程
```mermaid
sequenceDiagram
participant 发送方
participant 接收方
发送方->>发送方 : 初始化CRC32(0xFFFFFFFFL)
发送方->>发送方 : 计算数据CRC值
发送方->>接收方 : 发送数据和CRC校验码
接收方->>接收方 : 初始化CRC32(0xFFFFFFFFL)
接收方->>接收方 : 计算接收到数据的CRC值
接收方->>接收方 : 比对CRC值
alt CRC匹配
接收方->>发送方 : 发送确认
else CRC不匹配
接收方->>发送方 : 请求重传
end
```
**图示来源**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L797-L820)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1643-L1670)
**章节来源**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L790-L890)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1640-L1700)
## 依赖分析
CRC校验工具作为独立的工具类,被Zmodem文件传输模块所依赖。这种设计实现了关注点分离,使得CRC校验功能可以被多个模块复用,同时保持了代码的可维护性和可测试性。
```mermaid
graph TD
A[Zmodem.cpp] --> B[Crc16.cpp]
A --> C[Crc32.cpp]
B --> D[Crc16.h]
C --> E[Crc32.h]
```
**图示来源**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L5-L6)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L5-L6)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L5-L6)
## 性能考虑
CRC校验工具的性能优化主要体现在以下几个方面:
1. 查表法:通过预计算CRC表,将复杂的多项式除法运算转换为简单的查表操作
2. 静态初始化:CRC表只在首次使用时生成,避免重复计算
3. 内联函数:update方法被定义为内联函数,减少函数调用开销
4. 位运算优化:使用位移和异或操作替代乘除法运算
这些优化策略使得CRC计算具有很高的效率,适合在高频率数据传输场景中使用。
## 故障排除指南
在使用CRC校验工具时,可能遇到以下常见问题及解决方案:
1. **CRC计算结果不一致**
- 检查初始化值是否一致
- 确认多项式标准是否匹配
- 验证字节序处理是否正确
2. **性能瓶颈**
- 确认CRC表已正确初始化
- 检查是否重复创建CRC对象
- 考虑批量处理数据以减少对象创建开销
3. **内存问题**
- CRC表占用256*sizeof(unsigned short)或256*sizeof(unsigned long)内存
- 确保有足够的内存空间
**章节来源**
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L33-L52)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L33-L49)
## 结论
GeomativeStudio中的CRC校验工具实现了高效可靠的数据完整性校验机制。通过采用查表法优化和合理的架构设计,这些工具在保证计算准确性的同时,提供了优异的性能表现。在设备通信协议数据包、配置文件传输和测量数据存储等场景中,CRC校验有效防止了数据损坏,确保了系统的可靠运行。建议在高并发或大文件处理场景中复用CRC对象,以进一步优化性能。
@@ -0,0 +1,121 @@
# 数据格式处理
<cite>
**本文档引用的文件**
- [Markup.cpp](file://cpp/Tools/Markup.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp)
- [Res3DDatFileRecord.cpp](file://cpp/Tools/Res3DDatFileRecord.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [XML配置文件解析与生成](#xml配置文件解析与生成)
3. [文本测量数据读写](#文本测量数据读写)
4. [URF专有数据格式解析](#urf专有数据格式解析)
5. [三维测量结果数据存储](#三维测量结果数据存储)
6. [应用实例](#应用实例)
7. [性能优化与错误容忍](#性能优化与错误容忍)
8. [结论](#结论)
## 引言
Geomative Studio项目涉及多种数据格式的处理,包括用于配置的XML文件、用于测量数据交换的文本文件、专有的URF数据格式以及用于存储三维测量结果的二进制DAT文件。本文件详细阐述了`Markup.cpp``OperTxtFile.cpp``OperUrfFile.cpp``Res3DDatFile.cpp`四个核心模块的实现逻辑,分析其在项目缓存、任务脚本导出和结果文件生成中的应用,并讨论其性能优化与错误处理策略。
## XML配置文件解析与生成
`Markup.cpp`模块提供了一个功能完整的XML文档解析与生成器,其核心是`CMarkup`类。该模块实现了对XML配置文件的节点遍历、属性读取、嵌套结构处理和内存管理。
### 节点遍历与属性读取
该模块通过维护一个`ElemPos`(元素位置)结构数组来高效地表示XML文档的树形结构。每个`ElemPos`结构记录了节点在文档字符串中的起始位置、长度、标签长度、层级深度以及与其他节点的父子、兄弟关系。这种设计避免了在解析时进行昂贵的字符串分割操作,而是通过索引直接定位节点内容。
对于属性读取,模块提供了`SetAttrib``GetAttrib`等方法。当需要设置属性时,它会计算属性在标签字符串中的精确位置,并使用`x_StrInsertReplace`函数进行原地插入或替换,从而最小化内存拷贝开销。
### 嵌套结构处理
模块通过`iElemParent``iElemChild``iElemNext`等指针在`ElemPos`结构中构建了完整的树形关系。这使得`FindElem``IntoElem``OutOfElem`等方法能够高效地在嵌套的XML结构中进行导航。例如,`IntoElem`会将当前上下文移动到当前元素的第一个子元素,而`OutOfElem`则会返回到父元素。
### 内存管理策略
内存管理是该模块的核心优势。它采用了一种“分段数组”(Segmented Array)的策略来管理`ElemPos`结构。`ElemPosTree`类将`ElemPos`对象存储在多个连续的内存块(段)中,而不是一个巨大的连续数组。这避免了在文档变大时重新分配和复制整个数组的性能瓶颈。`GrowElemPosTree`方法在需要时动态增加新的内存段,确保了在处理大型XML文件时的内存效率和性能稳定性。
**节段来源**
- [Markup.cpp](file://cpp/Tools/Markup.cpp#L917-L998)
## 文本测量数据读写
`OperTxtFile.cpp`模块负责处理以文本格式存储的测量数据,支持多种编码和分隔符,主要用于任务脚本和配置的导出。
### 读写实现
该模块通过标准C库的`fopen``fwrite``fclose`函数进行文件操作。`OpenFileforWrite`方法以写入模式打开文件,`WriteFileContent`方法则负责将`CStringArray`中的内容写入文件。
### 编码与分隔符支持
虽然代码中未显式处理编码转换,但通过使用`CString`类,模块天然支持Unicode(UTF-16)和多字节字符集(MBCS)。文件的最终编码取决于系统区域设置和`fopen`函数的内部行为。对于分隔符,该模块采用了一种独特的“固定宽度”格式。`SetParamWidth`方法设置每个字段的固定宽度(默认18个字符),`WriteFileContent`方法会用空格填充不足的字段,从而形成类似表格的对齐效果。这虽然不是传统的逗号或制表符分隔,但提供了一种简单、可读性强的数据格式。
**节段来源**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
## URF专有数据格式解析
`OperUrfFile.cpp`模块专门用于解析和生成URFUniversal Resistivity File)专有数据格式,这是一种用于地球物理电阻率测量的行业标准文本格式。
### 解析规则
URF文件采用纯文本格式,包含注释行、元数据行和数据行。该模块的解析规则主要体现在`WriteUrfPoleInfo``WriteUrfPoleInfo_3D`等方法中:
1. **头部信息**:通过`WriteUrfHeadInfo``Write3DUrfHeadInfo`写入文件描述和单位信息。
2. **几何信息**:以`:Geometry`为分隔符,后跟`ID,X,Y,Z`的列标题,然后是电极的坐标数据。电极坐标的生成逻辑(如温纳装置、偶极装置等)由`WriteElecByAR`系列方法根据不同的测量阵列(AR)类型实现。
3. **测量信息**:以`:Measurements`为分隔符,后跟`A, B, M, N, V/I(ohm), I(mA), Error(%), Chargeability(mV/V)`的列标题,然后是实际的测量数据。
该模块通过`WriteElecByCrossHoleGeomative`等方法从数据库(如`TTaskBindElecInfo`表)中查询电极坐标,实现了URF文件与项目数据的动态绑定。
**节段来源**
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
## 三维测量结果数据存储
`Res3DDatFile.cpp`模块负责将三维测量结果以结构化的二进制布局存储到`.dat`文件中,该文件用于后续的数据处理和成像。
### 结构化存储机制
#### 二进制布局
该模块使用Windows API的`CreateFile``WriteFile`函数直接写入二进制数据。文件布局分为三个部分:
1. **头部**:包含标题、网格列数、行数、列间距、行间距、介质类型和记录点总数。所有数据均以ASCII文本形式写入,每项后跟换行符。
2. **记录数据**:包含多个测量记录。每个记录由A、B、M、N四个电极的坐标(X, Y)和电阻率值`R0`组成。坐标和`R0`均以固定格式的文本写入。
3. **尾部**:写入5个零值,作为文件结束的标记。
#### 元数据嵌入
元数据(如标题、网格尺寸、间距、介质类型)在文件头部以明文形式嵌入。`SetTitle``SetGriding``SetSpacing``SetMedium`等方法用于设置这些元数据。
#### 版本兼容性处理
代码中通过`VAL_ZERO``VAL_MINUS_ONE`等常量定义了默认值和无效值,这有助于在不同版本的软件之间保持一定的兼容性。例如,当电极ID为-1时,表示该电极未使用。然而,代码中未发现显式的版本号字段或复杂的向后/向前兼容性逻辑,其兼容性主要依赖于固定的文件结构和数据类型。
**节段来源**
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp)
- [Res3DDatFileRecord.cpp](file://cpp/Tools/Res3DDatFileRecord.cpp)
## 应用实例
上述数据格式处理模块在Geomative Studio中有着广泛的应用:
- **项目缓存**`Markup.cpp`用于读写`CACHE`目录下的`project.xml``testzone.xml`文件,保存和恢复项目状态。
- **任务脚本导出**`OperTxtFile.cpp`用于生成`.map``.rul`等脚本文件,`OperUrfFile.cpp`用于将任务导出为标准的URF格式,便于与其他软件交换数据。
- **结果文件生成**`Res3DDatFile.cpp`用于将三维测量结果生成`.dat`文件,供后续的反演和成像模块使用。
## 性能优化与错误容忍策略
### 性能优化
- **内存效率**`Markup.cpp`的分段数组设计避免了大文件解析时的内存抖动。
- **I/O效率**`Res3DDatFile.cpp``OperUrfFile.cpp`都使用了`fflush`来控制缓冲区刷新,平衡了性能和数据安全性。
- **算法优化**`Markup.cpp`中的`x_Hash`函数使用了简单的加法哈希,确保了在编码查找时的快速响应。
### 错误容忍策略
- **输入验证**:所有模块在关键操作前都进行了严格的输入验证,例如检查文件指针是否为空、参数是否在有效范围内。
- **异常处理**:通过`GetLastError()`获取系统错误码,并使用`AfxMessageBox``MessageBoxEx`向用户报告详细的错误信息(支持中英文)。
- **资源清理**:在析构函数和`CloseFile`方法中确保文件句柄被正确关闭,防止资源泄漏。
## 结论
Geomative Studio的数据格式处理体系结构清晰,各模块职责分明。`Markup.cpp`提供了一个高效、内存友好的XML处理方案;`OperTxtFile.cpp``OperUrfFile.cpp`分别处理通用文本和行业标准格式;`Res3DDatFile.cpp`则实现了专有的二进制结果存储。这些模块共同支撑了项目的配置管理、数据交换和结果保存功能。尽管在编码转换和版本兼容性方面有进一步提升的空间,但其整体设计稳健,错误处理完善,为地球物理测量软件的可靠运行提供了坚实的基础。
@@ -0,0 +1,274 @@
# 文件操作封装
<cite>
**本文档引用的文件**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp)
- [FileOperTools.h](file://h/FileOperTools.h)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp)
- [MyCopyFile.h](file://h/MyCopyFile.h)
- [AutoLock.cpp](file://cpp/Lock/AutoLock.cpp)
- [AutoLock.h](file://h/Lock/AutoLock.h)
- [RingBuffer.h](file://h/RingBuffer.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档全面解析`FileOperTools.cpp``MyCopyFile.cpp`中封装的文件系统操作功能。重点描述跨平台路径处理(支持Windows风格路径)、目录创建与遍历、文件锁定机制、原子性文件写入、大文件复制优化(缓冲区管理、异步I/O)等关键技术实现。说明这些工具类在项目配置保存、缓存管理、日志写入和数据导出等场景中的使用模式。提供接口调用示例,包括错误码处理、权限异常恢复和磁盘空间预检等最佳实践。分析其与MFC CFile类的差异与优势,以及在多线程环境下的线程安全设计。
## 项目结构
项目包含多个核心目录,其中`cpp/Tools`目录下存放了文件操作相关的工具类实现。`FileOperTools.cpp``MyCopyFile.cpp`位于此目录,分别提供基础文件操作和高级文件复制功能。`h/`目录下有对应的头文件声明。项目还包含日志管理、锁机制等辅助组件,支持文件操作的完整功能实现。
```mermaid
graph TD
subgraph "核心工具"
FileOperTools["FileOperTools.cpp<br/>基础文件操作"]
MyCopyFile["MyCopyFile.cpp<br/>高级文件复制"]
end
subgraph "辅助组件"
AutoLock["AutoLock.cpp<br/>自动锁机制"]
RingBuffer["RingBuffer.h<br/>环形缓冲区"]
end
subgraph "日志系统"
Log["日志文件<br/>(log\\general\\*.txt)"]
end
FileOperTools --> Log
MyCopyFile --> Log
FileOperTools --> AutoLock
MyCopyFile --> AutoLock
```
**图示来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
- [AutoLock.cpp](file://cpp/Lock/AutoLock.cpp#L1-L12)
**本节来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
## 核心组件
`FileOperTools`类提供基础文件操作功能,包括目录复制、文件存在性检查、文件删除、日志写入等。`MyCopyFile`类专注于大文件的高效复制,支持进度监控和传输中断处理。两个类都采用单例模式或静态成员实现,确保全局访问的一致性。通过临界区(CRITICAL_SECTION)实现线程安全的日志写入,避免多线程环境下的数据竞争。
**本节来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
- [FileOperTools.h](file://h/FileOperTools.h#L1-L42)
- [MyCopyFile.h](file://h/MyCopyFile.h#L1-L48)
## 架构概述
文件操作工具采用分层架构设计,上层为功能接口,中层为业务逻辑,底层为系统API调用。`FileOperTools`负责通用文件操作,`MyCopyFile`专注于文件传输场景。两者共享日志系统和线程安全机制。通过`AutoLock`类实现RAII风格的锁管理,确保异常安全的资源释放。
```mermaid
graph TB
subgraph "接口层"
A["CopyFolder"]
B["IsFileExist"]
C["DeleteDirectory"]
D["TransferFile"]
E["GetTransferInfo"]
end
subgraph "逻辑层"
F["FileOperTools"]
G["MyCopyFile"]
end
subgraph "安全层"
H["CRITICAL_SECTION"]
I["AutoLock"]
end
subgraph "系统层"
J["Windows API"]
K["KERNEL32"]
end
A --> F
B --> F
C --> F
D --> G
E --> G
F --> H
G --> H
H --> I
F --> J
G --> J
J --> K
```
**图示来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
- [AutoLock.cpp](file://cpp/Lock/AutoLock.cpp#L1-L12)
## 详细组件分析
### FileOperTools 分析
`CFileOperTools`类实现了一个单例模式的文件操作工具,提供目录复制、文件删除、日志管理等功能。通过`GetInstance()`方法获取唯一实例,确保全局状态的一致性。类中使用临界区保护日志文件的并发写入,避免多线程环境下的数据损坏。
#### 类图
```mermaid
classDiagram
class CFileOperTools {
+CFileOperTools()
+~CFileOperTools()
+static CFileOperTools* GetInstance()
+bool CopyFolder(CString strSrcPath, CString strDstPath)
+bool IsFileExist(CString strFileInfo)
+bool WriteComLog(const CString& strInfo)
+bool WriteComLog(unsigned char *pszData, int iDateLen)
+bool DeleteDirectory(CString strDirPath)
+bool DeleteFileDirect(CString strFilePath)
+CString GetDstFilePathFolder()
+bool GeneralLogName()
+bool DealGeneralLogFunc()
-void CloseComLog()
-static UINT DealGeneralLogThread(LPVOID lParam)
-static CFileOperTools* m_pFileOper
-FILE* m_pComLog
-CRITICAL_SECTION *m_pWriteLogSection
-CString m_strGeneralLogName
}
```
**图示来源**
- [FileOperTools.h](file://h/FileOperTools.h#L11-L42)
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
#### 目录复制流程
```mermaid
flowchart TD
Start([开始复制目录]) --> CheckPath["检查源路径和目标路径"]
CheckPath --> PathValid{"路径有效?"}
PathValid --> |否| ReturnError["返回错误"]
PathValid --> |是| RemoveTrailing["移除路径末尾反斜杠"]
RemoveTrailing --> CreateDir["创建目标目录"]
CreateDir --> FindFiles["查找源目录文件"]
FindFiles --> HasNext{"有更多文件?"}
HasNext --> |否| ReturnSuccess["返回成功"]
HasNext --> |是| GetNextFile["获取下一个文件"]
GetNextFile --> IsDot{"是.或..?"}
IsDot --> |是| FindFiles
IsDot --> |否| IsDir{"是目录?"}
IsDir --> |是| RecursiveCopy["递归复制子目录"]
RecursiveCopy --> FindFiles
IsDir --> |否| CopyFile["复制文件"]
CopyFile --> CheckError{"复制失败?"}
CheckError --> |是| LogError["记录错误并返回"]
CheckError --> |否| FindFiles
```
**图示来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L58-L124)
**本节来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [FileOperTools.h](file://h/FileOperTools.h#L1-L42)
### MyCopyFile 分析
`CMyCopyFile`类专注于大文件的高效、可靠传输。利用Windows API的`CopyFileEx`函数实现带进度回调的文件复制,支持传输过程中的取消操作。通过静态成员变量实现全局日志管理,确保传输日志的集中记录。
#### 类图
```mermaid
classDiagram
class CMyCopyFile {
+CMyCopyFile()
+~CMyCopyFile()
+bool TransferFile(CString strSrcDir, CString strDstDir, CString strFileName)
+void GetTransferInfo(DWORD &dwTransferedBytes, DWORD &dwTotalFileSize)
+int GetTansferLastError()
+void Initialize()
-void PrintLog(const CString& strLog)
-static DWORD CALLBACK CopyProgressInfo(LARGE_INTEGER, LARGE_INTEGER, ...)
-static FILE* g_pCopyFileLog
-static CRITICAL_SECTION* g_pLogCriticSec
-LARGE_INTEGER m_liTransferedBytes
-LARGE_INTEGER m_liTotalFileSize
-int m_iErrorCode
-BOOL m_bIsCancelCopy
}
```
**图示来源**
- [MyCopyFile.h](file://h/MyCopyFile.h#L18-L48)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
#### 文件传输流程
```mermaid
sequenceDiagram
participant Client as "客户端"
participant MyCopyFile as "CMyCopyFile"
participant OS as "操作系统"
Client->>MyCopyFile : TransferFile(参数)
MyCopyFile->>MyCopyFile : 检查源文件属性
MyCopyFile->>MyCopyFile : 删除目标文件
MyCopyFile->>OS : CopyFileEx(带进度回调)
loop 进度更新
OS->>MyCopyFile : 调用CopyProgressInfo
MyCopyFile->>MyCopyFile : 更新传输进度
MyCopyFile->>MyCopyFile : 检查设备连接状态
MyCopyFile->>MyCopyFile : 记录日志
MyCopyFile-->>OS : 返回PROGRESS_CONTINUE
end
OS-->>MyCopyFile : 复制完成
MyCopyFile-->>Client : 返回结果
```
**图示来源**
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L76-L107)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L137-L154)
**本节来源**
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
- [MyCopyFile.h](file://h/MyCopyFile.h#L1-L48)
## 依赖分析
文件操作工具依赖于Windows API进行底层文件操作,使用MFC的CString类处理字符串。通过临界区实现线程同步,依赖系统时间函数获取时间戳。`MyCopyFile`类还依赖`DetcGD10Dev`类检测设备连接状态,实现智能传输中断。
```mermaid
graph LR
FileOperTools --> WindowsAPI
MyCopyFile --> WindowsAPI
FileOperTools --> MFC
MyCopyFile --> MFC
FileOperTools --> AutoLock
MyCopyFile --> AutoLock
MyCopyFile --> DetcGD10Dev
AutoLock --> WindowsAPI
subgraph "外部依赖"
WindowsAPI["Windows API"]
MFC["MFC框架"]
end
subgraph "内部依赖"
DetcGD10Dev["DetcGD10Dev.cpp"]
end
```
**图示来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L5-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L5-L155)
- [AutoLock.cpp](file://cpp/Lock/AutoLock.cpp#L1-L12)
**本节来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
- [AutoLock.cpp](file://cpp/Lock/AutoLock.cpp#L1-L12)
## 性能考虑
文件操作工具在设计时考虑了性能优化。`CopyFolder`方法采用递归方式遍历目录,对于大型目录树可能产生较深的调用栈。`MyCopyFile`使用`CopyFileEx` API,该API内部实现了高效的缓冲区管理和异步I/O,适合大文件传输。日志系统通过临界区保护,但频繁的日志写入可能成为性能瓶颈。建议在生产环境中合理控制日志级别。
## 故障排除指南
常见问题包括文件访问权限不足、磁盘空间不足、路径过长等。`FileOperTools`在操作失败时会记录详细的错误码,可通过`GetLastError()`获取具体原因。`MyCopyFile`提供`GetTansferLastError()`方法获取传输错误码。当遇到"临界区创建失败"错误时,可能是系统资源不足。建议检查磁盘空间、文件权限和系统资源使用情况。
**本节来源**
- [FileOperTools.cpp](file://cpp/Tools/FileOperTools.cpp#L1-L420)
- [MyCopyFile.cpp](file://cpp/Tools/MyCopyFile.cpp#L1-L155)
## 结论
`FileOperTools``MyCopyFile`提供了完整的文件系统操作解决方案。前者侧重于通用文件操作,后者专注于大文件传输场景。两者都实现了线程安全的日志记录,通过临界区保护共享资源。与MFC CFile类相比,这些工具类提供了更高层次的抽象和更丰富的功能,特别是在目录操作和进度监控方面。在多线程环境下,通过RAII风格的`AutoLock`类确保了资源管理的安全性。
@@ -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设备的高效管理和控制。系统设计考虑了单例模式、线程安全和异步操作等性能优化策略,并通过详细的日志记录和错误处理机制保证了系统的稳定性。对于开发者而言,理解这些核心组件的交互方式和设计模式,对于维护和扩展系统功能至关重要。
@@ -0,0 +1,87 @@
# 辅助工具
<cite>
**本文档引用的文件**
- [GUCodeCreator.cpp](file://cpp/Tools/GUCodeCreator.cpp)
- [GUCodeCreator.h](file://h/GUCodeCreator.h)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [excel.h](file://h/excel.h)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp)
- [checkupdate.h](file://h/checkupdate.h)
- [floatedit.cpp](file://cpp/Tools/floatedit.cpp)
- [floatedit.h](file://h/floatedit.h)
- [GetProcessInfo.cpp](file://cpp/Tools/GetProcessInfo.cpp)
- [GetProcessInfo.h](file://h/GetProcessInfo.h)
- [SaveInIP.cpp](file://cpp/Tools/SaveInIP.cpp)
- [SaveInIP.h](file://h/SaveInIP.h)
- [SaveInRes.cpp](file://cpp/Tools/SaveInRes.cpp)
- [SaveInRes.h](file://h/SaveInRes.h)
</cite>
## 目录
1. [设备唯一标识码生成工具](#设备唯一标识码生成工具)
2. [测量数据导出工具](#测量数据导出工具)
3. [版本检查工具](#版本检查工具)
4. [浮点数输入控件增强工具](#浮点数输入控件增强工具)
5. [系统进程信息获取工具](#系统进程信息获取工具)
6. [测量结果存储优化工具](#测量结果存储优化工具)
7. [集成应用场景](#集成应用场景)
8. [资源管理与异常防护](#资源管理与异常防护)
## 设备唯一标识码生成工具
`GUCodeCreator`工具类负责生成设备的唯一标识码(GU Code),该标识码结合了设备的MAC地址和时间戳信息,用于设备认证和授权管理。该工具通过获取网卡的MAC地址,并将其与当前时间的总秒数进行编码,生成一个唯一的字符串标识。
**Section sources**
- [GUCodeCreator.cpp](file://cpp/Tools/GUCodeCreator.cpp#L1-L395)
- [GUCodeCreator.h](file://h/GUCodeCreator.h)
## 测量数据导出工具
`excel`工具类提供了将测量数据导出为Excel文件的功能。该工具利用COM接口与Microsoft Excel应用程序进行交互,实现了数据格式设置、单元格合并和图表生成等高级功能。通过该工具,用户可以将测量结果以结构化的表格形式保存,并进行可视化展示。
**Section sources**
- [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800)
- [excel.h](file://h/excel.h)
## 版本检查工具
`checkupdate`工具类实现了软件版本检查机制,包含请求构建、响应解析和更新提示流程。该工具通过HTTP协议向指定服务器请求版本信息文件,解析响应内容并与本地版本进行比较,从而判断是否需要更新。当检测到新版本时,会提示用户进行更新操作。
**Section sources**
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L800)
- [checkupdate.h](file://h/checkupdate.h)
## 浮点数输入控件增强工具
`floatedit`工具类对浮点数输入控件进行了增强处理,限制了用户输入的整数位和小数位长度,并支持负数输入。该工具通过重写`OnChar``OnKillfocus`等消息处理函数,实现了对输入字符的过滤和格式化,确保用户输入的数据符合预设的精度要求。
**Section sources**
- [floatedit.cpp](file://cpp/Tools/floatedit.cpp#L1-L282)
- [floatedit.h](file://h/floatedit.h)
## 系统进程信息获取工具
`GetProcessInfo`工具类提供了获取系统进程信息的方法,包括根据进程名获取进程ID、根据进程ID获取进程名以及获取父进程ID等。该工具利用Windows API函数`CreateToolhelp32Snapshot``Process32First`等,实现了对系统进程的枚举和查询功能。
**Section sources**
- [GetProcessInfo.cpp](file://cpp/Tools/GetProcessInfo.cpp#L1-L169)
- [GetProcessInfo.h](file://h/GetProcessInfo.h)
## 测量结果存储优化工具
`SaveInIP``SaveInRes`工具类对测量结果的存储进行了优化,支持多种装置类型的测量数据格式转换和文件存储。这些工具根据不同的测量方法和装置类型,将原始测量数据转换为特定格式的文本文件,并写入磁盘。同时,还支持地形信息的写入和文件头的生成。
**Section sources**
- [SaveInIP.cpp](file://cpp/Tools/SaveInIP.cpp#L1-L800)
- [SaveInIP.h](file://h/SaveInIP.h)
- [SaveInRes.cpp](file://cpp/Tools/SaveInRes.cpp#L1-L800)
- [SaveInRes.h](file://h/SaveInRes.h)
## 集成应用场景
这些辅助工具在设备认证、报告生成、系统监控等场景中具有广泛的应用。例如,在设备认证场景中,`GUCodeCreator`生成的唯一标识码可用于验证设备的合法性;在报告生成场景中,`excel`工具可将测量数据导出为Excel文件,便于生成专业的报告;在系统监控场景中,`GetProcessInfo`工具可用于监控关键进程的运行状态。
## 资源管理与异常防护
在使用这些工具时,需要注意资源管理和异常防护。例如,在使用`excel`工具时,应确保Excel应用程序的正确初始化和释放,避免资源泄漏;在使用`checkupdate`工具时,应处理网络请求失败等异常情况,确保程序的稳定性。此外,还应合理使用内存和文件句柄等系统资源,避免资源耗尽导致程序崩溃。
@@ -0,0 +1,330 @@
# 串口通信
<cite>
**本文引用的文件列表**
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp)
- [SComPort.h](file://h/SComPort.h)
- [Constant.h](file://h/Constant.h)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文围绕 SComPort 类对 Windows 串口通信进行系统化技术文档化,重点覆盖:
- 串口初始化流程:CreateFile 创建句柄、SetupComm 配置缓冲区、SetCommState 设置波特率(115200)与数据格式(8位数据位、无校验、1位停止位)
- 异步 I/O 操作中 OVERLAPPED 结构的应用,以及 ReadFile/WriteFile 与 GetOverlappedResult 的配合实现非阻塞读写
- ClearCommError 和 PurgeComm 在错误处理与缓冲区清理中的作用
- 基于事件驱动的通信模式:EV_RXCHAR 接收字符事件与 EV_BREAK 断线检测的实现原理
- 串口打开、数据收发、异常处理与资源释放的完整调用示例
- 多线程环境下线程安全策略与注意事项
## 项目结构
SComPort 类位于工具模块中,提供串口底层封装与上层命令交互能力;相关常量定义位于公共头文件;UI 层通过消息回调处理断线事件。
```mermaid
graph TB
subgraph "工具层"
SComPort["SComPort 类<br/>cpp/Tools/SComPort.cpp"]
SComPortWinXP["SComPort 兼容实现<br/>cpp/Tools/SComPort_winxp.cpp"]
Header["头文件声明<br/>h/SComPort.h"]
Const["常量定义<br/>h/Constant.h"]
end
subgraph "界面层"
MainFrm["主窗口消息处理<br/>cpp/Views/MainFrm.cpp"]
end
SComPort --> Header
SComPort --> Const
SComPortWinXP --> Header
SComPortWinXP --> Const
MainFrm --> |"WM_BREAKLINE"| SComPort
```
图表来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L126-L223)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L126-L221)
- [SComPort.h](file://h/SComPort.h#L14-L71)
- [Constant.h](file://h/Constant.h#L224-L232)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L126-L223)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L126-L221)
- [SComPort.h](file://h/SComPort.h#L14-L71)
- [Constant.h](file://h/Constant.h#L224-L232)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
## 核心组件
- SComPort 类:封装串口打开、配置、读写、Zmodem 收发、断线检测、日志与缓冲区清理等能力
- 常量定义:READBUFFER_SIZE、WRITEBUFFER_SIZE、COMM_TIMEOUT 等
- 主窗口消息处理:接收 WM_BREAKLINE 并关闭对应串口、更新设备状态
章节来源
- [SComPort.h](file://h/SComPort.h#L14-L71)
- [Constant.h](file://h/Constant.h#L224-L232)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
## 架构总览
SComPort 采用 Windows 异步串口 I/O 模式,使用 OVERLAPPED 结构与事件对象实现非阻塞读写;通过 SetCommMask 注册事件掩码,结合 WaitCommEvent 实现事件驱动的接收路径;ClearCommError 用于查询错误与队列长度;PurgeComm 用于清理发送/接收缓冲区;断线检测通过独立线程轮询端口是否存在并发送 WM_BREAKLINE 给 UI。
```mermaid
sequenceDiagram
participant UI as "UI/调用方"
participant Port as "SComPort"
participant WinIO as "Windows 串口API"
participant Mask as "事件掩码(EV_* )"
participant Thread as "断线检测线程"
UI->>Port : 打开串口(OpenComm)
Port->>WinIO : CreateFile(异步标志)
Port->>WinIO : SetupComm(读写缓冲区大小)
Port->>WinIO : Get/SetCommState(波特率115200/8N1)
Port->>WinIO : SetCommMask(EV_RXCHAR/EV_BREAK/...)
Note over Port,WinIO : 初始化完成
UI->>Port : 发送数据(SendDataDirectly)
Port->>WinIO : WriteFile(Overlapped)
WinIO-->>Port : ERROR_IO_PENDING
Port->>WinIO : WaitForSingleObject(Overlapped.hEvent)
WinIO-->>Port : 完成事件
Port->>WinIO : GetOverlappedResult(获取字节数)
UI->>Port : 接收数据(ReceiveDataDirectly)
Port->>WinIO : WaitCommEvent(EV_RXCHAR)
WinIO-->>Port : 事件触发
Port->>WinIO : ClearCommError(查询InQue)
Port->>WinIO : ReadFile(Overlapped)
WinIO-->>Port : ERROR_IO_PENDING
Port->>WinIO : WaitForSingleObject(Overlapped.hEvent)
WinIO-->>Port : 完成事件
Port->>WinIO : GetOverlappedResult(获取字节数)
Thread->>WinIO : CreateFile(轮询)
WinIO-->>Thread : ERROR_FILE_NOT_FOUND
Thread->>UI : SendMessage(WM_BREAKLINE)
UI->>Port : CloseComm()
```
图表来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L156-L223)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L306-L401)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L286-L380)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L382-L420)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L560-L607)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L746-L779)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
## 详细组件分析
### 串口初始化流程
- 句柄创建:使用 CreateFile 打开端口,启用 FILE_FLAG_OVERLAPPED 以支持异步 I/O
- 缓冲区配置:SetupComm 设置读写缓冲区大小(由常量 READBUFFER_SIZE/WRITEBUFFER_SIZE 决定)
- 参数设置:GetCommState 获取当前 DCB,随后设置 BaudRate=115200、ByteSize=8、Parity=NOPARITY、StopBits=ONESTOPBIT,并调用 SetCommState 应用
- 事件掩码:SetCommMask 注册 EV_BREAK、EV_CTS、EV_DSR、EV_ERR、EV_RING、EV_RLSD、EV_RXCHAR、EV_RXFLAG、EV_TXEMPTY 等事件
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L156-L223)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L155-L196)
- [Constant.h](file://h/Constant.h#L224-L226)
### 异步 I/O 与 OVERLAPPED
- 发送路径:SendDataDirectly 中为 OVERLAPPED.hEvent 创建事件对象,调用 WriteFile;若返回 ERROR_IO_PENDING,则通过 WaitForSingleObject 等待事件;最终通过 GetOverlappedResult 获取实际写入字节数
- 接收路径:ReceiveDataDirectly 中先调用 ClearCommError 查询 cbInQue,再根据需要调用 ReadFile;同样在 ERROR_IO_PENDING 情况下等待 Overlapped.hEvent 并用 GetOverlappedResult 获取结果
- Zmodem 路径:ZmodemSendDataDirectly/ZmodemReceiveDataDirectly 使用独立 OVERLAPPED 对象,发送前可 PurgeComm 清理发送缓冲区,接收时根据 cbInQue 读取
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L306-L401)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L716-L763)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L765-L900)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L382-L420)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L286-L380)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L560-L607)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L609-L744)
### 错误处理与缓冲区清理
- ClearCommError:用于查询通信错误标志与输入缓冲区字节数,避免在无数据时盲目 ReadFile
- PurgeComm:在关闭串口或需要清空缓冲区时使用 PURGE_RXCLEAR/PURGE_TXCLEAR/PURGE_RXABORT/PURGE_TXABORT 清理接收/发送队列
- 日志输出:通过 PrintLogLast 将通信过程与错误信息写入日志文件,便于定位问题
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L323-L335)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L268-L284)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L585-L595)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L937-L952)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L267-L284)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L429-L439)
### 事件驱动通信模式
- WaitCommEvent:在接收路径中等待 EV_RXCHAR 等事件触发,避免忙等
- EV_BREAK:断线检测通过 SetCommMask 注册 EV_BREAK,并结合断线检测线程轮询端口是否存在,当端口不可访问时向 UI 发送 WM_BREAKLINE
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L189-L196)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L225-L256)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L188-L196)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L224-L255)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
### 断线检测线程与 UI 回调
- 断线检测线程:SComPortDetectBreakThreadFun 循环尝试以独占方式打开端口,若返回 ERROR_FILE_NOT_FOUND 则判定断线,调用 CloseComm 并通过 SendMessage(WM_BREAKLINE) 通知 UI
- UI 处理:OnBreakLine 中根据通信 ID 关闭对应串口、更新设备状态、刷新界面
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L225-L256)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L224-L255)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
### 串口打开、数据收发、异常处理与资源释放的完整调用示例
- 打开串口:OpenComm -> CreateFile -> SetupComm -> Get/SetCommState -> SetCommMask
- 发送数据:SendDataDirectly -> WriteFile(Overlapped) -> WaitForSingleObject -> GetOverlappedResult
- 接收数据:WaitCommEvent(EV_RXCHAR) -> ClearCommError(cbInQue) -> ReadFile(Overlapped) -> WaitForSingleObject -> GetOverlappedResult
- 异常处理:ERROR_IO_PENDING 分支、超时处理、错误日志
- 资源释放:CloseComm -> PurgeComm -> CloseHandle
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L126-L223)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L306-L401)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L268-L284)
### 多线程环境下的线程安全策略
- 断线检测线程:独立线程轮询端口,避免阻塞主线程;线程内对串口句柄的创建/关闭遵循最小化持有原则
- 串口对象成员:构造函数初始化成员变量,析构函数负责关闭句柄与日志;代码中保留了 m_CriticalSection 字段但未启用,建议在多线程并发访问同一实例时增加互斥保护
- UI 与串口交互:通过消息 WM_BREAKLINE 解耦断线检测与 UI 更新,降低锁竞争
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L31-L57)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L87-L91)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L30-L57)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L86-L90)
## 依赖关系分析
- SComPort 依赖 Windows 串口 APICreateFile、SetupComm、GetCommState、SetCommState、SetCommMask、WaitCommEvent、ReadFile、WriteFile、GetOverlappedResult、ClearCommError、PurgeComm、CloseHandle
- 常量 READBUFFER_SIZE/WRITEBUFFER_SIZE、COMM_TIMEOUT 来自公共头文件
- UI 通过消息 WM_BREAKLINE 与串口断线检测解耦
```mermaid
graph LR
SComPort["SComPort 类"] --> WinAPI["Windows 串口API"]
SComPort --> Const["常量定义"]
SComPort --> UI["主窗口消息处理"]
WinAPI --> |"CreateFile/SetupComm/SetCommState/SetCommMask"| Port["物理串口"]
WinAPI --> |"WaitCommEvent/ReadFile/WriteFile"| Port
WinAPI --> |"ClearCommError/PurgeComm"| Port
```
图表来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L156-L223)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L306-L401)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L268-L284)
- [Constant.h](file://h/Constant.h#L224-L232)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L156-L223)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L306-L401)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L268-L284)
- [Constant.h](file://h/Constant.h#L224-L232)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
## 性能考量
- 缓冲区大小:READBUFFER_SIZE/WRITEBUFFER_SIZE 为 15360 字节,适合批量传输场景;可根据设备数据速率调整
- 超时控制:COMM_TIMEOUT 为 500ms,用于等待事件或 I/O 完成;在高延迟链路中可适当增大
- 异步 I/OOVERLAPPED + 事件对象避免阻塞,提高吞吐;注意避免多个操作共享同一 OVERLAPPED 导致状态混淆
- 日志输出:频繁写日志会影响性能,建议在调试阶段开启,生产环境关闭或降频
[本节为通用指导,无需列出具体文件来源]
## 故障排查指南
- 打开失败:检查 CreateFile 返回值与 GetLastError;确认端口名称格式(含“\\\\.\”前缀)
- 设置参数失败:检查 SetCommState 返回值;确认 DCB 字段赋值顺序与目标平台兼容性
- 无数据可读:使用 ClearCommError 检查 cbInQue;确保已注册 EV_RXCHAR 事件并正确等待
- 发送卡住:确认 WriteFile 返回 ERROR_IO_PENDING 后正确等待 Overlapped.hEvent;检查线程优先级与事件对象创建
- 断线误报:断线检测线程轮询间隔与 UI 回调需匹配;避免重复创建线程导致资源泄漏
- 日志定位:通过 PrintLogLast 输出的时间戳与错误码快速定位问题
章节来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L156-L223)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L323-L335)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L937-L952)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L155-L196)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L286-L380)
- [SComPort_winxp.cpp](file://cpp/Tools/SComPort_winxp.cpp#L560-L607)
## 结论
SComPort 类通过 Windows 异步串口 API 提供了稳定可靠的串口通信能力,覆盖初始化、异步读写、事件驱动接收、断线检测与资源管理。结合 ClearCommError 与 PurgeComm,能够有效处理缓冲区与错误状态;通过 WM_BREAKLINE 与 UI 解耦,提升用户体验。建议在多线程并发访问同一实例时增加互斥保护,并根据实际数据速率调整缓冲区与超时参数。
[本节为总结性内容,无需列出具体文件来源]
## 附录
### 关键流程图:ReceiveDataDirectly
```mermaid
flowchart TD
Start(["进入 ReceiveDataDirectly"]) --> CheckHandle["检查串口句柄是否有效"]
CheckHandle --> |无效| Fail["返回失败"]
CheckHandle --> |有效| ClearErr["ClearCommError 查询错误与InQue"]
ClearErr --> InQueZero{"InQue 是否为0"}
InQueZero --> |是| ReturnFalse["返回 FALSE"]
InQueZero --> |否| CalcNeed["计算需要读取字节数(min(最大读取, InQue))"]
CalcNeed --> Read["ReadFile(Overlapped)"]
Read --> Pending{"返回值是否为 FALSE"}
Pending --> |是 且 错误码为 ERROR_IO_PENDING| Wait["WaitForSingleObject(Overlapped.hEvent)"]
Wait --> Gor["GetOverlappedResult 获取字节数"]
Gor --> Compare["比较实际字节数与期望字节数"]
Compare --> Log["记录日志"]
Log --> ReturnTrue["返回成功"]
Pending --> |否| CheckRead["检查 ReadFile 返回字节数"]
CheckRead --> Log2["记录日志"]
Log2 --> ReturnTrue
```
图表来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L306-L401)
### 关键流程图:SendDataDirectly
```mermaid
flowchart TD
Start(["进入 SendDataDirectly"]) --> CheckHandle["检查串口句柄与输入参数"]
CheckHandle --> |无效| Fail["返回失败"]
CheckHandle --> |有效| Prepare["准备 OVERLAPPED.hEvent 与写缓冲区"]
Prepare --> Write["WriteFile(Overlapped)"]
Write --> Pending{"返回值是否为 FALSE"}
Pending --> |是 且 错误码为 ERROR_IO_PENDING| Wait["WaitForSingleObject(Overlapped.hEvent)"]
Wait --> Timeout{"等待结果"}
Timeout --> |超时| Purge["关闭句柄并返回失败"]
Timeout --> |成功| ReturnTrue["返回成功"]
Pending --> |否| ReturnTrue
```
图表来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
### 关键流程图:断线检测线程
```mermaid
flowchart TD
Loop["循环检测"] --> TryOpen["尝试以独占方式打开串口"]
TryOpen --> OpenFail{"打开失败?"}
OpenFail --> |是 且 错误码为 文件不存在| Break["标记断线并关闭串口"]
Break --> PostMsg["发送 WM_BREAKLINE 给 UI"]
PostMsg --> Exit["退出线程"]
OpenFail --> |否| CloseHandle["关闭句柄并继续循环"]
CloseHandle --> Sleep["Sleep(短时间)"]
Sleep --> Loop
```
图表来源
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L225-L256)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
@@ -0,0 +1,250 @@
# 文件传输协议
<cite>
**本文档引用的文件**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp)
- [Zmodem.h](file://h/Zmodem.h)
- [_zmodem.h](file://h/_zmodem.h)
- [FileTransfer.h](file://h/FileTransfer.h)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [SComPort.h](file://h/SComPort.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档全面阐述了基于Zmodem协议的可靠文件传输实现。该协议在Geomative Studio项目中用于设备与主机之间的固件升级、脚本文件和测量数据传输。Zmodem协议通过其强大的错误恢复机制、断点续传功能和高效的二进制传输,确保了在串行通信等不可靠信道上的数据完整性。本分析将深入解析Zmodem类的核心状态机,包括ZRQINIT请求初始化、ZRINIT应答、ZFILE文件信息帧、ZDATA数据帧、ZEOF文件结束和ZFIN传输结束等关键帧类型的交互流程。同时,文档将详细说明CRC-32校验、断点续传(通过ZRPOS携带文件偏移量)和错误恢复(ZCRC校验请求)机制的工作原理,并分析SendSingleFile和ReceiveSingleFile方法中数据分块读写、帧头封装(SendBinaryHeader)和数据帧发送(SendDataFrame)的实现细节。
## 项目结构
Geomative Studio项目是一个用于地质测量设备管理的复杂软件系统。文件传输功能是其核心模块之一,主要由`cpp/Tools/`目录下的工具类实现。与文件传输直接相关的文件包括`Zmodem.cpp``Zmodem.h`,它们实现了Zmodem协议的核心逻辑。`Zmodem`类继承自`FileTransfer`基类,后者定义了文件传输的通用接口。为了支持Zmodem协议,项目还包含了`Crc16.cpp``Crc32.cpp`文件,用于计算数据校验和。通信底层由`SComPort`类处理,它提供了与串口设备通信的接口。整个文件传输模块通过`FileTransfer`模块进行集成,为上层应用提供统一的文件收发功能。
```mermaid
graph TB
subgraph "文件传输模块"
Zmodem[Zmodem.cpp<br/>Zmodem协议实现]
FileTransfer[FileTransfer.cpp<br/>传输基类]
Crc32[Crc32.cpp<br/>CRC-32校验]
Crc16[Crc16.cpp<br/>CRC-16校验]
end
subgraph "通信模块"
SComPort[SComPort.h<br/>串口通信]
end
subgraph "应用层"
FileTransferModule[FileTransfer模块<br/>文件传输应用]
end
Zmodem --> FileTransfer
Zmodem --> Crc32
Zmodem --> Crc16
Zmodem --> SComPort
FileTransferModule --> Zmodem
```
**Diagram sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1-L1940)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp#L1-L47)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
- [SComPort.h](file://h/SComPort.h#L1-L74)
**Section sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1-L1940)
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
- [FileTransfer.h](file://h/FileTransfer.h#L1-L49)
## 核心组件
Zmodem协议的核心组件是`Zmodem`类,它封装了协议的所有状态机和数据处理逻辑。该类通过继承`FileTransfer`基类,实现了`Send``Receive`两个核心接口。`Zmodem`类维护了多个关键状态变量,如`transmitted_file_position`(已发送的文件位置)、`received_file_position`(已接收的文件位置)和`receiver_wants_crc32`(接收方是否支持CRC-32),这些变量共同驱动着协议的状态转换。协议的可靠性主要依赖于`SendBinaryHeader``ReadHeader``SendDataFrame`等方法,它们负责数据的封装、解析和校验。此外,`GetRinitHeader``SyncWithReceiver`等方法处理了协议的初始化和同步过程,确保了通信双方的协调一致。
**Section sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L33-L1940)
- [Zmodem.h](file://h/Zmodem.h#L31-L140)
## 架构概述
Zmodem协议的架构是一个典型的请求-响应式状态机,其核心是围绕一系列预定义的帧类型(Frame Types)进行交互。整个传输过程始于发送方的`ZRQINIT`请求,接收方通过`ZRINIT`帧进行应答,完成初始化握手。随后,发送方通过`ZFILE`帧发送文件名和元数据,接收方确认后,数据传输进入主循环,由`ZDATA`数据帧和`ZACK`确认帧构成。当文件传输完毕,发送方发送`ZEOF`帧,接收方确认后,发送方再发送`ZFIN`帧结束整个会话。该架构通过`ZRPOS`帧实现了断点续传,通过`ZCRC`帧实现了错误恢复,并通过`CAN`序列提供了紧急中断机制。
```mermaid
sequenceDiagram
participant 发送方 as 发送方 (Zmodem)
participant 接收方 as 接收方 (Zmodem)
发送方->>接收方 : ZRQINIT (请求初始化)
接收方->>发送方 : ZRINIT (初始化应答)
发送方->>接收方 : ZFILE (文件信息)
接收方->>发送方 : ZRPOS (请求从指定位置开始)
loop 数据传输
发送方->>接收方 : ZDATA (数据帧)
接收方->>发送方 : ZACK (确认)
end
发送方->>接收方 : ZEOF (文件结束)
接收方->>发送方 : ZRPOS (确认)
发送方->>接收方 : ZFIN (会话结束)
接收方->>发送方 : 'OO' (确认)
```
**Diagram sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L87-L126)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L385-L451)
- [_zmodem.h](file://h/_zmodem.h#L15-L36)
## 详细组件分析
### Zmodem状态机分析
Zmodem协议的状态机是其可靠性的核心。状态机的运行由`Send``Receive`方法驱动,它们分别调用`SendSingleFile``ReceiveSingleFile`来处理单个文件的传输。状态转换主要通过`ReadHeader`方法接收的帧类型来触发。例如,在`SendSingleFile`方法中,一个`ZCRC`帧会触发发送方重新计算并发送文件的CRC校验值;一个`ZRPOS`帧则会触发发送方跳转到指定的文件偏移量继续发送。在`ReceiveSingleFile`方法中,状态机通过`SendHexHeader`主动发送`ZRPOS`帧来请求数据,根据接收到的`ZDATA``ZEOF``ZSKIP`等帧来决定后续动作。这种基于事件驱动的状态机设计,使得协议能够灵活应对各种网络状况。
```mermaid
stateDiagram-v2
[*] --> 初始化
初始化 --> 发送文件信息 : ZFILE
发送文件信息 --> 等待响应 : 发送ZFILE
等待响应 --> 数据传输 : ZRPOS
等待响应 --> 跳过文件 : ZSKIP
等待响应 --> 错误恢复 : ZCRC
数据传输 --> 发送数据帧 : ZDATA
发送数据帧 --> 等待确认 : 发送ZDATA
等待确认 --> 数据传输 : ZACK
等待确认 --> 错误恢复 : TIMEOUT
错误恢复 --> 发送数据帧 : 重发
发送数据帧 --> 文件结束 : ZEOF
文件结束 --> 等待结束 : 发送ZEOF
等待结束 --> 传输结束 : ZRPOS
传输结束 --> [*] : ZFIN
```
**Diagram sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L153-L258)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L558-L775)
**Section sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L153-L775)
### 校验与错误恢复机制分析
Zmodem协议通过CRC校验和超时重试机制来保证数据的完整性。协议支持CRC-16和CRC-32两种校验算法,由`receiver_wants_crc32`标志位决定。`Crc32``Crc16`类实现了校验算法,其中`Crc32`类使用了预计算的查找表来提高计算效率。当接收方检测到数据帧的CRC校验失败时,它会发送一个`ZNAK`(否定应答)或`ZCRC`(请求校验)帧。发送方在`SyncWithReceiver`方法中处理这些错误,根据情况重发数据或重新同步。`ReadDataFrame`方法是错误处理的关键,它会循环读取数据直到收到正确的`GOTCRCW`等结束标志,否则会返回`ZERROR`。此外,协议还定义了`TIMEOUT``GARBAGE_COUNT`等错误码,用于处理超时和垃圾数据。
```mermaid
flowchart TD
A[开始读取数据帧] --> B{是否为ZDLE?}
B --> |是| C[读取转义字符]
B --> |否| D{是否为有效数据?}
D --> |是| E[更新CRC校验]
D --> |否| F[处理XON/XOFF]
C --> G{转义字符类型}
G --> H[ZCRCE/G/Q/W] --> I[读取4字节CRC]
G --> J[ZCAN] --> K[返回ZCAN]
G --> L[ZRUB0/1] --> M[替换为0x7f/0xff]
I --> N{CRC校验是否通过?}
N --> |是| O[返回GOTCRC*]
N --> |否| P[返回ZERROR]
E --> Q{缓冲区满?}
Q --> |否| B
Q --> |是| R[返回ZERROR]
```
**Diagram sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1154-L1340)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
**Section sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1154-L1340)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
### 数据传输流程分析
文件传输的核心流程由`SendSingleFile``ReceiveSingleFile`方法实现。发送流程始于`Send`方法,它首先发送`ZRQINIT`帧,然后进入`SendSingleFile`。在`SendSingleFile`中,发送方构造包含文件名和长度的`ZFILE`帧并发送,随后等待接收方的`ZRPOS`指令。一旦收到`ZRPOS`,发送方调用`SendFileContents`方法,该方法循环读取文件数据,封装成`ZDATA`帧发送,并根据策略(如`ZCRCW`)等待接收方的`ZACK`确认。接收流程始于`Receive`方法,它调用`WakeUpSender`发送`ZRINIT`帧,然后进入`ReceiveSingleFile`。接收方通过循环发送`ZRPOS`帧来请求数据,`ReadDataFrame`方法负责接收和校验`ZDATA`帧,并将有效数据写入文件。整个流程通过`m_WriteBuff``buff`等缓冲区来优化I/O性能。
**Section sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L153-L378)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L558-L775)
## 依赖分析
Zmodem协议的实现依赖于多个层次的组件。最底层是`SComPort`类,它通过`ZmodemSendDataDirectly``ZmodemReceiveDataDirectly`方法提供串口的直接读写能力。`Zmodem`类依赖于`Crc32``Crc16`类来计算数据校验和。`Zmodem`类本身是`FileTransfer`抽象基类的具体实现,它必须实现`Send``Receive`两个纯虚函数。此外,`Zmodem`类还依赖于标准C库的文件操作函数(如`fopen`, `fread`, `fclose`)来处理本地文件。这些依赖关系清晰地划分了职责,使得协议逻辑与底层通信、文件系统和校验算法解耦。
```mermaid
classDiagram
class FileTransfer {
<<abstract>>
+Send(files[] char*) BOOL
+Receive(Path CString) BOOL
-error(fmt char*, ...)
-status(fmt char*, ...)
}
class Zmodem {
-port CSComPort*
-file FILE*
-file_length long
-byte_count long
-receiver_wants_crc32 int
-received_file_position long
+Send(files[] char*) BOOL
+Receive(Path CString) BOOL
-SendSingleFile(name char*) int
-ReceiveSingleFile(Path CString) int
-SendBinaryHeader(length int, type int, header char*) void
-ReadHeader(header char*) int
-SendDataFrame(buffer char*, length int, frameend int) void
}
class Crc32 {
-crc unsigned long
+Crc32(init_value unsigned long)
+update(c int) void
+value() unsigned long
}
class Crc16 {
-crc unsigned short
+Crc16(init_value unsigned short)
+update(c int) void
+value() unsigned short
}
class CSComPort {
+ZmodemSendDataDirectly(pDataBuff char*, iDataSize int) BOOL
+ZmodemReceiveDataDirectly(pDataBuff char*, iDataSize int*) BOOL
}
FileTransfer <|-- Zmodem : "继承"
Zmodem --> Crc32 : "使用"
Zmodem --> Crc16 : "使用"
Zmodem --> CSComPort : "使用"
```
**Diagram sources**
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
- [Zmodem.h](file://h/Zmodem.h#L31-L140)
- [Crc32.h](file://h/Crc32.h#L12-L28)
- [Crc16.h](file://h/Crc16.h#L12-L27)
- [SComPort.h](file://h/SComPort.h#L14-L73)
**Section sources**
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
- [Zmodem.h](file://h/Zmodem.h#L31-L140)
- [Crc32.h](file://h/Crc32.h#L12-L28)
- [Crc16.h](file://h/Crc16.h#L12-L27)
- [SComPort.h](file://h/SComPort.h#L14-L73)
## 性能考虑
Zmodem协议的性能主要体现在其高效的二进制传输和流控机制上。协议通过`ZBIN32``ZBIN`帧头支持二进制传输,避免了ASCII编码的开销。`SendDataFrame`方法在发送数据时,会根据`receiver_wants_crc32`标志选择使用CRC-32或CRC-16,CRC-32虽然计算开销稍大,但能提供更强的错误检测能力。为了优化性能,代码中使用了`m_WriteBuff`写缓冲区,将多个`SendChar`调用合并为一次`ZmodemSendDataDirectly`调用,减少了系统调用的次数。在接收端,`ReadBuff`方法也实现了读缓冲,提高了数据读取效率。此外,`receiver_buffer_length`参数允许接收方告知发送方其缓冲区大小,从而实现简单的流量控制,防止接收方缓冲区溢出。
## 故障排除指南
当文件传输失败时,应首先检查日志文件(如`log\\zmodemSZLog.txt``log\\zmodemRZLog.txt`)。常见的错误包括:
- **ZERROR**: 通用错误,可能由多种原因引起,需结合上下文日志分析。
- **TIMEOUT**: 通信超时,检查串口连接、波特率设置和设备电源。
- **ZCAN**: 通信被对方取消,检查是否有用户手动中断或设备异常。
- **Bad CRC**: 数据校验失败,通常由通信线路噪声或波特率不匹配引起。
- **Open file failed**: 无法创建或打开文件,检查目标路径权限和磁盘空间。
代码中通过`error``status`方法输出详细的调试信息,并通过`PrintLogLast`方法将时间戳信息写入日志,便于问题定位。对于`ZCRC`错误,协议会自动请求重传,但如果错误频繁发生,则应检查物理连接。
**Section sources**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L28-L47)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1906-L1921)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp#L28-L46)
## 结论
本文档详细分析了Geomative Studio项目中基于Zmodem协议的文件传输实现。该实现是一个功能完整、健壮可靠的协议栈,它通过精心设计的状态机、强大的CRC校验和灵活的断点续传机制,确保了在复杂工业环境下的数据传输成功率。`Zmodem`类的代码结构清晰,职责分明,通过继承和组合的方式,有效地管理了与底层通信、文件系统和校验算法的依赖关系。该模块为设备的固件升级、脚本部署和数据回传提供了坚实的基础,是Geomative Studio系统不可或缺的核心组件。
@@ -0,0 +1,326 @@
# 网络通信
<cite>
**本文引用的文件**
- [TcpClient.h](file://h/TcpClient.h)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp)
- [TransferCtrl.h](file://h/TransferCtrl.h)
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
- [Constant.h](file://h/Constant.h)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件围绕 TcpClient 类实现的 TCP 客户端通信机制进行深入解析,覆盖 socket 创建、SOCK_STREAM 流式套接字配置、SO_LINGER 和 SO_KEEPALIVE 等套接字选项的作用与效果;connect 建立连接的三次握手过程与超时策略;SendData/RecvData 中 send/recv 的调用逻辑、非阻塞模式下的 select 使用、MSG_PEEK 探测接收状态与错误码处理;ReConnect 重连机制的实现、closesocket 资源释放与新 socket 重建的必要性;GetConnectStatus 通过 select+recv(MSG_PEEK) 组合检测连接存活状态的技术细节。最后给出连接管理、数据收发、异常重连与资源清理的完整流程图与示例路径,并说明在设备固件升级与数据同步场景中的应用。
## 项目结构
该项目为桌面应用工程,网络通信相关代码集中在 Tools 子目录,核心类为 TcpClient 与派生类 CTransferCtrl;协议定义位于 CtrlProtocolDef.h;常量与全局配置位于 Constant.h;设备管理与同步界面位于 Views 子目录;固件升级逻辑位于 Tools 子目录。
```mermaid
graph TB
subgraph "网络工具层"
TC["TcpClient<br/>h/TcpClient.h<br/>cpp/Tools/TcpClient.cpp"]
TCtrl["CTransferCtrl<br/>h/TransferCtrl.h<br/>cpp/Tools/TransferCtrl.cpp"]
end
subgraph "协议与常量"
Proto["CtrlProtocolDef.h"]
Const["Constant.h"]
end
subgraph "业务视图与操作"
View["devmngframe.cpp"]
Upg["checkupdate.cpp"]
end
TCtrl --> TC
TCtrl --> Proto
TC --> Const
View --> TCtrl
Upg --> TCtrl
```
图表来源
- [TcpClient.h](file://h/TcpClient.h#L1-L76)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L1-L449)
- [TransferCtrl.h](file://h/TransferCtrl.h#L1-L50)
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L1-L200)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L220-L235)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L120)
章节来源
- [TcpClient.h](file://h/TcpClient.h#L1-L76)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L1-L120)
- [TransferCtrl.h](file://h/TransferCtrl.h#L1-L50)
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L1-L120)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L220-L235)
## 核心组件
- TcpClient:封装 TCP 套接字生命周期、连接管理、数据收发、连接状态检测与重连。
- CTransferCtrl:基于 TcpClient 的控制协议封装,负责控制命令的打包、发送与响应解析,以及与业务层交互。
章节来源
- [TcpClient.h](file://h/TcpClient.h#L18-L76)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L26-L120)
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L50)
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L120-L180)
## 架构总览
下图展示 TcpClient 与 CTransferCtrl 的类关系、关键成员与方法,以及与协议定义的关联。
```mermaid
classDiagram
class CTcpClient {
+CTcpClient()
+~CTcpClient()
+Initialize() bool
+ConnectToServer(strIP, wPort) bool
+ReConnect() bool
+SendData(pData, iLen) int
+RecvData(pData, iLen, iActualLen) bool
+GetConnectStatus() bool
+CloseConnect() bool
+Disconnect() bool
+ClearRecvBuffer() bool
-InitailTcp() bool
-ConnectServer(strAddr, wPort) bool
-m_strIP : CString
-m_wPort : WORD
-m_iSndBuf : int
-m_iRcvBuf : int
-m_sockClient : SOCKET
-m_bIsConnect : bool
-m_bIsInitialed : bool
-m_pClearRcvBuf : char*
}
class CTransferCtrl {
+Initialize() bool
+SendCtrlInfo(pCtrlHeader, pData, wDataLen, DataType) bool
+RecvCtrlMsg(pData, pLen, iMaxLen, iTimeout) int
+RecvRspMsg(pData, pLen, iMaxLen, iTimeout) int
+GetCtrlRspLength(ucCMd) int
+InitialClient() bool
+IsCtrlMsg(ucCMd) bool
+IsPlcStatusMsg(ucCmd, ucSrcType) bool
+GetPlcAddr() uint32
+GetCurrCtrlCmd() int
-RecvEnoughMsg(pData, iLen, iTimeOut) bool
-RecvCommRspMsg(pData, pLen, iMaxLen, iRcvTimeout, bIsRcvCtrl) int
-SendCtrlInfoToDev(pTransInfo, pData, wDataLen, ucDataType) bool
}
CTransferCtrl --|> CTcpClient : "继承"
```
图表来源
- [TcpClient.h](file://h/TcpClient.h#L18-L76)
- [TransferCtrl.h](file://h/TransferCtrl.h#L34-L50)
## 详细组件分析
### 套接字创建与流式配置
- socket 创建:构造函数初始化成员,InitailTcp 在首次使用前创建流式套接字(AF_INET, SOCK_STREAM)。
- 缓冲区设置:通过 SO_RCVBUF/SO_SNDBUF 设置收发缓冲区大小。
- 连接保活:启用 SO_KEEPALIVE,提升链路异常检测能力。
- 关闭策略:禁用 SO_LINGER(立即丢弃未发送数据),避免长时间等待导致阻塞。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L48-L99)
### connect 建立连接与三次握手
- 连接发起:ConnectServer 将目标地址转换为 sockaddr_in 并调用 connect。
- 三次握手:由系统内核完成,应用层无需显式处理握手细节。
- 超时策略:当前实现未对 connect 设置超时,如需超时可在上层封装 select 或非阻塞 + 超时判断(建议在业务层统一处理)。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L101-L130)
### SendData 发送逻辑
- 连接状态检查:发送前调用 GetConnectStatus,若连接中断则返回错误。
- send 调用:调用 send 发送数据,记录日志与错误码。
- 返回值语义:返回实际发送字节数或错误标识,便于上层判断。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L149-L177)
### RecvData 接收逻辑与非阻塞 select
- 非阻塞探测:使用 select 设置超时(微秒级),在无数据时快速返回。
- 可读判定:select 返回正值且 FD_ISSET 检测到可读时,执行 recv。
- 异常处理:recv 返回非正数时标记连接中断并更新状态。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L282-L354)
### GetConnectStatus 连接存活检测
- select 立即轮询:使用零超时的 select 检查可读事件。
- MSG_PEEK 探测:对可读套接字执行 MSG_PEEK 探测,若返回值小于等于 0,通常表示对端关闭或连接异常。
- 状态维护:根据探测结果更新 m_bIsConnect。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L201-L249)
### ReConnect 重连机制
- 资源释放:先调用 CloseConnect 关闭当前连接。
- 新建套接字:调用 InitailTcp 重新创建套接字,以规避某些平台/驱动下“仅关闭连接无法再次成功”的限制。
- 再连接:使用原 IP/端口重新 ConnectToServer。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L252-L278)
### CTransferCtrl 控制协议封装
- 初始化:Initialize 调用基类 InitailTcp 完成套接字准备。
- 发送控制:SendCtrlInfoToDev 构造协议头与数据,调用 SendData 发送。
- 接收控制:RecvCtrlMsg/RecvRspMsg/RecvCommRspMsg 实现头部解析、长度校验、CRC 校验与超时处理。
- 协议常量:使用 CtrlProtocolDef.h 中的命令字、结构体与枚举。
章节来源
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L72-L180)
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L400)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L441-L548)
### 设备固件升级与数据同步场景
- 固件升级:checkupdate.cpp 展示了通过网络下载升级文件、向设备发送文件与执行升级命令的流程,体现网络通信在升级中的作用。
- 数据同步:devmngframe.cpp 展示了设备参数同步、任务参数下发与云端托管任务的交互,CTransferCtrl 在其中承担控制通道。
章节来源
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L120)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1042-L1336)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
## 依赖关系分析
- CTransferCtrl 依赖 TcpClient 提供的套接字生命周期与收发能力。
- CTransferCtrl 依赖 CtrlProtocolDef.h 的协议结构与命令字。
- TcpClient 依赖 Constant.h 中的缓冲区大小与超时常量。
- 视图层与操作层通过 CTransferCtrl 间接使用网络通信。
```mermaid
graph LR
TCtrl["CTransferCtrl"] --> TC["CTcpClient"]
TCtrl --> Proto["CtrlProtocolDef.h"]
TC --> Const["Constant.h"]
View["devmngframe.cpp"] --> TCtrl
Upg["checkupdate.cpp"] --> TCtrl
```
图表来源
- [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L1-L120)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L1-L120)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L220-L235)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1-L120)
## 性能考量
- 缓冲区大小:通过 SO_RCVBUF/SO_SNDBUF 调整可减少系统调用次数,提高吞吐。
- 非阻塞接收:使用 select 微秒级超时,避免长时间阻塞,适合高频轮询场景。
- MSG_PEEK 探测:零拷贝探测连接状态,降低开销。
- 重连策略:在出现异常时主动重建套接字,避免复用旧句柄导致的不可达。
[本节为通用指导,无需列出具体文件来源]
## 故障排查指南
- 连接失败:检查 InitailTcp 是否成功创建套接字、SOCK_STREAM 参数是否正确、SO_LINGER 与 SO_KEEPALIVE 设置是否生效。
- 发送失败:关注 WSAGetLastError 返回值,结合日志定位错误码。
- 接收超时:确认 RecvData 的 select 超时设置是否合理,避免过短导致频繁超时。
- 连接中断:GetConnectStatus 的 MSG_PEEK 探测返回非正数时,应视为连接异常并触发重连。
- 重连无效:若仅关闭连接而不重建套接字,可能无法再次连接,需遵循 ReConnect 的重建策略。
章节来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L48-L99)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L149-L177)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L282-L354)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L201-L249)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L252-L278)
## 结论
TcpClient 提供了简洁可靠的 TCP 客户端基础能力:套接字创建与配置、连接管理、非阻塞数据收发、连接状态探测与重连。CTransferCtrl 在此基础上实现了控制协议的编解码与业务交互,支撑设备固件升级与数据同步等场景。通过 MSG_PEEK 与 select 的组合,能够高效检测连接状态并在异常时快速恢复。建议在业务层补充 connect 超时与更细粒度的错误分类,以进一步提升鲁棒性。
[本节为总结性内容,无需列出具体文件来源]
## 附录
### 关键流程图
#### 连接建立与状态检测序列
```mermaid
sequenceDiagram
participant App as "应用"
participant Client as "CTcpClient"
participant Kernel as "系统内核"
App->>Client : "Initialize()"
Client->>Kernel : "socket(AF_INET, SOCK_STREAM)"
Client-->>App : "返回初始化结果"
App->>Client : "ConnectToServer(IP, Port)"
Client->>Kernel : "connect(目标地址)"
Kernel-->>Client : "三次握手完成/失败"
Client-->>App : "返回连接结果"
App->>Client : "GetConnectStatus()"
Client->>Kernel : "select(零超时)+recv(MSG_PEEK)"
Kernel-->>Client : "返回可读/不可读"
Client-->>App : "返回连接状态"
```
图表来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L48-L130)
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L201-L249)
#### 数据发送与接收流程
```mermaid
flowchart TD
Start(["进入 RecvData"]) --> CheckConn["检查连接状态"]
CheckConn --> ConnOK{"连接正常?"}
ConnOK --> |否| RetFalse["返回失败"]
ConnOK --> |是| SelectWait["select 设置微秒级超时"]
SelectWait --> SelRet{"select 返回值"}
SelRet --> |错误| HandleErr["记录错误并返回失败"]
SelRet --> |超时(0)| RetZero["返回成功(0字节)"]
SelRet --> |可读(>0)| FDCheck["FD_ISSET 检测套接字"]
FDCheck --> FDOK{"可读信号有效?"}
FDOK --> |否| HandleErr
FDOK --> |是| Recv["recv 接收数据"]
Recv --> RecvRet{"recv 返回值<=0"}
RecvRet --> |是| MarkDown["标记连接中断并返回失败"]
RecvRet --> |否| SaveLen["保存实际接收长度"]
SaveLen --> Log["记录日志"]
Log --> Done(["返回成功"])
```
图表来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L282-L354)
#### 重连机制流程
```mermaid
flowchart TD
RCStart(["ReConnect 开始"]) --> CloseOld["CloseConnect 关闭旧连接"]
CloseOld --> NewSock["InitailTcp 重新创建套接字"]
NewSock --> NewSockOK{"创建成功?"}
NewSockOK --> |否| ShowErr["提示套接字初始化失败"]
ShowErr --> RCEnd(["结束"])
NewSockOK --> |是| Reconnect["ConnectToServer(IP, Port)"]
Reconnect --> RCResult{"连接成功?"}
RCResult --> |是| RCOK["返回成功"]
RCResult --> |否| RCFail["返回失败"]
RCOK --> RCEnd
RCFail --> RCEnd
```
图表来源
- [TcpClient.cpp](file://cpp/Tools/TcpClient.cpp#L252-L278)
### 应用示例路径
- 设备参数同步与云端托管任务交互:参见 [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L470-L504)
- 固件升级流程(下载、发送文件、执行升级命令):参见 [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1042-L1336)
- 控制协议发送与接收:参见 [TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L120-L180)、[TransferCtrl.cpp](file://cpp/Tools/TransferCtrl.cpp#L245-L400)
@@ -0,0 +1,425 @@
# 通信工具
<cite>
**本文档引用的文件**
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp)
- [SComPort.h](file://h\SComPort.h)
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp)
- [TcpClient.h](file://h\TcpClient.h)
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp)
- [Zmodem.h](file://h\Zmodem.h)
- [FileTransfer.cpp](file://cpp\Tools\FileTransfer.cpp)
- [FileTransfer.h](file://h\FileTransfer.h)
- [FileTransfer_crul.cpp](file://cpp\Tools\FileTransfer_crul.cpp)
- [FileTransfer_crul.h](file://h\FileTransfer_crul.h)
- [HttpDownload.cpp](file://cpp\Tools\HttpDownload.cpp)
- [HttpDownload.h](file://h\HttpDownload.h)
- [Constant.h](file://h\Constant.h)
- [CtrlProtocolDef.h](file://h\CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [串口通信模块](#串口通信模块)
3. [TCP通信模块](#tcp通信模块)
4. [Zmodem文件传输协议](#zmodem文件传输协议)
5. [文件传输协作机制](#文件传输协作机制)
6. [HTTP下载功能](#http下载功能)
7. [应用场景与调用示例](#应用场景与调用示例)
8. [最佳实践](#最佳实践)
9. [结论](#结论)
## 引言
GeomativeStudio中的通信工具集成了多种通信方式,包括串口通信、TCP通信、Zmodem协议文件传输和HTTP下载功能。这些工具为设备连接、固件升级和数据同步等关键功能提供了底层支持。本文档详细分析了这些通信模块的实现机制与使用方法。
## 串口通信模块
### SComPort类实现
`SComPort`类封装了Windows平台下的串口通信功能,提供了异步读写、超时控制和多线程安全处理等特性。
**串口初始化与配置**
`SComPort`类通过`OpenComm`方法初始化串口连接,设置通信参数如波特率(115200)、数据位(8位)、奇偶校验(无)和停止位(1位)。该类使用重叠I/O(Overlapped I/O)实现异步通信,确保主线程不会被阻塞。
```mermaid
classDiagram
class CSComPort {
+CString m_szComName
+HANDLE m_hCom
+HWND m_hOwnerWnd
+long m_lCommID
+DCB m_dcbBlock
+char m_aWriteBuffer[WRITEBUFFER_SIZE]
+int m_iWriteSize
+char m_aReadBuffer[READBUFFER_SIZE]
+int m_iReadSize
+DWORD m_dwBLThreadID
+HANDLE m_hBLThread
+BOOL m_bIsDetBreakFun
+BOOL m_bIsScanBreak
+DWORD m_dwFactdata
+FILE* m_Log
+CSComPort()
+CSComPort(HWND hOwnerWnd, long lCommID)
+~CSComPort()
+BOOL FindComName(CStringArray* pStringArray)
+BOOL OpenComm(CString szComName)
+void SetOwnerWnd(HWND hOwnerWnd)
+void SetCommID(long lCommID)
+void CloseComm()
+BOOL ReceiveDataDirectly(char* pDataBuff, int* iDataSize)
+BOOL SendDataDirectly(char* pDataBuff, int iDataSize)
+void SetScanBreakSign(BOOL bIsScanBreak)
+void ClearCommSendBuff()
+void ClearCommReceiveBuff()
+BOOL ZmodemReceiveDataDirectly(char* pDataBuff, int* iDataSize)
+BOOL ZmodemSendDataDirectly(char* pDataBuff, int iDataSize)
+static UINT SComPortDetectBreakThreadFun(LPVOID pParam)
}
```
**Diagram sources**
- [SComPort.h](file://h\SComPort.h#L14-L73)
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L31-L285)
**异步读写机制**
`ReceiveDataDirectly``SendDataDirectly`方法实现了异步读写功能。读取操作首先通过`ClearCommError`检查输入缓冲区中的数据量,然后使用`ReadFile`函数进行异步读取。如果`ReadFile`立即返回`ERROR_IO_PENDING`,则通过`GetOverlappedResult`等待操作完成。
**超时控制**
通信超时通过`GetOverlappedResult`的最后一个参数`TRUE`实现,该参数指示函数应阻塞直到操作完成或超时。日志记录功能通过`fopen`打开日志文件"LOG\\commLog.txt"实现,所有发送和接收的数据都会被记录。
**多线程安全处理**
`SComPort`类通过`m_hBLThread`线程监控串口连接状态。`SComPortDetectBreakThreadFun`线程函数定期尝试重新打开串口,如果失败则通过`SendMessage`通知所有者窗口串口已断开。
**Section sources**
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L306-L403)
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L527-L576)
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L225-L256)
## TCP通信模块
### TcpClient类实现
`CTcpClient`类实现了TCP客户端通信功能,支持连接管理、数据收发和异常重连。
```mermaid
classDiagram
class CTcpClient {
+CString m_strIP
+WORD m_wPort
+SOCKET m_sockClient
+int m_iRcvBuf
+int m_iSndBuf
+bool m_bIsConnect
+char* m_pClearRcvBuf
+CTcpClient()
+~CTcpClient()
+bool InitailTcp()
+bool ConnectServer(CString strAddr, WORD wPort)
+bool ConnectToServer(CString strIP, WORD wPort)
+int SendData(const char* pData, int wLen)
+bool CloseConnect()
+bool GetConnectStatus()
+bool ReConnect()
+bool RecvData(char* pData, int iLen, int& iActualLen)
+bool Disconnect()
+bool ClearRecvBuffer()
}
```
**Diagram sources**
- [TcpClient.h](file://h\TcpClient.h#L18-L75)
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L26-L39)
**连接管理**
`InitailTcp`方法初始化套接字,设置套接字选项如`SO_LINGER`、接收/发送缓冲区大小和`SO_KEEPALIVE``ConnectServer`方法建立与服务器的连接,`CloseConnect`方法关闭连接并释放资源。
**数据收发**
`SendData`方法使用`send`函数发送数据,`RecvData`方法使用`select`函数实现非阻塞接收。`select`函数检查套接字是否有数据可读,超时时间为25毫秒。
**异常重连**
`ReConnect`方法实现了异常重连机制。当连接断开时,先调用`CloseConnect`关闭现有连接,然后重新初始化套接字并通过`ConnectToServer`重新连接。
**Section sources**
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L48-L97)
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L101-L130)
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L252-L278)
## Zmodem文件传输协议
### Zmodem类实现
`Zmodem`类实现了Zmodem协议,用于在串口连接上进行可靠的文件传输。
```mermaid
classDiagram
class Zmodem {
+CSComPort* port
+FILE* file
+long file_length
+long byte_count
+int file_count
+char file_name[128]
+char buffer[BUFFSIZE]
+unsigned long m_FileSize
+int m_ByteTransfer
+char m_WriteBuff[8192]
+int m_WriteBuffLength
+int m_nBufReadIndex
+FILE* zmodemLog
+DWORD dwBegin
+char cReadLog[2048]
+int nLogLength
+int nIndex
+Zmodem(CSComPort* rs232_port)
+~Zmodem()
+BOOL Send(char* files[])
+BOOL Receive(CString Path)
+BOOL SendCancelString()
+int GetTransferPosit()
+int GetFileSize()
}
```
**Diagram sources**
- [Zmodem.h](file://h\Zmodem.h#L31-L142)
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L33-L56)
**帧结构解析**
Zmodem协议使用多种帧类型进行通信,包括`ZRQINIT``ZRINIT``ZFILE``ZDATA``ZEOF``ZFIN``ReadHeader`方法解析接收到的帧头,`SendBinaryHeader`方法发送二进制帧头。
**错误校验**
Zmodem协议使用CRC-16或CRC-32进行错误校验。`Crc16``Crc32`类用于计算数据的校验和。`SendDataFrame`方法在发送数据帧时包含校验信息。
**断点续传机制**
`ReceiveSingleFile`方法实现了断点续传功能。当接收文件时,如果文件已存在且大小与远程文件相同,则发送`ZRPOS`帧请求从上次中断的位置继续传输。
**Section sources**
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L128-L127)
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L558-L774)
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L253-L258)
## 文件传输协作机制
### FileTransfer与FileTransfer_crul协作
`FileTransfer``FileTransfer_crul`类共同实现了设备与主机间的文件传输功能。
```mermaid
classDiagram
class FileTransfer {
+CSComPort* port
+FILE* file
+long file_length
+long byte_count
+int file_count
+char file_name[128]
+char buffer[BUFFSIZE]
+FileTransfer()
+virtual ~FileTransfer()
+virtual void error(char* fmt, ...)
+virtual void status(char* fmt, ...)
+virtual BOOL Send(char* files[]) = 0
+virtual BOOL Receive(CString Path) = 0
}
class FileTransfer_crul {
+CURL* m_pCrEasyHandl
+CURL* m_pCrPuteasyHandl
+FILE* m_pLog
+CString m_strUrl
+CString m_strSavePath
+CString m_strSaveName
+bool m_bIsNeedProgress
+bool m_bIsNeedErrInfo
+int m_nTimeOut
+bool m_bIsGobalInitial
+bool m_bIsHttpsFlag
+bool m_bIsSSLCertify
+FileTransfer_crul()
+virtual ~FileTransfer_crul()
+bool Inital()
+void UnInital()
+void SetOption(EnOptFlag enFlag, CString strInfo, bool bFlag = false)
+bool DownloadFile()
+DOUBLE GetFileSize()
+bool GetUrlResConValild()
+void InitalLogInfo()
+static size_t WriteToFile(void* ptr, size_t size, size_t nmemb, void* userp)
+static int xferinfo(void* p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
+static size_t WriteToBuff(void* ptr, size_t size, size_t nmemb, void* userp)
+static size_t WriteFuncForUrlTest(void* ptr, size_t size, size_t nmemb, void* userp)
+void PrintLog(CString strLog)
}
FileTransfer <|-- Zmodem : "extends"
FileTransfer_crul --> CURL : "uses"
```
**Diagram sources**
- [FileTransfer.h](file://h\FileTransfer.h#L26-L48)
- [FileTransfer_crul.h](file://h\FileTransfer_crul.h#L55-L110)
- [FileTransfer_crul.cpp](file://cpp\Tools\FileTransfer_crul.cpp#L24-L62)
**协作流程**
`FileTransfer`作为基类定义了文件传输的接口,`Zmodem`类继承自`FileTransfer`并实现了基于串口的文件传输。`FileTransfer_crul`类使用libcurl库实现HTTP/HTTPS文件下载功能。
**Section sources**
- [FileTransfer.cpp](file://cpp\Tools\FileTransfer.cpp#L28-L47)
- [FileTransfer_crul.cpp](file://cpp\Tools\FileTransfer_crul.cpp#L151-L281)
## HTTP下载功能
### HttpDownload类实现
`HttpDownload`类实现了HTTP协议下载功能,支持多线程下载和断点续传。
```mermaid
classDiagram
class HttpDownload {
+BOOL m_bSupportResume
+BOOL m_bResume
+BOOL m_bStop
+BOOL m_bIsUseFile
+BOOL m_bFileLocked
+BOOL m_bAddSize
+DWORD m_dwDownloadSize
+int runningThreadCnt
+int nComplete
+CString m_strServer
+CString m_strObject
+CString m_strSavePath
+CString m_strTempSavePath
+CString m_strReferer
+CString m_strDownloadUrl
+CTime m_TimeLastModified
+UINT m_nPort
+FILE* globalFile
+DWORD m_dwFileSize
+int m_dwThreadCnt
+InforImpl inforImpl
+NewTask TaskInfo
+CSocket m_pSocket
+HttpDownload()
+virtual ~HttpDownload()
+void FreeMemory()
+void SetStop(bool stop)
+BOOL StartHttpTask(NewTask task)
+bool CreateNewFile(CString fileName, DWORD size)
+void GetInfofromDevision()
+bool GetInfofromTemp(CString filename)
+void CreateInforImpl(CString str)
+UINT SendRequest(BOOL bHead = false)
+UINT GetInfo(LPCTSTR lpszHeader, DWORD& dwContentLength, DWORD& dwStatusCode, CTime& TimeLastModified)
+BOOL ParseURL(CString str)
+CTime GetTime(LPCTSTR lpszTime)
+bool WriteInfoToFile()
+bool WriteToFile(CString filePath, DWORD pos, char* buffer, int len)
+void CreateThread()
+bool Download(int index)
}
class InforImpl {
+CString server
+CString object
+CString savePath
+DWORD fileSize
+int threadCnt
+DWORD downloadSize
+FromToImpl* fromToImpl
}
class FromToImpl {
+DWORD from
+DWORD to
}
class NewTask {
+CString server
+CString object
+UINT port
+UINT threadCnt
+CString savepath
}
HttpDownload --> InforImpl : "contains"
HttpDownload --> FromToImpl : "contains"
HttpDownload --> NewTask : "uses"
```
**Diagram sources**
- [HttpDownload.h](file://h\HttpDownload.h#L69-L154)
- [HttpDownload.cpp](file://cpp\Tools\HttpDownload.cpp#L26-L46)
**多线程下载**
`StartHttpTask`方法首先发送HTTP请求获取文件大小,然后根据文件大小和线程数分配下载任务。每个线程负责下载文件的一部分,通过`Range`头指定下载范围。
**断点续传**
`GetInfofromTemp`方法从临时配置文件中读取已下载的文件信息,实现断点续传功能。如果文件大小发生变化,则重新开始下载。
**Section sources**
- [HttpDownload.cpp](file://cpp\Tools\HttpDownload.cpp#L68-L219)
- [HttpDownload.cpp](file://cpp\Tools\HttpDownload.cpp#L104-L209)
## 应用场景与调用示例
### 设备连接
```mermaid
sequenceDiagram
participant 应用程序
participant SComPort
participant 串口硬件
应用程序->>SComPort : OpenComm("COM1")
SComPort->>串口硬件 : CreateFile("\\\\.\\COM1")
串口硬件-->>SComPort : 返回句柄
SComPort->>SComPort : 设置DCB参数
SComPort-->>应用程序 : 返回TRUE
```
**Diagram sources**
- [SComPort.cpp](file://cpp\Tools\SComPort.cpp#L127-L223)
### 固件升级
```mermaid
sequenceDiagram
participant 应用程序
participant Zmodem
participant SComPort
应用程序->>Zmodem : Send(["firmware.bin"])
Zmodem->>SComPort : SendDataDirectly(ZRQINIT帧)
SComPort->>Zmodem : 接收响应
Zmodem->>Zmodem : 发送ZFILE帧
Zmodem->>SComPort : 发送数据帧
loop 数据传输
SComPort->>Zmodem : 接收数据帧
Zmodem->>SComPort : 发送ZACK确认
end
Zmodem->>SComPort : 发送ZFIN帧
SComPort->>Zmodem : 接收ZFIN响应
Zmodem-->>应用程序 : 返回TRUE
```
**Diagram sources**
- [Zmodem.cpp](file://cpp\Tools\Zmodem.cpp#L62-L127)
### 数据同步
```mermaid
sequenceDiagram
participant 应用程序
participant TcpClient
participant 服务器
应用程序->>TcpClient : ConnectToServer("192.168.1.100", 8080)
TcpClient->>服务器 : 建立TCP连接
服务器-->>TcpClient : 连接成功
TcpClient-->>应用程序 : 返回TRUE
应用程序->>TcpClient : SendData(同步数据)
TcpClient->>服务器 : 发送数据
服务器-->>TcpClient : 返回响应
TcpClient-->>应用程序 : 返回发送字节数
```
**Diagram sources**
- [TcpClient.cpp](file://cpp\Tools\TcpClient.cpp#L101-L130)
## 最佳实践
### 线程同步
使用Windows API的同步机制,如`CreateThread``WaitForSingleObject`,确保多线程环境下的数据一致性。
### 资源释放
在析构函数中释放所有分配的资源,如关闭文件句柄、套接字和线程句柄。
### 异常处理
使用`try-catch`块捕获异常,并通过日志记录详细的错误信息。
## 结论
GeomativeStudio的通信工具集成功了多种通信方式,为设备连接、固件升级和数据同步提供了可靠的基础。通过深入分析这些模块的实现机制,开发者可以更好地理解和使用这些工具,提高开发效率和系统稳定性。