15a5a1a07b35d432794ea20e841bd7e002538590..63686244746925d43248ceaf8d9e31f50df68a72
2025-09-01 LAPTOP-SNT8I5JK\Boounion
Merge branch 'clh'
636862 对比 | 目录
2025-08-27 mrDarker
Merge branch 'clh' into liuyang
3e0cea 对比 | 目录
2025-08-27 mrDarker
1. 设备配方列表添加显示配方名称
7ec501 对比 | 目录
2025-08-26 mrDarker
Merge branch 'clh' into liuyang
43c7dc 对比 | 目录
2025-08-09 mrDarker
Merge branch 'clh' into liuyang
a8fb41 对比 | 目录
2025-08-05 mrDarker
1. SGMeasurement的PLC监听超时设置5秒 2. SGMeasurement的PLC监听类添加注释
82114d 对比 | 目录
2025-08-05 mrDarker
1. SGMeasurement实现规划的地址 2. 优化读取位时输入的地址不是8的倍数的问题 3. 添加读写心跳的功能
f56051 对比 | 目录
2025-08-04 mrDarker
Merge branch 'clh' into liuyang
e53508 对比 | 目录
2025-08-04 mrDarker
1. 修改SGMeasurement工程文件,添加生成后事件和远程调试
f4a795 对比 | 目录
2025-08-04 mrDarker
1. SGMeasurement模块添加CC-Link通信 2. SGMeasurement模块添加PLC交互
a3943d 对比 | 目录
2025-08-02 mrDarker
1. 配方界面区分Master和设备列表
91632a 对比 | 目录
2025-08-02 mrDarker
Merge branch 'clh' into liuyang
72f380 对比 | 目录
2025-08-02 mrDarker
1. 添加计算时间戳宏 2. 重写切割两片玻璃函数 3. 添加分组过滤干扰点的函数
201046 对比 | 目录
2025-08-01 mrDarker
1. 添加日志文件
61ac29 对比 | 目录
2025-08-01 mrDarker
1. 新增以下功能函数并集成: - InitStorage():初始化存储区域 - StartStorage():开始数据存储 - ...
5a8bbd 对比 | 目录
2025-08-01 mrDarker
1. 添加光谱传感器模块
2be151 对比 | 目录
已添加32个文件
已修改5个文件
8417 ■■■■■ 文件已修改
SourceCode/Bond/GangBond2860.sln 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.cpp 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.h 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.cpp 1594 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.h 479 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/32bit/SGIF.h 1641 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/32bit/SGIFPJ.dll 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/32bit/SGIFPJ.lib 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/64bit/SGIF.h 1641 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/64bit/SGIFPJ.dll 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/64bit/SGIFPJ.lib 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/DLL/ZY系列通信库参考手册-V2.3.pdf 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/Logger.cpp 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/Logger.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/PLCSignalListener.h 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurement.cpp 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurement.h 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurement.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurement.vcxproj 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurement.vcxproj.filters 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurement.vcxproj.user 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp 1212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h 343 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/framework.h 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/pch.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/pch.h 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/res/SGMeasurement.ico 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/res/SGMeasurement.rc2 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/res/menu_close.ico 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/res/menu_restore.ico 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/resource.h 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/SGMeasurement/targetver.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.cpp 104 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.h 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/RecipeManager.cpp 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/RecipeManager.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/GangBond2860.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31729.503
# Visual Studio Version 17
VisualStudioVersion = 17.13.35913.81 d17.13
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BEQLibrary", "BEQLibrary\BEQLibrary.vcxproj", "{8421CE64-06F9-48F4-A3F3-ACFB683C94D4}"
EndProject
@@ -16,6 +16,8 @@
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BoounionPLC", "BoounionPLC\BoounionPLC.vcxproj", "{6DC0600E-5588-4033-A281-3626A4F74B67}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EAPSimulator", "EAPSimulator\EAPSimulator.vcxproj", "{9EA43050-B71C-47A7-AC90-F0D7A88C5F50}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SGMeasurement", "SGMeasurement\SGMeasurement.vcxproj", "{F8087F20-3A3E-18F2-09E3-9C139642EB58}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -81,6 +83,14 @@
        {9EA43050-B71C-47A7-AC90-F0D7A88C5F50}.Release|x64.Build.0 = Release|x64
        {9EA43050-B71C-47A7-AC90-F0D7A88C5F50}.Release|x86.ActiveCfg = Release|Win32
        {9EA43050-B71C-47A7-AC90-F0D7A88C5F50}.Release|x86.Build.0 = Release|Win32
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Debug|x64.ActiveCfg = Debug|x64
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Debug|x64.Build.0 = Debug|x64
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Debug|x86.ActiveCfg = Debug|Win32
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Debug|x86.Build.0 = Debug|Win32
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Release|x64.ActiveCfg = Release|x64
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Release|x64.Build.0 = Release|x64
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Release|x86.ActiveCfg = Release|Win32
        {F8087F20-3A3E-18F2-09E3-9C139642EB58}.Release|x86.Build.0 = Release|Win32
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
#include "pch.h"
#include "CCLinkIEControl.h"
CCCLinkIEControl::CCCLinkIEControl() : CPerformanceMelsec(BoardType::CC_LINK_IE_CONTROL) {}
CCCLinkIEControl::~CCCLinkIEControl() = default;
int CCCLinkIEControl::SetBoardModeEx(CCLinkIEControlMode mode) {
    return SetBoardMode(static_cast<short>(mode));
}
CCLinkIEControlMode CCCLinkIEControl::GetBoardModeEx() {
    short nMode = 0;
    const int nResult = GetBoardMode(nMode);
    if (nResult != 0) {
        return CCLinkIEControlMode::UNKNOWN;
    }
    return ConvertToCCLinkIEControlMode(nMode);
}
int CCCLinkIEControl::GetBoardStatusEx(BoardStatus& status) {
    const int nResult = GetBoardStatus(status);
    if (nResult != 0) {
        return nResult;
    }
    return ValidateBoardStatus(status);
}
int CCCLinkIEControl::ReadLedStatus(LedStatus& outLedStatus) {
    std::vector<short> vecLedBuffer;
    const int nRet = ReadBoardLed(vecLedBuffer);
    if (nRet != 0) {
        return nRet;
    }
    if (vecLedBuffer.empty()) {
        UpdateLastError(ERROR_CODE_INVALID_DATA);
        return ERROR_CODE_INVALID_DATA;
    }
    // è§£æžå„位状态
    const short nBuffer = vecLedBuffer[0];
    outLedStatus.bExtPw = (nBuffer & (1 << 15)) != 0;
    outLedStatus.bRd = (nBuffer & (1 << 6)) != 0;
    outLedStatus.bDLnk = (nBuffer & (1 << 5)) != 0;
    outLedStatus.bPrm = (nBuffer & (1 << 4)) != 0;
    outLedStatus.bErr = (nBuffer & (1 << 3)) != 0;
    outLedStatus.bSd = (nBuffer & (1 << 2)) != 0;
    outLedStatus.bMode = (nBuffer & (1 << 1)) != 0;
    outLedStatus.bRun = (nBuffer & (1 << 0)) != 0;
    return 0;
}
CCLinkIEControlMode CCCLinkIEControl::ConvertToCCLinkIEControlMode(const short nMode) {
    switch (static_cast<CCLinkIEControlMode>(nMode)) {
        case CCLinkIEControlMode::ONLINE: return CCLinkIEControlMode::ONLINE;                           // åœ¨çº¿
        case CCLinkIEControlMode::OFFLINE: return CCLinkIEControlMode::OFFLINE;                         // ç¦»çº¿
        case CCLinkIEControlMode::INTER_STATION_TEST: return CCLinkIEControlMode::INTER_STATION_TEST;   // ç«™é—´æµ‹è¯•
        case CCLinkIEControlMode::LINE_TEST: return CCLinkIEControlMode::LINE_TEST;                     // çº¿è·¯æµ‹è¯•
        case CCLinkIEControlMode::LOOPBACK_TEST: return CCLinkIEControlMode::LOOPBACK_TEST;             // è‡ªå›žé€æµ‹è¯•
        case CCLinkIEControlMode::HW_TEST: return CCLinkIEControlMode::HW_TEST;                         // H/W测试
        case CCLinkIEControlMode::BUS_IF_TEST: return CCLinkIEControlMode::BUS_IF_TEST;                 // æ€»çº¿I/F测试
        default: return CCLinkIEControlMode::UNKNOWN;
    }
}
int CCCLinkIEControl::ValidateBoardStatus(const BoardStatus& status) {
    if (status.nStationValue < 1 || status.nStationValue > 120) {
        return ERROR_CODE_STATION_OUT_OF_RANGE; // ç«™å·è¶…出范围
    }
    if (status.nGroupValue < 0 || status.nGroupValue > 32) {
        return ERROR_CODE_GROUP_OUT_OF_RANGE;   // ç»„超出范围
    }
    if (status.nNetworkValue < 1 || status.nNetworkValue > 239) {
        return ERROR_CODE_NETWORK_OUT_OF_RANGE; // ç½‘络号超出范围
    }
    return 0; // æ ¡éªŒé€šè¿‡
}
int CCCLinkIEControl::ReadDataEx(const StationIdentifier& station, DeviceType enDevType, long devNo, long size, void* pData)
{
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, static_cast<short>(size));
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        const short nDevType = CalculateDeviceType(station, enDevType);
        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, devNo, &size, pData);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
    }
    return nRet;
}
SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
#ifndef CCLINKIECONTROL_H
#define CCLINKIECONTROL_H
#include "PerformanceMelsec.h"
enum class CCLinkIEControlMode : short {
    UNKNOWN = 0x0194,               // Î´Öª
    ONLINE = 0x0000,                // åœ¨çº¿
    OFFLINE = 0x0002,               // ç¦»çº¿
    INTER_STATION_TEST = 0x0005,    // ç«™é—´æµ‹è¯•
    LINE_TEST = 0x0006,             // çº¿è·¯æµ‹è¯•
    LOOPBACK_TEST = 0x0007,         // è‡ªå›žé€æµ‹è¯•
    HW_TEST = 0x0009,               // H/W测试
    BUS_IF_TEST = 0x000E            // æ€»çº¿I/F测试
};
class CCCLinkIEControl final : public CPerformanceMelsec {
public:
    CCCLinkIEControl();
    ~CCCLinkIEControl() override;
    struct LedStatus {
        bool bExtPw; // å¤–部电源状态 (b15)
        bool bRd;    // æ•°æ®æŽ¥æ”¶çŠ¶æ€ (b6)
        bool bDLnk;  // æ•°æ®é“¾æŽ¥çŠ¶æ€ (b5)
        bool bPrm;   // ç®¡ç†åŠŸèƒ½çŠ¶æ€ (b4)
        bool bErr;   // é”™è¯¯çŠ¶æ€ (b3)
        bool bSd;    // æ•°æ®å‘送状态 (b2)
        bool bMode;  // åŠ¨ä½œæ¨¡å¼ (b1)
        bool bRun;   // è¿è¡ŒçŠ¶æ€ (b0)
        // è½¬æ¢ä¸ºå­—符串,用于调试
        std::string ToString() const {
            std::ostringstream oss;
            oss << "CC-Link IE Control Network LED Status: {"
                << "\n  Ext Power: " << (bExtPw ? "ON" : "OFF")
                << "\n  Receive Data: " << (bRd ? "Receiving" : "Not Receiving")
                << "\n  Data Link: " << (bDLnk ? "Linked" : "Not Linked")
                << "\n  Management: " << (bPrm ? "Managing" : "Not Managing")
                << "\n  Error: " << (bErr ? "Error Detected" : "No Error")
                << "\n  Send Data: " << (bSd ? "Sending" : "Not Sending")
                << "\n  Mode: " << (bMode ? "Executing" : "Not Executing")
                << "\n  Run: " << (bRun ? "Running" : "Stopped")
                << "\n}";
            return oss.str();
        }
    };
    // è¯»å–目标站点CPU类型
    // short ReadCPUCodeEx(const StationIdentifier& station, short& nCPUCode);
    // æ¿æ¨¡å¼èŽ·å–/设置
    int SetBoardModeEx(CCLinkIEControlMode mode);
    CCLinkIEControlMode GetBoardModeEx();
    // èŽ·å–æ¿çŠ¶æ€
    int GetBoardStatusEx(BoardStatus& status);
    // è¯»å–LED状态
    int ReadLedStatus(LedStatus& outLedStatus);
    int ReadDataEx(const StationIdentifier& station, DeviceType enDevType, long devNo, long size, void* pData);
private:
    static CCLinkIEControlMode ConvertToCCLinkIEControlMode(short nMode);
    static int ValidateBoardStatus(const BoardStatus& status);
};
#endif //CCLINKIECONTROL_H
SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1594 @@
// PerformanceMelsec.cpp: implementation of the CPerformanceMelsec class.
//
//////////////////////////////////////////////////////////////////////
#include "pch.h"
#include "PerformanceMelsec.h"
#include <windows.h>
#include <iostream>
#include <fstream>
#ifdef _DEBUG
#undef THIS_FILE
static char* THIS_FILE = __FILE__;
#define new DEBUG_NEW
#endif
#ifdef _DEBUG
#define LOG_ERROR(msg) \
std::cerr << "[ERROR] " << __FILE__ << ":" << __LINE__ << " (" << __FUNCTION__ << ") - " << msg << std::endl;
#define LOG_DEBUG(msg) \
std::cout << "[DEBUG] " << __FILE__ << ":" << __LINE__ << " (" << __FUNCTION__ << ") - " << msg << std::endl;
#else
#define LOG_ERROR(msg)
#define LOG_DEBUG(msg)
#endif
// åˆå§‹åŒ–静态成员变量
std::unordered_map<int, std::string> CPerformanceMelsec::m_mapError = {
    // æ¿å—SDK错误码
    {0, "No error, communication successful."},
    {1, "Driver not started. The driver is not running."},
    {2, "Timeout error (board response error). Request not completed within timeout."},
    {66, "Already OPEN error. The specified channel is OPEN."},
    {68, "Path error. The specified path is invalid."},
    {69, "Unsupported function execution error."},
    {70, "Station number error. The specified station number is invalid."},
    {71, "No received data error (during RECV function)."},
    {77, "Memory allocation error / insufficient memory resources."},
    {85, "SEND/RECV channel number error."},
    {100, "Board H/W resource busy."},
    {101, "Routing exception."},
    {102, "Board driver I/F error: Failed to send request data to the board driver."},
    {103, "Board driver I/F error: Failed to receive response data from the board driver."},
    {130, "Initial software component No. Error."},
    {131, "Capacity error."},
    {133, "Parameter error."},
    {16385, "Specified target station number does not exist."},
    {16386, "Received a request that the target station cannot process."},
    {16418, "Failed to create the event history file."},
    {16420, "Failed to access the event history file."},
    {16421, "Another board driver is using the event history file."},
    {16432, "The specified soft component type does not exist."},
    {16433, "Soft component specification error: Out of range or invalid start I/O or block number."},
    {16512, "Request data exception: Invalid data or unsupported module."},
    {16685, "File association error: Failed to create the event history file."},
    {16837, "File association error: Event history file does not exist."},
    {18944, "Link association error: Network does not exist, unsupported CPU, or incorrect network No./station number."},
    {-1, "Invalid path. The specified function is not supported for this path."},
    {-2, "Start component No. error. The specified component is out of range."},
    {-3, "Capacity error. The capacity exceeds the component range."},
    {-6, "Component type error. The specified type during write is invalid."},
    {-8, "Channel No. error. The channel specified is invalid."},
    {-12, "Target path error. The specified path points to an invalid target."},
    {-13, "Write protection area error. The specified range is protected."},
    {-16, "Target path conflict. The path conflicts with write protection settings."},
    {-17, "Device not found or target not responding."},
    {-18, "Invalid target. The device does not support the operation."},
    {-19, "Invalid path operation. An unsupported path operation was executed."},
    {-31, "DLL library call failed or path not initialized."},
    {-32, "Resource timeout error. Communication timed out or exceeded resource limits."},
    {-33, "Communication timeout error. The target is not responding or timed out."},
    {-34, "Unsupported communication target error. The specified network No. or station No. points to an unsupported model."},
    {-35, "Registry access error."},
    {-36, "Registry access error."},
    {-37, "Communication initialization error. The settings for initializing the communication path are invalid."},
    {-42, "Key information error. Authentication failed."},
    {-43, "Marking event error. TC waiting event write was executed on the CPU."},
    {-61, "Marking event error. TC waiting event write was executed on the CPU."},
    {-62, "Event waiting timeout. The specified external event waiting timed out."},
    {-63, "Timeout value is out of range."},
    {-64, "Timeout value is out of range."},
    {-65, "Event waiting timeout. The specified external event waiting timed out."},
    {-66, "Timeout-induced resource shortage."},
    {-67, "Irrelevant file access execution error."},
    {-69, "Operation executed, but the module does not support the function."},
    {-70, "The target event processing module returned a rejection."},
    {-71, "The remote station did not return data correctly."},
    {-72, "Pointer error. The specified pointer value is invalid."},
    {-73, "Specified address error."},
    {-2174, "Buffer data queue exception occurred. Read/write exception to device."},
    {-7656, "Buffer data queue exception. Read/write exception to the device."},
    {-7672, "Buffer data queue exception. Read/write exception to the device."},
    {-11683, "Buffer data transfer error."},
    {-11717, "Network No. error."},
    {-11746, "Station No. error."},
    {-12128, "Buffer data send/response error."},
    {-18560, "Module mode setting error."},
    {-18572, "Communication method error."},
    {-25056, "Processor error."},
    {-26334, "Duplicate program call or illegal CPU operation."},
    {-26336, "Routing request error to a station without routing function support."},
    {-27902, "Event register timeout error."},
    {-28079, "Communication No. read error."},
    {-28080, "Communication No. incorrect error."},
    {-28136, "Unsupported function in fast mode error."},
    {-28139, "Link disconnection error."},
    {-28140, "Incorrect mode setting error."},
    {-28141, "System reboot error."},
    {-28142, "Mode error."},
    {-28143, "Hardware self-diagnosis error."},
    {-28144, "Hardware self-diagnosis error."},
    {-28150, "Data reception interruption at remote station error."},
    {-28151, "Data reception interruption at remote station error."},
    {-28153, "Data reception interruption at remote station error."},
    {-28154, "Abnormal data reception error."},
    {-28158, "Driver WDT error."},
    {-28160, "Hardware resource error."},
    {-28622, "Dedicated instruction channel in-use error."},
    {-28634, "Hardware self-diagnosis error."},
    {-28636, "Hardware self-diagnosis error."},
    // è‡ªå®šä¹‰é”™è¯¯ç 
    {ERROR_CODE_UNKNOWN, "Error: Unknown error code."},
    {ERROR_CODE_NOT_CONNECTED, "Error: Not connected to the device."},
    {ERROR_CODE_INVALID_PARAM, "Error: Invalid parameter."},
    {ERROR_CODE_INVALID_DATA, "Error: Invalid data provided."},
    {ERROR_CODE_STATION_OUT_OF_RANGE, "Error: Station number is out of range."},
    {ERROR_CODE_GROUP_OUT_OF_RANGE, "Error: Group number is out of range."},
    {ERROR_CODE_NETWORK_OUT_OF_RANGE, "Error: Network number is out of range."}
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPerformanceMelsec::CPerformanceMelsec(const BoardType enBoardType) {
    m_nPath = 0;
    m_enBoardType = enBoardType;
    m_bConnected.store(false);
}
// æžæž„函数
CPerformanceMelsec::~CPerformanceMelsec() {
    Disconnect();
}
// èŽ·å–æœ€è¿‘çš„é”™è¯¯ä¿¡æ¯
std::string CPerformanceMelsec::GetLastError() const {
    return m_strLastError;
}
// ä¿å­˜é”™è¯¯ä¿¡æ¯
bool CPerformanceMelsec::SaveErrorInfoToFile(const std::string& filename) {
    // æ‰“开文件
    std::ofstream file(filename);
    if (!file.is_open()) {
        std::cerr << "Failed to open file for saving: " << filename << std::endl;
        return false;
    }
    // éåŽ†é™æ€æˆå‘˜å˜é‡ m_mapError å¹¶å°†æ¯ä¸ªé”™è¯¯ä¿¡æ¯å†™å…¥æ–‡ä»¶
    for (const auto& entry : m_mapError) {
        const int nCode = entry.first;
        const std::string& strMessage = entry.second;
        file << nCode << "|" << strMessage << "\n";
    }
    file.close();
    return true;
}
// åŠ è½½é”™è¯¯ä¿¡æ¯
bool CPerformanceMelsec::LoadErrorInfoFromFile(const std::string& filename) {
    std::ifstream inFile(filename);
    if (!inFile.is_open()) {
        std::cerr << "Failed to open file for loading: " << filename << std::endl;
        return false;
    }
    m_mapError.clear();
    std::string line;
    while (std::getline(inFile, line)) {
        std::istringstream iss(line);
        int nCode = 0;
        std::string strToken;
        std::string strMessage;
        // ä½¿ç”¨åˆ†éš”符 "|" è§£æžæ¯ä¸€è¡Œ
        if (std::getline(iss, strToken, '|')) {
            nCode = std::stoi(strToken);
        }
        if (std::getline(iss, strToken)) {
            strMessage = strToken;
        }
        if (!strMessage.empty()) {
            m_mapError[nCode] = strMessage;
        }
    }
    return true;
}
// è¿žæŽ¥åˆ°PLC
int CPerformanceMelsec::Connect(const short nChannel, const short nMode) {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (m_bConnected.load()) {
        return 0;
    }
    const BoardType enBoardType = FindBoardTypeByChannel(nChannel);
    if (enBoardType == BoardType::UNKNOWN || enBoardType != m_enBoardType) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    // è¿žæŽ¥PLC,显式类型转换以匹配 mdOpen çš„签名
    const short nRet = mdOpen(nChannel, nMode, &m_nPath);
    if (nRet == 0) {
        m_bConnected.store(true);
        m_enBoardType = enBoardType;
    }
    else {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ–­å¼€è¿žæŽ¥
int CPerformanceMelsec::Disconnect() {
    std::lock_guard<std::mutex> lock(m_mtx);
    short nRet = 0;
    if (m_bConnected.load()) {
        nRet = mdClose(m_nPath);
        m_bConnected.store(false);
        m_nPath = 0;
    }
    UpdateLastError(nRet);
    LOG_DEBUG("Close connect.");
    return nRet;
}
// å¯ç¼–程控制器软元件信息表的初始化
int CPerformanceMelsec::InitializeController() {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    const short nRet = mdInit(m_nPath);
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
int CPerformanceMelsec::GetBoardVersion(BoardVersion& version) {
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    // èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
    short buf[32] = { 0 };
    const short nRet = mdBdVerRead(m_nPath, buf);
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
        return nRet;
    }
    // å¡«å……版本信息到结构体
    version.fixedValue[0] = static_cast<char>(buf[0] & 0xFF);
    version.fixedValue[1] = static_cast<char>((buf[0] >> 8) & 0xFF);
    version.checksum[0] = static_cast<char>(buf[1] & 0xFF);
    version.checksum[1] = static_cast<char>((buf[1] >> 8) & 0xFF);
    version.swVersion[0] = static_cast<char>(buf[2] & 0xFF);
    version.swVersion[1] = static_cast<char>((buf[2] >> 8) & 0xFF);
    std::memcpy(version.date, &buf[3], 6);
    version.reserved = static_cast<uint32_t>(buf[6]) | (static_cast<uint32_t>(buf[7]) << 16);
    std::memcpy(version.swModel, &buf[8], 16);
    std::memcpy(version.hwModel, &buf[16], 16);
    version.twoPortMemory[0] = static_cast<char>(buf[18] & 0xFF);
    version.twoPortMemory[1] = static_cast<char>((buf[18] >> 8) & 0xFF);
    version.twoPortAttribute[0] = static_cast<char>(buf[19] & 0xFF);
    version.twoPortAttribute[1] = static_cast<char>((buf[19] >> 8) & 0xFF);
    version.availableBias[0] = static_cast<char>(buf[20] & 0xFF);
    version.availableBias[1] = static_cast<char>((buf[20] >> 8) & 0xFF);
    std::memcpy(version.moduleType, &buf[21], 10);
    return nRet;
}
// è¯»å–目标站点CPU类型
int CPerformanceMelsec::ReadCPUCode(const StationIdentifier& station, short& nCPUCode) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        nCPUCode = 0;
        std::lock_guard<std::mutex> lock(m_mtx);
        nRet = mdTypeRead(m_nPath, CombineStation(station), &nCPUCode);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ¿æ¨¡å¼è®¾ç½®
int CPerformanceMelsec::SetBoardMode(const short nMode) {
    // æ£€æŸ¥æ˜¯å¦å·²ç»è¿žæŽ¥
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    short nRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        nRet = mdBdModSet(m_nPath, nMode);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// èŽ·å–æ¿æ¨¡å¼
int CPerformanceMelsec::GetBoardMode(short& nMode) {
    // æ£€æŸ¥æ˜¯å¦å·²ç»è¿žæŽ¥
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    short nRet = 0;
    {
        nMode = 0;
        std::lock_guard<std::mutex> lock(m_mtx);
        nRet = mdBdModRead(m_nPath, &nMode);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_DEBUG("Raw Mode: " << nMode);
        LOG_ERROR(m_strLastError);
    }
    return 0;
}
// æ¿å¤ä½
int CPerformanceMelsec::BoardReset() {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    const short nRet = mdBdRst(m_nPath);
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ¿LED读取
int CPerformanceMelsec::ReadBoardLed(std::vector<short>& vecLedBuffer) {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    // æ¸…空 LED ç¼“冲区
    vecLedBuffer.clear();
    vecLedBuffer.resize(16, 0);
    // è°ƒç”¨ SDK å‡½æ•°è¯»å– LED æ•°æ®
    const short nRet = mdBdLedRead(m_nPath, vecLedBuffer.data());
    if (nRet != 0) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        LOG_ERROR("Error reading board LED, ErrorCode: " << nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// èŽ·å–æ¿çŠ¶æ€
int CPerformanceMelsec::GetBoardStatus(BoardStatus& status) {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    short buf[6] = { 0 };
    const short nRet = mdBdSwRead(m_nPath, buf);
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    // å°† buf æ˜ å°„到结构体
    status = BoardStatus::fromBuffer(buf);
    return 0;
}
// é€šç”¨è¯»æ•°æ®
int CPerformanceMelsec::ReadData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, std::vector<short>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, static_cast<short>(nSize));
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // åˆå§‹åŒ–读取缓冲区
    vecData.clear();
    vecData.resize(nSize, 0);
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        short* pData = vecData.data();
        nSize *= sizeof(short);
        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, (long)(unsigned short)nDevNo, &nSize, pData);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    if (nRet != 0) {
        vecData.clear(); // å¦‚果读取失败,清空缓冲区
    }
    return nRet;
}
// è¯»å–位数据
int CPerformanceMelsec::ReadBitData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nBitCount, BitContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nBitCount);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    if (nDevNo % 8 != 0) {
        nRet = -2;
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>((static_cast<int>(nBitCount) + 15) / 16);  // è®¡ç®—需要读取的字数量(向上取整)
    std::vector<short> vecTempBuffer(nSize, 0);
    nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
    if (nRet == 0) {
        vecData.clear();
        // å°†å­—数据解析为位数据
        for (short nIdx = 0; nIdx < nSize; ++nIdx) {
            const short nCurrentValue = vecTempBuffer[nIdx];
            // éåŽ†å½“å‰ short ä¸­çš„æ¯ä¸€ä½
            for (int bitIdx = 0; bitIdx < 16; ++bitIdx) {
                bool bBit = (nCurrentValue & (1 << bitIdx)) != 0;
                vecData.push_back(bBit);
                if (vecData.size() >= nBitCount) {
                    return nRet;  // å¦‚果已经读取完所需的位数,提前退出
                }
            }
        }
    }
    return nRet;
}
// è¯»å–字数据
int CPerformanceMelsec::ReadWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nWordCount, WordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nWordCount);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    std::vector<short> vecTempBuffer(nWordCount, 0);
    nRet = ReadData(station, nDevType, nDevNo, nWordCount, vecTempBuffer);
    if (nRet == 0) {
        vecData.clear();
        vecData.assign(vecTempBuffer.begin(), vecTempBuffer.end());
    }
    return nRet;
}
// è¯»å–双字数据
int CPerformanceMelsec::ReadDWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nDWordCount, DWordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nDWordCount);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const auto nSize = static_cast<short>(nDWordCount * 2); // æ¯ä¸ªåŒå­—占两个字(每个双字占 4 å­—节)
    const short nDevType = CalculateDeviceType(station, enDevType);
    std::vector<short> vecTempBuffer(nSize, 0);
    nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
    if (nRet == 0) {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToUint32(vecTempBuffer, vecData);
    }
    return nRet;
}
// é€šç”¨å†™æ•°æ®
int CPerformanceMelsec::WriteData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, short* pData) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // æ•°æ®æœ‰æ•ˆæ€§
    if (nSize < 0 || pData == nullptr) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        nSize *= sizeof(short);
        nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, pData);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// å†™ä½æ•°æ®
int CPerformanceMelsec::WriteBitData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const BitContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    if (nDevNo % 8 != 0) {
        nRet = -2;
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>((static_cast<int>(vecData.size()) + 15) / 16);  // è®¡ç®—需要写入的字数量(向上取整)
    // å‡†å¤‡ä¸´æ—¶ç¼“冲区来存储转换后的 16 ä½æ•°æ®
    std::vector<short> vecTempBuffer(nSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        // å°†ä½æ•°æ®æŒ‰å­—打包到临时缓冲区
        for (int i = 0; i < vecData.size(); ++i) {
            if (vecData[i]) {
                // ä½¿ç”¨ & 0xFFFF ä¿è¯ä¸ä¼šè¶…过 16 ä½ï¼Œé˜²æ­¢æº¢å‡º
                vecTempBuffer[i / 16] |= static_cast<short>((1 << (i % 16)) & 0xFFFF);
            }
        }
    }
    return WriteData(station, nDevType, nDevNo, nSize, vecTempBuffer.data());
}
// å†™å­—数据
int CPerformanceMelsec::WriteWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const WordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    const int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // è®¡ç®—需要写入的字节数(每个字占 2 å­—节)
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>(vecData.size());
    const auto pData = const_cast<short*>(reinterpret_cast<const short*>(vecData.data()));
    return WriteData(station, nDevType, nDevNo, nSize, pData);
}
// å†™åŒå­—数据
int CPerformanceMelsec::WriteDWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const DWordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    const int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // è®¡ç®—需要写入的字节数(每个双字占 4 å­—节)
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>(vecData.size() * sizeof(short));
    std::vector<short> vecBuffer(nSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertUint32ToShort(vecData, vecBuffer);
    }
    return WriteData(station, nDevType, nDevNo, nSize, vecBuffer.data());
}
// æ‰©å±•读数据
long CPerformanceMelsec::ReadDataEx(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和读取大小是否有效
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    if (nSize < 0) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    nSize = nSize % 2 != 0 ? nSize + 1 : nSize;
    std::vector<short> vecBuffer(nSize / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    else {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        vecData.resize(nSize);
        ConvertShortToChar(vecBuffer, vecData);
    }
    return 0;
}
// æ‰©å±•读取位数据
long CPerformanceMelsec::ReadBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nBitCount, BitContainer& vecData) {
    long nRet = ValidateStationAndSize(station, static_cast<short>(nBitCount));
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    // === è‡ªåŠ¨å¯¹é½åˆ°èµ·å§‹å­— ===
    long nWordAlignedStartBit = nDevNo / 16 * 16;
    long nBitOffset = nDevNo - nWordAlignedStartBit;
    long nTotalBits = nBitOffset + nBitCount;
    long nWordCount = (nTotalBits + 15) / 16;
    long nByteSize = nWordCount * sizeof(short);
    std::vector<char> vecRaw;
    nRet = ReadDataEx(station, nDevType, nWordAlignedStartBit, nByteSize, vecRaw);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    vecData.clear();
    for (long i = 0; i < nWordCount; ++i) {
        short word = static_cast<unsigned char>(vecRaw[i * 2]) |
            (static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
        for (int j = 0; j < 16; ++j) {
            long bitIndex = i * 16 + j;
            if (bitIndex >= nBitOffset && vecData.size() < static_cast<size_t>(nBitCount)) {
                vecData.push_back((word & (1 << j)) != 0);
            }
        }
    }
    return 0;
}
// æ‰©å±•读取字数据
long CPerformanceMelsec::ReadWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nWordCount, WordContainer& vecData) {
    long nRet = ValidateStationAndSize(station, static_cast<short>(nWordCount));
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    const long nByteSize = nWordCount * sizeof(short);
    std::vector<char> vecRaw;
    nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
    if (nRet != 0) {
        return nRet;
    }
    vecData.clear();
    for (long i = 0; i < nWordCount; ++i) {
        short value = static_cast<unsigned char>(vecRaw[i * 2]) |
            (static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
        vecData.push_back(value);
    }
    return 0;
}
// æ‰©å±•读取双字数据
long CPerformanceMelsec::ReadDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nDWordCount, DWordContainer& vecData) {
    long nRet = ValidateStationAndSize(station, static_cast<short>(nDWordCount));
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    const long nByteSize = nDWordCount * sizeof(uint32_t);
    std::vector<char> vecRaw;
    nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
    if (nRet != 0) {
        return nRet;
    }
    vecData.clear();
    for (long i = 0; i < nDWordCount; ++i) {
        uint32_t val = static_cast<unsigned char>(vecRaw[i * 4 + 0]) |
            (static_cast<unsigned char>(vecRaw[i * 4 + 1]) << 8) |
            (static_cast<unsigned char>(vecRaw[i * 4 + 2]) << 16) |
            (static_cast<unsigned char>(vecRaw[i * 4 + 3]) << 24);
        vecData.push_back(val);
    }
    return 0;
}
// æ‰©å±•写数据
long CPerformanceMelsec::WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // å°† vecData è½¬æ¢ä¸º short ç±»åž‹çš„缓冲区
    long nSize = static_cast<long>(vecData.size());
    nSize = nSize % 2 != 0 ? nSize + 1 : nSize;
    std::vector<short> vecBuffer(nSize / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
    }
    // é”™è¯¯å¤„理和日志记录
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ‰©å±•写位数据
long CPerformanceMelsec::WriteBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const BitContainer& vecData) {
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    // === 1. è‡ªåŠ¨å¯¹é½èµ·å§‹åœ°å€ ===
    long nWordAlignedStartBit = nDevNo / 16 * 16;
    long nBitOffset = nDevNo - nWordAlignedStartBit;
    long nTotalBits = nBitOffset + static_cast<long>(vecData.size());
    size_t nWordCount = (nTotalBits + 15) / 16;
    // === 2. å…ˆè¯»å–原始值以支持非对齐覆盖 ===
    std::vector<char> vecRaw;
    nRet = ReadDataEx(station, nDevType, nWordAlignedStartBit, static_cast<long>(nWordCount * sizeof(short)), vecRaw);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // === 3. åˆå¹¶æ–°æ•°æ® ===
    std::vector<short> vecWordBuffer(nWordCount, 0);
    for (size_t i = 0; i < nWordCount; ++i) {
        vecWordBuffer[i] = static_cast<unsigned char>(vecRaw[i * 2]) | (static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
    }
    for (size_t i = 0; i < vecData.size(); ++i) {
        size_t bitIndex = nBitOffset + i;
        size_t wordIdx = bitIndex / 16;
        size_t bitPos = bitIndex % 16;
        if (vecData[i]) {
            vecWordBuffer[wordIdx] |= (1 << bitPos);
        }
        else {
            vecWordBuffer[wordIdx] &= ~(1 << bitPos);
        }
    }
    // === 4. è½¬ä¸ºå­—节流写入 ===
    std::vector<char> vecByteBuffer(nWordCount * 2);
    for (size_t i = 0; i < nWordCount; ++i) {
        vecByteBuffer[i * 2] = static_cast<char>(vecWordBuffer[i] & 0xFF);
        vecByteBuffer[i * 2 + 1] = static_cast<char>((vecWordBuffer[i] >> 8) & 0xFF);
    }
    return WriteDataEx(station, nDevType, nWordAlignedStartBit, vecByteBuffer);
}
// æ‰©å±•写字数据
long CPerformanceMelsec::WriteWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const WordContainer& vecData) {
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    std::vector<char> vecByteBuffer;
    vecByteBuffer.resize(vecData.size() * sizeof(short));
    for (size_t i = 0; i < vecData.size(); ++i) {
        vecByteBuffer[i * 2] = static_cast<char>(vecData[i] & 0xFF);
        vecByteBuffer[i * 2 + 1] = static_cast<char>((vecData[i] >> 8) & 0xFF);
    }
    return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
}
// æ‰©å±•写双字数据
long CPerformanceMelsec::WriteDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const DWordContainer& vecData) {
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    std::vector<char> vecByteBuffer;
    vecByteBuffer.resize(vecData.size() * sizeof(uint32_t));
    for (size_t i = 0; i < vecData.size(); ++i) {
        vecByteBuffer[i * 4] = static_cast<char>(vecData[i] & 0xFF);
        vecByteBuffer[i * 4 + 1] = static_cast<char>((vecData[i] >> 8) & 0xFF);
        vecByteBuffer[i * 4 + 2] = static_cast<char>((vecData[i] >> 16) & 0xFF);
        vecByteBuffer[i * 4 + 3] = static_cast<char>((vecData[i] >> 24) & 0xFF);
    }
    return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
}
// æ‰©å±•软元件随机读取
long CPerformanceMelsec::ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData) {
    if (vecSoftElements.empty()) {
        UpdateLastError(ERROR_INVALID_PARAMETER);
        LOG_ERROR("Invalid parameters: soft elements are empty.");
        return ERROR_INVALID_PARAMETER;
    }
    // å‡†å¤‡ dev æ•°æ®
    std::vector<short> devBuffer(vecSoftElements.size() * 3 + 1, 0); // æ¯ä¸ªè½¯å…ƒä»¶éœ€è¦ 3 ä¸ª short,外加一个计数器
    devBuffer[0] = static_cast<short>(vecSoftElements.size());                 // ç¬¬ä¸€ä¸ªå…ƒç´ æ˜¯è½¯å…ƒä»¶æ•°é‡
    for (size_t i = 0; i < vecSoftElements.size(); ++i) {
        const SoftElement& element = vecSoftElements[i];
        devBuffer[i * 3 + 1] = element.nType;                        // è½¯å…ƒä»¶ç±»åž‹
        devBuffer[i * 3 + 2] = static_cast<short>(element.nStartNo); // èµ·å§‹è½¯å…ƒä»¶ç¼–号
        devBuffer[i * 3 + 3] = element.nElementCount;                // ç‚¹æ•°
    }
    // è®¡ç®—读取数据所需缓冲区大小
    long nBufferSize = 0;
    for (const auto& element : vecSoftElements) {
        nBufferSize += element.nElementCount * 2; // æ¯ä¸ªç‚¹å ç”¨ 2 ä¸ªå­—节
    }
    // é”ä¿æŠ¤åŠè°ƒç”¨ mdRandREx
    long nRet = 0;
    std::vector<short> vecBuffer(nBufferSize / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // ç¡®ä¿çº¿ç¨‹å®‰å…¨
        nRet = mdRandREx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), nBufferSize);
    }
    // é”™è¯¯å¤„理和日志记录
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
        return nRet;
    }
    // å°†è¯»å–到的 short æ•°æ®è½¬æ¢ä¸º char æ•°æ®
    vecData.resize(nBufferSize);
    for (size_t i = 0; i < vecBuffer.size(); ++i) {
        vecData[i * 2] = static_cast<char>(vecBuffer[i] & 0xFF);            // ä½Žå­—节
        vecData[i * 2 + 1] = static_cast<char>((vecBuffer[i] >> 8) & 0xFF); // é«˜å­—节
    }
    return nRet;
}
// æ‰©å±•软元件随机写入(支持多个软元件)
long CPerformanceMelsec::WriteRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, const std::vector<char>& vecData) {
    if (vecSoftElements.empty() || vecData.empty()) {
        UpdateLastError(ERROR_INVALID_PARAMETER);
        LOG_ERROR("Invalid parameters: soft elements or data is empty.");
        return ERROR_INVALID_PARAMETER;
    }
    // å‡†å¤‡ dev æ•°æ®
    std::vector<long> devBuffer(vecSoftElements.size() * 3 + 1, 0); // æ¯ä¸ªè½¯å…ƒä»¶éœ€è¦ 3 ä¸ª long,外加一个计数器
    devBuffer[0] = static_cast<long>(vecSoftElements.size());                 // ç¬¬ä¸€ä¸ªå…ƒç´ æ˜¯è½¯å…ƒä»¶æ•°é‡
    for (size_t i = 0; i < vecSoftElements.size(); ++i) {
        const SoftElement& element = vecSoftElements[i];
        devBuffer[i * 3 + 1] = static_cast<long>(element.nType);    // è½¯å…ƒä»¶ç±»åž‹
        devBuffer[i * 3 + 2] = element.nStartNo;                    // èµ·å§‹è½¯å…ƒä»¶ç¼–号(已经是 long ç±»åž‹ï¼Œæ— éœ€è½¬æ¢ï¼‰
        devBuffer[i * 3 + 3] = static_cast<long>(element.nElementCount); // ç‚¹æ•°
    }
    // é”ä¿æŠ¤åŠè°ƒç”¨ mdRandWEx
    long nRet = 0;
    std::vector<short> vecBuffer(vecData.size() / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // ç¡®ä¿çº¿ç¨‹å®‰å…¨
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdRandWEx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), static_cast<long>(vecBuffer.size()));
    }
    // é”™è¯¯å¤„理和日志记录
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器读取
long CPerformanceMelsec::ReadRemoteBuffer(const StationIdentifier& station, long nOffset, long nSize, std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    if (nSize < 0) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    long nActualSize = (nSize + 1) / 2;
    std::vector<short> vecBuffer(nActualSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdRemBufReadEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nActualSize, vecBuffer.data());
    }
    if (nRet != 0) {
        UpdateLastError(nRet); // æ›´æ–°é”™è¯¯ç 
        LOG_ERROR(m_strLastError);
    }
    else {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToChar(vecBuffer, vecData);
    }
    return nRet;
}
// è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器写入
long CPerformanceMelsec::WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // å°† vecData è½¬æ¢ä¸º short ç±»åž‹çš„缓冲区
    long nSize = static_cast<long>(vecData.size());
    std::vector<short> vecBuffer((nSize + 1) / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdRemBufWriteEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nSize, vecBuffer.data());
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// è¿œç¨‹ç«™çš„缓冲存储器读取 å¯¹è±¡ç«™IP地址指定
long CPerformanceMelsec::ReadRemoteBufferByIp(const std::string& strIP, long nOffset, long nSize, std::vector<char>& vecData) {
    uint32_t nAddress = 0;
    if (nSize < 0 || !ConvertIpStringToUint32(strIP, nAddress)) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    // å°†ç¼“冲区大小调整为 nSize
    vecData.resize(nSize, 0);
    std::vector<short> vecBuffer((nSize + 1) / 2, 0); // è½¬æ¢ä¸º short ç±»åž‹
    // è°ƒç”¨åº•层 SDK
    long nRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdRemBufReadIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    else {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToChar(vecBuffer, vecData);
    }
    return nRet;
}
// è¿œç¨‹ç«™çš„缓冲存储器写入 å¯¹è±¡ç«™IP地址指定
long CPerformanceMelsec::WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector<char>& vecData) {
    uint32_t nAddress = 0;
    if (vecData.empty() || !ConvertIpStringToUint32(strIP, nAddress)) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    // è½¬æ¢ vecData ä¸º short ç±»åž‹çš„缓冲区
    long nSize = static_cast<long>(vecData.size());
    std::vector<short> vecBuffer((nSize + 1) / 2, 0);
    long nRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdRemBufWriteIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// è®¾ç½®(ON)对象站的指定位软元件
int CPerformanceMelsec::SetBitDevice(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨
        const short nDevType = CalculateDeviceType(station, enDevType);
        nRet = mdDevSet(m_nPath, CombineStation(station), nDevType, nDevNo);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// å¤ä½(OFF)对象站的指定位软元件
int CPerformanceMelsec::ResetBitDevice(const StationIdentifier& station, const DeviceType enDevType, const short enDevNo) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        const short nDevType = CalculateDeviceType(station, enDevType);
        nRet = mdDevRst(m_nPath, CombineStation(station), nDevType, enDevNo);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ‰©å±•位软元件设置
long CPerformanceMelsec::SetBitDeviceEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo) {
    std::lock_guard<std::mutex> lock(m_mtx);
    // æ£€æŸ¥å‚数有效性
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    long nDevType = static_cast<long>(enDevType);
    nRet = mdDevSetEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo);
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ‰©å±•位软元件复位
long CPerformanceMelsec::ResetBitDeviceEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo) {
    std::lock_guard<std::mutex> lock(m_mtx);
    // æ£€æŸ¥å‚数有效性
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    long nDevType = static_cast<long>(enDevType);
    nRet = mdDevRstEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo);
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// æ‰§è¡Œå¯¹è±¡ç«™çš„CPU
int CPerformanceMelsec::ControlCPU(const StationIdentifier& station, ControlCode enControlCode) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // éªŒè¯æŽ§åˆ¶ç æ˜¯å¦åˆæ³•
    const auto nControlCode = static_cast<short>(enControlCode);
    if (nControlCode < 0 || nControlCode > 2) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM); // å‚数错误
        return ERROR_CODE_INVALID_PARAM;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        nRet = mdControl(m_nPath, CombineStation(station), nControlCode);
    }
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
// äº‹ä»¶ç­‰å¾…
int CPerformanceMelsec::WaitForBoardEvent(std::vector<short> vecEventNumbers, const int nTimeoutMs, EventDetails& details) {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    if (vecEventNumbers.empty() || vecEventNumbers.size() > 64) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    // ç¬¬ 0 ä¸ªå…ƒç´ å­˜å‚¨æ•°é‡ï¼Œæœ€å¤§æ”¯æŒ 64 ä¸ªäº‹ä»¶
    std::array<short, 65> eventno = { 0 };
    eventno[0] = static_cast<short>(vecEventNumbers.size());
    std::copy(vecEventNumbers.begin(), vecEventNumbers.end(), eventno.begin() + 1);
    // åˆå§‹åŒ–输出参数
    details.nEventNo = 0;
    details.details.fill(0);
    const int nRet = mdWaitBdEvent(m_nPath, eventno.data(), nTimeoutMs, &details.nEventNo, details.details.data());
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
    }
    return nRet;
}
//============================================辅助函数=======================================================
// æ›´æ–°æœ€è¿‘的错误信息
void CPerformanceMelsec::UpdateLastError(const int nCode) {
    if (nCode == 0) {
        return;
    }
    // æ£€æŸ¥é”™è¯¯ç æ˜¯å¦å­˜åœ¨äºŽæ˜ å°„表中
    const auto it = m_mapError.find(nCode);
    if (it != m_mapError.end()) {
        // å¦‚果找到,直接返回对应语言的错误信息
        m_strLastError = it->second;
    }
    else {
        // å¦‚果未找到,处理特殊范围
        m_strLastError = "Unknown error.";
        if (nCode == -28611 || nCode == -28612) {
            // ç³»ç»Ÿå‡ºé”™
            m_strLastError = "System error.";
        }
        if (nCode >= -20480 && nCode <= -16384) {
            // CC-Link ç³»ç»Ÿæ£€æµ‹å‡ºçš„错误
            m_strLastError = "Error detected in the CC-Link system.";
        }
        if (nCode >= -12288 && nCode <= -8193) {
            // CC-Link IE TSN ç³»ç»Ÿæ£€æµ‹å‡ºçš„错误
            m_strLastError = "Error detected in the CC-Link IE TSN system.";
        }
        if (nCode >= -8192 && nCode <= -4097) {
            // CC-Link IE æŽ§åˆ¶ç½‘络系统检测出的错误
            m_strLastError = "Error detected in the CC-Link IE control network system.";
        }
        if (nCode >= -4096 && nCode <= -257) {
            // MELSECNET/10 æˆ– MELSECNET/网络系统错误范围
            m_strLastError = "Errors detected in MELSECNET/10 or MELSECNET/network system.";
        }
        if (nCode >= 4096 && nCode <= 16383) {
            // MELSEC æ•°æ®é“¾æŽ¥åº“范围
            m_strLastError = "Internal error detected by MELSEC Data Link Library.";
        }
        if (nCode == 18944 || nCode == 18945) {
            // é“¾æŽ¥å…³è”出错
            m_strLastError = "Link association error: Network does not exist, unsupported CPU, or incorrect network No./station number.";
        }
        if (nCode >= 16384 && nCode <= 20479) {
            // PLC CPU æ£€æµ‹èŒƒå›´
            m_strLastError = "Errors detected by the programmable controller CPU in the target station.";
        }
        if (nCode >= 28416 && nCode <= 28671) {
            // å†—余功能模块范围
            m_strLastError = "Error detected in the redundancy module of the target station.";
        }
    }
}
// æ£€æŸ¥è¿žæŽ¥çŠ¶æ€å’Œç«™ç‚¹å‚æ•°æœ‰æ•ˆæ€§
int CPerformanceMelsec::ValidateStation(const StationIdentifier& station) const {
    // æ£€æŸ¥æ˜¯å¦å·²è¿žæŽ¥
    if (!m_bConnected.load()) {
        return ERROR_CODE_NOT_CONNECTED;
    }
    // æ£€æŸ¥ç½‘络号和站点号范围
    if (station.nNetNo < 0 || station.nNetNo > 239 || station.nStNo < 0 || station.nStNo > 255) {
        return ERROR_CODE_INVALID_PARAM;
    }
    return 0; // å‚数有效
}
// éªŒè¯ç«™ç‚¹å‚数和数据有效性
int CPerformanceMelsec::ValidateStationAndSize(const StationIdentifier& station, const short nCount) const {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    const int nRet = ValidateStation(station);
    if (nRet != 0) {
        return nRet; // å¦‚果站点验证失败,返回对应错误码
    }
    if (nCount <= 0) {
        return ERROR_CODE_INVALID_PARAM;
    }
    return 0; // éªŒè¯é€šè¿‡
}
// IP字符串转uint32_t
bool CPerformanceMelsec::ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP) {
    nIP = 0;
    std::stringstream ss(strIP);
    std::string strSegment;
    int nShift = 24;
    while (std::getline(ss, strSegment, '.')) {
        const auto nByte = static_cast<uint32_t>(std::stoi(strSegment));
        if (nByte > 255) {
            return false;
        }
        nIP |= (nByte << nShift);
        nShift -= 8;
    }
    return true;
}
//============================================静态辅助函数====================================================
// å»¶æ—¶ï¼Œå¹¶ä¸”转发窗口消息
void CPerformanceMelsec::Delay(const unsigned int nDelayMs) {
    MSG message;
    // å¦‚果延迟时间为 0,仅处理一次消息队列
    if (nDelayMs == 0) {
        // éžé˜»å¡žçš„æ£€æŸ¥æ¶ˆæ¯é˜Ÿåˆ—
        if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&message);  // å°†æ¶ˆæ¯è½¬åŒ–为有效的窗口消息
            DispatchMessage(&message);   // æ´¾å‘消息给相应的窗口过程
        }
        return;
    }
    DWORD finish;
    const DWORD start = GetTickCount();  // èŽ·å–å½“å‰çš„æ—¶é—´æˆ³ï¼ˆä»Žç³»ç»Ÿå¯åŠ¨ä»¥æ¥çš„æ¯«ç§’æ•°ï¼‰
    do {
        if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&message);  // è½¬æ¢æ¶ˆæ¯
            DispatchMessage(&message);   // å¤„理消息
        }
        Sleep(1);   // æš‚停 1 æ¯«ç§’,防止过度占用 CPU
        finish = GetTickCount(); // èŽ·å–å½“å‰çš„æ—¶é—´æˆ³
    } while ((finish - start) < nDelayMs);  // å¾ªçŽ¯ç›´åˆ°ç»è¿‡çš„æ—¶é—´å¤§äºŽæŒ‡å®šçš„å»¶è¿Ÿæ—¶é—´
}
BoardType CPerformanceMelsec::FindBoardTypeByChannel(const int nChannel) {
    if (nChannel >= MELSECNET_CHANNEL(1) && nChannel <= MELSECNET_CHANNEL(4)) {
        return BoardType::MELSECNET_H;
    }
    else if (nChannel >= CC_LINK_CHANNEL(1) && nChannel <= CC_LINK_CHANNEL(4)) {
        return BoardType::CC_LINK_VER_2;
    }
    else if (nChannel >= CC_LINK_IE_CONTROL_CHANNEL(1) && nChannel <= CC_LINK_IE_CONTROL_CHANNEL(4)) {
        return BoardType::CC_LINK_IE_CONTROL;
    }
    else if (nChannel >= CC_LINK_IE_FIELD_CHANNEL(1) && nChannel <= CC_LINK_IE_FIELD_CHANNEL(4)) {
        return BoardType::CC_LINK_IE_FIELD;
    }
    else if (nChannel >= CC_LINK_IE_TSN_CHANNEL(1) && nChannel <= CC_LINK_IE_TSN_CHANNEL(4)) {
        return BoardType::CC_LINK_IE_TSN;
    }
    return BoardType::UNKNOWN;
}
// åˆå¹¶ç½‘络号和站点号
short CPerformanceMelsec::CombineStation(const StationIdentifier& station) {
    return static_cast<short>(station.nStNo | ((station.nNetNo << 8) & 0xFF00));
}
// è®¡ç®—软元件类型
short CPerformanceMelsec::CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType) {
    int nDevType = static_cast<int>(enDevType);
    // æ ¹æ®è½¯å…ƒä»¶ç±»åž‹çš„特定规则进行计算
    if (enDevType == DeviceType::LX || enDevType == DeviceType::LY ||
        enDevType == DeviceType::LB || enDevType == DeviceType::LW ||
        enDevType == DeviceType::LSB || enDevType == DeviceType::LSW) {
        // ç½‘络号加偏移
        nDevType += station.nNetNo;
    }
    else if (enDevType == DeviceType::ER) {
        // æ–‡ä»¶å¯„存器的块号加偏移
        nDevType += 0;
    }
    else if (enDevType == DeviceType::SPG) {
        // èµ·å§‹ I/O No. Ã· 16 çš„值
        nDevType += 0 / 16;
    }
    return static_cast<short>(nDevType);
}
// std::vector<char>转换为std::vector<short>
void CPerformanceMelsec::ConvertCharToShort(const std::vector<char>& vecChar, std::vector<short>& vecShort) {
    vecShort.resize((vecChar.size() + 1) / 2, 0); // è°ƒæ•´ short å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecChar.size(); i++) {
        if (i % 2 == 0) {
            vecShort[i / 2] = static_cast<unsigned char>(vecChar[i]);       // ä½Žå­—节
        }
        else {
            vecShort[i / 2] |= static_cast<unsigned char>(vecChar[i]) << 8; // é«˜å­—节
        }
    }
}
// std::vector<short>转换为std::vector<char>
void CPerformanceMelsec::ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar) {
    vecChar.resize(vecShort.size() * 2); // è°ƒæ•´ char å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecShort.size(); i++) {
        vecChar[i * 2] = static_cast<char>(vecShort[i] & 0xFF);             // ä½Žå­—节
        vecChar[i * 2 + 1] = static_cast<char>((vecShort[i] >> 8) & 0xFF);  // é«˜å­—节
    }
}
// std::vector<uint8_t>转换为std::vector<short>
void CPerformanceMelsec::ConvertUint8ToShort(const std::vector<uint8_t>& vecUint8, std::vector<short>& vecShort) {
    vecShort.resize((vecUint8.size() + 1) / 2, 0); // è°ƒæ•´ short å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecUint8.size(); i++) {
        if (i % 2 == 0) {
            vecShort[i / 2] = static_cast<short>(vecUint8[i]);          // ä½Žå­—节
        }
        else {
            vecShort[i / 2] |= static_cast<short>(vecUint8[i] << 8);    // é«˜å­—节
        }
    }
}
// std::vector<short>转换为std::vector<uint8_t>
void CPerformanceMelsec::ConvertShortToUint8(const std::vector<short>& vecShort, std::vector<uint8_t>& vecUint8) {
    vecUint8.resize(vecShort.size() * 2); // è°ƒæ•´ uint8_t å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecShort.size(); i++) {
        vecUint8[i * 2] = static_cast<uint8_t>(vecShort[i] & 0xFF);             // ä½Žå­—节
        vecUint8[i * 2 + 1] = static_cast<uint8_t>((vecShort[i] >> 8) & 0xFF);  // é«˜å­—节
    }
}
// std::vector<uint32_t>转换为std::vector<short>
void CPerformanceMelsec::ConvertUint32ToShort(const std::vector<uint32_t>& vecUint32, std::vector<short>& vecShort) {
    vecShort.resize(vecUint32.size() * 2); // æ¯ä¸ª uint32_t è½¬æ¢ä¸ºä¸¤ä¸ª short
    for (size_t i = 0; i < vecUint32.size(); i++) {
        vecShort[i * 2] = static_cast<short>(vecUint32[i] & 0xFFFF);             // ä½Ž16位
        vecShort[i * 2 + 1] = static_cast<short>((vecUint32[i] >> 16) & 0xFFFF); // é«˜16位
    }
}
// std::vector<short>转换为std::vector<uint32_t>
void CPerformanceMelsec::ConvertShortToUint32(const std::vector<short>& vecShort, std::vector<uint32_t>& vecUint32) {
    vecUint32.resize((vecShort.size() + 1) / 2, 0); // æ¯ä¸¤ä¸ª short åˆå¹¶ä¸ºä¸€ä¸ª uint32_t
    for (size_t i = 0; i < vecUint32.size(); i++) {
        vecUint32[i] = (static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2 + 1])) << 16) | // é«˜16位
            static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2]));              // ä½Ž16位
    }
}
//============================================模板辅助函数====================================================
// éªŒè¯ç«™ç‚¹å‚数和数据有效性
template <typename T>
int CPerformanceMelsec::ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    const int nRet = ValidateStation(station);
    if (nRet != 0) {
        return nRet; // å¦‚果站点验证失败,返回对应错误码
    }
    // éªŒè¯æ•°æ®æ˜¯å¦ä¸ºç©º
    if (vecData.empty()) {
        return ERROR_CODE_INVALID_PARAM;
    }
    return 0; // éªŒè¯é€šè¿‡
}
// ç”±ä½Žè½¬é«˜å®¹å™¨çš„æ¨¡æ¿ï¼ˆæ•´åž‹ï¼‰
template <typename T, typename U>
void CPerformanceMelsec::ConvertLowToHigh(const std::vector<T>& vecLow, std::vector<U>& vecHigh) {
    static_assert(std::is_integral<T>::value && std::is_integral<U>::value, "T and U must be integral types");
    // è‡ªåŠ¨è®¡ç®— nGroupSize
    constexpr size_t nGroupSize = sizeof(U) / sizeof(T);
    // å¦‚æžœ T å’Œ U çš„大小相等,直接转换
    if (sizeof(T) == sizeof(U)) {
        vecHigh.assign(vecLow.begin(), vecLow.end());
        return;
    }
    // å¦‚æžœ U çš„大小是 T çš„倍数,正常组合
    static_assert(sizeof(U) > sizeof(T), "Size of U must be greater than or equal to size of T");
    // è®¡ç®—完整组的数量
    size_t nHighSize = (vecLow.size() + nGroupSize - 1) / nGroupSize; // å‘上取整
    vecHigh.resize(nHighSize, 0);
    // åˆå¹¶ä½Žä½æ•°æ®åˆ°é«˜ä½æ•°æ®
    for (size_t i = 0; i < vecLow.size(); i++) {
        vecHigh[i / nGroupSize] |= (static_cast<U>(vecLow[i]) << ((i % nGroupSize) * CHAR_BIT * sizeof(T)));
    }
    return vecHigh;
}
// ç”±é«˜è½¬ä½Žå®¹å™¨çš„æ¨¡æ¿ï¼ˆæ•´åž‹ï¼‰
template <typename T, typename U>
void CPerformanceMelsec::ConvertHighToLow(const std::vector<T>& vecHigh, std::vector<U>& vecLow) {
    static_assert(std::is_integral<T>::value && std::is_integral<U>::value, "T and U must be integral types");
    // è‡ªåŠ¨è®¡ç®— nGroupSize
    constexpr size_t nGroupSize = sizeof(T) / sizeof(U);
    // å¦‚æžœ T å’Œ U çš„大小相等,直接转换
    if (sizeof(T) == sizeof(U)) {
        vecLow.assign(vecHigh.begin(), vecHigh.end());
        return;
    }
    // å¦‚æžœ T çš„大小是 U çš„倍数,正常分解
    static_assert(sizeof(T) > sizeof(U), "Size of T must be greater than or equal to size of U");
    size_t nLowSize = vecHigh.size() * nGroupSize; // ä½Žå®¹å™¨çš„大小
    vecLow.resize(nLowSize, 0);
    // åˆ†è§£é«˜ä½æ•°æ®åˆ°ä½Žä½æ•°æ®
    for (size_t i = 0; i < vecHigh.size(); i++) {
        for (size_t j = 0; j < nGroupSize; j++) {
            vecLow[i * nGroupSize + j] = static_cast<U>((vecHigh[i] >> (j * CHAR_BIT * sizeof(U))) & ((1ULL << (CHAR_BIT * sizeof(U))) - 1));
        }
    }
    return vecLow;
}
SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,479 @@
#ifndef PERFORMANCE_MELSEC_H
#define PERFORMANCE_MELSEC_H
#include "Mdfunc.h"
#include <map>
#include <array>
#include <mutex>
#include <string>
#include <vector>
#include <atomic>
#include <sstream>
#include <unordered_map>
// è¿žæŽ¥å‚æ•°
#define PLC_MAX_RETRY 3        // æœ€å¤§é‡è¯•次数:在与PLC通信时,如果发生通信错误,将最多重试3次
#define PLC_TIMEOUT 500        // è¶…时时间(毫秒):每次通信操作的超时等待时间为500毫秒
/*
 * ç½‘络通道:指定通信所使用的网络通道号,通常在多通道通信中设置
 * 51 åˆ° 54 æ˜¯ MELSECNET/H çš„ 1-4 é€šé“
 * 81 åˆ° 84 æ˜¯ CC-Link çš„ 1-4 é€šé“
 * 151 åˆ° 154 æ˜¯ CC-Link IE æŽ§åˆ¶å™¨ç½‘络的 1-4 é€šé“
 * 181 åˆ° 184 æ˜¯ CC-Link IE çŽ°åœºç½‘ç»œçš„ 1-4 é€šé“
 * 281 åˆ° 284 æ˜¯ CC-Link IE TSN ç½‘络的 1-4 é€šé“
 **/
#define MELSECNET_CHANNEL(x) (50 + (x))           // x èŒƒå›´ï¼š1~4
#define CC_LINK_CHANNEL(x) (80 + (x))              // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_CONTROL_CHANNEL(x) (150 + (x)) // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_FIELD_CHANNEL(x) (180 + (x))   // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_TSN_CHANNEL(x) (280 + (x))     // x èŒƒå›´ï¼š1~4
 // è‡ªå®šä¹‰é”™è¯¯ç 
#define ERROR_CODE_UNKNOWN                0x00010000 // Î´Öª
#define ERROR_CODE_NOT_CONNECTED        0x00020000 // æœªè¿žæŽ¥
#define ERROR_CODE_INVALID_PARAM        0x00030000 // å‚数无效
#define ERROR_CODE_INVALID_DATA            0x00040000 // æ•°æ®æ— æ•ˆ
#define ERROR_CODE_STATION_OUT_OF_RANGE 0x00050000 // ç«™å·è¶…出范围
#define ERROR_CODE_GROUP_OUT_OF_RANGE   0x00060000 // ç»„号超出范围
#define ERROR_CODE_NETWORK_OUT_OF_RANGE 0x00070000 // ç½‘络号超出范围
// æ¿å—类型
enum class BoardType {
    UNKNOWN = -1,                                        // æœªçŸ¥ç±»åž‹
    MELSECNET_H = MELSECNET_CHANNEL(1),                    // MELSECNET/H
    CC_LINK_VER_2 = CC_LINK_CHANNEL(1),                    // CC-Link Ver. 2
    CC_LINK_IE_CONTROL = CC_LINK_IE_CONTROL_CHANNEL(1),    // CC-Link IE æŽ§åˆ¶ç½‘络
    CC_LINK_IE_FIELD = CC_LINK_IE_FIELD_CHANNEL(1),     // CC-Link IE çŽ°åœºç½‘ç»œ
    CC_LINK_IE_TSN = CC_LINK_IE_TSN_CHANNEL(1)          // CC-Link IE TSN
};
// è½¯å…ƒä»¶ç±»åž‹æžšä¸¾
enum class DeviceType {
    /*
     * ER、LX、LY、LB、LW、LSB、LSW和SPG软元件都是范围型
     * ER:DevER0~256
     * LX:DevLX1~255,DevLX(x)    (DevX*1000+(x))
     * LY:DevLY1~255,DevLY(x)    (DevY*1000+(x))
     * LB:DevLB1~255,DevLB(x)    (DevB*1000+(x))
     * LW:DevLW1~255,DevLW(x)    (DevW*1000+(x))
     * LSB:DevLSB1~255,DevLSB(x) (DevQSB*1000+(x))
     * LSW:DevLSW1~255,DevLSW(x) (DevQSW*1000+(x))
     * SPG:DevSPG0~255,DevSPG(x) (29*1000+(x))
     * æ‰©å±•文件寄存器代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定块No.(0~256)
     * é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ä»£ç æŒ‡å®š(10进制数)的后3位数及软元件名指定的数值中,应指定网络No.(1~255)
     * æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ä»£ç æŒ‡å®š(10进制数)的后3位数及软元件名指定的数值中,应指定(起始I/ONo.÷16)的值
     * æ‰©å±•文件寄存器和链接直接软元件在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束
     * MAIL和MAILMC在SEND功能及RECV功能中,与软元件访问一样,指定各功能对应的软元件类型,进行数据的发送(mdSend、mdSendEx)或数据的读取(mdReceive、mdReceiveEx)
     **/
    X = 0x0001,      // è¾“å…¥ (位)
    Y = 0x0002,      // è¾“出 (位)
    L = 0x0003,      // é”å­˜ç»§ç”µå™¨ (位)
    M = 0x0004,      // å†…部继电器 (位)
    SM = 0x0005,     // ç‰¹æ®Šç»§ç”µå™¨ (位)
    F = 0x0006,      // æŠ¥è­¦å™¨ (位)
    TT = 0x0007,     // å®šæ—¶å™¨ (触点) (位)
    TC = 0x0008,     // è®¡æ•°å™¨ (线圈) (位)
    CT = 0x0009,     // è®¡æ•°å™¨ (触点) (位)
    CC = 0x000A,     // è®¡æ•°å™¨ (线圈) (字)
    TN = 0x000B,     // å®šæ—¶å™¨ (当前值) (字)
    CN = 0x000C,     // è®¡æ•°å™¨ (当前值) (字)
    D = 0x000D,      // æ•°æ®å¯„存器 (字)
    SD = 0x000E,     // ç‰¹æ®Šå¯„存器 (字)
    TM = 0x000F,     // å®šæ—¶å™¨ (设置值主) (字)
    TS = 0x0010,     // å®šæ—¶å™¨ (设置值主1) (字)
    TS2 = 0x3E82,    // å®šæ—¶å™¨ (设置值主2) (字)
    TS3 = 0x3E83,    // å®šæ—¶å™¨ (设置值主3) (字)
    CM = 0x0011,     // è®¡æ•°å™¨ (设置值主) (字)
    CS = 0x0012,     // è®¡æ•°å™¨ (设置值主1) (字)
    CS2 = 0x4652,    // è®¡æ•°å™¨ (设置值主2) (字)
    CS3 = 0x4653,    // è®¡æ•°å™¨ (设置值主3) (字)
    A = 0x0013,      // ç´¯åР噍 (字)
    Z = 0x0014,      // å˜å€å¯„存器 (字)
    V = 0x0015,      // å˜å€å¯„存器 (字)
    R = 0x0016,      // æ–‡ä»¶å¯„存器 (块切换方式) (字)
    ER = 0x55F0,     // æ‰©å±•文件寄存器 (块切换方式) (0x55F0~0x56F0) (字) (在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束。(读取数据不正确。))
    ZR = 0x00DC,     // æ–‡ä»¶å¯„存器 (连号访问方式) (字)
    B = 0x0017,      // é“¾æŽ¥ç»§ç”µå™¨ (位)
    W = 0x0018,      // é“¾æŽ¥å¯„存器 (字)
    QSB = 0x0019,    // é“¾æŽ¥ç‰¹æ®Šç»§ç”µå™¨ (位)
    STT = 0x001A,    // ç´¯è®¡å®šæ—¶å™¨ (触点) (位)
    STC = 0x001B,    // ç´¯è®¡å®šæ—¶å™¨ (线圈) (位)
    QSW = 0x001C,    // é“¾æŽ¥ç‰¹æ®Šå¯„存器 (字)
    QV = 0x001E,     // å˜å€ç»§ç”µå™¨ (位)
    MRB = 0x0021,     // éšæœºè®¿é—®ç¼“冲 (字)
    STN = 0x0023,    // ç´¯è®¡å®šæ—¶å™¨ (当前值) (字)
    LZ = 0x0026,     // è¶…长变址寄存器 (双字)
    RD = 0x0027,     // åˆ·æ–°æ•°æ®å¯„存器 (字)
    LTT = 0x0029,    // è¶…长定时器 (触点) (位)
    LTC = 0x002A,    // è¶…长定时器 (线圈) (位)
    LTN = 0x002B,    // è¶…长定时器 (当前值) (双字)
    LCT = 0x002C,    // è¶…长计数器 (触点) (位)
    LCC = 0x002D,    // è¶…长计数器 (线圈) (位)
    LCN = 0x002E,    // è¶…长计数器 (当前值) (双字)
    LSTT = 0x002F,   // è¶…长累计定时器 (触点) (位)
    LSTC = 0x0030,   // è¶…长累计定时器 (线圈) (位)
    LSTN = 0x0031,   // è¶…长累计定时器 (当前值) (双字)
    SPB = 0x0032,     // ç¼“冲存储器 (字)
    MAIL = 0x0065,   // ç‰¹æ®Šè½¯å…ƒä»¶ç±»åž‹ï¼šé‚®ä»¶ç±»åž‹ (10进制 101)
    MAILMC = 0x0066, // ç‰¹æ®Šè½¯å…ƒä»¶ç±»åž‹ï¼šæ— ç¡®è®¤é‚®ä»¶ (10进制 102)
    LX = 0x03E8,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输入) (0x03E9~0x04E7) (位)
    LY = 0x07D0,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输出) (0x07D1~0x08CF) (位)
    LB = 0x59D8,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接继电器) (0x59D9~0x5AD7) (位)
    LW = 0x5DC0,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接寄存器) (0x5DC1~0x5EBF) (字)
    LSB = 0x61A8,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊继电器) (0x61A9~0x62A7) (位)
    LSW = 0x6D60,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊寄存器) (0x6D61~0x6E5F) (字)
    SPG = 0x7147,    // æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ (0x7148~0x7247) (字)
};
// æ•°æ®ç±»åž‹
enum class DataType {
    BIT = 1,   // Î» (1λ)
    WORD = 2,  // å­— (16位)
    DWORD = 4  // åŒå­— (32位)
};
// æŽ§åˆ¶ä»£ç 
enum class ControlCode {
    RUN = 0,   // è¿œç¨‹ RUN
    STOP = 1,  // è¿œç¨‹ STOP
    PAUSE = 2  // è¿œç¨‹ PAUSE
};
// ç‰ˆæœ¬ä¿¡æ¯
struct BoardVersion {
    char fixedValue[2];       // å›ºå®šå€¼
    char checksum[2];         // æ ¡éªŒå’Œ
    char swVersion[2];        // è½¯ä»¶ç‰ˆæœ¬
    char date[6];             // æ—¥æœŸ (格式 YYMMDD)
    uint32_t reserved;        // ä¿ç•™åŒºåŸŸ (4 å­—节)
    char swModel[16];         // è½¯ä»¶åž‹å·
    char hwModel[16];         // ç¡¬ä»¶åž‹å·
    char twoPortMemory[2];    // ä¸¤ç«¯å£å­˜å‚¨å™¨å ç”¨å®¹é‡
    char twoPortAttribute[2]; // ä¸¤ç«¯å£å±žæ€§
    char availableBias[2];    // å¯ä½¿ç”¨åç½®
    char moduleType[10];      // æœºåž‹ç±»åž‹
    // è¾“出结构体内容为字符串 (便于调试)
    std::string toString() const {
        std::ostringstream oss;
        oss << "Fixed Value: " << fixedValue[0] << fixedValue[1] << "\n"
            << "Checksum: " << checksum[0] << checksum[1] << "\n"
            << "SW Version: " << swVersion[0] << swVersion[1] << "\n"
            << "Date: " << std::string(date, 6) << "\n"
            << "Reserved: " << reserved << "\n"
            << "SW Model: " << std::string(swModel, 16) << "\n"
            << "HW Model: " << std::string(hwModel, 16) << "\n"
            << "Two Port Memory: " << twoPortMemory[0] << twoPortMemory[1] << "\n"
            << "Two Port Attribute: " << twoPortAttribute[0] << twoPortAttribute[1] << "\n"
            << "Available Bias: " << availableBias[0] << availableBias[1] << "\n"
            << "Module Type: " << std::string(moduleType, 10) << "\n";
        return oss.str();
    }
};
// ç«™ç‚¹æ ‡è¯†ç¬¦ï¼Œé»˜è®¤ä½¿ç”¨æœ¬ç«™
struct StationIdentifier {
    /*
     * [Network No.]
     * 0 è¡¨ç¤ºæœ¬ç«™
     * 1~239 è¡¨ç¤ºæ™®é€šç½‘络号
     **/
     /*
      * [Station No.]
      * MELSECNET/H:1~64 è¡¨ç¤ºå…¶ä»–站点,255 è¡¨ç¤ºæœ¬ç«™
      * CC-Link ç³»åˆ—网络的范围类似,区别在于站号的取值范围
      * MELSECNET/H             : 1~64(Other stations),255(Own station)
      * CC-Link                 : 0~63(Other stations),255(Own station)
      * CC-Link IE Controller   : 1~120(Other stations),255(Own station)
      * CC-Link IE Field        : 0~120(Other stations),255(Own station)
      * CC-Link IE TSN          : 0~120(Other stations),255(Own station)
      **/
      /*
       * é«˜ 8 ä½ï¼ˆç½‘络号): æŒ‡å®šè®¾å¤‡æ‰€å±žçš„网络
       * ä½Ž 8 ä½ï¼ˆç«™ç‚¹å·ï¼‰ï¼š æŒ‡å®šè®¾å¤‡åœ¨ç½‘络中的编号
       * ç”¨ä¸€ä¸ªå‚数传递设备的网络号和站点号时: nSt = station.nStNo | ((station.nNetNo << 8) & 0xFF00);
       **/
    short nNetNo = 0;    // ç½‘络编号:PLC所连接的网络编号,0表示默认网络
    short nStNo = 255;   // ç«™ç‚¹ç¼–号:指定与PLC连接的站点编号,255通常表示广播或所有站点
    // è‡ªå®šä¹‰æž„造函数,覆盖默认值
    explicit StationIdentifier(const short net, const short st) : nNetNo(net), nStNo(st) {}
    StationIdentifier()
    {
        nNetNo = 0;
        nStNo = 255;
    }
    // å°†â€œç½‘络号”和“站点号”组合成一个最终编码
    short StationIdentifier::toNetworkStationCode() const {
        return static_cast<short>(nStNo | ((nNetNo << 8) & 0xFF00));
    }
    // é‡è½½ < è¿ç®—符(用于排序或比较,通常用于 map æˆ– set ä¸­ä½œä¸º key)
    bool operator<(const StationIdentifier& other) const {
        return std::tie(nNetNo, nStNo) <
            std::tie(other.nNetNo, other.nStNo);
    }
    // é‡è½½ == è¿ç®—符(用于相等比较)
    bool operator==(const StationIdentifier& other) const {
        return std::tie(nNetNo, nStNo) ==
            std::tie(other.nNetNo, other.nStNo);
    }
    // é‡è½½ = è¿ç®—符(用于赋值)
    StationIdentifier& operator=(const StationIdentifier& other) {
        if (this != &other) {
            nNetNo = other.nNetNo;
            nStNo = other.nStNo;
        }
        return *this;
    }
};
// æ¿çŠ¶æ€
struct BoardStatus {
    short nStationValue = 0;    // ç«™å·çš„设备值 (buf[0])
    short nGroupValue = 0;      // ç»„ No. çš„设备值 (buf[1])
    short nNetworkValue = 0;    // ç½‘络 No. çš„设备值 (buf[2])
    short nReserved1 = 0;       // ä¿ç•™å­—段 (buf[3])
    short nReserved2 = 0;       // ä¿ç•™å­—段 (buf[4])
    short nReserved3 = 0;       // ä¿ç•™å­—段 (buf[5])
    // å°†æ•°ç»„映射到结构体
    static BoardStatus fromBuffer(const short buf[6]) {
        return {
            buf[0],
            buf[1],
            buf[2],
            buf[3],
            buf[4],
            buf[5]
        };
    }
    // å°†ç»“构体内容映射到数组
    void toBuffer(short buf[6]) const {
        buf[0] = nStationValue;
        buf[1] = nGroupValue;
        buf[2] = nNetworkValue;
        buf[3] = nReserved1;
        buf[4] = nReserved2;
        buf[5] = nReserved3;
    }
    // è°ƒè¯•输出
    std::string toString() const {
        std::ostringstream oss;
        oss << "Station Value: " << nStationValue << "\n"
            << "Group Value: " << nGroupValue << "\n"
            << "Network Value: " << nNetworkValue << "\n"
            << "Reserved1: " << nReserved1 << "\n"
            << "Reserved2: " << nReserved2 << "\n"
            << "Reserved3: " << nReserved3 << "\n";
        return oss.str();
    }
};
// äº‹ä»¶è¯¦æƒ…
struct EventDetails {
    short nEventNo;                      // å‘生的事件号
    std::array<short, 4> details;         // å­˜å‚¨äº‹ä»¶è¯¦æƒ…信息
    // è§£æžäº‹ä»¶è¯¦æƒ…,返回格式化字符串
    std::string toString() const {
        std::ostringstream oss;
        oss << "Details[0]: " << details[0] << ", "
            << "Details[1]: " << details[1] << ", "
            << "Details[2]: " << details[2] << ", "
            << "Details[3]: " << details[3];
        return oss.str();
    }
};
// SoftElement ç»“构体定义
struct SoftElement {
    short nType;         // è½¯å…ƒä»¶ç±»åž‹
    short nElementCount; // ç‚¹æ•°
    long nStartNo;       // èµ·å§‹è½¯å…ƒä»¶ç¼–号
};
// é”™è¯¯ä¿¡æ¯
struct ErrorInfo {
    int nErrorCode = 0;              // é”™è¯¯ç 
    std::string strErrorMessageCn;   // ä¸­æ–‡æè¿°
    std::string strErrorMessageEn;   // è‹±æ–‡æè¿°
    // å°†ç»“构体序列化为字符串
    std::string toString() const {
        std::ostringstream oss;
        oss << nErrorCode << "|" << strErrorMessageCn << "|" << strErrorMessageEn;
        return oss.str();
    }
    // ä»Žå­—符串反序列化为结构体
    static ErrorInfo fromString(const std::string& line) {
        ErrorInfo info;
        std::istringstream iss(line);
        std::string token;
        // ä½¿ç”¨åˆ†éš”符 "|" è§£æžå­—符串
        std::getline(iss, token, '|');
        info.nErrorCode = std::stoi(token);
        std::getline(iss, token, '|');
        info.strErrorMessageCn = token;
        std::getline(iss, token, '|');
        info.strErrorMessageEn = token;
        return info;
    }
};
using BitContainer = std::vector<bool>;            // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 1  ä½
using WordContainer = std::vector<uint16_t>;    // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 16 ä½
using DWordContainer = std::vector<uint32_t>;    // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 32 ä½
// CPerformanceMelsec ç±»å£°æ˜Ž
class CPerformanceMelsec {
public:
    // èŽ·å–æœ€è¿‘çš„é”™è¯¯ä¿¡æ¯
    std::string GetLastError() const;
    // é”™è¯¯ä¿¡æ¯åŠ è½½ä¸Žä¿å­˜æŽ¥å£
    static bool LoadErrorInfoFromFile(const std::string& filename);  // ä»Žæ–‡ä»¶åŠ è½½é”™è¯¯ä¿¡æ¯
    static bool SaveErrorInfoToFile(const std::string& filename);    // ä¿å­˜é”™è¯¯ä¿¡æ¯åˆ°æ–‡ä»¶
    // è¿žæŽ¥/断开
    int Connect(short nChannel, short nMode = -1);
    int Disconnect();
    // åˆå§‹åŒ–可编程控制器软元件信息表
    int InitializeController();
    //    èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
    int GetBoardVersion(BoardVersion& version);
    // æ¿å¤ä½
    int BoardReset();
    // æ¿LED读取
    int ReadBoardLed(std::vector<short>& vecLedBuffer);
    // è¯»å–目标站点CPU类型
    int ReadCPUCode(const StationIdentifier& station, short& nCPUCode);
    // æ¿æ¨¡å¼èŽ·å–/设置
    int SetBoardMode(short nMode);
    int GetBoardMode(short& nMode);
    // èŽ·å–æ¿çŠ¶æ€
    int GetBoardStatus(BoardStatus& status);
    // è¯»å†™æ•°æ®
    int ReadData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<short>& vecData);
    int ReadBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nBitCount, BitContainer& vecData);
    int ReadWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nWordCount, WordContainer& vecData);
    int ReadDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nDWordCount, DWordContainer& vecData);
    int WriteData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, short* pData);
    int WriteBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const BitContainer& vecData);
    int WriteWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const WordContainer& vecData);
    int WriteDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const DWordContainer& vecData);
    // æ‰©å±•读写数据
    long ReadDataEx(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<char>& vecData);
    long ReadBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nBitCount, BitContainer& vecData);
    long ReadWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nWordCount, WordContainer& vecData);
    long ReadDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nDWordCount, DWordContainer& vecData);
    long WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData);
    long WriteBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const BitContainer& vecData);
    long WriteWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const WordContainer& vecData);
    long WriteDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const DWordContainer& vecData);
    // æ‰©å±•软元件随机读写(支持多个软元件)
    long ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData);
    long WriteRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, const std::vector<char>& vecData);
    // è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器读写
    long ReadRemoteBuffer(const StationIdentifier& station, long nOffset, long nSize, std::vector<char>& vecData);
    long WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector<char>& vecData);
    long ReadRemoteBufferByIp(const std::string& strIP, long nOffset, long nSize, std::vector<char>& vecData);
    long WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector<char>& vecData);
    // è®¾ç½®/复位对象站的指定位软元件
    int SetBitDevice(const StationIdentifier& station, DeviceType enDevType, short nDevNo);
    int ResetBitDevice(const StationIdentifier& station, DeviceType enDevType, short enDevNo);
    // æ‰©å±•设置/复位对象站的指定位软元件
    long SetBitDeviceEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo);
    long ResetBitDeviceEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo);
    // æ‰§è¡Œå¯¹è±¡ç«™çš„CPU
    int ControlCPU(const StationIdentifier& station, ControlCode enControlCode);
    // äº‹ä»¶ç­‰å¾…,vecEventNumbers[0, 64],nTimeoutMs[-1, 2147483647]
    // åŒæ—¶å‘生了多个事件的情况下,首先检测出其中一个事件。 å†æ¬¡æ‰§è¡Œäº†æœ¬å‡½æ•°çš„æƒ…况下检测出其它事件。
    int WaitForBoardEvent(std::vector<short> vecEventNumbers, int nTimeoutMs, EventDetails& details);
private:
    // é”å®šä¸Žè§£é”ï¼ˆå¤šçº¿ç¨‹åŒæ­¥ä¿æŠ¤ï¼‰
    void Lock() { m_mtx.lock(); }
    void Unlock() { m_mtx.unlock(); }
protected:
    // æž„造函数/析构函数
    explicit CPerformanceMelsec(BoardType enBoardType);
    virtual ~CPerformanceMelsec();
    // è¾…助函数
    void UpdateLastError(int nCode);                                 // æ›´æ–°æœ€è¿‘的错误信息
    int ValidateStation(const StationIdentifier& station) const;     // æ£€æŸ¥è¿žæŽ¥çŠ¶æ€å’Œç«™ç‚¹å‚æ•°æœ‰æ•ˆæ€§
    int ValidateStationAndSize(const StationIdentifier& station, short nCount) const;
    // é™æ€è¾…助函数
    static void Delay(unsigned int nDelayMs);                        // å»¶æ—¶ï¼Œå¹¶ä¸”转发窗口消息
    static BoardType FindBoardTypeByChannel(int nChannel);            // æŸ¥æ‰¾æ¿å—类型
    static short CombineStation(const StationIdentifier& station);  // åˆå¹¶ç½‘络号和站点号
    static short CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType); // è®¡ç®—软元件类型
    // IP转换
    static bool ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP);
    // å®¹å™¨è½¬æ¢
    static void ConvertCharToShort(const std::vector<char>& vecChar, std::vector<short>& vecShort);
    static void ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar);
    static void ConvertUint8ToShort(const std::vector<uint8_t>& vecUint8, std::vector<short>& vecShort);
    static void ConvertShortToUint8(const std::vector<short>& vecShort, std::vector<uint8_t>& vecUint8);
    static void ConvertUint32ToShort(const std::vector<uint32_t>& vecUint32, std::vector<short>& vecShort);
    static void ConvertShortToUint32(const std::vector<short>& vecShort, std::vector<uint32_t>& vecUint32);
    // æ¨¡æ¿è¾…助函数
    template <typename T>
    int ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData);
    template <typename T, typename U>
    void ConvertLowToHigh(const std::vector<T>& vecLow, std::vector<U>& vecHigh);
    template <typename T, typename U>
    void ConvertHighToLow(const std::vector<T>& vecHigh, std::vector<U>& vecLow);
    // æˆå‘˜å˜é‡
    std::mutex m_mtx;                       // äº’斥锁保护
    BoardType m_enBoardType;                // æ¿å—类型
    long m_nPath;                           // é€šä¿¡è·¯å¾„
    std::atomic<bool> m_bConnected;         // æ˜¯å¦å·²è¿žæŽ¥
    std::string m_strLastError;             // æœ€è¿‘一次错误信息
    // é™æ€æˆå‘˜å˜é‡
    static std::unordered_map<int, std::string> m_mapError; // é”™è¯¯ç æ˜ å°„表
};
#endif // PERFORMANCE_MELSEC_H
SourceCode/Bond/SGMeasurement/DLL/32bit/SGIF.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1641 @@
#ifdef SGIF_EXPORTS
#define EXP __declspec(dllexport)
#else
#define EXP __declspec(dllimport)
#endif
#include "Winsock2.h"
#include "Ws2tcpip.h"
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "WS2_32.lib")
// Return Code List
typedef enum {
    RC_OK = 0x0000,
    // The operation is completed successfully.
    ///////////////////////////////////////////////
    // Communication error from controller notification
    //
    RC_NAK_COMMAND = 0x1001,        // Command error
    RC_NAK_COMMAND_LENGTH,            // Command length error
    RC_NAK_TIMEOUT,                    // Timeout
    RC_NAK_CHECKSUM,                // Check sum error
    RC_NAK_INVALID_STATE,            // Status error
    RC_NAK_OTHER,                    // Other error
    RC_NAK_PARAMETER,                // Parameter error
    RC_NAK_OUT_STAGE,                // OUT calculation count limitation error
    RC_NAK_OUT_HEAD_NUM,            // No. of used head/OUT over error
    RC_NAK_PARAM_RANGE_DATA_STORED,    // OUT No which data reserved over acctive out count
    RC_NAK_OUT_INVALID_CALC,        // OUT which cannot be used for calculation was specified for calculation.
    RC_NAK_OUT_VOID,                // OUT which specified for calculation is not found.
    RC_NAK_INVALID_CYCLE,            // Unavailable sampling cycle
    RC_NAK_CTRL_ERROR,                // Main unit error
    RC_NAK_SRAM_ERROR,                // Setting value error
    ///////////////////////////////////////////////
    // Communication DLL error notification
    //
    RC_ERR_OPEN_DEVICE = 0x2000,// Opening the device failed.
    RC_ERR_NO_DEVICE,            // The device is not open.
    RC_ERR_SEND,                // Command sending error
    RC_ERR_RECEIVE,                // Response receiving error
    RC_ERR_TIMEOUT,                // Timeout
    RC_ERR_NODATA,                // No data
    RC_ERR_NOMEMORY,            // No free memory
    RC_ERR_DISCONNECT,            // Cable disconnection suspected
    RC_ERR_UNKNOWN,                // Undefined error
    RC_ERR_DEVID_OVER,            // over dev_id scale
    RC_ERR_NET_NO_CONN,            // no connected at the deviceID
    RC_ERR_IP_EXISTED,
    RC_ERR_SELECT,                // select of /socket error
    RC_ERR_NULL_PARAMETER,        // NULL point exception from parameter
    RC_ERR_DIY_FUNC,            // error due to dir function
    RC_ERR_OVER_PARAMENTER,        // paramenter over the limition
    RC_ERR_NOT_SUPPORT            // åŠŸèƒ½ä¸æ”¯æŒ
} RC;
//device Version
typedef enum {
    SG3035 = 0,
    SG3030 = 1,
    SG3085 = 2,
    SG3080 = 3,
    SG5025 = 4,
    SG5020 = 5,
    SG5055 = 6,
    SG5050 = 7,
    SG5085 = 8,
    SG5080 = 9,
    SG5155 = 10,
    SG5150 = 11,
    SC04025 = 12,
    SC03560 = 13,
    SGI500 = 14,
    SGI505 = 15,
    SGI400 = 16,
    SGI405 = 17,
    SGI150 = 18,
    SGI155 = 19,
    SGI080 = 20,
    SGI085 = 21,
    SGI050 = 22,
    SGI055 = 23,
    SGI030 = 24,
    SGI035 = 25,
    SGI020 = 26,
    SGI025 = 27,
    SG3155 = 28,
    SG3150 = 29,
    SC01045 = 30,
    SC10015 = 31,
    SC20011 = 32,
    SC01236 = 33,
    SCI04025 = 34,
    SCI03560 = 35,
    SCI01045 = 36,
    SCI10015 = 37,
    SCI20011 = 38,
    SCI01236 = 39,
}SGIF_DEVICE_TYPE;
// Measurement value structures
typedef enum {
    SGIF_FLOATRESULT_VALID,            // valid data
    SGIF_FLOATRESULT_RANGEOVER_P,    // over range at positive (+) side
    SGIF_FLOATRESULT_RANGEOVER_N,    // over range at negative (-) side
    SGIF_FLOATRESULT_WAITING,        // Wait for comparator result
    SGIF_FLOATRESULT_ALARM,            // alarm
    SGIF_FLOATRESULT_INVALID,        // Invalid (error, etc.)
} SGIF_FLOATRESULT;
// Set ABLE
typedef enum {
    SGIF_ABLEMODE_AUTO,                // AUTO
    SGIF_ABLEMODE_MANUAL,            // manual
} SGIF_ABLEMODE;
// Set Measurement Mode
typedef enum {
    SGIF_MEASUREMODE_NORMAL,                        // normal
    SGIF_MEASUREMODE_HALF_T,                        // translucent object
    SGIF_MEASUREMODE_TRAN_1,                        // transparent object
    SGIF_MEASUREMODE_TRAN_2,                        // transparent object 2
    SGIF_MEASUREMODE_MRS,                            // multireflective object
    SGIF_MEASUREMODE_OPAQUE = SGIF_MEASUREMODE_MRS,    // Semi opaque object
} SGIF_MEASUREMODE;
// Set Basic Point
typedef enum {
    SGIF_BASICPOINT_NEAR,            // NEAR
    SGIF_BASICPOINT_FAR,            // FAR
} SGIF_BASICPOINT;
// Set Mounting Mode
typedef enum {
    SGIF_REFLECTIONMODE_DIFFUSION,    // diffuse reflection
    SGIF_REFLECTIONMODE_MIRROR,        // specular reflection
} SGIF_REFLECTIONMODE;
// Set Median
typedef enum {
    SGIF_MEDIAN_OFF,                // OFF
    SGIF_MEDIAN_7,                    // 7 point
    SGIF_MEDIAN_15,                    // 15 point
    SGIF_MEDIAN_31,                    // 31 point
} SGIF_MEDIAN;
// Set LASER CTRL group.
typedef enum {
    SGIF_LASER_CTRL_GROUP_1,        // LASER CTRL 1
    SGIF_LASER_CTRL_GROUP_2,        // LASER CTRL 2
} SGIF_LASER_CTRL_GROUP;
// Set a range.
typedef enum {
    SGIF_RANGE_CENTER,                // CENTER
    SGIF_RANGE_FAR,                    // FAR
} SGIF_RANGE;
// Set Mutual Interference Prevention Group
typedef enum {
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP_A,    // Group A
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP_B,    // Group B
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP_C,    // Group C
} SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP;
// Set calculation method.
typedef enum {
    SGIF_CALCMETHOD_HEADA,                    // head A
    SGIF_CALCMETHOD_HEADB,                    // head B
    SGIF_CALCMETHOD_HEAD_HEADA_PLUS_HEADB,    // head A+head B
    SGIF_CALCMETHOD_HEAD_HEADA_MINUS_HEADB,    // head A-head B
    SGIF_CALCMETHOD_HEAD_HEADA_TRANSPARENT,    // head A transparent object
    SGIF_CALCMETHOD_HEAD_HEADB_TRANSPARENT,    // head B transparent object
    SGIF_CALCMETHOD_HEAD = 0,    // head
    SGIF_CALCMETHOD_OUT,        // OUT
    SGIF_CALCMETHOD_ADD,        // ADD
    SGIF_CALCMETHOD_SUB,        // SUB
    SGIF_CALCMETHOD_AVE,        // AVE
    SGIF_CALCMETHOD_MAX,        // MAX
    SGIF_CALCMETHOD_MIN,        // MIN
    SGIF_CALCMETHOD_PP,            // P-P
} SGIF_CALCMETHOD;
// Set Target Surface
typedef enum {
    SGIF_CALCTARGET_PEAK_1,        // peak 1
    SGIF_CALCTARGET_PEAK_2,        // peak 2
    SGIF_CALCTARGET_PEAK_3,        // peak 3
    SGIF_CALCTARGET_PEAK_4,        // peak 4
    SGIF_CALCTARGET_PEAK_1_2,    // peak 1-peak 2
    SGIF_CALCTARGET_PEAK_1_3,    // peak 1-peak 3
    SGIF_CALCTARGET_PEAK_1_4,    // peak 1-peak 4
    SGIF_CALCTARGET_PEAK_2_3,    // peak 2-peak 3
    SGIF_CALCTARGET_PEAK_2_4,    // peak 2-peak 4
    SGIF_CALCTARGET_PEAK_3_4,    // peak 3-peak 4
} SGIF_CALCTARGET;
// Set Filter Mode
typedef enum {
    SGIF_FILTERMODE_MOVING_AVERAGE,            // moving average
} SGIF_FILTERMODE;
// Specify the filter parameter. (The number of averaging for moving average, or the cutoff frequency for LPF/HPF.)
typedef enum {
    SGIF_FILTERPARA_AVE_1 = 0,        // 1 time
    SGIF_FILTERPARA_AVE_4,            // 4 times
    SGIF_FILTERPARA_AVE_16,            // 16 times
    SGIF_FILTERPARA_AVE_64,            // 64 times
    SGIF_FILTERPARA_AVE_256,        // 256 times
    SGIF_FILTERPARA_AVE_1024,        // 1024 times
    SGIF_FILTERPARA_AVE_4096,        // 4096 times
    SGIF_FILTERPARA_AVE_16384,        // 16384 times
    SGIF_FILTERPARA_AVE_65536,        // 65536 times
    SGIF_FILTERPARA_AVE_262144,        // 262144 times
}SGIF_FILTERPARA;
// Set Trigger Mode
typedef enum {
    SGIF_TRIGGERMODE_EXT1,        // external trigger 1
    SGIF_TRIGGERMODE_EXT2,        // external trigger 2
} SGIF_TRIGGERMODE;
// Set the Measurement Mode.
typedef enum {
    SGIF_CALCMODE_NORMAL,            // normal
    SGIF_CALCMODE_PEAKHOLD,            // peak hold
    SGIF_CALCMODE_BOTTOMHOLD,        // bottom hold
    SGIF_CALCMODE_PEAKTOPEAKHOLD,    // peak-to-peak hold
    SGIF_CALCMODE_SAMPLEHOLD,        // sample hold
} SGIF_CALCMODE;
// Set Minimum Display Unit
typedef enum {
    SGIF_DISPLAYUNIT_0000_01MM = 0,    // 0.01mm
    SGIF_DISPLAYUNIT_000_001MM,        // 0.001mm
    SGIF_DISPLAYUNIT_00_0001MM,        // 0.0001mm
    SGIF_DISPLAYUNIT_0_00001MM,        // 0.00001mm
    SGIF_DISPLAYUNIT_00000_1UM,        // 0.1um
    SGIF_DISPLAYUNIT_0000_01UM,        // 0.01um
    SGIF_DISPLAYUNIT_000_001UM,        // 0.001um
} SGIF_DISPLAYUNIT;
// Specify OUT
typedef enum {
    SGIF_OUTNO_01 = 0x0001,            // OUT01
    SGIF_OUTNO_02 = 0x0002,            // OUT02
    SGIF_OUTNO_03 = 0x0004,            // OUT03
    SGIF_OUTNO_04 = 0x0008,            // OUT04
    SGIF_OUTNO_ALL = 0x000F,        // All OUTs
} SGIF_OUTNO;
// Set Storage (Cycle)
typedef enum {
    SGIF_STORAGECYCLE_1,            // sampling rate x 1
    SGIF_STORAGECYCLE_2,            // sampling rate x 2
    SGIF_STORAGECYCLE_5,            // sampling rate x 5
    SGIF_STORAGECYCLE_10,            // sampling rate x 10
    SGIF_STORAGECYCLE_20,            // sampling rate x 20
    SGIF_STORAGECYCLE_50,            // sampling rate x 50
    SGIF_STORAGECYCLE_100,            // sampling rate x 100
    SGIF_STORAGECYCLE_200,            // sampling rate x 200
    SGIF_STORAGECYCLE_500,            // sampling rate x 500
    SGIF_STORAGECYCLE_1000,            // sampling rate x 1000
    SGIF_STORAGECYCLE_TIMING,        // Timing sync
} SGIF_STORAGECYCLE;
// Set Sampling Rate
typedef enum {
    //SG5000系列
    SGIF_5000_SAMPLINGCYCLE_590KHZ,     // 590kHz
    SGIF_5000_SAMPLINGCYCLE_400KHZ,        // 400kHz
    SGIF_5000_SAMPLINGCYCLE_200KHZ,        // 200kHz
    SGIF_5000_SAMPLINGCYCLE_88KHZ,        // 88kHz
    SGIF_5000_SAMPLINGCYCLE_50KHZ,        // 50kHz
    SGIF_5000_SAMPLINGCYCLE_20KHZ,        // 20kHz
    SGIF_5000_SAMPLINGCYCLE_10KHZ,        // 10kHz
    SGIF_5000_SAMPLINGCYCLE_5KHZ,        // 5kHz
    SGIF_5000_SAMPLINGCYCLE_2KHZ,        // 2kHz
    SGIF_5000_SAMPLINGCYCLE_1KHZ,        // 1kHz+
    //SG3000系列
    SGIF_3000_SAMPLINGCYCLE_88KHZ = 10,    // 88kHz
    SGIF_3000_SAMPLINGCYCLE_50KHZ,        // 50kHz
    SGIF_3000_SAMPLINGCYCLE_20KHZ,        // 20kHz
    SGIF_3000_SAMPLINGCYCLE_10KHZ,        // 10kHz
    SGIF_3000_SAMPLINGCYCLE_5KHZ,        // 5kHz
    //SGIF_3000_SAMPLINGCYCLE_2KHZ,        // 2kHz
    SGIF_3000_SAMPLINGCYCLE_1KHZ,        // 1kHz
    //SCI系列
    SCI_SAMPLINGCYCLE_33KHZ = 30,    // 33kHz
    SCI_SAMPLINGCYCLE_20KHZ,        // 20kHz
    SCI_SAMPLINGCYCLE_15KHZ,        // 15kHz
    SCI_SAMPLINGCYCLE_10KHZ,        // 10kHz
    SCI_SAMPLINGCYCLE_5KHZ,            // 5kHz
    SCI_SAMPLINGCYCLE_2KHZ,            // 2kHz
    SCI_SAMPLINGCYCLE_1KHZ,            // 1kHz
    SCI_SAMPLINGCYCLE_05KHZ,        // 0.5kHz
} SGIF_SAMPLINGCYCLE;
// Set Mutual interference prevention
typedef enum {
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_OFF,    // OFF
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_AB_ON,    // AB-ON
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_ABC_ON,    // ABC-ON
} SGIF_MUTUAL_INTERFERENCE_PREVENTION;
// Set Strobe Time
typedef enum {
    SGIF_STOROBETIME_2MS,        // 2ms
    SGIF_STOROBETIME_5MS,        // 5ms
    SGIF_STOROBETIME_10MS,        // 10ms
    SGIF_STOROBETIME_20MS,        // 20ms
} SGIF_STOROBETIME;
// Mode Switch
typedef enum {
    SGIF_MODE_NORMAL,                // normal mode
    SGIF_MODE_COMMUNICATION,        // setting mode
} SGIF_MODE;
//Encoder ext
typedef enum {
    SGIF_EmRunningMode_cont,//off
    SGIF_EmRunningMode_time,
    SGIF_EmRunningMode_trig,
}SGIF_EmRunningMode;
typedef enum {
    SGIF_EmDirection_all,//+-
    SGIF_EmDirection_pos,
    SGIF_EmDirection_neg,
}SGIF_EmDirection;
typedef enum {
    SGIF_EmEncoderInput_1x1,
    SGIF_EmEncoderInput_2x1,
    SGIF_EmEncoderInput_2x2,
    SGIF_EmEncoderInput_2x4,
}SGIF_EmEncoderInput;
typedef enum {
    SGIF_EmInputTime_100 = 100,
    SGIF_EmInputTime_200 = 200,
    SGIF_EmInputTime_500 = 500,
    SGIF_EmInputTime_1000 = 1000,
    SGIF_EmInputTime_2000 = 2000,
    SGIF_EmInputTime_5000 = 5000,
    SGIF_EmInputTime_10000 = 10000,
    SGIF_EmInputTime_20000 = 20000,
}SGIF_EmInputTime;
// Measurement value
typedef struct {
    int                    OutNo;            // OUT No(1-4)
    SGIF_FLOATRESULT    FloatResult;    // valid or invalid data
    float                Value;            // Measurement value
} SGIF_FLOATVALUE_OUT;
typedef struct {
    SGIF_FLOATRESULT    FloatResult;    // valid or invalid data
    float                Value;            // Measurement value
} SGIF_FLOATVALUE;
// IP address
typedef struct {
    IN_ADDR                IPAddress;
} SGIF_OPENPARAM_ETHERNET;
//Mask Minimum Display Unit(0.01mm)
#define MASKUNIT 100
#ifdef __cplusplus
extern "C"
{
#endif
    EXP RC WINAPI SGIF_GetDeviceType(IN int DeviceID, OUT SGIF_DEVICE_TYPE* deviceType);
    // Measured control commands
    ///
    /// \brief SGIF_GetCameraSpotType    å…‰æ–‘类型(不支持SCI)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param ControlType:                è¾“出0:小光斑,1:大光斑
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCameraSpotType(IN int DeviceID, OUT int *EissionSpotType);
    ///////////////////////////////////////////////
    // Measurement control commands
    //
    // Measured value output (single)
    ///
    /// \brief SGIF_GetCalcDataSingle    æµ‹é‡å€¼è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \param CalcData:                æµ‹é‡å€¼
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcDataSingle(IN int DeviceID, IN int OutNo, OUT SGIF_FLOATVALUE_OUT * CalcData);
    // Measured value output (multiple)
    ///
    /// \brief SGIF_GetCalcDataMulti    å¤šä¸ªæµ‹é‡å€¼è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \param CalcData:                æµ‹é‡å€¼æ•°ç»„
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcDataMulti(IN int DeviceID, IN SGIF_OUTNO OutNo, OUT SGIF_FLOATVALUE_OUT * CalcData);
    // Measured value output (ALL)
    ///
    /// \brief SGIF_GetCalcDataALL        å…¨éƒ¨æµ‹é‡å€¼è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param CalcData:                æµ‹é‡å€¼æ•°ç»„
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcDataALL(IN int DeviceID, OUT SGIF_FLOATVALUE_OUT * CalcData);
    // Timing ON/OFF (single)
    ///
    /// \brief SGIF_SetTimingSingle        è®¡æ—¶ON/OFF(一个)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTimingSingle(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Timing ON/OFF (multiple)
    ///
    /// \brief SGIF_SetTimingMulti        è®¡æ—¶ON/OFF(多个)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTimingMulti(IN int DeviceID, IN SGIF_OUTNO OutNo, IN BOOL OnOff);
    // Timing ON/OFF (synchronous)
    ///
    /// \brief SGIF_SetTimingSync        è®¡æ—¶ON/OFF(同步)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTimingSync(IN int DeviceID, IN BOOL OnOff);
    // Auto-zero ON/OFF (single)
    ///
    /// \brief SGIF_SetZeroSingle        è‡ªåŠ¨å½’é›¶ï¼ˆä¸€ä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetZeroSingle(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Auto-zero ON/OFF (multiple)
    ///
    /// \brief SGIF_SetZeroMulti        è‡ªåŠ¨å½’é›¶ï¼ˆå¤šä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetZeroMulti(IN int DeviceID, IN SGIF_OUTNO OutNo, IN BOOL OnOff);
    // Auto-zero ON/OFF (synchronous)
    ///
    /// \brief SGIF_SetZeroSync            è‡ªåŠ¨å½’é›¶ï¼ˆåŒæ­¥ï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetZeroSync(IN int DeviceID, IN BOOL OnOff);
    // Measured value reset (single)
    ///
    /// \brief SGIF_SetResetSingle        é‡ç½®ï¼ˆä¸€ä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetResetSingle(IN int DeviceID, IN int OutNo);
    // Measured value reset (multiple)
    ///
    /// \brief SGIF_SetResetMulti        é‡ç½®ï¼ˆå¤šä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetResetMulti(IN int DeviceID, IN SGIF_OUTNO OutNo);
    // Measured value reset (synchronous)
    ///
    /// \brief SGIF_SetResetSync        é‡ç½®ï¼ˆåŒæ­¥ï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetResetSync(IN int DeviceID);
    // Program Change
    ///
    /// \brief SGIF_SetProgramNo        ç¨‹åºåˆ‡æ¢
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param ProgramNo:                ç¨‹åºç¼–号(0到7)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetProgramNo(IN int DeviceID, IN int ProgramNo);
    // Program Check
    ///
    /// \brief SGIF_GetProgramNo        ç¨‹åºç¡®è®¤
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param ProgramNo:                ç¨‹åºç¼–号(0到7)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetProgramNo(IN int DeviceID, OUT int * ProgramNo);
    // Starting the Data Storage
    ///
    /// \brief SGIF_DataStorageStart    æ•°æ®å­˜å‚¨å¼€å§‹
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageStart(IN int DeviceID);
    // Stopping the Data Storage
    ///
    /// \brief SGIF_DataStorageStop        æ•°æ®å­˜å‚¨åœæ­¢
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageStop(IN int DeviceID);
    // Outputting the Data Storage
    ///
    /// \brief SGIF_DataStorageGetData    æ•°æ®å­˜å‚¨æ•°æ®è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param NumOfBuffer                ç¼“冲区大小(最多可接受多少个数据)
    /// \param OutBuffer                æ•°æ®æ•°ç»„
    /// \param NumReceived                å®žé™…接收的数据个数
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageGetData(IN int DeviceID, IN int OutNo, IN int NumOfBuffer, OUT float * OutBuffer, OUT int *NumReceived);
    // Initializing the Data Storage
    ///
    /// \brief SGIF_DataStorageInit        æ•°æ®å­˜å‚¨åˆå§‹åŒ–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageInit(IN int DeviceID);
    // Data Storage Accumulation Status Output
    ///
    /// \brief SGIF_DataStorageGetStatus    æ•°æ®å­˜å‚¨çŠ¶æ€è¾“å‡º
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param lsStorage                    å­˜å‚¨çŠ¶æ€
    /// \param NumStorageData                å„输出口存储数量数组
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageGetStatus(IN int DeviceID, OUT BOOL * lsStorage, OUT int  * NumStorageData);
    ///////////////////////////////////////////////
    // Setting change commands
    //
    // Set Tolerance
    ///
    /// \brief SGIF_SetTolerance            å…¬å·®è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param UpperLimit                    ä¸Šé™ï¼Œä¼ å…¥ä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param LowerLimit                    ä¸‹é™ï¼Œä¼ å…¥ä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param Hystersys                    æ»žåŽï¼Œä¼ å…¥ä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTolerance(IN int DeviceID, IN int OutNo, IN int UpperLimit, IN int LowerLimit, IN int Hystersys);
    // Set ABLE
    ///
    /// \brief SGIF_SetAbleMode                Able模式设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AbleMode                        Ä£Ê½
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAbleMode(IN int DeviceID, IN int HeadNo, IN SGIF_ABLEMODE AbleMode);
    // Set ABLE Control Range
    ///
    /// \brief SGIF_SetAbleMinMax            Able控制范围设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Min                            ä¸‹é™
    /// \param Max                            ä¸Šé™
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAbleMinMax(IN int DeviceID, IN int HeadNo, IN int Min, IN int Max);
    // Set Detection mode
    ///
    /// \brief SGIF_SetMeasureMode            æµ‹é‡æ¨¡å¼è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \MeasureMode                        æµ‹é‡æ¨¡å¼
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMeasureMode(IN int DeviceID, IN int HeadNo, IN SGIF_MEASUREMODE MeasureMode);
    // Set Base point
    ///
    /// \brief SGIF_SetBasicPoint            åŸºå‡†ç‚¹è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param BasicPoint                    åŸºå‡†ç‚¹
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetBasicPoint(IN int DeviceID, IN int HeadNo, IN SGIF_BASICPOINT BasicPoint);
    // Set Number of Times of Alarm Processing
    ///
    /// \brief SGIF_SetNumAlarm                è­¦æŠ¥æ•°é‡è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmNum                        è­¦æŠ¥æ•°é‡
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetNumAlarm(IN int DeviceID, IN int HeadNo, IN int AlarmNum);
    // Set Number of Times of Alarm Recovery
    ///
    /// \brief SGIF_SetNumRecovery            æ¢å¤æ•°é‡è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param RecoveryNum                    æ¢å¤æ¬¡æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetNumRecovery(IN int DeviceID, IN int HeadNo, IN int RecoveryNum);
    // Set Alarm Level
    ///
    /// \brief SGIF_SetAlarmLevel            è­¦æŠ¥çº§åˆ«è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmLevel                    è­¦æŠ¥çº§åˆ«
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAlarmLevel(IN int DeviceID, IN int HeadNo, IN int AlarmLevel);
    // Starting the ABLE Calibration
    ///
    /// \brief SGIF_AbleStart                Able校准开始
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_AbleStart(IN int DeviceID, IN int HeadNo);
    // Finishing the ABLE Calibration
    ///
    /// \brief SGIF_AbleStop                Able校准完成
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_AbleStop(IN int DeviceID);
    // Stopping the ABLE Calibration
    ///
    /// \brief SGIF_AbleCancel                AbleУ׼ֹͣ
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_AbleCancel(IN int DeviceID);
    // Set Mounting Mode
    ///
    /// \brief SGIF_SetReflectionMode        å®‰è£…模式设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param ReflectionMode                åå°„模式
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetReflectionMode(IN int DeviceID, IN int HeadNo, IN SGIF_REFLECTIONMODE ReflectionMode);
    // Set Mask
    ///
    /// \brief SGIF_SetMask                    å±è”½è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param OnOff                        å¼€å…³
    /// \param HeadNo                        ç‚¹ä½1
    /// \param HeadNo                        ç‚¹ä½2
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMask(IN int DeviceID, IN int HeadNo, IN BOOL OnOff, IN int Pos1, IN int Pos2);
    // Set Median
    ///
    /// \brief SGIF_SetMedian                ä¸­ä½æ•°è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Median                        ä¸­ä½æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMedian(IN int DeviceID, IN int HeadNo, IN SGIF_MEDIAN Median);
    // Set LASER CTRL group
    ///
    /// \brief SGIF_SetLaserCtrlGroup        Laser Ctrl组设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param LaserCtrlGroup                Laser Ctrl组
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetLaserCtrlGroup(IN int DeviceID, IN int HeadNo, IN SGIF_LASER_CTRL_GROUP LaserCtrlGroup);
    // Set Mutual interference prevention group
    ///
    /// \brief SGIF_SetMutualInterferencePreventionGroup        é˜²æ­¢äº’相干扰组设定
    /// \param DeviceID                                            è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                                            ä¼ æ„Ÿå¤´ç¼–号
    /// \param Group                                            ç»„
    /// \return
    ///     >0:                                                    å¤±è´¥.
    ///     =0:                                                    æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMutualInterferencePreventionGroup(IN int DeviceID, IN int HeadNo, IN SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP Group);
    // Set Calculation method
    ///
    /// \brief SGIF_SetCalcMethod        è®¡ç®—方式设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMethod                è®¡ç®—方法
    /// \param HeadOutNo                ä¼ æ„Ÿå¤´è¾“出编号
    /// \return
    ///     >0:                                                    å¤±è´¥.
    ///     =0:                                                    æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetCalcMethod(IN int DeviceID, IN int OutNo, IN SGIF_CALCMETHOD CalcMethod, IN int HeadOutNo);
    // Set Surface to be measured
    ///
    /// \brief SGIF_SetCalcTarget        æµ‹é‡ç›®æ ‡è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcTarget                è®¡ç®—标签
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetCalcTarget(IN int DeviceID, IN int OutNo, IN SGIF_CALCTARGET CalcTarget);
    // Set OUT to be calculated (ADD, SUB)
    ///
    /// \brief SGIF_SetOutAddSub        å¾…计算的OUT(Add,Sub)设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param AddSub1                    å¾…计算的OUT
    /// \param AddSub2                    å¾…计算的OUT
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOutAddSub(IN int DeviceID, IN int OutNo, IN int AddSub1, IN int AddSub2);
    // Set OUT to be calculated (AVE, MAX, MIN, P-P)
    ///
    /// \brief SGIF_SetOutOperation        å¾…计算的OUT(Ave,Max,Min,P-P)设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TargetOut                å¤šä¸ªOUT组合
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOutOperation(IN int DeviceID, IN int OutNo, IN SGIF_OUTNO TargetOut);
    // Set Scaling
    ///
    /// \brief SGIF_SetScaling            ç¼©æ”¾è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param InputValue1                ç‚¹1的测量值(输入值),传有效数字(去掉小数点后的整形)
    /// \param OutputValue1                ç‚¹1的显示值(输出值),传有效数字(去掉小数点后的整形)
    /// \param InputValue2                ç‚¹2的测量值(输入值),传有效数字(去掉小数点后的整形)
    /// \param OutputValue2                ç‚¹2的显示值(输出值),传有效数字(去掉小数点后的整形)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetScaling(IN int DeviceID, IN int OutNo, IN int InputValue1, IN int OutputValue1, IN int InputValue2, IN int OutputValue2);
    // Set Filter Mode
    ///
    /// \brief SGIF_SetFilter            æ»¤æ³¢å™¨è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param FilterMode                æ»¤æ³¢æ¨¡å¼
    /// \param FilterPara                æ»¤æ³¢å‚æ•°
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetFilter(IN int DeviceID, IN int OutNo, IN SGIF_FILTERMODE FilterMode, IN SGIF_FILTERPARA FilterPara);
    // Set Trigger Mode
    ///
    /// \brief SGIF_SetTriggerMode        è§¦å‘模式设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TriggerMode                è§¦å‘模式
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTriggerMode(IN int DeviceID, IN int OutNo, IN SGIF_TRIGGERMODE TriggerMode);
    // Set Offset
    ///
    /// \brief SGIF_SetOffset            åç§»è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param Offset                    åç§»é‡
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOffset(IN int DeviceID, IN int OutNo, IN int Offset);
    // Set Calculation Mode
    ///
    /// \brief SGIF_SetCalcMode            æ£€æµ‹æ¨¡å¼ï¼ˆæµ‹é‡æ¨¡å¼ï¼‰è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMode                    æ£€æµ‹æ¨¡å¼ç¼–号
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetCalcMode(IN int DeviceID, IN int OutNo, IN SGIF_CALCMODE CalcMode);
    // Set Minimum Display Unit
    ///
    /// \brief SGIF_SetDisplayUnit        è®¾å®šæ˜¾ç¤ºå•位设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param DisplayUnit                æ˜¾ç¤ºå•位
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetDisplayUnit(IN int DeviceID, IN int OutNo, IN SGIF_DISPLAYUNIT DisplayUnit);
    // Set Synchronization
    ///
    /// \brief SGIF_SetSynchronization        åŒæ­¥è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetSynchronization(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Set Storage (OUT No. specification)
    ///
    /// \brief SGIF_SetStorageTarget        å­˜å‚¨ï¼ˆOUT编号规格)设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetStorageTarget(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Set Sampling Rate
    ///
    /// \brief SGIF_SetSamplingCycle        é‡‡æ ·å‘¨æœŸè®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param SamplingCycle                é‡‡æ ·å‘¨æœŸ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetSamplingCycle(IN int DeviceID, IN SGIF_SAMPLINGCYCLE SamplingCycle);
    // Set Mutual Interference Prevention
    ///
    /// \brief SGIF_SetMutualInterferencePrevention        é˜²æ­¢äº’相干扰组设定
    /// \param DeviceID                                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff                                    ç»„设定
    /// \return
    ///     >0:                                            å¤±è´¥.
    ///     =0:                                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMutualInterferencePrevention(IN int DeviceID, IN SGIF_MUTUAL_INTERFERENCE_PREVENTION OnOff);
    // Set Strobe Time
    ///
    /// \brief SGIF_SetStrobeTime            é€‰é€šæ—¶é—´è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param StrobeTime                    é€‰é€šæ—¶é—´
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetStrobeTime(IN int DeviceID, IN SGIF_STOROBETIME StrobeTime);
    // Set Data Storage
    ///
    /// \brief SGIF_SetDataStorage            æ•°æ®å­˜å‚¨è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param NumStorage                    å¾…存储数据的编号
    /// \param StorageCycle                    å­˜å‚¨å‘¨æœŸ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetDataStorage(IN int DeviceID, IN int NumStorage, IN SGIF_STORAGECYCLE StorageCycle);
    // EncoderSetting
    ///
    /// \brief SGIF_SetRunningMode            è¿è¡Œæ¨¡å¼è®¾ç½®(不支持SCI设备)
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param runningmode                    è¿è¡Œæ¨¡å¼ 0:OFF/1:定时/2:触发
    /// \param CatchDirection               æ£€æµ‹æ–¹å‘ 0:正负计时/1:正计时/2:负计时
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetRunningMode(IN int DeviceID, IN SGIF_EmRunningMode Runningmode, IN SGIF_EmDirection CatchDirection);
    // EncoderInputSetting
    ///
    /// \brief SGIF_SetEncoderMode            ç¼–码器输入模式设置(不支持SCI设备)
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param Inputmode                    è¿è¡Œæ¨¡å¼ 0:1相1递增/1:2相1递增/2:2相2递增,3:2相4递增
    /// \param MinInputTime                    æœ€å°è¾“入时间
    /// \param TrigInterval                    è§¦å‘é—´éš”
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetEncoderMode(IN int DeviceID, IN SGIF_EmEncoderInput Inputmode,IN SGIF_EmInputTime InputTime,IN int TrigInterval);
    // SGIF_SetFormula
    ///
    /// \brief SGIF_SetFormula                è®¾ç½®é…æ–¹
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param filePath                        é…æ–¹è·¯å¾„
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///  derive
    EXP RC WINAPI SGIF_SetFormula(IN int DeviceID, IN char* filePath );
    // SGIF_SetFormula
    ///
    /// \brief SGIF_SetFormula                è®¾ç½®é…æ–¹
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param filePath                        é…æ–¹è·¯å¾„
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DeriveFormula(IN int DeviceID, IN char* filePath);
    ///////////////////////////////////////////////
    // Setting confirmation commands
    //
    // Get Tolerance
    ///
    /// \brief SGIF_GetTolerance            å…¬å·®è®¾å®šèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param UpperLimit                    ä¸Šé™ï¼Œä¼ å‡ºä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param LowerLimit                    ä¸‹é™ï¼Œä¼ å‡ºä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param Hysteresis                    æ»žåŽï¼Œä¼ å‡ºä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetTolerance(IN int DeviceID, IN int OutNo, OUT int * UpperLimit, OUT int * LowerLimit, OUT int * Hysteresis);
    // Get ABLE
    ///
    /// \brief SGIF_GetAbleMode                Able设定获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AbleMode                        Ableģʽ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAbleMode(IN int DeviceID, IN int HeadNo, OUT SGIF_ABLEMODE * AbleMode);
    // Get ABLE Control Range
    ///
    /// \brief SGIF_GetAbleMinMax            Able控制范围获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Min                            æœ€å°å€¼
    /// \param Max                            æœ€å¤§å€¼
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAbleMinMax(IN int DeviceID, IN int HeadNo, OUT int * Min, OUT int * Max);
    // Get Detection mode
    ///
    /// \brief SGIF_GetMeasureMode            æµ‹é‡æ¨¡å¼èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param MeasureMode                    æµ‹é‡æ¨¡å¼
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMeasureMode(IN int DeviceID, IN int HeadNo, OUT SGIF_MEASUREMODE * MeasureMode);
    // Get Base point
    ///
    /// \brief SGIF_GetBasicPoint            åŸºå‡†ç‚¹èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param BasicPoint                    åŸºå‡†ç‚¹
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetBasicPoint(IN int DeviceID, IN int HeadNo, OUT SGIF_BASICPOINT * BasicPoint);
    // Get Number of Times of Alarm Processing
    ///
    /// \brief SGIF_GetNumAlarm                è­¦æŠ¥å¤„理次数获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmNum                        è­¦æŠ¥æ¬¡æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumAlarm(IN int DeviceID, IN int HeadNo, OUT int * AlarmNum);
    // Get Number of Times of Alarm Recovery
    ///
    /// \brief SGIF_GetNumRecovery            è­¦æŠ¥æ¢å¤æ¬¡æ•°èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param RecoveryNum                    æ¢å¤æ¬¡æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumRecovery(IN int DeviceID, IN int HeadNo, OUT int * RecoveryNum);
    // Get Alarm Level
    ///
    /// \brief SGIF_GetAlarmLevel            è­¦æŠ¥çº§åˆ«èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmLevel                    è­¦æŠ¥çº§åˆ«
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAlarmLevel(IN int DeviceID, IN int HeadNo, OUT int * AlarmLevel);
    // Get Mounting Mode
    ///
    /// \brief SGIF_GetReflectionMode        å®‰è£…模式获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param ReflectionMode                åå°„模式
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetReflectionMode(IN int DeviceID, IN int HeadNo, OUT SGIF_REFLECTIONMODE * ReflectionMode);
    // Get Mask
    ///
    /// \brief SGIF_GetMask                    å±è”½è®¾å®šèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param OnOff                        å¼€å…³
    /// \param Pos1                            ä½ç½®1
    /// \param Pos2                            ä½ç½®2
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMask(IN int DeviceID, IN int HeadNo, OUT BOOL * OnOff, OUT int * Pos1, OUT int * Pos2);
    // Get Median
    ///
    /// \brief SGIF_GetMedian                ä¸­ä½æ•°èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Median                        ä¸­ä½æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMedian(IN int DeviceID, IN int HeadNo, OUT SGIF_MEDIAN * Median);
    // Get LASER CTRL group
    ///
    /// \brief SGIF_GetLaserCtrlGroup        Laser Ctrl组获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param LaserCtrlGroup                Laser Ctrl组
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetLaserCtrlGroup(IN int DeviceID, IN int HeadNo, OUT SGIF_LASER_CTRL_GROUP * LaserCtrlGroup);
    // Get Mutual interference prevention group
    ///
    /// \brief SGIF_GetMutualInterferencePreventionGroup    é˜²æ­¢äº’相干扰组获取
    /// \param DeviceID                                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Group                                        ç»„
    /// \return
    ///     >0:                                                å¤±è´¥.
    ///     =0:                                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMutualInterferencePreventionGroup(IN int DeviceID, IN int HeadNo, OUT SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP * Group);
    // Get Calculation method
    ///
    /// \brief SGIF_GetCalcMethod        è®¡ç®—方式获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMethod                è®¡ç®—方法
    /// \param HeadOutNo                ä¼ æ„Ÿå¤´æˆ–OUT编号
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcMethod(IN int DeviceID, IN int OutNo, OUT SGIF_CALCMETHOD * CalcMethod, OUT int * HeadOutNo);
    // Get Surface to be measured
    ///
    /// \brief SGIF_GetCalcTarget        æµ‹é‡ç›®æ ‡èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcTarget                è®¡ç®—标签
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcTarget(IN int DeviceID, IN int OutNo, OUT SGIF_CALCTARGET * CalcTarget);
    // Get OUT to be calculated (ADD, SUB)
    ///
    /// \brief SGIF_GetOutAddSub        å¾…计算的OUT(Add,Sub)获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param AddSub1                    å¾…计算的OUT编号1
    /// \param AddSub2                    å¾…计算的OUT编号2
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetOutAddSub(IN int DeviceID, IN int OutNo, OUT int * AddSub1, OUT int * AddSub2);
    // Get OUT to be calculated (AVE, MAX, MIN, P-P)
    ///
    /// \brief SGIF_GetOutOperation        å¾…计算的OUT(Ave,Max,Min,P-P)获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TargetOut                å¤šä¸ªOUT或HEAD组合
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetOutOperation(IN int DeviceID, IN int OutNo, OUT SGIF_OUTNO * TargetOut);
    // Get Scaling
    ///
    /// \brief SGIF_GetScaling            ç¼©æ”¾è®¾å®šèŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param InputValue1                ç‚¹1的测量值(输入值),传出为有效数字(去掉小数点后的整形)
    /// \param OutputValue1                ç‚¹1的显示值(输出值),传出为有效数字(去掉小数点后的整形)
    /// \param InputValue2                ç‚¹2的测量值(输入值),传出为有效数字(去掉小数点后的整形)
    /// \param OutputValue2                ç‚¹2的显示值(输出值),传出为有效数字(去掉小数点后的整形)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetScaling(IN int DeviceID, IN int OutNo, OUT int * InputValue1, OUT int * OutputValue1, OUT int * InputValue2, OUT int * OutputValue2);
    // Get Filter Mode
    ///
    /// \brief SGIF_GetFilter            æ»¤æ³¢å™¨è®¾å®šèŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param FilterMode                æ»¤æ³¢å™¨æ¨¡å¼
    /// \param FilterPara                æ»¤æ³¢å‚æ•°
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetFilter(IN int DeviceID, IN int OutNo, OUT SGIF_FILTERMODE * FilterMode, OUT SGIF_FILTERPARA * FilterPara);
    // Get Trigger Mode
    ///
    /// \brief SGIF_GetTriggerMode        è§¦å‘模式获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TriggerMode                è§¦å‘模式
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetTriggerMode(IN int DeviceID, IN int OutNo, OUT SGIF_TRIGGERMODE * TriggerMode);
    // Get Offset
    ///
    /// \brief SGIF_GetOffset            åç§»èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param Offset                    åç§»é‡
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetOffset(IN int DeviceID, IN int OutNo, OUT int * Offset);
    // Get Calculation Mode
    ///
    /// \brief SGIF_GetCalcMode            æ£€æµ‹æ¨¡å¼ï¼ˆæµ‹é‡æ¨¡å¼ï¼‰èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMode                    æµ‹é‡æ¨¡å¼
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcMode(IN int DeviceID, IN int OutNo, OUT SGIF_CALCMODE * CalcMode);
    // Get Minimum Display Unit
    ///
    /// \brief SGIF_GetDisplayUnit        æ˜¾ç¤ºæœ€å°å•位获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param DisplayUnit                æ˜¾ç¤ºæœ€å°å•位
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetDisplayUnit(IN int DeviceID, IN int OutNo, OUT SGIF_DISPLAYUNIT * DisplayUnit);
    // Get Synchronization
    ///
    /// \brief SGIF_GetSynchronization        åŒæ­¥è®¾å®šèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetSynchronization(IN int DeviceID, IN int OutNo, OUT BOOL * OnOff);
    // Get Storage (OUT No. specification)
    ///
    /// \brief SGIF_GetStorageTarget        å­˜å‚¨ï¼ˆOUT编号设定)获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetStorageTarget(IN int DeviceID, IN int OutNo, OUT BOOL * OnOff);
    // Get Sampling Rate
    ///
    /// \brief SGIF_GetSamplingCycle        é‡‡æ ·å‘¨æœŸèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param SamplingCycle                é‡‡æ ·å‘¨æœŸ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetSamplingCycle(IN int DeviceID, OUT SGIF_SAMPLINGCYCLE * SamplingCycle);
    // Get Mutual Interference Prevention
    ///
    /// \brief SGIF_GetMutualInterferencePrevention        é˜²æ­¢äº’相干扰获取
    /// \param DeviceID                                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff                                    å¼€å…³
    /// \return
    ///     >0:                                            å¤±è´¥.
    ///     =0:                                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMutualInterferencePrevention(IN int DeviceID, OUT SGIF_MUTUAL_INTERFERENCE_PREVENTION * OnOff);
    // Get Strobe Time
    ///
    /// \brief SGIF_GetStrobeTime        é€‰é€šæ—¶é—´èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutputFormat                è¾“出形式
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetStrobeTime(IN int DeviceID, OUT SGIF_STOROBETIME * StrobeTime);
    // Get Data Storage
    ///
    /// \brief SGIF_GetDataStorage        æ•°æ®å­˜å‚¨èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param NumStorage                å¸¦å­˜å‚¨æ•°æ®ç¼–号
    /// \param StorageCycle                å­˜å‚¨å‘¨æœŸ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetDataStorage(IN int DeviceID, OUT int * NumStorage, OUT SGIF_STORAGECYCLE * StorageCycle);
    // Get Active head count
    ///
    /// \brief SGIF_GetNumOfUsedHeads        ä¸»åЍOUT计数获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param NumOfUsedHeads                ä¸»åЍOUT/传感头计数
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumOfUsedHeads(IN int DeviceID, OUT int * NumOfUsedHeads);
    // Get Active OUT count
    ///
    /// \brief SGIF_GetNumOfUsedOut            ä¸»åŠ¨ä¼ æ„Ÿå¤´è®¡æ•°èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param NumOfUsedHeads                ä¸»åЍOUT/传感头计数
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumOfUsedOut(IN int DeviceID, OUT int * NumOfUsedOut);
    // Get Active Running Time
    ///
    /// \brief SGIF_GetDeviceRuningTime        èŽ·å–ç›¸æœºè¿è¡Œæ—¶é•¿ï¼Œå•ä½s
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        0:控制器; 1-4:传感头编号
    /// \param RuningTime                    è¿è¡Œæ—¶é—´
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetDeviceRuningTime(IN int DeviceID, IN int HeadNo, OUT unsigned int * RuningTime);
    ///////////////////////////////////////////////
    // Other commands
    //
    // Opens the Ethernet device.
    ///
    /// \brief SGIF_OpenDeviceETHER            æ‰“开设备网络连接
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OpenParam                    ç½‘络连接参数
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_OpenDeviceETHER(IN int DeviceID, SGIF_OPENPARAM_ETHERNET * OpenParam,DWORD TIMEOUT=3);
    // Closes the currently open device.
    ///
    /// \brief SGIF_CloseDevice                å…³é—­è®¾å¤‡ç½‘络连接
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_CloseDevice(IN int DeviceID);
    ///////////////////////////////////////////////
    // Mode change commands
    //
    // Mode Switch
    ///
    /// \brief SGIF_SetMode                    æ¨¡å¼åˆ‡æ¢
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param Mode                            Ä£Ê½
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMode(IN int DeviceID, IN SGIF_MODE Mode);
    EXP RC WINAPI SGIF_Refresh(IN int DeviceID);
    //////////////////////////////////////////////一次回调相关///////////////////////////////////////
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutBuffer                æ•°æ®æ•°ç»„
    /// \param NumReceived                å®žé™…接收的数据个数
    ///
    typedef void(*SGIF_DataStorageOneTimeCallBack)(OUT int DeviceID);
    ///////////////////////////////////////////////
    /// \brief SGIF_SetOneDataStorage        æ³¨å†Œä¸€æ¬¡å›žè°ƒ
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param SGIF_BatchOneTimeCallBack    å›žè°ƒå‡½æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOneDataStorage(IN int DeviceID, IN SGIF_DataStorageOneTimeCallBack CallFunc);
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Get encoder store value
    /// \brief SGIF_GetEncoderStoreValue编码器值存储数据输出(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号
    /// \param NumOfBuffer                ç¼“冲区大小(最多可接受多少个数据)
    /// \param OutBuffer                æ•°æ®æ•°ç»„
    /// \param NumReceived                å®žé™…接收的数据个数
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderStoreValue(IN int DeviceID, IN int OutNo, IN int NumOfBuffer, OUT int * OutBuffer, OUT int *NumReceived);
    // Get encoder value
    /// \brief SGIF_GetEncoderCurrentValue    è¯»å–编码器当前值(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderCurrentValue(IN int DeviceID, IN int OutNo, OUT int * OutBuffer);
    // encoder Reset
    /// \brief SGIF_EncoderReset        ç¼–码器值置零(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_EncoderReset(IN int DeviceID, IN int OutNo);
    // Set Encoder Number
    /// \brief SGIF_SetEncoderNumber    é€‰æ‹©ç¼–码器(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetEncoderNumber(IN int DeviceID, IN int OutNo);
    // Get encoder number
    /// \brief SGIF_GetEncoderNumber    è¯»å–设置的编码器编号(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderNumber(IN int DeviceID, OUT int * OutBuffer);
    //Set Encoder Parameters
    /// \brief SGIF_SetEncoderParameters设置编码器参数(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \param InputMode                è¾“入模式(0-3)
    /// \param InputTime                æœ€ä½Žè¾“入时间(100,200,500,1000,2000,5000,10000,20000)(ns)
    /// \param interval                    é—´éš”(1-10000)
    /// \param OperatingMode            è¿è¡Œæ¨¡å¼ï¼ˆ0-2)
    /// \param DetectionDirection        æ£€æµ‹æ–¹å‘(0-2)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetEncoderParameters(IN int DeviceID, IN int OutNo, IN int InputMode, IN int InputTime, IN int interval, IN int OperatingMode, IN int DetectionDirection);
    //Get Encoder Parameters
    /// \brief SGIF_GetEncoderParameters读取编码器参数(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \param InputMode                è¾“入模式(0-3)
    /// \param InputTime                æœ€ä½Žè¾“入时间(100,200,500,1000,2000,5000,10000,20000)(ns)
    /// \param interval                    é—´éš”(1-10000)
    /// \param OperatingMode            è¿è¡Œæ¨¡å¼ï¼ˆ0-2)
    /// \param DetectionDirection        æ£€æµ‹æ–¹å‘(0-2)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///4
    EXP RC WINAPI SGIF_GetEncoderParameters(IN int DeviceID, IN int OutNo, OUT int * InputMode, OUT int * InputTime, OUT int * interval, OUT int * OperatingMode, OUT int * DetectionDirection);
    //Set Analog Output
    /// \brief SGIF_SetAnalogOutput        è®¾ç½®æ¨¡æ‹Ÿé‡è¾“出(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ¨¡æ‹Ÿé‡ç¼–号(1-3)
    /// \param OutputChannel            è¾“出通道(0-3)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAnalogOutput(IN int DeviceID, IN int OutNo, IN int OutputChannel);
    // Retrieve Analog Output Channel Number
    /// \brief SGIF_GetAnalogOutputChannel    èŽ·å–æ¨¡æ‹Ÿé‡è¾“å‡ºé€šé“ç¼–å·(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ¨¡æ‹Ÿé‡ç¼–号(1-3)
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAnalogOutputChannel(IN int DeviceID, IN int OutNo, OUT int * OutBuffer);
    //Set IO Digital Output
    /// \brief SGIF_SetIODigitalOutput    è®¾ç½®IO数字输出(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ•°å­—输出编号(1-4)
    /// \param Level                    è¾“出位数(0:OFF,1:HI,2:GO,3:LO,4:STROBE)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetIODigitalOutput(IN int DeviceID, IN int OutNo, IN int Level);
    // Retrieve IO Digital Output Channel Number
    /// \brief SGIF_GetIOOutputChannel    èŽ·å–IO数字量输出通道编号(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ•°å­—输出编号(1-4)
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetIOOutputChannel(IN int DeviceID, IN int OutNo, OUT int * OutBuffer);
#ifdef __cplusplus
}
#endif
SourceCode/Bond/SGMeasurement/DLL/32bit/SGIFPJ.dll
Binary files differ
SourceCode/Bond/SGMeasurement/DLL/32bit/SGIFPJ.lib
Binary files differ
SourceCode/Bond/SGMeasurement/DLL/64bit/SGIF.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1641 @@
#ifdef SGIF_EXPORTS
#define EXP __declspec(dllexport)
#else
#define EXP __declspec(dllimport)
#endif
#include "Winsock2.h"
#include "Ws2tcpip.h"
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "WS2_32.lib")
// Return Code List
typedef enum {
    RC_OK = 0x0000,
    // The operation is completed successfully.
    ///////////////////////////////////////////////
    // Communication error from controller notification
    //
    RC_NAK_COMMAND = 0x1001,        // Command error
    RC_NAK_COMMAND_LENGTH,            // Command length error
    RC_NAK_TIMEOUT,                    // Timeout
    RC_NAK_CHECKSUM,                // Check sum error
    RC_NAK_INVALID_STATE,            // Status error
    RC_NAK_OTHER,                    // Other error
    RC_NAK_PARAMETER,                // Parameter error
    RC_NAK_OUT_STAGE,                // OUT calculation count limitation error
    RC_NAK_OUT_HEAD_NUM,            // No. of used head/OUT over error
    RC_NAK_PARAM_RANGE_DATA_STORED,    // OUT No which data reserved over acctive out count
    RC_NAK_OUT_INVALID_CALC,        // OUT which cannot be used for calculation was specified for calculation.
    RC_NAK_OUT_VOID,                // OUT which specified for calculation is not found.
    RC_NAK_INVALID_CYCLE,            // Unavailable sampling cycle
    RC_NAK_CTRL_ERROR,                // Main unit error
    RC_NAK_SRAM_ERROR,                // Setting value error
    ///////////////////////////////////////////////
    // Communication DLL error notification
    //
    RC_ERR_OPEN_DEVICE = 0x2000,// Opening the device failed.
    RC_ERR_NO_DEVICE,            // The device is not open.
    RC_ERR_SEND,                // Command sending error
    RC_ERR_RECEIVE,                // Response receiving error
    RC_ERR_TIMEOUT,                // Timeout
    RC_ERR_NODATA,                // No data
    RC_ERR_NOMEMORY,            // No free memory
    RC_ERR_DISCONNECT,            // Cable disconnection suspected
    RC_ERR_UNKNOWN,                // Undefined error
    RC_ERR_DEVID_OVER,            // over dev_id scale
    RC_ERR_NET_NO_CONN,            // no connected at the deviceID
    RC_ERR_IP_EXISTED,
    RC_ERR_SELECT,                // select of /socket error
    RC_ERR_NULL_PARAMETER,        // NULL point exception from parameter
    RC_ERR_DIY_FUNC,            // error due to dir function
    RC_ERR_OVER_PARAMENTER,        // paramenter over the limition
    RC_ERR_NOT_SUPPORT            // åŠŸèƒ½ä¸æ”¯æŒ
} RC;
//device Version
typedef enum {
    SG3035 = 0,
    SG3030 = 1,
    SG3085 = 2,
    SG3080 = 3,
    SG5025 = 4,
    SG5020 = 5,
    SG5055 = 6,
    SG5050 = 7,
    SG5085 = 8,
    SG5080 = 9,
    SG5155 = 10,
    SG5150 = 11,
    SC04025 = 12,
    SC03560 = 13,
    SGI500 = 14,
    SGI505 = 15,
    SGI400 = 16,
    SGI405 = 17,
    SGI150 = 18,
    SGI155 = 19,
    SGI080 = 20,
    SGI085 = 21,
    SGI050 = 22,
    SGI055 = 23,
    SGI030 = 24,
    SGI035 = 25,
    SGI020 = 26,
    SGI025 = 27,
    SG3155 = 28,
    SG3150 = 29,
    SC01045 = 30,
    SC10015 = 31,
    SC20011 = 32,
    SC01236 = 33,
    SCI04025 = 34,
    SCI03560 = 35,
    SCI01045 = 36,
    SCI10015 = 37,
    SCI20011 = 38,
    SCI01236 = 39,
}SGIF_DEVICE_TYPE;
// Measurement value structures
typedef enum {
    SGIF_FLOATRESULT_VALID,            // valid data
    SGIF_FLOATRESULT_RANGEOVER_P,    // over range at positive (+) side
    SGIF_FLOATRESULT_RANGEOVER_N,    // over range at negative (-) side
    SGIF_FLOATRESULT_WAITING,        // Wait for comparator result
    SGIF_FLOATRESULT_ALARM,            // alarm
    SGIF_FLOATRESULT_INVALID,        // Invalid (error, etc.)
} SGIF_FLOATRESULT;
// Set ABLE
typedef enum {
    SGIF_ABLEMODE_AUTO,                // AUTO
    SGIF_ABLEMODE_MANUAL,            // manual
} SGIF_ABLEMODE;
// Set Measurement Mode
typedef enum {
    SGIF_MEASUREMODE_NORMAL,                        // normal
    SGIF_MEASUREMODE_HALF_T,                        // translucent object
    SGIF_MEASUREMODE_TRAN_1,                        // transparent object
    SGIF_MEASUREMODE_TRAN_2,                        // transparent object 2
    SGIF_MEASUREMODE_MRS,                            // multireflective object
    SGIF_MEASUREMODE_OPAQUE = SGIF_MEASUREMODE_MRS,    // Semi opaque object
} SGIF_MEASUREMODE;
// Set Basic Point
typedef enum {
    SGIF_BASICPOINT_NEAR,            // NEAR
    SGIF_BASICPOINT_FAR,            // FAR
} SGIF_BASICPOINT;
// Set Mounting Mode
typedef enum {
    SGIF_REFLECTIONMODE_DIFFUSION,    // diffuse reflection
    SGIF_REFLECTIONMODE_MIRROR,        // specular reflection
} SGIF_REFLECTIONMODE;
// Set Median
typedef enum {
    SGIF_MEDIAN_OFF,                // OFF
    SGIF_MEDIAN_7,                    // 7 point
    SGIF_MEDIAN_15,                    // 15 point
    SGIF_MEDIAN_31,                    // 31 point
} SGIF_MEDIAN;
// Set LASER CTRL group.
typedef enum {
    SGIF_LASER_CTRL_GROUP_1,        // LASER CTRL 1
    SGIF_LASER_CTRL_GROUP_2,        // LASER CTRL 2
} SGIF_LASER_CTRL_GROUP;
// Set a range.
typedef enum {
    SGIF_RANGE_CENTER,                // CENTER
    SGIF_RANGE_FAR,                    // FAR
} SGIF_RANGE;
// Set Mutual Interference Prevention Group
typedef enum {
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP_A,    // Group A
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP_B,    // Group B
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP_C,    // Group C
} SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP;
// Set calculation method.
typedef enum {
    SGIF_CALCMETHOD_HEADA,                    // head A
    SGIF_CALCMETHOD_HEADB,                    // head B
    SGIF_CALCMETHOD_HEAD_HEADA_PLUS_HEADB,    // head A+head B
    SGIF_CALCMETHOD_HEAD_HEADA_MINUS_HEADB,    // head A-head B
    SGIF_CALCMETHOD_HEAD_HEADA_TRANSPARENT,    // head A transparent object
    SGIF_CALCMETHOD_HEAD_HEADB_TRANSPARENT,    // head B transparent object
    SGIF_CALCMETHOD_HEAD = 0,    // head
    SGIF_CALCMETHOD_OUT,        // OUT
    SGIF_CALCMETHOD_ADD,        // ADD
    SGIF_CALCMETHOD_SUB,        // SUB
    SGIF_CALCMETHOD_AVE,        // AVE
    SGIF_CALCMETHOD_MAX,        // MAX
    SGIF_CALCMETHOD_MIN,        // MIN
    SGIF_CALCMETHOD_PP,            // P-P
} SGIF_CALCMETHOD;
// Set Target Surface
typedef enum {
    SGIF_CALCTARGET_PEAK_1,        // peak 1
    SGIF_CALCTARGET_PEAK_2,        // peak 2
    SGIF_CALCTARGET_PEAK_3,        // peak 3
    SGIF_CALCTARGET_PEAK_4,        // peak 4
    SGIF_CALCTARGET_PEAK_1_2,    // peak 1-peak 2
    SGIF_CALCTARGET_PEAK_1_3,    // peak 1-peak 3
    SGIF_CALCTARGET_PEAK_1_4,    // peak 1-peak 4
    SGIF_CALCTARGET_PEAK_2_3,    // peak 2-peak 3
    SGIF_CALCTARGET_PEAK_2_4,    // peak 2-peak 4
    SGIF_CALCTARGET_PEAK_3_4,    // peak 3-peak 4
} SGIF_CALCTARGET;
// Set Filter Mode
typedef enum {
    SGIF_FILTERMODE_MOVING_AVERAGE,            // moving average
} SGIF_FILTERMODE;
// Specify the filter parameter. (The number of averaging for moving average, or the cutoff frequency for LPF/HPF.)
typedef enum {
    SGIF_FILTERPARA_AVE_1 = 0,        // 1 time
    SGIF_FILTERPARA_AVE_4,            // 4 times
    SGIF_FILTERPARA_AVE_16,            // 16 times
    SGIF_FILTERPARA_AVE_64,            // 64 times
    SGIF_FILTERPARA_AVE_256,        // 256 times
    SGIF_FILTERPARA_AVE_1024,        // 1024 times
    SGIF_FILTERPARA_AVE_4096,        // 4096 times
    SGIF_FILTERPARA_AVE_16384,        // 16384 times
    SGIF_FILTERPARA_AVE_65536,        // 65536 times
    SGIF_FILTERPARA_AVE_262144,        // 262144 times
}SGIF_FILTERPARA;
// Set Trigger Mode
typedef enum {
    SGIF_TRIGGERMODE_EXT1,        // external trigger 1
    SGIF_TRIGGERMODE_EXT2,        // external trigger 2
} SGIF_TRIGGERMODE;
// Set the Measurement Mode.
typedef enum {
    SGIF_CALCMODE_NORMAL,            // normal
    SGIF_CALCMODE_PEAKHOLD,            // peak hold
    SGIF_CALCMODE_BOTTOMHOLD,        // bottom hold
    SGIF_CALCMODE_PEAKTOPEAKHOLD,    // peak-to-peak hold
    SGIF_CALCMODE_SAMPLEHOLD,        // sample hold
} SGIF_CALCMODE;
// Set Minimum Display Unit
typedef enum {
    SGIF_DISPLAYUNIT_0000_01MM = 0,    // 0.01mm
    SGIF_DISPLAYUNIT_000_001MM,        // 0.001mm
    SGIF_DISPLAYUNIT_00_0001MM,        // 0.0001mm
    SGIF_DISPLAYUNIT_0_00001MM,        // 0.00001mm
    SGIF_DISPLAYUNIT_00000_1UM,        // 0.1um
    SGIF_DISPLAYUNIT_0000_01UM,        // 0.01um
    SGIF_DISPLAYUNIT_000_001UM,        // 0.001um
} SGIF_DISPLAYUNIT;
// Specify OUT
typedef enum {
    SGIF_OUTNO_01 = 0x0001,            // OUT01
    SGIF_OUTNO_02 = 0x0002,            // OUT02
    SGIF_OUTNO_03 = 0x0004,            // OUT03
    SGIF_OUTNO_04 = 0x0008,            // OUT04
    SGIF_OUTNO_ALL = 0x000F,        // All OUTs
} SGIF_OUTNO;
// Set Storage (Cycle)
typedef enum {
    SGIF_STORAGECYCLE_1,            // sampling rate x 1
    SGIF_STORAGECYCLE_2,            // sampling rate x 2
    SGIF_STORAGECYCLE_5,            // sampling rate x 5
    SGIF_STORAGECYCLE_10,            // sampling rate x 10
    SGIF_STORAGECYCLE_20,            // sampling rate x 20
    SGIF_STORAGECYCLE_50,            // sampling rate x 50
    SGIF_STORAGECYCLE_100,            // sampling rate x 100
    SGIF_STORAGECYCLE_200,            // sampling rate x 200
    SGIF_STORAGECYCLE_500,            // sampling rate x 500
    SGIF_STORAGECYCLE_1000,            // sampling rate x 1000
    SGIF_STORAGECYCLE_TIMING,        // Timing sync
} SGIF_STORAGECYCLE;
// Set Sampling Rate
typedef enum {
    //SG5000系列
    SGIF_5000_SAMPLINGCYCLE_590KHZ,     // 590kHz
    SGIF_5000_SAMPLINGCYCLE_400KHZ,        // 400kHz
    SGIF_5000_SAMPLINGCYCLE_200KHZ,        // 200kHz
    SGIF_5000_SAMPLINGCYCLE_88KHZ,        // 88kHz
    SGIF_5000_SAMPLINGCYCLE_50KHZ,        // 50kHz
    SGIF_5000_SAMPLINGCYCLE_20KHZ,        // 20kHz
    SGIF_5000_SAMPLINGCYCLE_10KHZ,        // 10kHz
    SGIF_5000_SAMPLINGCYCLE_5KHZ,        // 5kHz
    SGIF_5000_SAMPLINGCYCLE_2KHZ,        // 2kHz
    SGIF_5000_SAMPLINGCYCLE_1KHZ,        // 1kHz+
    //SG3000系列
    SGIF_3000_SAMPLINGCYCLE_88KHZ = 10,    // 88kHz
    SGIF_3000_SAMPLINGCYCLE_50KHZ,        // 50kHz
    SGIF_3000_SAMPLINGCYCLE_20KHZ,        // 20kHz
    SGIF_3000_SAMPLINGCYCLE_10KHZ,        // 10kHz
    SGIF_3000_SAMPLINGCYCLE_5KHZ,        // 5kHz
    //SGIF_3000_SAMPLINGCYCLE_2KHZ,        // 2kHz
    SGIF_3000_SAMPLINGCYCLE_1KHZ,        // 1kHz
    //SCI系列
    SCI_SAMPLINGCYCLE_33KHZ = 30,    // 33kHz
    SCI_SAMPLINGCYCLE_20KHZ,        // 20kHz
    SCI_SAMPLINGCYCLE_15KHZ,        // 15kHz
    SCI_SAMPLINGCYCLE_10KHZ,        // 10kHz
    SCI_SAMPLINGCYCLE_5KHZ,            // 5kHz
    SCI_SAMPLINGCYCLE_2KHZ,            // 2kHz
    SCI_SAMPLINGCYCLE_1KHZ,            // 1kHz
    SCI_SAMPLINGCYCLE_05KHZ,        // 0.5kHz
} SGIF_SAMPLINGCYCLE;
// Set Mutual interference prevention
typedef enum {
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_OFF,    // OFF
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_AB_ON,    // AB-ON
    SGIF_MUTUAL_INTERFERENCE_PREVENTION_ABC_ON,    // ABC-ON
} SGIF_MUTUAL_INTERFERENCE_PREVENTION;
// Set Strobe Time
typedef enum {
    SGIF_STOROBETIME_2MS,        // 2ms
    SGIF_STOROBETIME_5MS,        // 5ms
    SGIF_STOROBETIME_10MS,        // 10ms
    SGIF_STOROBETIME_20MS,        // 20ms
} SGIF_STOROBETIME;
// Mode Switch
typedef enum {
    SGIF_MODE_NORMAL,                // normal mode
    SGIF_MODE_COMMUNICATION,        // setting mode
} SGIF_MODE;
//Encoder ext
typedef enum {
    SGIF_EmRunningMode_cont,//off
    SGIF_EmRunningMode_time,
    SGIF_EmRunningMode_trig,
}SGIF_EmRunningMode;
typedef enum {
    SGIF_EmDirection_all,//+-
    SGIF_EmDirection_pos,
    SGIF_EmDirection_neg,
}SGIF_EmDirection;
typedef enum {
    SGIF_EmEncoderInput_1x1,
    SGIF_EmEncoderInput_2x1,
    SGIF_EmEncoderInput_2x2,
    SGIF_EmEncoderInput_2x4,
}SGIF_EmEncoderInput;
typedef enum {
    SGIF_EmInputTime_100 = 100,
    SGIF_EmInputTime_200 = 200,
    SGIF_EmInputTime_500 = 500,
    SGIF_EmInputTime_1000 = 1000,
    SGIF_EmInputTime_2000 = 2000,
    SGIF_EmInputTime_5000 = 5000,
    SGIF_EmInputTime_10000 = 10000,
    SGIF_EmInputTime_20000 = 20000,
}SGIF_EmInputTime;
// Measurement value
typedef struct {
    int                    OutNo;            // OUT No(1-4)
    SGIF_FLOATRESULT    FloatResult;    // valid or invalid data
    float                Value;            // Measurement value
} SGIF_FLOATVALUE_OUT;
typedef struct {
    SGIF_FLOATRESULT    FloatResult;    // valid or invalid data
    float                Value;            // Measurement value
} SGIF_FLOATVALUE;
// IP address
typedef struct {
    IN_ADDR                IPAddress;
} SGIF_OPENPARAM_ETHERNET;
//Mask Minimum Display Unit(0.01mm)
#define MASKUNIT 100
#ifdef __cplusplus
extern "C"
{
#endif
    EXP RC WINAPI SGIF_GetDeviceType(IN int DeviceID, OUT SGIF_DEVICE_TYPE* deviceType);
    // Measured control commands
    ///
    /// \brief SGIF_GetCameraSpotType    å…‰æ–‘类型(不支持SCI)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param ControlType:                è¾“出0:小光斑,1:大光斑
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCameraSpotType(IN int DeviceID, OUT int *EissionSpotType);
    ///////////////////////////////////////////////
    // Measurement control commands
    //
    // Measured value output (single)
    ///
    /// \brief SGIF_GetCalcDataSingle    æµ‹é‡å€¼è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \param CalcData:                æµ‹é‡å€¼
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcDataSingle(IN int DeviceID, IN int OutNo, OUT SGIF_FLOATVALUE_OUT * CalcData);
    // Measured value output (multiple)
    ///
    /// \brief SGIF_GetCalcDataMulti    å¤šä¸ªæµ‹é‡å€¼è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \param CalcData:                æµ‹é‡å€¼æ•°ç»„
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcDataMulti(IN int DeviceID, IN SGIF_OUTNO OutNo, OUT SGIF_FLOATVALUE_OUT * CalcData);
    // Measured value output (ALL)
    ///
    /// \brief SGIF_GetCalcDataALL        å…¨éƒ¨æµ‹é‡å€¼è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param CalcData:                æµ‹é‡å€¼æ•°ç»„
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcDataALL(IN int DeviceID, OUT SGIF_FLOATVALUE_OUT * CalcData);
    // Timing ON/OFF (single)
    ///
    /// \brief SGIF_SetTimingSingle        è®¡æ—¶ON/OFF(一个)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTimingSingle(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Timing ON/OFF (multiple)
    ///
    /// \brief SGIF_SetTimingMulti        è®¡æ—¶ON/OFF(多个)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTimingMulti(IN int DeviceID, IN SGIF_OUTNO OutNo, IN BOOL OnOff);
    // Timing ON/OFF (synchronous)
    ///
    /// \brief SGIF_SetTimingSync        è®¡æ—¶ON/OFF(同步)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTimingSync(IN int DeviceID, IN BOOL OnOff);
    // Auto-zero ON/OFF (single)
    ///
    /// \brief SGIF_SetZeroSingle        è‡ªåŠ¨å½’é›¶ï¼ˆä¸€ä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetZeroSingle(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Auto-zero ON/OFF (multiple)
    ///
    /// \brief SGIF_SetZeroMulti        è‡ªåŠ¨å½’é›¶ï¼ˆå¤šä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetZeroMulti(IN int DeviceID, IN SGIF_OUTNO OutNo, IN BOOL OnOff);
    // Auto-zero ON/OFF (synchronous)
    ///
    /// \brief SGIF_SetZeroSync            è‡ªåŠ¨å½’é›¶ï¼ˆåŒæ­¥ï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff:                    å¼€æˆ–å…³
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetZeroSync(IN int DeviceID, IN BOOL OnOff);
    // Measured value reset (single)
    ///
    /// \brief SGIF_SetResetSingle        é‡ç½®ï¼ˆä¸€ä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetResetSingle(IN int DeviceID, IN int OutNo);
    // Measured value reset (multiple)
    ///
    /// \brief SGIF_SetResetMulti        é‡ç½®ï¼ˆå¤šä¸ªï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo:                    è¾“出OUT编号组合
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetResetMulti(IN int DeviceID, IN SGIF_OUTNO OutNo);
    // Measured value reset (synchronous)
    ///
    /// \brief SGIF_SetResetSync        é‡ç½®ï¼ˆåŒæ­¥ï¼‰
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetResetSync(IN int DeviceID);
    // Program Change
    ///
    /// \brief SGIF_SetProgramNo        ç¨‹åºåˆ‡æ¢
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param ProgramNo:                ç¨‹åºç¼–号(0到7)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetProgramNo(IN int DeviceID, IN int ProgramNo);
    // Program Check
    ///
    /// \brief SGIF_GetProgramNo        ç¨‹åºç¡®è®¤
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param ProgramNo:                ç¨‹åºç¼–号(0到7)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetProgramNo(IN int DeviceID, OUT int * ProgramNo);
    // Starting the Data Storage
    ///
    /// \brief SGIF_DataStorageStart    æ•°æ®å­˜å‚¨å¼€å§‹
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageStart(IN int DeviceID);
    // Stopping the Data Storage
    ///
    /// \brief SGIF_DataStorageStop        æ•°æ®å­˜å‚¨åœæ­¢
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageStop(IN int DeviceID);
    // Outputting the Data Storage
    ///
    /// \brief SGIF_DataStorageGetData    æ•°æ®å­˜å‚¨æ•°æ®è¾“出
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param NumOfBuffer                ç¼“冲区大小(最多可接受多少个数据)
    /// \param OutBuffer                æ•°æ®æ•°ç»„
    /// \param NumReceived                å®žé™…接收的数据个数
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageGetData(IN int DeviceID, IN int OutNo, IN int NumOfBuffer, OUT float * OutBuffer, OUT int *NumReceived);
    // Initializing the Data Storage
    ///
    /// \brief SGIF_DataStorageInit        æ•°æ®å­˜å‚¨åˆå§‹åŒ–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageInit(IN int DeviceID);
    // Data Storage Accumulation Status Output
    ///
    /// \brief SGIF_DataStorageGetStatus    æ•°æ®å­˜å‚¨çŠ¶æ€è¾“å‡º
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param lsStorage                    å­˜å‚¨çŠ¶æ€
    /// \param NumStorageData                å„输出口存储数量数组
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DataStorageGetStatus(IN int DeviceID, OUT BOOL * lsStorage, OUT int  * NumStorageData);
    ///////////////////////////////////////////////
    // Setting change commands
    //
    // Set Tolerance
    ///
    /// \brief SGIF_SetTolerance            å…¬å·®è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param UpperLimit                    ä¸Šé™ï¼Œä¼ å…¥ä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param LowerLimit                    ä¸‹é™ï¼Œä¼ å…¥ä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param Hystersys                    æ»žåŽï¼Œä¼ å…¥ä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTolerance(IN int DeviceID, IN int OutNo, IN int UpperLimit, IN int LowerLimit, IN int Hystersys);
    // Set ABLE
    ///
    /// \brief SGIF_SetAbleMode                Able模式设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AbleMode                        Ä£Ê½
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAbleMode(IN int DeviceID, IN int HeadNo, IN SGIF_ABLEMODE AbleMode);
    // Set ABLE Control Range
    ///
    /// \brief SGIF_SetAbleMinMax            Able控制范围设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Min                            ä¸‹é™
    /// \param Max                            ä¸Šé™
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAbleMinMax(IN int DeviceID, IN int HeadNo, IN int Min, IN int Max);
    // Set Detection mode
    ///
    /// \brief SGIF_SetMeasureMode            æµ‹é‡æ¨¡å¼è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \MeasureMode                        æµ‹é‡æ¨¡å¼
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMeasureMode(IN int DeviceID, IN int HeadNo, IN SGIF_MEASUREMODE MeasureMode);
    // Set Base point
    ///
    /// \brief SGIF_SetBasicPoint            åŸºå‡†ç‚¹è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param BasicPoint                    åŸºå‡†ç‚¹
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetBasicPoint(IN int DeviceID, IN int HeadNo, IN SGIF_BASICPOINT BasicPoint);
    // Set Number of Times of Alarm Processing
    ///
    /// \brief SGIF_SetNumAlarm                è­¦æŠ¥æ•°é‡è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmNum                        è­¦æŠ¥æ•°é‡
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetNumAlarm(IN int DeviceID, IN int HeadNo, IN int AlarmNum);
    // Set Number of Times of Alarm Recovery
    ///
    /// \brief SGIF_SetNumRecovery            æ¢å¤æ•°é‡è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param RecoveryNum                    æ¢å¤æ¬¡æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetNumRecovery(IN int DeviceID, IN int HeadNo, IN int RecoveryNum);
    // Set Alarm Level
    ///
    /// \brief SGIF_SetAlarmLevel            è­¦æŠ¥çº§åˆ«è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmLevel                    è­¦æŠ¥çº§åˆ«
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAlarmLevel(IN int DeviceID, IN int HeadNo, IN int AlarmLevel);
    // Starting the ABLE Calibration
    ///
    /// \brief SGIF_AbleStart                Able校准开始
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_AbleStart(IN int DeviceID, IN int HeadNo);
    // Finishing the ABLE Calibration
    ///
    /// \brief SGIF_AbleStop                Able校准完成
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_AbleStop(IN int DeviceID);
    // Stopping the ABLE Calibration
    ///
    /// \brief SGIF_AbleCancel                AbleУ׼ֹͣ
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_AbleCancel(IN int DeviceID);
    // Set Mounting Mode
    ///
    /// \brief SGIF_SetReflectionMode        å®‰è£…模式设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param ReflectionMode                åå°„模式
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetReflectionMode(IN int DeviceID, IN int HeadNo, IN SGIF_REFLECTIONMODE ReflectionMode);
    // Set Mask
    ///
    /// \brief SGIF_SetMask                    å±è”½è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param OnOff                        å¼€å…³
    /// \param HeadNo                        ç‚¹ä½1
    /// \param HeadNo                        ç‚¹ä½2
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMask(IN int DeviceID, IN int HeadNo, IN BOOL OnOff, IN int Pos1, IN int Pos2);
    // Set Median
    ///
    /// \brief SGIF_SetMedian                ä¸­ä½æ•°è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Median                        ä¸­ä½æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMedian(IN int DeviceID, IN int HeadNo, IN SGIF_MEDIAN Median);
    // Set LASER CTRL group
    ///
    /// \brief SGIF_SetLaserCtrlGroup        Laser Ctrl组设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param LaserCtrlGroup                Laser Ctrl组
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetLaserCtrlGroup(IN int DeviceID, IN int HeadNo, IN SGIF_LASER_CTRL_GROUP LaserCtrlGroup);
    // Set Mutual interference prevention group
    ///
    /// \brief SGIF_SetMutualInterferencePreventionGroup        é˜²æ­¢äº’相干扰组设定
    /// \param DeviceID                                            è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                                            ä¼ æ„Ÿå¤´ç¼–号
    /// \param Group                                            ç»„
    /// \return
    ///     >0:                                                    å¤±è´¥.
    ///     =0:                                                    æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMutualInterferencePreventionGroup(IN int DeviceID, IN int HeadNo, IN SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP Group);
    // Set Calculation method
    ///
    /// \brief SGIF_SetCalcMethod        è®¡ç®—方式设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMethod                è®¡ç®—方法
    /// \param HeadOutNo                ä¼ æ„Ÿå¤´è¾“出编号
    /// \return
    ///     >0:                                                    å¤±è´¥.
    ///     =0:                                                    æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetCalcMethod(IN int DeviceID, IN int OutNo, IN SGIF_CALCMETHOD CalcMethod, IN int HeadOutNo);
    // Set Surface to be measured
    ///
    /// \brief SGIF_SetCalcTarget        æµ‹é‡ç›®æ ‡è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcTarget                è®¡ç®—标签
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetCalcTarget(IN int DeviceID, IN int OutNo, IN SGIF_CALCTARGET CalcTarget);
    // Set OUT to be calculated (ADD, SUB)
    ///
    /// \brief SGIF_SetOutAddSub        å¾…计算的OUT(Add,Sub)设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param AddSub1                    å¾…计算的OUT
    /// \param AddSub2                    å¾…计算的OUT
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOutAddSub(IN int DeviceID, IN int OutNo, IN int AddSub1, IN int AddSub2);
    // Set OUT to be calculated (AVE, MAX, MIN, P-P)
    ///
    /// \brief SGIF_SetOutOperation        å¾…计算的OUT(Ave,Max,Min,P-P)设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TargetOut                å¤šä¸ªOUT组合
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOutOperation(IN int DeviceID, IN int OutNo, IN SGIF_OUTNO TargetOut);
    // Set Scaling
    ///
    /// \brief SGIF_SetScaling            ç¼©æ”¾è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param InputValue1                ç‚¹1的测量值(输入值),传有效数字(去掉小数点后的整形)
    /// \param OutputValue1                ç‚¹1的显示值(输出值),传有效数字(去掉小数点后的整形)
    /// \param InputValue2                ç‚¹2的测量值(输入值),传有效数字(去掉小数点后的整形)
    /// \param OutputValue2                ç‚¹2的显示值(输出值),传有效数字(去掉小数点后的整形)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetScaling(IN int DeviceID, IN int OutNo, IN int InputValue1, IN int OutputValue1, IN int InputValue2, IN int OutputValue2);
    // Set Filter Mode
    ///
    /// \brief SGIF_SetFilter            æ»¤æ³¢å™¨è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param FilterMode                æ»¤æ³¢æ¨¡å¼
    /// \param FilterPara                æ»¤æ³¢å‚æ•°
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetFilter(IN int DeviceID, IN int OutNo, IN SGIF_FILTERMODE FilterMode, IN SGIF_FILTERPARA FilterPara);
    // Set Trigger Mode
    ///
    /// \brief SGIF_SetTriggerMode        è§¦å‘模式设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TriggerMode                è§¦å‘模式
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetTriggerMode(IN int DeviceID, IN int OutNo, IN SGIF_TRIGGERMODE TriggerMode);
    // Set Offset
    ///
    /// \brief SGIF_SetOffset            åç§»è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param Offset                    åç§»é‡
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOffset(IN int DeviceID, IN int OutNo, IN int Offset);
    // Set Calculation Mode
    ///
    /// \brief SGIF_SetCalcMode            æ£€æµ‹æ¨¡å¼ï¼ˆæµ‹é‡æ¨¡å¼ï¼‰è®¾å®š
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMode                    æ£€æµ‹æ¨¡å¼ç¼–号
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetCalcMode(IN int DeviceID, IN int OutNo, IN SGIF_CALCMODE CalcMode);
    // Set Minimum Display Unit
    ///
    /// \brief SGIF_SetDisplayUnit        è®¾å®šæ˜¾ç¤ºå•位设定
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param DisplayUnit                æ˜¾ç¤ºå•位
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetDisplayUnit(IN int DeviceID, IN int OutNo, IN SGIF_DISPLAYUNIT DisplayUnit);
    // Set Synchronization
    ///
    /// \brief SGIF_SetSynchronization        åŒæ­¥è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetSynchronization(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Set Storage (OUT No. specification)
    ///
    /// \brief SGIF_SetStorageTarget        å­˜å‚¨ï¼ˆOUT编号规格)设定
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetStorageTarget(IN int DeviceID, IN int OutNo, IN BOOL OnOff);
    // Set Sampling Rate
    ///
    /// \brief SGIF_SetSamplingCycle        é‡‡æ ·å‘¨æœŸè®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param SamplingCycle                é‡‡æ ·å‘¨æœŸ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetSamplingCycle(IN int DeviceID, IN SGIF_SAMPLINGCYCLE SamplingCycle);
    // Set Mutual Interference Prevention
    ///
    /// \brief SGIF_SetMutualInterferencePrevention        é˜²æ­¢äº’相干扰组设定
    /// \param DeviceID                                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff                                    ç»„设定
    /// \return
    ///     >0:                                            å¤±è´¥.
    ///     =0:                                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMutualInterferencePrevention(IN int DeviceID, IN SGIF_MUTUAL_INTERFERENCE_PREVENTION OnOff);
    // Set Strobe Time
    ///
    /// \brief SGIF_SetStrobeTime            é€‰é€šæ—¶é—´è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param StrobeTime                    é€‰é€šæ—¶é—´
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetStrobeTime(IN int DeviceID, IN SGIF_STOROBETIME StrobeTime);
    // Set Data Storage
    ///
    /// \brief SGIF_SetDataStorage            æ•°æ®å­˜å‚¨è®¾å®š
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param NumStorage                    å¾…存储数据的编号
    /// \param StorageCycle                    å­˜å‚¨å‘¨æœŸ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetDataStorage(IN int DeviceID, IN int NumStorage, IN SGIF_STORAGECYCLE StorageCycle);
    // EncoderSetting
    ///
    /// \brief SGIF_SetRunningMode            è¿è¡Œæ¨¡å¼è®¾ç½®(不支持SCI设备)
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param runningmode                    è¿è¡Œæ¨¡å¼ 0:OFF/1:定时/2:触发
    /// \param CatchDirection               æ£€æµ‹æ–¹å‘ 0:正负计时/1:正计时/2:负计时
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetRunningMode(IN int DeviceID, IN SGIF_EmRunningMode Runningmode, IN SGIF_EmDirection CatchDirection);
    // EncoderInputSetting
    ///
    /// \brief SGIF_SetEncoderMode            ç¼–码器输入模式设置(不支持SCI设备)
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param Inputmode                    è¿è¡Œæ¨¡å¼ 0:1相1递增/1:2相1递增/2:2相2递增,3:2相4递增
    /// \param MinInputTime                    æœ€å°è¾“入时间
    /// \param TrigInterval                    è§¦å‘é—´éš”
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetEncoderMode(IN int DeviceID, IN SGIF_EmEncoderInput Inputmode,IN SGIF_EmInputTime InputTime,IN int TrigInterval);
    // SGIF_SetFormula
    ///
    /// \brief SGIF_SetFormula                è®¾ç½®é…æ–¹
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param filePath                        é…æ–¹è·¯å¾„
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///  derive
    EXP RC WINAPI SGIF_SetFormula(IN int DeviceID, IN char* filePath );
    // SGIF_SetFormula
    ///
    /// \brief SGIF_SetFormula                è®¾ç½®é…æ–¹
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param filePath                        é…æ–¹è·¯å¾„
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_DeriveFormula(IN int DeviceID, IN char* filePath);
    ///////////////////////////////////////////////
    // Setting confirmation commands
    //
    // Get Tolerance
    ///
    /// \brief SGIF_GetTolerance            å…¬å·®è®¾å®šèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param UpperLimit                    ä¸Šé™ï¼Œä¼ å‡ºä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param LowerLimit                    ä¸‹é™ï¼Œä¼ å‡ºä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \param Hysteresis                    æ»žåŽï¼Œä¼ å‡ºä¸ºæœ‰æ•ˆæ•°å­—(去掉小数点后的整形)
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetTolerance(IN int DeviceID, IN int OutNo, OUT int * UpperLimit, OUT int * LowerLimit, OUT int * Hysteresis);
    // Get ABLE
    ///
    /// \brief SGIF_GetAbleMode                Able设定获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AbleMode                        Ableģʽ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAbleMode(IN int DeviceID, IN int HeadNo, OUT SGIF_ABLEMODE * AbleMode);
    // Get ABLE Control Range
    ///
    /// \brief SGIF_GetAbleMinMax            Able控制范围获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Min                            æœ€å°å€¼
    /// \param Max                            æœ€å¤§å€¼
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAbleMinMax(IN int DeviceID, IN int HeadNo, OUT int * Min, OUT int * Max);
    // Get Detection mode
    ///
    /// \brief SGIF_GetMeasureMode            æµ‹é‡æ¨¡å¼èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param MeasureMode                    æµ‹é‡æ¨¡å¼
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMeasureMode(IN int DeviceID, IN int HeadNo, OUT SGIF_MEASUREMODE * MeasureMode);
    // Get Base point
    ///
    /// \brief SGIF_GetBasicPoint            åŸºå‡†ç‚¹èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param BasicPoint                    åŸºå‡†ç‚¹
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetBasicPoint(IN int DeviceID, IN int HeadNo, OUT SGIF_BASICPOINT * BasicPoint);
    // Get Number of Times of Alarm Processing
    ///
    /// \brief SGIF_GetNumAlarm                è­¦æŠ¥å¤„理次数获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmNum                        è­¦æŠ¥æ¬¡æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumAlarm(IN int DeviceID, IN int HeadNo, OUT int * AlarmNum);
    // Get Number of Times of Alarm Recovery
    ///
    /// \brief SGIF_GetNumRecovery            è­¦æŠ¥æ¢å¤æ¬¡æ•°èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param RecoveryNum                    æ¢å¤æ¬¡æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumRecovery(IN int DeviceID, IN int HeadNo, OUT int * RecoveryNum);
    // Get Alarm Level
    ///
    /// \brief SGIF_GetAlarmLevel            è­¦æŠ¥çº§åˆ«èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param AlarmLevel                    è­¦æŠ¥çº§åˆ«
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAlarmLevel(IN int DeviceID, IN int HeadNo, OUT int * AlarmLevel);
    // Get Mounting Mode
    ///
    /// \brief SGIF_GetReflectionMode        å®‰è£…模式获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param ReflectionMode                åå°„模式
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetReflectionMode(IN int DeviceID, IN int HeadNo, OUT SGIF_REFLECTIONMODE * ReflectionMode);
    // Get Mask
    ///
    /// \brief SGIF_GetMask                    å±è”½è®¾å®šèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param OnOff                        å¼€å…³
    /// \param Pos1                            ä½ç½®1
    /// \param Pos2                            ä½ç½®2
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMask(IN int DeviceID, IN int HeadNo, OUT BOOL * OnOff, OUT int * Pos1, OUT int * Pos2);
    // Get Median
    ///
    /// \brief SGIF_GetMedian                ä¸­ä½æ•°èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Median                        ä¸­ä½æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMedian(IN int DeviceID, IN int HeadNo, OUT SGIF_MEDIAN * Median);
    // Get LASER CTRL group
    ///
    /// \brief SGIF_GetLaserCtrlGroup        Laser Ctrl组获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param LaserCtrlGroup                Laser Ctrl组
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetLaserCtrlGroup(IN int DeviceID, IN int HeadNo, OUT SGIF_LASER_CTRL_GROUP * LaserCtrlGroup);
    // Get Mutual interference prevention group
    ///
    /// \brief SGIF_GetMutualInterferencePreventionGroup    é˜²æ­¢äº’相干扰组获取
    /// \param DeviceID                                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                                        ä¼ æ„Ÿå¤´ç¼–号
    /// \param Group                                        ç»„
    /// \return
    ///     >0:                                                å¤±è´¥.
    ///     =0:                                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMutualInterferencePreventionGroup(IN int DeviceID, IN int HeadNo, OUT SGIF_MUTUAL_INTERFERENCE_PREVENTION_GROUP * Group);
    // Get Calculation method
    ///
    /// \brief SGIF_GetCalcMethod        è®¡ç®—方式获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMethod                è®¡ç®—方法
    /// \param HeadOutNo                ä¼ æ„Ÿå¤´æˆ–OUT编号
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcMethod(IN int DeviceID, IN int OutNo, OUT SGIF_CALCMETHOD * CalcMethod, OUT int * HeadOutNo);
    // Get Surface to be measured
    ///
    /// \brief SGIF_GetCalcTarget        æµ‹é‡ç›®æ ‡èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcTarget                è®¡ç®—标签
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcTarget(IN int DeviceID, IN int OutNo, OUT SGIF_CALCTARGET * CalcTarget);
    // Get OUT to be calculated (ADD, SUB)
    ///
    /// \brief SGIF_GetOutAddSub        å¾…计算的OUT(Add,Sub)获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param AddSub1                    å¾…计算的OUT编号1
    /// \param AddSub2                    å¾…计算的OUT编号2
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetOutAddSub(IN int DeviceID, IN int OutNo, OUT int * AddSub1, OUT int * AddSub2);
    // Get OUT to be calculated (AVE, MAX, MIN, P-P)
    ///
    /// \brief SGIF_GetOutOperation        å¾…计算的OUT(Ave,Max,Min,P-P)获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TargetOut                å¤šä¸ªOUT或HEAD组合
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetOutOperation(IN int DeviceID, IN int OutNo, OUT SGIF_OUTNO * TargetOut);
    // Get Scaling
    ///
    /// \brief SGIF_GetScaling            ç¼©æ”¾è®¾å®šèŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param InputValue1                ç‚¹1的测量值(输入值),传出为有效数字(去掉小数点后的整形)
    /// \param OutputValue1                ç‚¹1的显示值(输出值),传出为有效数字(去掉小数点后的整形)
    /// \param InputValue2                ç‚¹2的测量值(输入值),传出为有效数字(去掉小数点后的整形)
    /// \param OutputValue2                ç‚¹2的显示值(输出值),传出为有效数字(去掉小数点后的整形)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetScaling(IN int DeviceID, IN int OutNo, OUT int * InputValue1, OUT int * OutputValue1, OUT int * InputValue2, OUT int * OutputValue2);
    // Get Filter Mode
    ///
    /// \brief SGIF_GetFilter            æ»¤æ³¢å™¨è®¾å®šèŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param FilterMode                æ»¤æ³¢å™¨æ¨¡å¼
    /// \param FilterPara                æ»¤æ³¢å‚æ•°
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetFilter(IN int DeviceID, IN int OutNo, OUT SGIF_FILTERMODE * FilterMode, OUT SGIF_FILTERPARA * FilterPara);
    // Get Trigger Mode
    ///
    /// \brief SGIF_GetTriggerMode        è§¦å‘模式获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param TriggerMode                è§¦å‘模式
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetTriggerMode(IN int DeviceID, IN int OutNo, OUT SGIF_TRIGGERMODE * TriggerMode);
    // Get Offset
    ///
    /// \brief SGIF_GetOffset            åç§»èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param Offset                    åç§»é‡
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetOffset(IN int DeviceID, IN int OutNo, OUT int * Offset);
    // Get Calculation Mode
    ///
    /// \brief SGIF_GetCalcMode            æ£€æµ‹æ¨¡å¼ï¼ˆæµ‹é‡æ¨¡å¼ï¼‰èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param CalcMode                    æµ‹é‡æ¨¡å¼
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetCalcMode(IN int DeviceID, IN int OutNo, OUT SGIF_CALCMODE * CalcMode);
    // Get Minimum Display Unit
    ///
    /// \brief SGIF_GetDisplayUnit        æ˜¾ç¤ºæœ€å°å•位获取
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    è¾“出OUT编号
    /// \param DisplayUnit                æ˜¾ç¤ºæœ€å°å•位
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetDisplayUnit(IN int DeviceID, IN int OutNo, OUT SGIF_DISPLAYUNIT * DisplayUnit);
    // Get Synchronization
    ///
    /// \brief SGIF_GetSynchronization        åŒæ­¥è®¾å®šèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetSynchronization(IN int DeviceID, IN int OutNo, OUT BOOL * OnOff);
    // Get Storage (OUT No. specification)
    ///
    /// \brief SGIF_GetStorageTarget        å­˜å‚¨ï¼ˆOUT编号设定)获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                        è¾“出OUT编号
    /// \param OnOff                        å¼€å…³
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetStorageTarget(IN int DeviceID, IN int OutNo, OUT BOOL * OnOff);
    // Get Sampling Rate
    ///
    /// \brief SGIF_GetSamplingCycle        é‡‡æ ·å‘¨æœŸèŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param SamplingCycle                é‡‡æ ·å‘¨æœŸ
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetSamplingCycle(IN int DeviceID, OUT SGIF_SAMPLINGCYCLE * SamplingCycle);
    // Get Mutual Interference Prevention
    ///
    /// \brief SGIF_GetMutualInterferencePrevention        é˜²æ­¢äº’相干扰获取
    /// \param DeviceID                                    è®¾å¤‡ID号,范围为0-63.
    /// \param OnOff                                    å¼€å…³
    /// \return
    ///     >0:                                            å¤±è´¥.
    ///     =0:                                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetMutualInterferencePrevention(IN int DeviceID, OUT SGIF_MUTUAL_INTERFERENCE_PREVENTION * OnOff);
    // Get Strobe Time
    ///
    /// \brief SGIF_GetStrobeTime        é€‰é€šæ—¶é—´èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutputFormat                è¾“出形式
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetStrobeTime(IN int DeviceID, OUT SGIF_STOROBETIME * StrobeTime);
    // Get Data Storage
    ///
    /// \brief SGIF_GetDataStorage        æ•°æ®å­˜å‚¨èŽ·å–
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param NumStorage                å¸¦å­˜å‚¨æ•°æ®ç¼–号
    /// \param StorageCycle                å­˜å‚¨å‘¨æœŸ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetDataStorage(IN int DeviceID, OUT int * NumStorage, OUT SGIF_STORAGECYCLE * StorageCycle);
    // Get Active head count
    ///
    /// \brief SGIF_GetNumOfUsedHeads        ä¸»åЍOUT计数获取
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param NumOfUsedHeads                ä¸»åЍOUT/传感头计数
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumOfUsedHeads(IN int DeviceID, OUT int * NumOfUsedHeads);
    // Get Active OUT count
    ///
    /// \brief SGIF_GetNumOfUsedOut            ä¸»åŠ¨ä¼ æ„Ÿå¤´è®¡æ•°èŽ·å–
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param NumOfUsedHeads                ä¸»åЍOUT/传感头计数
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetNumOfUsedOut(IN int DeviceID, OUT int * NumOfUsedOut);
    // Get Active Running Time
    ///
    /// \brief SGIF_GetDeviceRuningTime        èŽ·å–ç›¸æœºè¿è¡Œæ—¶é•¿ï¼Œå•ä½s
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param HeadNo                        0:控制器; 1-4:传感头编号
    /// \param RuningTime                    è¿è¡Œæ—¶é—´
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetDeviceRuningTime(IN int DeviceID, IN int HeadNo, OUT unsigned int * RuningTime);
    ///////////////////////////////////////////////
    // Other commands
    //
    // Opens the Ethernet device.
    ///
    /// \brief SGIF_OpenDeviceETHER            æ‰“开设备网络连接
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param OpenParam                    ç½‘络连接参数
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_OpenDeviceETHER(IN int DeviceID, SGIF_OPENPARAM_ETHERNET * OpenParam,DWORD TIMEOUT=3);
    // Closes the currently open device.
    ///
    /// \brief SGIF_CloseDevice                å…³é—­è®¾å¤‡ç½‘络连接
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_CloseDevice(IN int DeviceID);
    ///////////////////////////////////////////////
    // Mode change commands
    //
    // Mode Switch
    ///
    /// \brief SGIF_SetMode                    æ¨¡å¼åˆ‡æ¢
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param Mode                            Ä£Ê½
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetMode(IN int DeviceID, IN SGIF_MODE Mode);
    EXP RC WINAPI SGIF_Refresh(IN int DeviceID);
    //////////////////////////////////////////////一次回调相关///////////////////////////////////////
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutBuffer                æ•°æ®æ•°ç»„
    /// \param NumReceived                å®žé™…接收的数据个数
    ///
    typedef void(*SGIF_DataStorageOneTimeCallBack)(OUT int DeviceID);
    ///////////////////////////////////////////////
    /// \brief SGIF_SetOneDataStorage        æ³¨å†Œä¸€æ¬¡å›žè°ƒ
    /// \param DeviceID                        è®¾å¤‡ID号,范围为0-63.
    /// \param SGIF_BatchOneTimeCallBack    å›žè°ƒå‡½æ•°
    /// \return
    ///     >0:                                å¤±è´¥.
    ///     =0:                                æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetOneDataStorage(IN int DeviceID, IN SGIF_DataStorageOneTimeCallBack CallFunc);
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Get encoder store value
    /// \brief SGIF_GetEncoderStoreValue编码器值存储数据输出(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号
    /// \param NumOfBuffer                ç¼“冲区大小(最多可接受多少个数据)
    /// \param OutBuffer                æ•°æ®æ•°ç»„
    /// \param NumReceived                å®žé™…接收的数据个数
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderStoreValue(IN int DeviceID, IN int OutNo, IN int NumOfBuffer, OUT int * OutBuffer, OUT int *NumReceived);
    // Get encoder value
    /// \brief SGIF_GetEncoderCurrentValue    è¯»å–编码器当前值(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderCurrentValue(IN int DeviceID, IN int OutNo, OUT int * OutBuffer);
    // encoder Reset
    /// \brief SGIF_EncoderReset        ç¼–码器值置零(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_EncoderReset(IN int DeviceID, IN int OutNo);
    // Set Encoder Number
    /// \brief SGIF_SetEncoderNumber    é€‰æ‹©ç¼–码器(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetEncoderNumber(IN int DeviceID, IN int OutNo);
    // Get encoder number
    /// \brief SGIF_GetEncoderNumber    è¯»å–设置的编码器编号(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderNumber(IN int DeviceID, OUT int * OutBuffer);
    //Set Encoder Parameters
    /// \brief SGIF_SetEncoderParameters设置编码器参数(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \param InputMode                è¾“入模式(0-3)
    /// \param InputTime                æœ€ä½Žè¾“入时间(100,200,500,1000,2000,5000,10000,20000)(ns)
    /// \param interval                    é—´éš”(1-10000)
    /// \param OperatingMode            è¿è¡Œæ¨¡å¼ï¼ˆ0-2)
    /// \param DetectionDirection        æ£€æµ‹æ–¹å‘(0-2)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetEncoderParameters(IN int DeviceID, IN int OutNo, IN int InputMode, IN int InputTime, IN int interval, IN int OperatingMode, IN int DetectionDirection);
    //Get Encoder Parameters
    /// \brief SGIF_GetEncoderParameters读取编码器参数(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    ç¼–码器编号(1-3)
    /// \param InputMode                è¾“入模式(0-3)
    /// \param InputTime                æœ€ä½Žè¾“入时间(100,200,500,1000,2000,5000,10000,20000)(ns)
    /// \param interval                    é—´éš”(1-10000)
    /// \param OperatingMode            è¿è¡Œæ¨¡å¼ï¼ˆ0-2)
    /// \param DetectionDirection        æ£€æµ‹æ–¹å‘(0-2)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetEncoderParameters(IN int DeviceID, IN int OutNo, OUT int * InputMode, OUT int * InputTime, OUT int * interval, OUT int * OperatingMode, OUT int * DetectionDirection);
    //Set Analog Output
    /// \brief SGIF_SetAnalogOutput        è®¾ç½®æ¨¡æ‹Ÿé‡è¾“出(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ¨¡æ‹Ÿé‡ç¼–号(1-3)
    /// \param OutputChannel            è¾“出通道(0-3)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetAnalogOutput(IN int DeviceID, IN int OutNo, IN int OutputChannel);
    // Retrieve Analog Output Channel Number
    /// \brief SGIF_GetAnalogOutputChannel    èŽ·å–æ¨¡æ‹Ÿé‡è¾“å‡ºé€šé“ç¼–å·(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ¨¡æ‹Ÿé‡ç¼–号(1-3)
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetAnalogOutputChannel(IN int DeviceID, IN int OutNo, OUT int * OutBuffer);
    //Set IO Digital Output
    /// \brief SGIF_SetIODigitalOutput    è®¾ç½®IO数字输出(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ•°å­—输出编号(1-4)
    /// \param Level                    è¾“出位数(0:OFF,1:HI,2:GO,3:LO,4:STROBE)
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_SetIODigitalOutput(IN int DeviceID, IN int OutNo, IN int Level);
    // Retrieve IO Digital Output Channel Number
    /// \brief SGIF_GetIOOutputChannel    èŽ·å–IO数字量输出通道编号(仅SCI设备支持)
    /// \param DeviceID                    è®¾å¤‡ID号,范围为0-63.
    /// \param OutNo                    æ•°å­—输出编号(1-4)
    /// \param OutBuffer                æ•°æ®æŒ‡é’ˆ
    /// \return
    ///     >0:                            å¤±è´¥.
    ///     =0:                            æˆåŠŸ.
    ///
    EXP RC WINAPI SGIF_GetIOOutputChannel(IN int DeviceID, IN int OutNo, OUT int * OutBuffer);
#ifdef __cplusplus
}
#endif
SourceCode/Bond/SGMeasurement/DLL/64bit/SGIFPJ.dll
Binary files differ
SourceCode/Bond/SGMeasurement/DLL/64bit/SGIFPJ.lib
Binary files differ
SourceCode/Bond/SGMeasurement/DLL/ZYϵÁÐͨÐÅ¿â²Î¿¼ÊÖ²á-V2.3.pdf
Binary files differ
SourceCode/Bond/SGMeasurement/Logger.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
#include "pch.h"
#include "Logger.h"
CLogger& CLogger::Instance()
{
    static CLogger instance;
    return instance;
}
CLogger::CLogger()
{
    OpenLogFile();
}
CLogger::~CLogger()
{
    CloseLogFile();
}
void CLogger::OpenLogFile()
{
    CSingleLock lock(&m_csLogLock, TRUE);
    CTime now = CTime::GetCurrentTime();
    CString strLogDir = _T("Log");
    if (!PathFileExists(strLogDir)) {
        CreateDirectory(strLogDir, NULL);
    }
    CString strNewPath;
    strNewPath.Format(_T("%s\\SG_%04d%02d%02d.log"), strLogDir, now.GetYear(), now.GetMonth(), now.GetDay());
    if (m_strCurrentLogPath.CompareNoCase(strNewPath) != 0 || m_logFile.m_pStream == nullptr) {
        if (m_logFile.m_pStream) {
            m_logFile.Flush();
            m_logFile.Close();
        }
        if (m_logFile.Open(strNewPath,
            CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite | CFile::typeBinary)) {
            if (m_logFile.GetLength() == 0) {
                WCHAR bom = 0xFEFF;
                m_logFile.Write(&bom, sizeof(WCHAR));
            }
            m_logFile.SeekToEnd();
            m_strCurrentLogPath = strNewPath;
        }
    }
}
void CLogger::WriteLine(CString str)
{
    CSingleLock lock(&m_csLogLock, TRUE);
    OpenLogFile();
    if (m_logFile.m_pStream) {
        CTime now = CTime::GetCurrentTime();
        CString strTime;
        strTime.Format(_T("[%02d:%02d:%02d]"), now.GetHour(), now.GetMinute(), now.GetSecond());
        CString strLine = strTime + str + _T("\r\n");
        m_logFile.Write((LPCTSTR)strLine, strLine.GetLength() * sizeof(WCHAR));
    }
}
void CLogger::CloseLogFile()
{
    CSingleLock lock(&m_csLogLock, TRUE);
    if (m_logFile.m_pStream) {
        m_logFile.Flush();
        m_logFile.Close();
        m_strCurrentLogPath.Empty();
    }
}
SourceCode/Bond/SGMeasurement/Logger.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
#pragma once
#include <afx.h>
class CLogger
{
public:
    static CLogger& Instance();  // èŽ·å–å•ä¾‹
    void WriteLine(CString str); // å†™ä¸€è¡Œæ—¥å¿—
    void CloseLogFile();         // å…³é—­æ—¥å¿—文件
private:
    CLogger();
    ~CLogger();
    void OpenLogFile();          // å†…部打开文件
    CCriticalSection m_csLogLock;
    CString m_strCurrentLogPath;
    CStdioFile m_logFile;
};
#define LOG_LINE(x) CLogger::Instance().WriteLine(x)
#define LOG_LINEF(fmt, ...)                     \
    do {                                        \
        CString __log__;                        \
        __log__.Format(fmt, __VA_ARGS__);       \
        CLogger::Instance().WriteLine(__log__); \
    } while (0)
SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,309 @@
#include "pch.h"
#include "PLCSignalListener.h"
// === æ—¥å¿—打印类型 ===
#define LOG_TYPE_ERROR     -1
#define LOG_TYPE_SUCCESS    0
#define LOG_TYPE_WARNING    1
#define LOG_TYPE_NORMAL     2
// === æ—¥å¿—打印宏定义 ===
#define LOG_MSG(msg, type) LogInfo(msg, type)
// === PLC å¿ƒè·³ç›¸å…³é…ç½® ===
#define PLC_HEARTBEAT_PC_TO_PLC_ADDR   0x107F   // PC -> PLC:PC å†™å…¥å¿ƒè·³
#define PLC_HEARTBEAT_PLC_TO_PC_ADDR   0x6C40   // PLC -> PC:PC è¯»å– PLC å†™å…¥çš„心跳
#define MAX_MISSED_HEARTBEAT           5        // å…è®¸è¿žç»­ä¸¢å¤±å¿ƒè·³çš„æœ€å¤§æ¬¡æ•°ï¼Œè¶…过则判定 PLC æŽ‰çº¿
// === PLC å‘½ä»¤è¾“入配置(PLC -> PC) ===
#define PLC_CMD_BIT_START       0x6CD3  // PLC命令起始位(通常为B6CD3)
#define PLC_CMD_BIT_COUNT       2       // æ€»å…±å‡ ä¸ªå‘½ä»¤ä½ï¼ˆB6CD3=Start, B6CD4=Stop)
// === PLC åº”答输出配置(PC -> PLC) ===
#define PLC_ACK_MAX_LIFE        25      // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs æ¯«ç§’)
#define PLC_ACK_BASE_BIT        0x1060  // PLC应答起始地址(B1060表示B6CD3的应答;B1061表示B6CD4的应答)
// === PLC软元件类型宏(用于应答、数据写入)===
#define PLC_BIT_DEVICE_TYPE     DeviceType::B   // ä½æ“ä½œè®¾å¤‡ç±»åž‹ï¼ˆå¦‚M、B)
#define PLC_WORD_DEVICE_TYPE    DeviceType::W   // å­—操作设备类型(如D、W)
// === PLC结果寄存器地址配置 ===
#define PLC_RESULT_ADDR_START   0x37B0  // PLC结果寄存器起始地址(如W37B0)
#define PLC_RESULT_ADDR_COUNT   4       // ç»“果寄存器数量(如W37B0, W37B2, W37B4, W37B6)
#define IS_RISING_EDGE(prev, curr) (!(prev) && (curr))
CPLCSignalListener::CPLCSignalListener() = default;
CPLCSignalListener::~CPLCSignalListener() {
    Stop();
}
bool CPLCSignalListener::Initialize(StationIdentifier station, int nIntervalMs/* = 200*/)
{
    m_pPlc = std::make_unique<CCCLinkIEControl>();
    if (!m_pPlc) {
        LOG_MSG(_T("PLC控制器初始化失败,无法创建 CCCLinkIEControl å®žä¾‹ã€‚"), LOG_TYPE_ERROR);
        return false;
    }
    int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1));
    if (ret != 0) {
        m_bConnected = false;
        CString strError;
        strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret);
        LOG_MSG(strError, LOG_TYPE_ERROR);
        return false;
    }
    m_bConnected = true;
    m_station = station;
    m_nIntervalMs = nIntervalMs;
    m_vecPrevBits.assign(PLC_CMD_BIT_COUNT, false);
    return true;
}
void CPLCSignalListener::SetStartCallback(Callback cb)
{
    m_cbStart = std::move(cb);
}
void CPLCSignalListener::SetStopCallback(Callback cb)
{
    m_cbStop = std::move(cb);
}
void CPLCSignalListener::SetAnalyzeCallback(AnalyzeCallback cb)
{
    m_cbAnalyze = std::move(cb);
}
void CPLCSignalListener::SetLogCallback(LogCallback cb)
{
    m_cbLog = std::move(cb);
}
bool CPLCSignalListener::Start()
{
    if (m_bRunning || !m_pPlc) {
        LOG_MSG(_T("PLC信号监听器已在运行或PLC控制器未初始化。"), LOG_TYPE_ERROR);
        return false;
    }
    m_bRunning = true;
    m_thread = std::thread(&CPLCSignalListener::ThreadProc, this);
    StartHeartbeatMonitor();
    return true;
}
void CPLCSignalListener::Stop()
{
    m_bRunning = false;
    if (m_thread.joinable()) {
        m_thread.join();
    }
    StopHeartbeatMonitor();
}
void CPLCSignalListener::LogInfo(const CString& strText, int nType)
{
    if (m_cbLog) {
        m_cbLog(strText, nType);
    }
}
bool CPLCSignalListener::SendHeartbeat()
{
    if (!m_pPlc || !m_bConnected) {
        return false;
    }
    static bool bToggle = false;
    bToggle = !bToggle;
    int ret = m_pPlc->WriteBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PC_TO_PLC_ADDR, BitContainer{ bToggle });
    return (ret == 0);
}
bool CPLCSignalListener::CheckHeartbeat()
{
    static bool bLastHeartbeat = false;
    if (!m_pPlc || !m_bConnected) {
        return false;
    }
    BitContainer vec;
    int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PLC_TO_PC_ADDR, 1, vec);
    if (ret != 0 || vec.empty()) {
        return false;
    }
    bool bCurrent = vec[0];
    bool bChanged = (bCurrent != bLastHeartbeat);
    bLastHeartbeat = bCurrent;
    return bChanged;
}
bool CPLCSignalListener::MonitorHeartbeat()
{
    if (CheckHeartbeat()) {
        m_nMissedHeartbeatCount = 0;
        if (m_bHeartbeatLost) {
            m_bHeartbeatLost = false;
            LOG_MSG(_T("PLC心跳恢复!"), LOG_TYPE_SUCCESS);
        }
        return true;
    }
    else {
        m_nMissedHeartbeatCount++;
        if (m_nMissedHeartbeatCount > MAX_MISSED_HEARTBEAT) {
            if (!m_bHeartbeatLost) {
                m_bHeartbeatLost = true;
                m_nMissedHeartbeatCount = 0;
                LOG_MSG(_T("PLC心跳信号中断!"), LOG_TYPE_ERROR);
            }
            return false;
        }
    }
    return true;
}
void CPLCSignalListener::StartHeartbeatMonitor()
{
    m_bHeartbeatRunning = true;
    m_heartbeatThread = std::thread([this]() {
        while (m_bHeartbeatRunning) {
            SendHeartbeat();
            MonitorHeartbeat();
            std::this_thread::sleep_for(std::chrono::milliseconds(m_nIntervalMs * 5));
        }
    });
}
void CPLCSignalListener::StopHeartbeatMonitor()
{
    m_bHeartbeatRunning = false;
    if (m_heartbeatThread.joinable()) {
        m_heartbeatThread.join();
    }
}
void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, long nBitNo, int nDelayMs/* = 50*/)
{
    m_pPlc->SetBitDeviceEx(m_station, eDevType, nBitNo);
    ::Sleep(nDelayMs);
    m_pPlc->ResetBitDeviceEx(m_station, eDevType, nBitNo);
}
void CPLCSignalListener::HandleAckLife(int i, bool bCurrTriggerBit)
{
    if (m_vecAckSent[i] && !bCurrTriggerBit) {
        m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i));
        m_vecAckSent[i] = false;
    }
    if (m_vecAckSent[i]) {
        if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) {
            m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i));
            m_vecAckSent[i] = false;
        }
    }
}
void CPLCSignalListener::ThreadProc()
{
    while (m_bRunning && m_bConnected) {
        BitContainer vecBits;
        int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits);
        if (ret != 0 && vecBits.size() != PLC_CMD_BIT_COUNT) {
            ::Sleep(m_nIntervalMs);
            CString strError;
            strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret);
            LOG_MSG(strError, LOG_TYPE_ERROR);
            continue;
        }
        for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) {
            if (IS_RISING_EDGE(m_vecPrevBits[i], vecBits[i])) {
                // ä¸Šå‡æ²¿è§¦å‘
                switch (i) {
                case 0:
                    if (m_cbStart) {
                        m_cbStart();
                        WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 });
                        if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
                            m_vecAckSent[i] = true;
                            m_vecAckCounter[i] = 0;
                        }
                    }
                    break;
                case 1:
                    if (m_cbStop) {
                        m_cbStop();
                        if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
                            m_vecAckSent[i] = true;
                            m_vecAckCounter[i] = 0;
                        }
                    }
                    if (m_cbAnalyze) {
                        auto results = m_cbAnalyze();
                        WriteOutValues(results);
                    }
                    break;
                }
            }
            HandleAckLife(i, vecBits[i]);
            m_vecPrevBits[i] = vecBits[i];
        }
        ::Sleep(m_nIntervalMs);
    }
}
bool CPLCSignalListener::WriteOutValues(const OutValuesArray& values)
{
    if (!m_pPlc || !m_bConnected) {
        LOG_MSG(_T("PLC未连接或未初始化,无法写入输出值。"), LOG_TYPE_ERROR);
        return false;
    }
    if (PLC_RESULT_ADDR_COUNT != 4) {
        LOG_MSG(_T("PLC结果寄存器数量配置错误,必须为4个。"), LOG_TYPE_ERROR);
        return false;
    }
    for (int i = 0; i < PLC_RESULT_ADDR_COUNT; ++i) {
        // æ”¾å¤§100倍并四舍五入,转为PLC整数
        uint16_t nScaled = static_cast<uint16_t>(std::round(values[i] * 100.0));
        WordContainer vec = { nScaled };
        short nTargetAddr = PLC_RESULT_ADDR_START + i * 2;
        int ret = m_pPlc->WriteWordDataEx(m_station, PLC_WORD_DEVICE_TYPE, nTargetAddr, vec);
        if (ret != 0) {
            CString msg;
            msg.Format(_T("写入OUT%d到地址%d失败,值=%.2f"), i + 1, nTargetAddr, values[i]);
            LOG_MSG(msg, LOG_TYPE_ERROR);
            return false;
        }
    }
    return true;
}
SourceCode/Bond/SGMeasurement/PLCSignalListener.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,178 @@
#pragma once
#include "CCLinkIEControl.h"
#include <thread>
#include <atomic>
#include <functional>
#include <vector>
using OutValuesArray = std::array<double, 4>;
using Callback = std::function<void()>;
using AnalyzeCallback = std::function<OutValuesArray()>;
using LogCallback = std::function<void(const CString& strContent, int type)>;
class CPLCSignalListener
{
public:
    CPLCSignalListener();
    ~CPLCSignalListener();
    /**
     * @brief åˆå§‹åŒ– PLC ä¿¡å·ç›‘听器。
     *
     * @param station      ç›®æ ‡ PLC çš„站号标识符。
     * @param nIntervalMs  è½®è¯¢å‘¨æœŸï¼ˆå•位:毫秒),默认 200ms。
     * @return true        åˆå§‹åŒ–成功。
     * @return false       åˆå§‹åŒ–失败。
     */
    bool Initialize(StationIdentifier station, int nIntervalMs = 200);
    /**
     * @brief è®¾ç½®å¼€å§‹å‘½ä»¤çš„回调函数(对应 PLC çš„ Start ä¿¡å·ï¼‰ã€‚
     *
     * @param cb  ç”¨æˆ·è‡ªå®šä¹‰çš„开始回调函数。
     */
    void SetStartCallback(Callback cb);
    /**
     * @brief è®¾ç½®åœæ­¢å‘½ä»¤çš„回调函数(对应 PLC çš„ Stop ä¿¡å·ï¼‰ã€‚
     *
     * @param cb  ç”¨æˆ·è‡ªå®šä¹‰çš„停止回调函数。
     */
    void SetStopCallback(Callback cb);
    /**
     * @brief è®¾ç½®åˆ†æžè®¡ç®—回调函数,在接收到停止命令后调用。
     *
     * @param cb  è¿”回计算结果数组(OUT1~OUT4)的函数。
     */
    void SetAnalyzeCallback(AnalyzeCallback cb);
    /**
     * @brief è®¾ç½®æ—¥å¿—输出回调函数。
     *
     * @param cb  ç”¨æˆ·æä¾›çš„æ—¥å¿—输出接口(包含日志内容和日志类型)。
     */
    void SetLogCallback(LogCallback cb);
    /**
     * @brief å¯åŠ¨ä¿¡å·ç›‘å¬çº¿ç¨‹ã€‚
     *
     * @return true   å¯åŠ¨æˆåŠŸã€‚
     * @return false  å¯åŠ¨å¤±è´¥ï¼ˆå¯èƒ½å·²è¿è¡Œæˆ–æœªåˆå§‹åŒ–ï¼‰ã€‚
     */
    bool Start();
    /**
     * @brief åœæ­¢ä¿¡å·ç›‘听线程。
     */
    void Stop();
    /**
     * @brief å‘ PLC å†™å…¥åˆ†æžç»“果值(通常为 OUT1 ~ OUT4)。
     *
     * @param values  åŒ…含四个 double ç±»åž‹çš„结果值,将转换为整数后写入 PLC。
     * @return true   å†™å…¥æˆåŠŸã€‚
     * @return false  å†™å…¥å¤±è´¥ã€‚
     */
    bool WriteOutValues(const OutValuesArray& values);
private:
    /**
     * @brief è¾“出日志信息(封装日志回调)。
     *
     * @param strText æ—¥å¿—内容文本。
     * @param nType   æ—¥å¿—类型(LOG_TYPE_NORMAL / ERROR / WARNING ç­‰ï¼‰ã€‚
     */
    void LogInfo(const CString& strText, int nType);
    /**
     * @brief å‘ PLC å†™å…¥å¿ƒè·³ä¿¡å·ï¼ˆäº¤æ›¿ä½ï¼‰ã€‚
     *
     * @return true  å†™å…¥æˆåŠŸã€‚
     * @return false å†™å…¥å¤±è´¥ï¼ˆå¦‚未连接)。
     */
    bool SendHeartbeat();
    /**
     * @brief æ£€æŸ¥ä»Ž PLC è¯»å–到的心跳信号是否发生变化。
     *
     * @return true  å¿ƒè·³æœ‰å˜åŒ–(PLC æ­£å¸¸åœ¨çº¿ï¼‰ã€‚
     * @return false å¿ƒè·³æ— å˜åŒ–(可能离线)。
     */
    bool CheckHeartbeat();
    /**
     * @brief ç›‘控 PLC å¿ƒè·³æ˜¯å¦ä¸­æ–­ï¼Œå¹¶è‡ªåŠ¨è®°å½•çŠ¶æ€ã€‚
     *
     * @return true  PLC åœ¨çº¿æˆ–在允许的未响应次数内。
     * @return false PLC å¿ƒè·³ä¸­æ–­ï¼Œè¶…过允许阈值。
     */
    bool MonitorHeartbeat();
    /**
     * @brief å¯åŠ¨å¿ƒè·³ç›‘æŽ§çº¿ç¨‹ï¼ˆç‹¬ç«‹äºŽä¿¡å·ç›‘å¬çº¿ç¨‹ï¼‰ã€‚
     */
    void StartHeartbeatMonitor();
    /**
     * @brief åœæ­¢å¿ƒè·³ç›‘控线程。
     */
    void StopHeartbeatMonitor();
    /**
     * @brief å‘指定软元件位写入一个脉冲(先写1,延时后自动写0)。
     *
     * @param eDevType ä½è½¯å…ƒä»¶ç±»åž‹ï¼ˆå¦‚ M/B)。
     * @param nBitNo   ä½åœ°å€ç¼–号。
     * @param nDelayMs è„‰å†²æŒç»­æ—¶é—´ï¼Œé»˜è®¤50毫秒。
     */
    void PulseBitDevice(DeviceType eDevType, long nBitNo, int nDelayMs = 50);
    /**
     * @brief ç®¡ç† ACK å“åº”的生命周期,超时自动清除。
     *
     * @param i                æŽ§åˆ¶ä½ç´¢å¼•(0=Start,1=Stop)。
     * @param bCurrTriggerBit  å½“前从 PLC è¯»å–到的触发位状态。
     */
    void HandleAckLife(int i, bool bCurrTriggerBit);
    /**
     * @brief ä¸»ç›‘听线程逻辑,循环读取 PLC æŽ§åˆ¶ä¿¡å·å¹¶å¤„理触发。
     */
    void ThreadProc();
private:
    // === PLC é€šä¿¡æ ¸å¿ƒå¯¹è±¡ ===
    std::unique_ptr<CCCLinkIEControl> m_pPlc; // PLC é€šä¿¡æŽ§åˆ¶å™¨
    StationIdentifier m_station;              // PLC ç«™å·
    std::atomic<bool> m_bConnected{ false };  // æ˜¯å¦æˆåŠŸè¿žæŽ¥
    // === æŽ§åˆ¶å‚æ•° ===
    int m_nIntervalMs = 200;                  // è½®è¯¢å‘¨æœŸï¼ˆms)
    // === å‘½ä»¤è§¦å‘状态缓存 ===
    std::vector<bool> m_vecPrevBits;          // ä¸Šä¸€å‘¨æœŸçš„命令位状态(用于检测上升沿)
    // === å›žè°ƒå‡½æ•°ï¼ˆæŽ§åˆ¶/计算/日志)===
    Callback m_cbStart;                       // Start å‘½ä»¤å›žè°ƒ
    Callback m_cbStop;                        // Stop å‘½ä»¤å›žè°ƒ
    AnalyzeCallback m_cbAnalyze;              // Analyze è®¡ç®—回调(返回 OUT1~OUT4)
    LogCallback m_cbLog;                      // æ—¥å¿—输出回调
    // === ä¸»çº¿ç¨‹æŽ§åˆ¶ ===
    std::atomic<bool> m_bRunning{ false };    // ä¸»ç›‘听线程是否运行
    std::thread m_thread;                     // ä¸»ç›‘听线程对象
    // === ACK ä¿¡å·çŠ¶æ€ ===
    std::array<bool, 2> m_vecAckSent = { false, false }; // æ˜¯å¦å·²å‘送应答信号(B10/B11)
    std::array<int, 2>  m_vecAckCounter = { 0, 0 };      // å¯¹åº”应答信号的生命周期计数器
    // === å¿ƒè·³æ£€æµ‹ç›¸å…³ ===
    std::thread m_heartbeatThread;                  // å¿ƒè·³æ£€æµ‹çº¿ç¨‹å¯¹è±¡
    std::atomic<bool> m_bHeartbeatRunning = false;  // å¿ƒè·³çº¿ç¨‹è¿è¡Œæ ‡å¿—
    std::atomic<bool> m_bHeartbeatLost = false;     // å¿ƒè·³ä¸¢å¤±æ ‡å¿—
    int m_nMissedHeartbeatCount = 0;                // å¿ƒè·³æœªå˜åŒ–次数(用于检测 PLC æŽ‰çº¿ï¼‰
};
SourceCode/Bond/SGMeasurement/SGMeasurement.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@

// SGMeasurement.cpp: å®šä¹‰åº”用程序的类行为。
//
#include "pch.h"
#include "framework.h"
#include "SGMeasurement.h"
#include "SGMeasurementDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CSGMeasurementApp
BEGIN_MESSAGE_MAP(CSGMeasurementApp, CWinApp)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// CSGMeasurementApp æž„造
CSGMeasurementApp::CSGMeasurementApp()
{
    // æ”¯æŒé‡æ–°å¯åŠ¨ç®¡ç†å™¨
    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
    // TODO: åœ¨æ­¤å¤„添加构造代码,
    // å°†æ‰€æœ‰é‡è¦çš„初始化放置在 InitInstance ä¸­
}
// å”¯ä¸€çš„ CSGMeasurementApp å¯¹è±¡
CSGMeasurementApp theApp;
// CSGMeasurementApp åˆå§‹åŒ–
BOOL CSGMeasurementApp::InitInstance()
{
    // å¦‚果应用程序存在以下情况,Windows XP ä¸Šéœ€è¦ InitCommonControlsEx()
    // ä½¿ç”¨ ComCtl32.dll ç‰ˆæœ¬ 6 æˆ–更高版本来启用可视化方式,则需要 InitCommonControlsEx()。否则,将无法创建窗口。
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // å°†å®ƒè®¾ç½®ä¸ºåŒ…括所有要在应用程序中使用的
    // å…¬å…±æŽ§ä»¶ç±»ã€‚
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);
    CWinApp::InitInstance();
    // åˆå§‹åŒ– MFC RichEdit æŽ§ä»¶
    AfxInitRichEdit2();
    AfxEnableControlContainer();
    // åˆ›å»º shell ç®¡ç†å™¨ï¼Œä»¥é˜²å¯¹è¯æ¡†åŒ…含
    // ä»»ä½• shell æ ‘视图控件或 shell åˆ—表视图控件。
    CShellManager *pShellManager = new CShellManager;
    // æ¿€æ´»â€œWindows Native”视觉管理器,以便在 MFC æŽ§ä»¶ä¸­å¯ç”¨ä¸»é¢˜
    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
    // æ ‡å‡†åˆå§‹åŒ–
    // å¦‚果未使用这些功能并希望减小
    // æœ€ç»ˆå¯æ‰§è¡Œæ–‡ä»¶çš„大小,则应移除下列
    // ä¸éœ€è¦çš„特定初始化例程
    // æ›´æ”¹ç”¨äºŽå­˜å‚¨è®¾ç½®çš„æ³¨å†Œè¡¨é¡¹
    // TODO: åº”适当修改该字符串,
    // ä¾‹å¦‚修改为公司或组织名
    SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
    CSGMeasurementDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // TODO:“确定”来关闭对话框的代码
    }
    else if (nResponse == IDCANCEL)
    {
        // TODO:“取消”来关闭对话框的代码
    }
    else if (nResponse == -1)
    {
        TRACE(traceAppMsg, 0, "警告: å¯¹è¯æ¡†åˆ›å»ºå¤±è´¥ï¼Œåº”用程序将意外终止。\n");
        TRACE(traceAppMsg, 0, "警告: å¦‚果您在对话框上使用 MFC æŽ§ä»¶ï¼Œåˆ™æ— æ³• #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
    }
    // åˆ é™¤ä¸Šé¢åˆ›å»ºçš„ shell ç®¡ç†å™¨ã€‚
    if (pShellManager != nullptr)
    {
        delete pShellManager;
    }
#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
    ControlBarCleanUp();
#endif
    // ç”±äºŽå¯¹è¯æ¡†å·²å…³é—­ï¼Œæ‰€ä»¥å°†è¿”回 FALSE ä»¥ä¾¿é€€å‡ºåº”用程序,而不是启动应用程序的消息泵。
    return FALSE;
}
SourceCode/Bond/SGMeasurement/SGMeasurement.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@

// SGMeasurement.h: PROJECT_NAME åº”用程序的主头文件
//
#pragma once
#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含 'pch.h' ä»¥ç”Ÿæˆ PCH"
#endif
#include "resource.h"        // ä¸»ç¬¦å·
// CSGMeasurementApp:
// æœ‰å…³æ­¤ç±»çš„实现,请参阅 SGMeasurement.cpp
//
class CSGMeasurementApp : public CWinApp
{
public:
    CSGMeasurementApp();
// é‡å†™
public:
    virtual BOOL InitInstance();
// å®žçް
    DECLARE_MESSAGE_MAP()
};
extern CSGMeasurementApp theApp;
SourceCode/Bond/SGMeasurement/SGMeasurement.rc
Binary files differ
SourceCode/Bond/SGMeasurement/SGMeasurement.vcxproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>17.0</VCProjectVersion>
    <ProjectGuid>{F8087F20-3A3E-18F2-09E3-9C139642EB58}</ProjectGuid>
    <Keyword>MFCProj</Keyword>
    <RootNamespace>SGMeasurement</RootNamespace>
    <WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v141</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Dynamic</UseOfMfc>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v141</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Dynamic</UseOfMfc>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v141</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Dynamic</UseOfMfc>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v141</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Dynamic</UseOfMfc>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
      <AdditionalIncludeDirectories>.;..;.\DLL\64bit;.\CCLinkPerformance;..\MELSECSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <AdditionalLibraryDirectories>.\DLL\64bit;..\MELSECSDK\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalDependencies>SGIFPJ.lib;MdFunc32.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0804</Culture>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
      <AdditionalIncludeDirectories>.\DLL\32bit;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <AdditionalLibraryDirectories>.\DLL\32bit;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalDependencies>SGIFPJ.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0804</Culture>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
      <AdditionalIncludeDirectories>.\DLL\32bit;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalLibraryDirectories>.\DLL\32bit;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalDependencies>SGIFPJ.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0804</Culture>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
      <AdditionalIncludeDirectories>.;..;.\DLL\64bit;.\CCLinkPerformance;..\MELSECSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <Optimization>MaxSpeed</Optimization>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalLibraryDirectories>.\DLL\64bit;..\MELSECSDK\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalDependencies>SGIFPJ.lib;MdFunc32.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0804</Culture>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
    <PostBuildEvent>
      <Command>if exist "\\DESKTOP-IODBVIQ\SGMeasurement\" (
    xcopy /Y /D "$(OutDir)SGIFPJ.dll" "\\DESKTOP-IODBVIQ\SGMeasurement\"
    xcopy /Y /D "$(OutDir)$(ProjectName).exe" "\\DESKTOP-IODBVIQ\SGMeasurement\"
    xcopy /Y /D "$(OutDir)$(ProjectName).pdb" "\\DESKTOP-IODBVIQ\SGMeasurement\"
)</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h" />
    <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h" />
    <ClInclude Include="framework.h" />
    <ClInclude Include="Logger.h" />
    <ClInclude Include="pch.h" />
    <ClInclude Include="PLCSignalListener.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="SGMeasurement.h" />
    <ClInclude Include="SGMeasurementDlg.h" />
    <ClInclude Include="targetver.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp" />
    <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp" />
    <ClCompile Include="Logger.cpp" />
    <ClCompile Include="pch.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="PLCSignalListener.cpp" />
    <ClCompile Include="SGMeasurement.cpp" />
    <ClCompile Include="SGMeasurementDlg.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="SGMeasurement.rc" />
  </ItemGroup>
  <ItemGroup>
    <None Include="res\SGMeasurement.rc2" />
  </ItemGroup>
  <ItemGroup>
    <Image Include="res\menu_close.ico" />
    <Image Include="res\menu_restore.ico" />
    <Image Include="res\SGMeasurement.ico" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>
SourceCode/Bond/SGMeasurement/SGMeasurement.vcxproj.filters
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="源文件">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="头文件">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="资源文件">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
    <Filter Include="CCLinkPerformance">
      <UniqueIdentifier>{5874a2ba-95ca-44c8-a816-3e468f17564e}</UniqueIdentifier>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="SGMeasurement.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="SGMeasurementDlg.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="framework.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="targetver.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Resource.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="pch.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Logger.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h">
      <Filter>CCLinkPerformance</Filter>
    </ClInclude>
    <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h">
      <Filter>CCLinkPerformance</Filter>
    </ClInclude>
    <ClInclude Include="PLCSignalListener.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="SGMeasurement.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="SGMeasurementDlg.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="pch.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Logger.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp">
      <Filter>CCLinkPerformance</Filter>
    </ClCompile>
    <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp">
      <Filter>CCLinkPerformance</Filter>
    </ClCompile>
    <ClCompile Include="PLCSignalListener.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="SGMeasurement.rc">
      <Filter>资源文件</Filter>
    </ResourceCompile>
  </ItemGroup>
  <ItemGroup>
    <None Include="res\SGMeasurement.rc2">
      <Filter>资源文件</Filter>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Image Include="res\SGMeasurement.ico">
      <Filter>资源文件</Filter>
    </Image>
    <Image Include="res\menu_restore.ico">
      <Filter>资源文件</Filter>
    </Image>
    <Image Include="res\menu_close.ico">
      <Filter>资源文件</Filter>
    </Image>
  </ItemGroup>
</Project>
SourceCode/Bond/SGMeasurement/SGMeasurement.vcxproj.user
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <RESOURCE_FILE>SGMeasurement.rc</RESOURCE_FILE>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <RemoteDebuggerCommand>\\DESKTOP-IODBVIQ\SGMeasurement\$(ProjectName).exe</RemoteDebuggerCommand>
    <RemoteDebuggerWorkingDirectory>\\DESKTOP-IODBVIQ\SGMeasurement</RemoteDebuggerWorkingDirectory>
    <RemoteDebuggerServerName>DESKTOP-IODBVIQ</RemoteDebuggerServerName>
    <DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor>
  </PropertyGroup>
</Project>
SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1212 @@

// SGMeasurementDlg.cpp: å®žçŽ°æ–‡ä»¶
//
#include "pch.h"
#include "framework.h"
#include "SGMeasurement.h"
#include "SGMeasurementDlg.h"
#include "afxdialogex.h"
#include "SGIF.h"
#include "Logger.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define DeviceID 0
// æ‰˜ç›˜å›¾æ ‡ ID ä¸Žæ¶ˆæ¯å®
#define ID_TRAY_RESTORE           2001                // æ¢å¤çª—口
#define ID_TRAY_EXIT           2002                // é€€å‡ºç¨‹åº
#define WM_TRAY_ICON_NOTIFY    (WM_USER + 1000) // æ‰˜ç›˜å›¾æ ‡å›žè°ƒæ¶ˆæ¯ ID
// æ‰˜ç›˜æç¤ºæ–‡æœ¬å®
#define TRAY_ICON_TOOLTIP_TEXT  _T("SGMeasurement")
// æ—¥å¿—颜色宏定义
#define LOG_COLOR_NORMAL   RGB(0, 0, 0)         // æ™®é€šï¼šé»‘色
#define LOG_COLOR_SUCCESS  RGB(0, 128, 0)       // æˆåŠŸï¼šç»¿è‰²
#define LOG_COLOR_ERROR    RGB(255, 0, 0)       // é”™è¯¯ï¼šçº¢è‰²
#define LOG_COLOR_WARNING  RGB(255, 165, 0)     // è­¦å‘Šï¼šæ©™è‰²
#define LOG_COLOR_TIME     RGB(0, 0, 255)       // æ—¶é—´æˆ³ï¼šè“è‰²
// å®šæ—¶å™¨ç›¸å…³å®å®šä¹‰
#define TIMER_INTERVAL_MS        500
#define TIMER_ID_OUTPUT_UPDATE    1
// è®¡æ—¶å®å®šä¹‰
#define MEASURE_FUNC_START() \
    clock_t __startClock = clock();
#define MEASURE_FUNC_END() \
    do { \
        clock_t __endClock = clock(); \
        double __elapsedMs = 1000.0 * (__endClock - __startClock) / CLOCKS_PER_SEC; \
        CString __strElapsed; \
        __strElapsed.Format(_T("%s æ‰§è¡Œè€—时:%.1f ms"), _T(__FUNCTION__), __elapsedMs); \
        AppendLogLineRichStyled(__strElapsed, LOG_COLOR_SUCCESS); \
    } while (0)
class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
// å®žçް
protected:
    DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
CSGMeasurementDlg::CSGMeasurementDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_SGMEASUREMENT_DIALOG, pParent)
    , m_bConnected(false)
    , m_bSaving(false)
    , m_dOutValues{ 0.0, 0.0, 0.0, 0.0 }
    , m_nUseTrigger(0)
    , m_nSavePointCount(100000)
    , m_fJumpThreshold(0.2f)
    , m_nJumpWindow(3)
    , m_nValleyMargin(0)
    , m_nMinGlass1Count(10)
    , m_nFixedCount(5)
    , m_fMaxDelta(0.05f)
    , m_nTrayIconID(0)
    , m_bTrayIconCreated(FALSE)
    , m_bExitingFromTray(FALSE)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSGMeasurementDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDIT_OUT1, m_dOutValues[0]);
    DDX_Text(pDX, IDC_EDIT_OUT2, m_dOutValues[1]);
    DDX_Text(pDX, IDC_EDIT_OUT3, m_dOutValues[2]);
    DDX_Text(pDX, IDC_EDIT_OUT4, m_dOutValues[3]);
    DDX_Control(pDX, IDC_RICHEDIT_LOG, m_editLog);
    DDX_Check(pDX, IDC_CHECK_USE_TRIGGER, m_nUseTrigger);
    DDX_Control(pDX, IDC_COMBO_OUTPUT_PORT, m_comboOutputPort);
    DDX_Text(pDX, IDC_EDIT_STORE_COUNT, m_nSavePointCount);
    DDX_Text(pDX, IDC_EDIT_JUMP_WINDOW, m_nJumpWindow);
    DDX_Text(pDX, IDC_EDIT_VALLEY_MARGIN, m_nValleyMargin);
    DDX_Text(pDX, IDC_EDIT_MIN_GLASS_COUNT, m_nMinGlass1Count);
    DDX_Text(pDX, IDC_EDIT_FIXED_COUNT, m_nFixedCount);
    DDX_Text(pDX, IDC_EDIT_JUMP_THRESHOLD, m_fJumpThreshold);
    DDX_Text(pDX, IDC_EDIT_MAX_DELTA, m_fMaxDelta);
}
void CSGMeasurementDlg::ExitApplication()
{
    // æ–­å¼€è®¾å¤‡è¿žæŽ¥ï¼ˆå¦‚已连接)
    if (m_bConnected) {
        DisconnectFromDevice();
    }
    // åˆ é™¤æ‰˜ç›˜å›¾æ ‡ï¼ˆå¦‚已添加)
    if (m_bTrayIconCreated) {
        Shell_NotifyIcon(NIM_DELETE, &m_trayIconData);
        m_bTrayIconCreated = FALSE;
    }
    m_plcListener.Stop();
    DestroyWindow();
    CDialogEx::OnClose();
}
void CSGMeasurementDlg::UpdateControlStatus(BOOL bConnected, BOOL bStoring/* = FALSE*/)
{
    // è¿žæŽ¥æŒ‰é’®å’Œæ–­å¼€æŒ‰é’®çŠ¶æ€äº’æ–¥
    GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(!bConnected);
    GetDlgItem(IDC_BUTTON_DISCONNECT)->EnableWindow(bConnected);
    // IP地址输入只允许在未连接时修改
    GetDlgItem(IDC_IPADDRESS)->EnableWindow(!bConnected);
    // å­˜å‚¨é…ç½®æŽ§ä»¶ä»…在已连接且未开始存储时允许操作
    BOOL bCanConfigure = bConnected && !bStoring;
    /*GetDlgItem(IDC_CHECK_USE_TRIGGER)->EnableWindow(bCanConfigure);*/
    GetDlgItem(IDC_COMBO_OUTPUT_PORT)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_STORE_COUNT)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_JUMP_THRESHOLD)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_JUMP_WINDOW)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_VALLEY_MARGIN)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_MIN_GLASS_COUNT)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_FIXED_COUNT)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_EDIT_MAX_DELTA)->EnableWindow(bCanConfigure);
    // å­˜å‚¨ç›¸å…³æŒ‰é’®
    GetDlgItem(IDC_BUTTON_RECEIVE_FROM_CTRL)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_BUTTON_SEND_TO_CTRL)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_BUTTON_CLEAR_STORE)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_BUTTON_START_STORE)->EnableWindow(bCanConfigure);
    GetDlgItem(IDC_BUTTON_STOP_STORE)->EnableWindow(bStoring);
}
void CSGMeasurementDlg::AppendLogLineBatchBegin()
{
    m_editLog.SetRedraw(FALSE);
    m_editLog.SetEventMask(0); // é˜²æ­¢è§¦å‘不必要的通知
}
void CSGMeasurementDlg::AppendLogLineBatchEnd()
{
    m_editLog.SetRedraw(TRUE);
    m_editLog.Invalidate();    // å¼ºåˆ¶é‡ç»˜
    m_editLog.SetEventMask(ENM_CHANGE | ENM_SELCHANGE);
}
void CSGMeasurementDlg::TrimRichEditLineLimit(int nMaxLines)
{
    int nLineCount = m_editLog.GetLineCount();
    if (nLineCount < nMaxLines) {
        return;
    }
    // èŽ·å–å¤šä½™è¡Œçš„å­—ç¬¦æ•°èŒƒå›´
    int charIndex = m_editLog.LineIndex(nMaxLines);
    m_editLog.SetSel(0, charIndex); // é€‰ä¸­å¤šä½™å†…容
    m_editLog.ReplaceSel(_T(""));   // åˆ é™¤
}
void CSGMeasurementDlg::AppendLogLineRichStyled(const CString& strContent, COLORREF color /*= RGB(0, 0, 0)*/)
{
    if (!::IsWindow(GetSafeHwnd()) || !::IsWindow(m_editLog.GetSafeHwnd())) {
        return;
    }
    // æ—¶é—´æˆ³
    CString strTimestamp;
    CTime now = CTime::GetCurrentTime();
    strTimestamp.Format(_T("[%02d:%02d:%02d] "), now.GetHour(), now.GetMinute(), now.GetSecond());
    // æ’入点移到最后(也可以设为 0 è¡¨ç¤ºé¡¶éƒ¨ï¼‰
    m_editLog.SetSel(-1, -1);
    // æ’入时间(蓝色)
    CHARFORMAT2 cfTime = {};
    cfTime.cbSize = sizeof(cfTime);
    cfTime.dwMask = CFM_COLOR;
    cfTime.crTextColor = LOG_COLOR_TIME;
    m_editLog.SetSelectionCharFormat(cfTime);
    m_editLog.ReplaceSel(strTimestamp);
    // ç”Ÿæˆæ—¥å¿—级别标签
    CString strLevel;
    if (color == LOG_COLOR_WARNING) {
        strLevel = _T("[警告]");
    }
    else if (color == LOG_COLOR_ERROR) {
        strLevel = _T("[错误]");
    }
    else if (color == LOG_COLOR_NORMAL) {
        strLevel = _T("[信息]");
    }
    else if (color == LOG_COLOR_SUCCESS) {
        strLevel = _T("[成功]");
    }
    else {
        strLevel = _T("[未知]");
    }
    // æ’入日志正文(传入颜色)
    CHARFORMAT2 cfMsg = {};
    cfMsg.cbSize = sizeof(cfMsg);
    cfMsg.dwMask = CFM_COLOR;
    cfMsg.crTextColor = color;
    m_editLog.SetSelectionCharFormat(cfMsg);
    m_editLog.ReplaceSel(strLevel + strContent + _T("\r\n"));
    // é™åˆ¶æœ€å¤§è¡Œæ•°
    TrimRichEditLineLimit(100);
    // æ‹¼æŽ¥å®Œæ•´æ—¥å¿—行
    CString strFullLogLine;
    strFullLogLine.Format(_T("%s %s"), strLevel, strContent);
    // å†™å…¥æ—¥å¿—文件
    // LOG_LINE(strFullLogLine);
}
void CSGMeasurementDlg::HighlightAllMatches(const CString& strSearch, COLORREF clrHighlight/* = RGB(255, 165, 0)*/)
{
    if (strSearch.IsEmpty()) {
        return;
    }
    long nStart = 0;
    long nEnd = m_editLog.GetTextLength();
    FINDTEXTEX ft = { 0 };
    ft.chrg.cpMin = 0;
    ft.chrg.cpMax = nEnd;
    ft.lpstrText = strSearch.GetString();
    // é«˜äº®å‰ä¸æ¸…除全文颜色,避免历史多色混淆
    while (m_editLog.FindText(FR_DOWN, &ft) != -1) {
        m_editLog.SetSel(ft.chrgText.cpMin, ft.chrgText.cpMax);
        CHARFORMAT2 cf = {};
        cf.cbSize = sizeof(cf);
        cf.dwMask = CFM_COLOR;
        cf.crTextColor = clrHighlight;
        m_editLog.SetSelectionCharFormat(cf);
        // ä¸‹æ¬¡æœç´¢ä»ŽåŽé¢å¼€å§‹
        ft.chrg.cpMin = ft.chrgText.cpMax;
    }
    m_editLog.SetSel(-1, 0);
}
void CSGMeasurementDlg::PrintSampleData(int nOutNo, const std::vector<float>& vecBuffer)
{
    int nReceived = static_cast<int>(vecBuffer.size());
    if (vecBuffer.empty() || nReceived < 0) {
        CString strError;
        strError.Format(_T("OUT%d: æŽ¥æ”¶æ•°æ®ä¸ºç©ºæˆ–无效,无法打印。"), nOutNo);
        AppendLogLineRichStyled(strError, LOG_COLOR_WARNING);
        return;
    }
    CString strLine;
    for (int i = 0; i < nReceived; ++i) {
        CString strOne;
        strOne.Format(_T("%10.3f "), vecBuffer[i]);
        strLine += strOne;
        // æ¯ 7 ä¸ªå€¼è¾“出一行
        if ((i + 1) % 7 == 0 || i == nReceived - 1) {
            AppendLogLineRichStyled(strLine, LOG_COLOR_NORMAL);
            strLine.Empty();
        }
    }
}
bool CSGMeasurementDlg::ConnectToDevice()
{
    if (m_bConnected) {
        AppendLogLineRichStyled(_T("设备已连接,请先断开连接。"), LOG_COLOR_WARNING);
        return false;
    }
    SGIF_OPENPARAM_ETHERNET stIpAddress = { 0 };
    CIPAddressCtrl* pIPCtrl = (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS);
    if (!::IsWindow(pIPCtrl->GetSafeHwnd())) {
        AppendLogLineRichStyled(_T("IP æŽ§ä»¶æ— æ•ˆï¼Œè¿žæŽ¥å¤±è´¥ï¼"), LOG_COLOR_ERROR);
        return false;
    }
    pIPCtrl->GetAddress(
        stIpAddress.IPAddress.S_un.S_un_b.s_b1,
        stIpAddress.IPAddress.S_un.S_un_b.s_b2,
        stIpAddress.IPAddress.S_un.S_un_b.s_b3,
        stIpAddress.IPAddress.S_un.S_un_b.s_b4
    );
    RC nRet = SGIF_OpenDeviceETHER(DeviceID, &stIpAddress);
    if (nRet == RC_OK) {
        AppendLogLineRichStyled(_T("打开连接成功!"), LOG_COLOR_SUCCESS);
        m_bConnected = TRUE;
        UpdateControlStatus(TRUE, FALSE);
        SetTimer(TIMER_ID_OUTPUT_UPDATE, TIMER_INTERVAL_MS, nullptr);
        return true;
    }
    else {
        CString strError;
        strError.Format(_T("打开连接失败,错误码:%#X"), nRet);
        AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
        m_bConnected = FALSE;
        UpdateControlStatus(FALSE, FALSE);
        return false;
    }
}
bool CSGMeasurementDlg::DisconnectFromDevice()
{
    if (!m_bConnected) {
        AppendLogLineRichStyled(_T("设备未连接,无需断开。"), LOG_COLOR_WARNING);
        return false;
    }
    // åœæ­¢å®šæ—¶å™¨ï¼Œé¿å…åœ¨æ–­å¼€åŽä»å°è¯•更新输出数据
    KillTimer(TIMER_ID_OUTPUT_UPDATE);
    // å…ˆåœæ­¢æ•°æ®å­˜å‚¨ï¼ˆå¦‚果正在进行)
    RC nRet;
    if (m_bConnected && m_bSaving) {
        nRet = SGIF_DataStorageStop(DeviceID);
        if (nRet == RC_OK) {
            m_bSaving = FALSE;
            AppendLogLineRichStyled(_T("数据存储已停止。"), LOG_COLOR_SUCCESS);
        }
        else {
            CString strError;
            strError.Format(_T("停止数据存储失败,错误码:%#X"), nRet);
            AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
        }
    }
    // æ–­å¼€è®¾å¤‡è¿žæŽ¥
    nRet = SGIF_CloseDevice(DeviceID);
    if (nRet == RC_OK) {
        AppendLogLineRichStyled(_T("断开连接成功!"), LOG_COLOR_SUCCESS);
        m_bConnected = FALSE;
        UpdateControlStatus(FALSE, FALSE);
        return true;
    }
    else {
        CString strError;
        strError.Format(_T("断开连接失败,错误码:%#X"), nRet);
        AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
        AppendLogLineRichStyled(_T("保持当前状态,断开失败。"), LOG_COLOR_ERROR);
        UpdateControlStatus(m_bConnected, m_bSaving);
        return false;
    }
}
void CSGMeasurementDlg::CleanInvalidValuesInPlace(int nOutNo, std::vector<float>& vecData, float fInvalid/* = -999.0f*/)
{
    MEASURE_FUNC_START();
    // æ‰¾åˆ°ç¬¬ä¸€ä¸ªæœ‰æ•ˆå€¼
    auto itStart = std::find_if(vecData.begin(), vecData.end(), [=](float v) { return v > fInvalid; });
    // æ‰¾åˆ°æœ€åŽä¸€ä¸ªæœ‰æ•ˆå€¼
    auto itEnd = std::find_if(vecData.rbegin(), vecData.rend(), [=](float v) { return v > fInvalid; }).base();
    // æ£€æŸ¥æ˜¯å¦æœ‰æœ‰æ•ˆæ•°æ®
    if (itStart < itEnd) {
        // å…ˆè£è¾¹
        std::vector<float> vecTrimmed(itStart, itEnd);
        // å†ç§»é™¤ä¸­é—´çš„æ— æ•ˆå€¼
        auto itNewEnd = std::remove_if(vecTrimmed.begin(), vecTrimmed.end(), [=](float v) { return v == fInvalid; });
        vecTrimmed.erase(itNewEnd, vecTrimmed.end());
        vecData = std::move(vecTrimmed);
        CString strLog;
        strLog.Format(_T("OUT%d: å·²è£å‰ªæ— æ•ˆè¾¹ç•Œæ•°æ®ï¼Œå‰©ä½™æœ‰æ•ˆæ•°æ® %d ä¸ªã€‚"), nOutNo, static_cast<int>(vecData.size()));
        AppendLogLineRichStyled(strLog, LOG_COLOR_NORMAL);
        if (vecData.size() < 20) {
            AppendLogLineRichStyled(_T("警告:有效数据量过少,可能影响后续处理。"), LOG_COLOR_WARNING);
        }
        else {
            CString strInfo;
            strInfo.Format(_T("OUT%d: æœ‰æ•ˆæ•°æ®èŒƒå›´ [%f, %f]"), nOutNo, *std::min_element(vecData.begin(), vecData.end()), *std::max_element(vecData.begin(), vecData.end()));
            AppendLogLineRichStyled(strInfo, LOG_COLOR_NORMAL);
        }
        PrintSampleData(nOutNo, vecData);
    }
    else {
        vecData.clear();
    }
    MEASURE_FUNC_END();
}
bool CSGMeasurementDlg::SplitGlassSegments(int nOutNo, const std::vector<float>& vecData, std::vector<float>& vecGlass1, std::vector<float>& vecGlass2, float fJumpThreshold /*= 0.2f*/, int nWindow /*= 3*/, int nValleyMargin /*= 0*/, int nMinGlassCount /*= 10*/)
{
    MEASURE_FUNC_START();
    CString strLog;
    const int nTotal = static_cast<int>(vecData.size());
    if (nTotal < 2 * nWindow + 1 + nMinGlassCount) {
        strLog.Format(_T("OUT%d: æ•°æ®é‡ä¸è¶³ï¼Œè‡³å°‘需要 %d ä¸ªç‚¹æ‰èƒ½åˆ‡å‰²ã€‚"), nOutNo, 2 * nWindow + 1 + nMinGlassCount);
        AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING);
        return false;
    }
    // ä»Žä¸­é—´å‘两边查找 valley å€™é€‰ç‚¹
    int nMid = nTotal / 2;
    int nValleyLeft = -1, nValleyRight = -1;
    // å‘左查找 valley
    for (int i = nMid; i >= nWindow; --i) {
        float fDelta = std::fabs(vecData[i] - vecData[i - nWindow]);
        if (fDelta > fJumpThreshold &&
            vecData[i] < vecData[i - 1] &&
            vecData[i] < vecData[i + 1]) {
            nValleyLeft = i;
            break;
        }
    }
    // å‘右查找 valley
    for (int i = nMid; i <= nTotal - nWindow - 2; ++i) {
        float fDelta = std::fabs(vecData[i + nWindow] - vecData[i]);
        if (fDelta > fJumpThreshold &&
            vecData[i] < vecData[i - 1] &&
            vecData[i] < vecData[i + 1]) {
            nValleyRight = i;
            break;
        }
    }
    // é€‰å®š valley ç‚¹
    int nValleyIdx = -1;
    if (nValleyLeft > 0 && nValleyRight > 0) {
        nValleyIdx = (vecData[nValleyLeft] < vecData[nValleyRight]) ? nValleyLeft : nValleyRight;
    }
    else if (nValleyLeft > 0) {
        nValleyIdx = nValleyLeft;
    }
    else if (nValleyRight > 0) {
        nValleyIdx = nValleyRight;
    }
    // fallback: valley æœªæ‰¾åˆ°ï¼Œä½¿ç”¨ä¸­é—´åˆ‡å‰²æ³•
    if (nValleyIdx < 0) {
        AppendLogLineRichStyled(_T("未找到 valley è·³å˜ç‚¹ï¼Œä½¿ç”¨ä¸­é—´ä½ç½®åˆ‡å‰²ã€‚"), LOG_COLOR_WARNING);
        nValleyIdx = nMid;
    }
    // åº”用切割位置,限制边界
    int nCutPos = max(1, min(nTotal - 1, nValleyIdx + nValleyMargin));
    vecGlass1.assign(vecData.begin(), vecData.begin() + nCutPos);
    vecGlass2.assign(vecData.begin() + nCutPos, vecData.end());
    int nGlass1Count = static_cast<int>(vecGlass1.size());
    int nGlass2Count = static_cast<int>(vecGlass2.size());
    // æ—¥å¿—输出
    strLog.Format(_T("OUT%d: åˆ‡å‰²æˆåŠŸï¼Œç¬¬ä¸€ç‰‡çŽ»ç’ƒ %d ç‚¹ï¼Œç¬¬äºŒç‰‡çŽ»ç’ƒ %d ç‚¹ã€‚"), nOutNo, nGlass1Count, nGlass2Count);
    AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS);
    if (nGlass1Count < nMinGlassCount) {
        strLog.Format(_T("OUT%d: ç¬¬ä¸€ç‰‡çŽ»ç’ƒæ•°æ®é‡å°‘äºŽ %d ç‚¹ï¼Œå¯èƒ½å½±å“è®¡ç®—。"), nOutNo, nMinGlassCount);
        AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING);
    }
    if (nGlass2Count < nMinGlassCount) {
        strLog.Format(_T("OUT%d: ç¬¬äºŒç‰‡çŽ»ç’ƒæ•°æ®é‡å°‘äºŽ %d ç‚¹ï¼Œå¯èƒ½å½±å“è®¡ç®—。"), nOutNo, nMinGlassCount);
        AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING);
    }
    AppendLogLineRichStyled(_T("第一片玻璃数据:"), LOG_COLOR_NORMAL);
    PrintSampleData(nOutNo, vecGlass1);
    AppendLogLineRichStyled(_T("第二片玻璃数据:"), LOG_COLOR_NORMAL);
    PrintSampleData(nOutNo, vecGlass2);
    MEASURE_FUNC_END();
    return true;
}
bool CSGMeasurementDlg::FilterDominantGroup(int nOutNo, const std::vector<float>& vecInput, std::vector<float>& vecOutput)
{
    MEASURE_FUNC_START();
    if (vecInput.empty()) {
        AppendLogLineRichStyled(_T("输入数据为空,无法进行分组筛选。"), LOG_COLOR_WARNING);
        return false;
    }
    // åˆ†ç»„:map<int整数部分, vector<float>>
    std::map<int, std::vector<float>> mapGroup;
    for (float fVal : vecInput) {
        int nKey = static_cast<int>(fVal);
        mapGroup[nKey].push_back(fVal);
    }
    // æ‰¾å‡ºæ•°é‡æœ€å¤šçš„那组
    size_t nMaxCount = 0;
    auto itMaxGroup = mapGroup.begin();
    for (auto it = mapGroup.begin(); it != mapGroup.end(); ++it) {
        if (it->second.size() > nMaxCount) {
            nMaxCount = it->second.size();
            itMaxGroup = it;
        }
    }
    if (nMaxCount == 0) {
        AppendLogLineRichStyled(_T("所有数据都被过滤或为空,无法筛选出主要分组。"), LOG_COLOR_WARNING);
        return false;
    }
    vecOutput = itMaxGroup->second;
    CString strLog;
    strLog.Format(_T("成功从 %d ä¸ªç»„中筛选出主要分组:值约为 %d,共 %zu ä¸ªç‚¹ã€‚"), static_cast<int>(mapGroup.size()), itMaxGroup->first, nMaxCount);
    AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS);
    // æ‰“印筛选后的数据
    AppendLogLineRichStyled(_T("筛选后的主要分组数据:"), LOG_COLOR_NORMAL);
    PrintSampleData(nOutNo, vecOutput);
    MEASURE_FUNC_END();
    return true;
}
bool CSGMeasurementDlg::ExtractStableRegionFixed(int nOutNo, const std::vector<float>& vecIn, std::vector<float>& vecOut, int nFixedCount/* = 5*/, float fMaxDelta/* = 0.04f*/)
{
    MEASURE_FUNC_START();
    const int n = static_cast<int>(vecIn.size());
    if (n < nFixedCount) {
        CString strError;
        strError.Format(_T("OUT%d: æ•°æ®é‡ä¸è¶³ï¼Œè‡³å°‘需要 %d ä¸ªç‚¹æ‰èƒ½æå–稳定区。"), nOutNo, nFixedCount);
        return false;
    }
    int nBestStart = -1;
    float fBestRange = FLT_MAX;
    for (int i = 0; i <= n - nFixedCount; ++i) {
        auto first = vecIn.begin() + i;
        auto last = first + nFixedCount;
        float fMinVal = *std::min_element(first, last);
        float fMaxVal = *std::max_element(first, last);
        float fRange = fMaxVal - fMinVal;
        if (fRange <= fMaxDelta && fRange < fBestRange) {
            fBestRange = fRange;
            nBestStart = i;
        }
    }
    if (nBestStart < 0) {
        return false;
    }
    vecOut.assign(vecIn.begin() + nBestStart, vecIn.begin() + nBestStart + nFixedCount);
    CString strLog;
    strLog.Format(_T("OUT%d: æå–稳定区成功,起始点索引 %d,范围 %.3f。"), nOutNo, nBestStart, fBestRange);
    AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS);
    if (vecOut.size() < nFixedCount) {
        CString strWarning;
        strWarning.Format(_T("OUT%d: æå–的稳定区数据量不足,可能影响后续处理。"), nOutNo);
        AppendLogLineRichStyled(strWarning, LOG_COLOR_WARNING);
    }
    // æ‰“印提取的稳定区数据
    AppendLogLineRichStyled(_T("提取的稳定区数据:"), LOG_COLOR_NORMAL);
    PrintSampleData(nOutNo, vecOut);
    MEASURE_FUNC_END();
    return true;
}
bool CSGMeasurementDlg::CalcGlassOffset(const std::vector<float>& vecGlass1, const std::vector<float>& vecGlass2, float& fAvg1, float& fAvg2, float& fOffset)
{
    MEASURE_FUNC_START();
    if (vecGlass1.empty() || vecGlass2.empty()) {
        AppendLogLineRichStyled(_T("稳定区数据为空,无法计算平均值和偏移。"), LOG_COLOR_WARNING);
        return false;
    }
    auto CalcAverage = [](const std::vector<float>& data) -> float {
        float sum = std::accumulate(data.begin(), data.end(), 0.0f);
        return sum / static_cast<float>(data.size());
    };
    fAvg1 = CalcAverage(vecGlass1);
    fAvg2 = CalcAverage(vecGlass2);
    fOffset = std::fabs(fAvg2 - fAvg1);  // ç¬¬äºŒç‰‡ - ç¬¬ä¸€ç‰‡
    CString strLog;
    strLog.Format(_T("第一片玻璃平均值: %.3f,第二片玻璃平均值: %.3f,偏移量: %.3f"), fAvg1, fAvg2, fOffset);
    AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS);
    MEASURE_FUNC_END();
    return true;
}
bool CSGMeasurementDlg::InitDataStorage()
{
    if (!m_bConnected) {
        AppendLogLineRichStyled(_T("设备未连接,请先连接设备。"), LOG_COLOR_WARNING);
        return false;
    }
    if (m_bSaving) {
        AppendLogLineRichStyled(_T("数据存储正在进行中,请先停止存储。"), LOG_COLOR_WARNING);
        return false;
    }
    RC nRet = SGIF_DataStorageInit(DeviceID);
    if (nRet == RC_OK) {
        AppendLogLineRichStyled(_T("数据存储已清除。"), LOG_COLOR_SUCCESS);
        return true;
    }
    CString strError;
    strError.Format(_T("清除数据存储失败,错误码:%#X"), nRet);
    AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
    return false;
}
bool CSGMeasurementDlg::StartDataStorage()
{
    if (m_bSaving) {
        AppendLogLineRichStyled(_T("数据存储已在进行中,请先停止存储。"), LOG_COLOR_WARNING);
        return false;
    }
    RC nRet = SGIF_DataStorageStart(DeviceID);
    if (nRet == RC_OK) {
        m_bSaving = TRUE;
        AppendLogLineRichStyled(_T("数据存储已开始。"), LOG_COLOR_SUCCESS);
        return true;
    }
    CString strError;
    strError.Format(_T("开始数据存储失败,错误码:%#X"), nRet);
    AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
    return false;
}
bool CSGMeasurementDlg::StopDataStorage()
{
    if (!m_bSaving) {
        AppendLogLineRichStyled(_T("数据存储未在进行中,请先开始存储。"), LOG_COLOR_WARNING);
        return false;
    }
    RC nRet = SGIF_DataStorageStop(DeviceID);
    if (nRet == RC_OK) {
        m_bSaving = FALSE;
        AppendLogLineRichStyled(_T("数据存储已停止。"), LOG_COLOR_SUCCESS);
        return true;
    }
    CString strError;
    strError.Format(_T("停止数据存储失败,错误码:%#X"), nRet);
    AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
    return false;
}
float CSGMeasurementDlg::AnalyzeStoredData(int nOutNo)
{
    MEASURE_FUNC_START();
    UpdateData(TRUE);
    if (m_nUseTrigger) {
        UpdateControlStatus(m_bConnected, m_bSaving);
        AfxMessageBox(_T("当前是硬触发模式,请检查触发器状态。"), MB_ICONINFORMATION);
        return -1.0f;
    }
    if (!m_bConnected) {
        AppendLogLineRichStyled(_T("设备未连接,请先连接设备。"), LOG_COLOR_WARNING);
        return -1.0f;
    }
    if (m_bSaving) {
        AppendLogLineRichStyled(_T("数据存储正在进行中,请先停止存储。"), LOG_COLOR_WARNING);
        return -1.0f;
    }
    if (nOutNo < 1 || nOutNo > 4) {
        AppendLogLineRichStyled(_T("输出端口编号无效,必须在 1 åˆ° 4 ä¹‹é—´ã€‚"), LOG_COLOR_ERROR);
        return -1.0f;
    }
    if (m_nSavePointCount < 0) {
        AppendLogLineRichStyled(_T("数据点数必须大于 0。"), LOG_COLOR_ERROR);
        return -1.0f;
    }
    std::vector<float> vecBuffer(m_nSavePointCount, 0.0f);
    int nReceived = 0;
    RC nRet = SGIF_DataStorageGetData(DeviceID, nOutNo, m_nSavePointCount, vecBuffer.data(), &nReceived);
    if (nRet != RC_OK) {
        CString strError;
        strError.Format(_T("读取 OUT%d æ•°æ®å¤±è´¥ï¼Œé”™è¯¯ç ï¼š%#X"), nOutNo, nRet);
        AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
        return -1.0f;
    }
    vecBuffer.resize(nReceived);
    CleanInvalidValuesInPlace(nOutNo, vecBuffer);
    std::vector<float> vecGlass1, vecGlass2;
    if (!SplitGlassSegments(nOutNo, vecBuffer, vecGlass1, vecGlass2, m_fJumpThreshold, m_nJumpWindow, m_nValleyMargin, m_nMinGlass1Count)) {
        AppendLogLineRichStyled(_T("未能识别出两片玻璃的数据。"), LOG_COLOR_WARNING);
        return -1.0f;
    }
    std::vector<float> vecGlass1Filtered, vecGlass2Filtered;
    bool bGlass1Filtered = FilterDominantGroup(nOutNo, vecGlass1, vecGlass1Filtered);
    bool bGlass2Filtered = FilterDominantGroup(nOutNo, vecGlass2, vecGlass2Filtered);
    if (!bGlass1Filtered) {
        AppendLogLineRichStyled(_T("Glass1 åˆ†æ®µä¸­æœªèƒ½è¯†åˆ«å‡ºä¸»æ•°æ®ç»„,使用原始数据。"), LOG_COLOR_WARNING);
        vecGlass1Filtered = vecGlass1;
    }
    else {
        AppendLogLineRichStyled(_T("Glass1 ä¸»æ•°æ®ç»„已提取。"), LOG_COLOR_SUCCESS);
    }
    if (!bGlass2Filtered) {
        AppendLogLineRichStyled(_T("Glass2 åˆ†æ®µä¸­æœªèƒ½è¯†åˆ«å‡ºä¸»æ•°æ®ç»„,使用原始数据。"), LOG_COLOR_WARNING);
        vecGlass2Filtered = vecGlass2;
    }
    else {
        AppendLogLineRichStyled(_T("Glass2 ä¸»æ•°æ®ç»„已提取。"), LOG_COLOR_SUCCESS);
    }
    std::vector<float> vecStable1, vecStable2;
    bool bStable1 = ExtractStableRegionFixed(nOutNo, vecGlass1Filtered, vecStable1, m_nFixedCount, m_fMaxDelta);
    bool bStable2 = ExtractStableRegionFixed(nOutNo, vecGlass2Filtered, vecStable2, m_nFixedCount, m_fMaxDelta);
    float fAvg1 = 0.0f, fAvg2 = 0.0f, fOffset = 0.0f;
    if (bStable1 && bStable2) {
        AppendLogLineRichStyled(_T("成功提取到两片玻璃的稳定区数据。"), LOG_COLOR_SUCCESS);
        CalcGlassOffset(vecStable1, vecStable2, fAvg1, fAvg2, fOffset);
    }
    else {
        AppendLogLineRichStyled(_T("未能提取到稳定区数据,尝试使用原始分段数据计算偏移。"), LOG_COLOR_WARNING);
        CalcGlassOffset(vecGlass1, vecGlass2, fAvg1, fAvg2, fOffset);
    }
    MEASURE_FUNC_END();
    return fOffset;
}
BEGIN_MESSAGE_MAP(CSGMeasurementDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_TIMER()
    ON_WM_MEASUREITEM()
    ON_WM_DRAWITEM()
    ON_WM_CLOSE()
    ON_MESSAGE(WM_TRAY_ICON_NOTIFY, &CSGMeasurementDlg::OnTrayIconClick)
    ON_COMMAND(ID_TRAY_RESTORE, &CSGMeasurementDlg::OnTrayRestore)
    ON_COMMAND(ID_TRAY_EXIT, &CSGMeasurementDlg::OnTrayExit)
    ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CSGMeasurementDlg::OnBnClickedButtonConnect)
    ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, &CSGMeasurementDlg::OnBnClickedButtonDisconnect)
    ON_BN_CLICKED(IDC_BUTTON_RECEIVE_FROM_CTRL, &CSGMeasurementDlg::OnBnClickedButtonReceiveFromCtrl)
    ON_BN_CLICKED(IDC_BUTTON_SEND_TO_CTRL, &CSGMeasurementDlg::OnBnClickedButtonSendToCtrl)
    ON_BN_CLICKED(IDC_BUTTON_CLEAR_STORE, &CSGMeasurementDlg::OnBnClickedButtonClearStore)
    ON_BN_CLICKED(IDC_BUTTON_START_STORE, &CSGMeasurementDlg::OnBnClickedButtonStartStore)
    ON_BN_CLICKED(IDC_BUTTON_STOP_STORE, &CSGMeasurementDlg::OnBnClickedButtonStopStore)
    ON_BN_CLICKED(IDC_BUTTON_CLEAR_LOG, &CSGMeasurementDlg::OnBnClickedButtonClearLog)
END_MESSAGE_MAP()
BOOL CSGMeasurementDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // å°†â€œå…³äºŽ...”菜单项添加到系统菜单中。
    // IDM_ABOUTBOX å¿…须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);
    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }
    // è®¾ç½®æ­¤å¯¹è¯æ¡†çš„图标。  å½“应用程序主窗口不是对话框时,框架将自动
    //  æ‰§è¡Œæ­¤æ“ä½œ
    SetIcon(m_hIcon, TRUE);            // è®¾ç½®å¤§å›¾æ ‡
    SetIcon(m_hIcon, FALSE);        // è®¾ç½®å°å›¾æ ‡
    // TODO: åœ¨æ­¤æ·»åŠ é¢å¤–çš„åˆå§‹åŒ–ä»£ç 
    UpdateData(FALSE);
    UpdateControlStatus(FALSE, FALSE);
    // æ‰˜ç›˜å›¾æ ‡åˆå§‹åŒ–
    m_trayIconData.cbSize = sizeof(NOTIFYICONDATA);                  // è®¾ç½®æ‰˜ç›˜å›¾æ ‡æ•°æ®ç»“构的大小
    m_trayIconData.hWnd = m_hWnd;                                    // è®¾ç½®çª—口句柄
    m_trayIconData.uID = m_nTrayIconID;                              // è®¾ç½®æ‰˜ç›˜å›¾æ ‡ ID
    m_trayIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;          // è®¾ç½®æ‰˜ç›˜å›¾æ ‡çš„æ ‡å¿—(图标、消息、提示文本)
    m_trayIconData.uCallbackMessage = WM_TRAY_ICON_NOTIFY;           // è®¾ç½®å›žè°ƒæ¶ˆæ¯ WM_TRAY_ICON_NOTIFY
    m_trayIconData.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);      // åŠ è½½æ‰˜ç›˜å›¾æ ‡
    lstrcpy(m_trayIconData.szTip, TRAY_ICON_TOOLTIP_TEXT);           // è®¾ç½®æ‰˜ç›˜æç¤ºæ–‡æœ¬
    // æ·»åŠ æ‰˜ç›˜å›¾æ ‡
    Shell_NotifyIcon(NIM_ADD, &m_trayIconData);
    m_bTrayIconCreated = TRUE;
    for (int i = 0; i < 4; i++) {
        CString str;
        str.Format(_T("OUT%d"), i + 1);
        m_comboOutputPort.AddString(str);
    }
    m_comboOutputPort.SetCurSel(0);
    // åˆå§‹åŒ–IP地址控件,设置为默认IP地址
    ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->SetAddress(192, 168, 0, 10);
    // è®¾ç½® PLC ç›‘听器的日志回调函数
    m_plcListener.SetLogCallback([this](const CString& msg, int type) {
        if (type == -1) {
            AppendLogLineRichStyled(msg, LOG_COLOR_ERROR);
        }
        else if (type == 0) {
            AppendLogLineRichStyled(msg, LOG_COLOR_SUCCESS);
        }
        else if (type == 1) {
            AppendLogLineRichStyled(msg, LOG_COLOR_WARNING);
        }
        else if (type == 2) {
            AppendLogLineRichStyled(msg, LOG_COLOR_NORMAL);
        }
    });
    // åˆå§‹åŒ– PLC ç›‘听器
    m_plcListener.Initialize(StationIdentifier(0, 255), 200);
    // è®¾ç½® PLC ç›‘听器的开始采集回调函数
    m_plcListener.SetStartCallback([this]() {
        if (!m_bConnected) {
            ConnectToDevice();
        }
        if (InitDataStorage()) {
            StartDataStorage();
            UpdateControlStatus(m_bConnected, m_bSaving);
        }
    });
    // è®¾ç½® PLC ç›‘听器的停止采集回调函数
    m_plcListener.SetStopCallback([this]() {
        StopDataStorage();
        UpdateControlStatus(m_bConnected, m_bSaving);
    });
    // è®¾ç½® PLC ç›‘听器的分析回调函数
    m_plcListener.SetAnalyzeCallback([this]() {
        if (!m_bConnected) {
            AppendLogLineRichStyled(_T("设备未连接,请先连接设备。"), LOG_COLOR_WARNING);
            return std::array<double, 4>{ -1.0, -1.0, -1.0, -1.0 };
        }
        std::array<double, 4> result;
        for (int i = 0; i < 4; ++i) {
            result[i] = AnalyzeStoredData(i + 1); // OUT1 ~ OUT4
        }
        if (std::any_of(result.begin(), result.end(), [](double v) { return v < 0; })) {
            AppendLogLineRichStyled(_T("分析失败,某些输出端口数据无效。"), LOG_COLOR_ERROR);
            return std::array<double, 4>{ -1.0, -1.0, -1.0, -1.0 };
        }
        CString strLog;
        strLog.Format(_T("分析结果:OUT1: %.3f, OUT2: %.3f, OUT3: %.3f, OUT4: %.3f"), result[0], result[1], result[2], result[3]);
        return result;
    });
    m_plcListener.Start();
    // åˆå§‹åŒ–日志框
    AppendLogLineRichStyled(_T("准备就绪..."), LOG_COLOR_SUCCESS);
    return TRUE;  // é™¤éžå°†ç„¦ç‚¹è®¾ç½®åˆ°æŽ§ä»¶ï¼Œå¦åˆ™è¿”回 TRUE
}
void CSGMeasurementDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}
void CSGMeasurementDlg::OnPaint()
{
    if (IsIconic()) {
        CPaintDC dc(this);
        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
        // ä½¿å›¾æ ‡åœ¨å·¥ä½œåŒºçŸ©å½¢ä¸­å±…中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;
        // ç»˜åˆ¶å›¾æ ‡
        dc.DrawIcon(x, y, m_hIcon);
    }
    else {
        CDialogEx::OnPaint();
    }
}
//当用户拖动最小化窗口时系统调用此函数取得光标显示。
HCURSOR CSGMeasurementDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}
void CSGMeasurementDlg::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: åœ¨æ­¤æ·»åŠ æ¶ˆæ¯å¤„ç†ç¨‹åºä»£ç å’Œ/或调用默认值
    if (nIDEvent == TIMER_ID_OUTPUT_UPDATE) {
        SGIF_FLOATVALUE_OUT value[4] = { 0 };
        RC nRet = SGIF_GetCalcDataALL(DeviceID, value);
        if (nRet == RC_OK) {
            for (int i = 0; i < 4; ++i) {
                m_dOutValues[i] = value[i].Value;
            }
            // æ›´æ–°ç»‘定控件
            UpdateData(FALSE);
        }
        else {
            CString strError;
            strError.Format(_T("获取测量值失败,错误码:%#X"), nRet);
            AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
            // æ–­å¼€è¿žæŽ¥
            if (m_bConnected) {
                DisconnectFromDevice();
            }
        }
    }
    CDialogEx::OnTimer(nIDEvent);
}
void CSGMeasurementDlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
    if (lpMeasureItemStruct->CtlType == ODT_MENU) {
        lpMeasureItemStruct->itemHeight = 24;
        lpMeasureItemStruct->itemWidth = 140;
    }
}
void CSGMeasurementDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    if (lpDrawItemStruct->CtlType != ODT_MENU) {
        return;
    }
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect rc = lpDrawItemStruct->rcItem;
    UINT id = lpDrawItemStruct->itemID;
    // èƒŒæ™¯
    COLORREF bgColor = (lpDrawItemStruct->itemState & ODS_SELECTED) ? RGB(200, 220, 255) : RGB(255, 255, 255);
    pDC->FillSolidRect(rc, bgColor);
    // å›¾æ ‡
    HICON hIcon = nullptr;
    if (id == ID_TRAY_RESTORE) {
        hIcon = AfxGetApp()->LoadIcon(IDI_ICON_RESTORE);
    }
    if (id == ID_TRAY_EXIT) {
        hIcon = AfxGetApp()->LoadIcon(IDI_ICON_EXIT);
    }
    if (hIcon) {
        DrawIconEx(pDC->GetSafeHdc(), rc.left + 4, rc.top + 4, hIcon, 16, 16, 0, NULL, DI_NORMAL);
    }
    // æ–‡æœ¬
    CString str;
    if (id == ID_TRAY_RESTORE) {
        str = _T("恢复界面");
    }
    if (id == ID_TRAY_EXIT) {
        str = _T("退出程序");
    }
    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(RGB(0, 0, 0));
    pDC->DrawText(str, CRect(rc.left + 28, rc.top, rc.right, rc.bottom), DT_SINGLELINE | DT_VCENTER | DT_LEFT);
}
void CSGMeasurementDlg::OnClose()
{
    // TODO: åœ¨æ­¤æ·»åŠ æ¶ˆæ¯å¤„ç†ç¨‹åºä»£ç å’Œ/或调用默认值
    if (m_bExitingFromTray) {
        // ä»Žæ‰˜ç›˜é€€å‡ºæµç¨‹
        ExitApplication();
    }
    else {
        // æ­£å¸¸å…³é—­æŒ‰é’®
        int nResult = AfxMessageBox(_T("是否最小化到托盘?"), MB_YESNO | MB_ICONQUESTION);
        if (nResult == IDYES) {
            ShowWindow(SW_HIDE);
        }
        else {
            ExitApplication();
        }
    }
}
LRESULT CSGMeasurementDlg::OnTrayIconClick(WPARAM wParam, LPARAM lParam) {
    if (wParam == m_nTrayIconID) {
        if (LOWORD(lParam) == WM_LBUTTONUP) {
            // å·¦é”®ç‚¹å‡»æ¢å¤çª—口
            ShowWindow(SW_SHOW);
            SetForegroundWindow();
        }
        else if (LOWORD(lParam) == WM_RBUTTONUP) {
            // å³é”®ç‚¹å‡»å¼¹å‡ºèœå•
            CMenu menu;
            menu.CreatePopupMenu();
            menu.AppendMenu(MF_OWNERDRAW, ID_TRAY_RESTORE, (LPCTSTR)ID_TRAY_RESTORE);
            menu.AppendMenu(MF_OWNERDRAW, ID_TRAY_EXIT, (LPCTSTR)ID_TRAY_EXIT);
            // åŠ è½½å›¾æ ‡
            HICON hIconRestore = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON_RESTORE), IMAGE_ICON, 16, 16, LR_SHARED);
            HICON hIconExit = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON_EXIT), IMAGE_ICON, 16, 16, LR_SHARED);
            // è®¾ç½®å›¾æ ‡åˆ°èœå•项
            MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
            mii.fMask = MIIM_BITMAP;
            // æ¢å¤èœå•项图标
            mii.hbmpItem = HBMMENU_CALLBACK;
            menu.SetMenuItemInfo(ID_TRAY_RESTORE, &mii);
            // é€€å‡ºèœå•项图标
            mii.hbmpItem = HBMMENU_CALLBACK;
            menu.SetMenuItemInfo(ID_TRAY_EXIT, &mii);
            // èŽ·å–é¼ æ ‡å½“å‰ä½ç½®ï¼Œå¹¶æ˜¾ç¤ºèœå•
            POINT pt;
            GetCursorPos(&pt);
            SetForegroundWindow();
            menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);
        }
    }
    return 0;
}
void CSGMeasurementDlg::OnTrayRestore()
{
    ShowWindow(SW_SHOW);      // æ¢å¤çª—口
    SetForegroundWindow();  // å°†çª—口置于前端
}
void CSGMeasurementDlg::OnTrayExit()
{
    // ä»Žæ‰˜ç›˜å›¾æ ‡èœå•选择“退出程序”
    if (AfxMessageBox(_T("确定要退出程序吗?"), MB_YESNO | MB_ICONQUESTION) == IDYES) {
        m_bExitingFromTray = TRUE;
        PostMessage(WM_CLOSE);
    }
}
void CSGMeasurementDlg::OnBnClickedButtonConnect()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    ConnectToDevice();
}
void CSGMeasurementDlg::OnBnClickedButtonDisconnect()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    DisconnectFromDevice();
}
void CSGMeasurementDlg::OnBnClickedButtonReceiveFromCtrl()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    if (!m_bConnected) {
        AppendLogLineRichStyled(_T("设备未连接,请先连接设备。"), LOG_COLOR_WARNING);
        return;
    }
}
void CSGMeasurementDlg::OnBnClickedButtonSendToCtrl()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    if (!m_bConnected) {
        AppendLogLineRichStyled(_T("设备未连接,请先连接设备。"), LOG_COLOR_WARNING);
        return;
    }
}
void CSGMeasurementDlg::OnBnClickedButtonClearStore()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    InitDataStorage();
}
void CSGMeasurementDlg::OnBnClickedButtonStartStore()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    StartDataStorage();
    UpdateControlStatus(m_bConnected, m_bSaving);
}
void CSGMeasurementDlg::OnBnClickedButtonStopStore()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    StopDataStorage();
    UpdateControlStatus(m_bConnected, m_bSaving);
    int nSel = m_comboOutputPort.GetCurSel();
    if (CB_ERR == nSel) {
        AppendLogLineRichStyled(_T("请选择一个有效的输出端口。"), LOG_COLOR_WARNING);
        return;
    }
    int nOutNo = nSel + 1;
    AnalyzeStoredData(nOutNo);
}
void CSGMeasurementDlg::OnBnClickedButtonClearLog()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    if (::IsWindow(m_editLog.GetSafeHwnd())) {
        m_editLog.SetWindowText(_T(""));
    }
}
SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,343 @@

// SGMeasurementDlg.h: å¤´æ–‡ä»¶
//
#pragma once
#include "PLCSignalListener.h"
#include <map>
#include <vector>
#include <numeric>
#include <algorithm>
// CSGMeasurementDlg å¯¹è¯æ¡†
class CSGMeasurementDlg : public CDialogEx
{
// æž„造
public:
    CSGMeasurementDlg(CWnd* pParent = nullptr);    // æ ‡å‡†æž„造函数
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_SGMEASUREMENT_DIALOG };
#endif
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
// å®žçް
protected:
    HICON m_hIcon;
    // ç”Ÿæˆçš„æ¶ˆæ¯æ˜ å°„函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
    afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
    afx_msg void OnClose();
    afx_msg LRESULT OnTrayIconClick(WPARAM wParam, LPARAM lParam);
    afx_msg void OnTrayRestore();
    afx_msg void OnTrayExit();
    afx_msg void OnBnClickedButtonConnect();
    afx_msg void OnBnClickedButtonDisconnect();
    afx_msg void OnBnClickedButtonReceiveFromCtrl();
    afx_msg void OnBnClickedButtonSendToCtrl();
    afx_msg void OnBnClickedButtonClearStore();
    afx_msg void OnBnClickedButtonStartStore();
    afx_msg void OnBnClickedButtonStopStore();
    afx_msg void OnBnClickedButtonClearLog();
    DECLARE_MESSAGE_MAP()
private:
    /**
     * @brief é€€å‡ºç¨‹åºæ—¶çš„æ¸…理操作。
     *
     * æ­¤å‡½æ•°åœ¨ç¨‹åºé€€å‡ºå‰è¢«è°ƒç”¨ï¼Œç”¨äºŽæ‰§è¡Œå¿…要的资源释放与状态恢复,
     * åŒ…括断开设备连接、移除托盘图标等。
     * æœ€ç»ˆé”€æ¯ä¸»çª—口并退出应用。
     */
    void ExitApplication();
    /**
     * @brief æ›´æ–°ç•Œé¢æŽ§ä»¶çš„可用状态。
     *
     * æ ¹æ®è®¾å¤‡è¿žæŽ¥çŠ¶æ€ `bConnected` å’Œå­˜å‚¨çŠ¶æ€ `bStoring` åŠ¨æ€æŽ§åˆ¶ç•Œé¢ä¸ŠæŒ‰é’®ã€
     * ç¼–辑框、下拉框等控件的可用/禁用状态。
     *
     * @param bConnected è®¾å¤‡å½“前是否已连接,TRUE è¡¨ç¤ºå·²è¿žæŽ¥ï¼ŒFALSE è¡¨ç¤ºæœªè¿žæŽ¥ã€‚
     * @param bStoring å½“前是否正在进行数据存储,TRUE è¡¨ç¤ºæ­£åœ¨å­˜å‚¨ã€‚
     */
    void UpdateControlStatus(BOOL bConnected, BOOL bStoring = FALSE);
    /**
     * @brief å¯åŠ¨æ‰¹é‡æ—¥å¿—è¿½åŠ ï¼Œæš‚åœè‡ªåŠ¨æ»šåŠ¨ï¼Œæé«˜æ€§èƒ½ã€‚
     */
    void AppendLogLineBatchBegin();
    /**
     * @brief ç»“束批量日志追加,恢复自动滚动并刷新显示。
     */
    void AppendLogLineBatchEnd();
    /**
     * @brief é™åˆ¶å¯Œæ–‡æœ¬æ¡†ä¸­çš„æœ€å¤§è¡Œæ•°ï¼Œé¿å…æ—¥å¿—过多导致性能问题。
     *
     * @param maxLines æœ€å¤§ä¿ç•™çš„行数,默认值为 100。
     */
    void TrimRichEditLineLimit(int maxLines = 100);
    /**
     * @brief å‘日志窗口追加一条带颜色样式的日志行。
     *
     * @param content æ—¥å¿—内容。
     * @param color å­—体颜色,默认为黑色。
     */
    void AppendLogLineRichStyled(const CString& strContent, COLORREF color = RGB(0, 0, 0));
    /**
     * @brief é«˜äº®æ—¥å¿—中所有匹配指定字符串的部分。
     *
     * @param strSearch è¦åŒ¹é…çš„字符串。
     * @param clrHighlight é«˜äº®é¢œè‰²ï¼Œé»˜è®¤ä¸ºæ©™è‰²ï¼ˆRGB(255, 165, 0))。
     */
    void HighlightAllMatches(const CString& strSearch, COLORREF clrHighlight = RGB(255, 165, 0));
    /**
     * @brief ä»¥æ ¼å¼åŒ–方式输出指定通道的测量数据样本到日志。
     *
     * æ¯è¡Œè¾“出固定数量(如 7)个浮点数据,带时间戳、通道编号标识,便于调试查看。
     *
     * @param nOutNo è¾“出端口编号,用于标识日志来源,如 OUT1、OUT2 ç­‰ã€‚
     * @param vecBuffer æµ‹é‡æ•°æ®ç¼“存,将被逐行打印到日志中。
     */
    void PrintSampleData(int nOutNo, const std::vector<float>& vecBuffer);
    /**
     * @brief å°è¯•连接到测量设备。
     *
     * @return true è¡¨ç¤ºè¿žæŽ¥æˆåŠŸï¼Œfalse è¡¨ç¤ºè¿žæŽ¥å¤±è´¥ã€‚
     */
    bool ConnectToDevice();
    /**
     * @brief æ–­å¼€ä¸Žæµ‹é‡è®¾å¤‡çš„连接。
     *
     * @return true è¡¨ç¤ºæ–­å¼€æˆåŠŸï¼Œfalse è¡¨ç¤ºæ–­å¼€å¤±è´¥ã€‚
     */
    bool DisconnectFromDevice();
    /**
     * @brief åŽŸåœ°æ¸…é™¤æ— æ•ˆå€¼ï¼ˆå¦‚ -999.0f)并更新数据。
     *
     * @param nOutNo è¾“出通道编号,用于日志记录。
     * @param vecData è¾“入输出数据容器,内部将被就地裁剪。
     * @param fInvalid æ— æ•ˆå€¼çš„判断阈值,默认值为 -999.0f。
     */
    void CleanInvalidValuesInPlace(int nOutNo, std::vector<float>& vecData, float fInvalid = -999.0f);
    /**
     * @brief å°†æœ‰æ•ˆæ•°æ®åˆ‡å‰²æˆä¸¤æ®µçŽ»ç’ƒæ•°æ®ï¼ˆGlass1 ä¸Ž Glass2)。
     *
     * @param nOutNo è¾“出通道编号,用于日志记录。
     * @param validData è¾“入的有效数据(应已裁剪边界)。
     * @param vecGlass1 è¾“出第一段玻璃数据。
     * @param vecGlass2 è¾“出第二段玻璃数据。
     * @param fJumpThreshold è·³å˜é˜ˆå€¼ï¼Œç”¨äºŽæ£€æµ‹æ•°æ®çš„æ˜Žæ˜¾æ–­ç‚¹ã€‚
     * @param nWindow è·³å˜åˆ¤æ–­çš„前后窗口宽度。
     * @param nValleyMargin valley ç‚¹ä¹‹åŽå¤šå°‘个点作为实际切割点。
     * @param nMinGlass1Count æœ€å°‘有效点数限制。
     *
     * @return true è¡¨ç¤ºåˆ‡å‰²æˆåŠŸï¼Œfalse è¡¨ç¤ºå¤±è´¥ï¼ˆä¾‹å¦‚数据不足或无明显跳变)。
     */
    bool SplitGlassSegments(int nOutNo, const std::vector<float>& validData,
        std::vector<float>& vecGlass1, std::vector<float>& vecGlass2,
        float fJumpThreshold = 0.2f, int nWindow = 3, int nValleyMargin = 0,
        int nMinGlassCount = 10);
    /**
     * @brief å¯¹æ•°æ®æŒ‰æ•´æ•°éƒ¨åˆ†è¿›è¡Œåˆ†ç»„,保留数据量最多的一组(排除异常/干扰)。
     *
     * @param nOutNo è¾“出通道编号,用于日志记录。
     * @param vecInput åŽŸå§‹æµ®ç‚¹æ•°æ®ï¼ˆå·²è£å‰ªæ— æ•ˆå€¼ï¼‰ã€‚
     * @param vecOutput è¾“出被保留的主要分组数据(最多的那组)。
     *
     * @return true è¡¨ç¤ºæˆåŠŸè¿‡æ»¤å‡ºä¸»åˆ†ç»„ï¼Œfalse è¡¨ç¤ºæ‰€æœ‰æ•°æ®éƒ½è¢«è¿‡æ»¤æˆ–为空。
     */
    bool FilterDominantGroup(int nOutNo, const std::vector<float>& vecInput, std::vector<float>& vecOutput);
    /**
     * @brief ä»Žè¾“入数据中提取一个固定长度的稳定区间。
     *
     * @param nOutNo è¾“出通道编号,用于日志记录。
     * @param vecIn è¾“入原始数据。
     * @param vecOut è¾“出提取的稳定区域数据。
     * @param nFixedCount ç¨³å®šåŒºåŸŸçš„点数要求(必须固定数量)。
     * @param fMaxDelta å…è®¸çš„æœ€å¤§æ³¢åŠ¨èŒƒå›´ï¼ˆæœ€å¤§å€¼ - æœ€å°å€¼ï¼‰ã€‚
     *
     * @return true è¡¨ç¤ºæˆåŠŸæ‰¾åˆ°ç¨³å®šåŒºé—´ï¼Œfalse è¡¨ç¤ºæœªæ‰¾åˆ°ã€‚
     */
    bool ExtractStableRegionFixed(int nOutNo,
        const std::vector<float>& vecIn,
        std::vector<float>& vecOut,
        int nFixedCount = 5, float fMaxDelta = 0.05f);
    /**
     * @brief è®¡ç®—两片玻璃稳定区域的平均值和偏移量。
     *
     * @param vecGlass1 ç¬¬ä¸€æ®µç¨³å®šæ•°æ®ã€‚
     * @param vecGlass2 ç¬¬äºŒæ®µç¨³å®šæ•°æ®ã€‚
     * @param fAvg1 è¿”回第一段的平均值。
     * @param fAvg2 è¿”回第二段的平均值。
     * @param fOffset è¿”回两段的偏移值(绝对值差)。
     *
     * @return true è¡¨ç¤ºè®¡ç®—成功,false è¡¨ç¤ºè¾“入无效(如空数据)。
     */
    bool CalcGlassOffset(const std::vector<float>& vecGlass1,
        const std::vector<float>& vecGlass2,
        float& fAvg1, float& fAvg2, float& fOffset);
    /**
     * @brief åˆå§‹åŒ–设备端的数据存储缓冲区。
     *
     * è°ƒç”¨åº•层接口清除当前存储区内容,为新一轮的数据采集做准备。
     * å¿…须在设备连接成功且未进行数据存储时调用。
     *
     * @return true è¡¨ç¤ºåˆå§‹åŒ–成功;false è¡¨ç¤ºå¤±è´¥ï¼ˆå¯èƒ½æ˜¯è®¾å¤‡æœªè¿žæŽ¥æˆ–调用接口错误)。
     */
    bool InitDataStorage();
    /**
     * @brief å¯åŠ¨è®¾å¤‡ç«¯æ•°æ®é‡‡é›†å’Œå­˜å‚¨ã€‚
     *
     * è°ƒç”¨æ­¤å‡½æ•°åŽè®¾å¤‡å¼€å§‹é‡‡é›†å¹¶ç¼“存数据。
     * é€šå¸¸é…åˆè§¦å‘模式进行采集。
     *
     * @return true è¡¨ç¤ºå¯åŠ¨æˆåŠŸï¼›false è¡¨ç¤ºå¯åŠ¨å¤±è´¥ã€‚
     */
    bool StartDataStorage();
    /**
     * @brief åœæ­¢æ•°æ®é‡‡é›†å¹¶ä»Žè®¾å¤‡èŽ·å–å½“å‰å­˜å‚¨æ•°æ®ã€‚
     *
     * è°ƒç”¨åŽè®¾å¤‡åœæ­¢é‡‡é›†ï¼Œå¹¶å°è¯•读取指定端口的数据,供后续分析处理。
     *
     * @return true è¡¨ç¤ºåœæ­¢å¹¶è¯»å–数据成功;false è¡¨ç¤ºå¤±è´¥ï¼ˆå¦‚设备未响应或数据无效)。
     */
    bool StopDataStorage();
    /**
     * @brief åˆ†æžæŒ‡å®šç«¯å£çš„存储数据,并提取两段玻璃数据与稳定区,计算偏移。
     *
     * @param nOutNo     è¾“出端口编号(1~4)
     * @return float     æˆåŠŸè¿”å›žè®¡ç®—å‡ºçš„åç§»é‡ï¼Œå¤±è´¥è¿”å›ž -1.0f
     */
    float AnalyzeStoredData(int nOutNo);
    // === ç³»ç»ŸçŠ¶æ€ä¸Žè¿è¡Œæ•°æ® ===
    /**
     * @brief å½“前是否已连接到传感器控制器
     */
    bool m_bConnected;
    /**
     * @brief å½“前是否正在进行数据存储
     */
    bool m_bSaving;
    /**
     * @brief å››ä¸ªè¾“出端口的当前计算结果(如偏移量或厚度等)
     */
    double m_dOutValues[4];
    // === å­˜å‚¨è®¾ç½®ç›¸å…³ ===
    /**
     * @brief æ˜¯å¦ä½¿ç”¨ç¡¬ä»¶è§¦å‘信号(0=否,1=是)
     */
    int m_nUseTrigger;
    /**
     * @brief æ¯æ¬¡é‡‡é›†çš„æ•°æ®ç‚¹æ•°é‡
     */
    int m_nSavePointCount;
    /**
     * @brief è¾“出端口选择下拉框控件(用于设置采集端口)
     */
    CComboBox m_comboOutputPort;
    // === è·³å˜æ£€æµ‹ä¸ŽçŽ»ç’ƒè¯†åˆ«å‚æ•°ï¼ˆSplitGlassSegments ä½¿ç”¨ï¼‰ ===
    /**
     * @brief è·³å˜é˜ˆå€¼ï¼ˆä¾‹å¦‚ 0.2mm),用于检测两片玻璃之间的高度跳变
     */
    float m_fJumpThreshold;
    /**
     * @brief è·³å˜æ£€æµ‹çª—口半宽度(用于差分计算)
     */
    int m_nJumpWindow;
    /**
     * @brief valley ç‚¹å³ç§»çš„偏移量,用于最终确定分割点
     */
    int m_nValleyMargin;
    /**
     * @brief ç¬¬ä¸€ç‰‡çŽ»ç’ƒæœ€å°‘æ‰€éœ€çš„æ•°æ®ç‚¹æ•°
     */
    int m_nMinGlass1Count;
    // === ç¨³å®šåŒºåŸŸæå–参数(ExtractStableRegionFixed ä½¿ç”¨ï¼‰ ===
    /**
     * @brief æ¯æ®µç¨³å®šåŒºåŸŸè¦æå–的固定数据点数
     */
    int m_nFixedCount;
    /**
     * @brief æœ€å¤§å…è®¸æ³¢åŠ¨èŒƒå›´ï¼ˆä¾‹å¦‚ 0.05mm),判断是否为“稳定”区域
     */
    float m_fMaxDelta;
    // === æ—¥å¿—控件 ===
    /**
     * @brief å¯Œæ–‡æœ¬æŽ§ä»¶ï¼Œç”¨äºŽè¾“出带颜色的日志信息
     */
    CRichEditCtrl m_editLog;
    // === æ‰˜ç›˜å›¾æ ‡ç®¡ç† ===
    /**
     * @brief æ‰˜ç›˜å›¾æ ‡ç›¸å…³æ•°æ®ç»“构(NOTIFYICONDATA)
     */
    NOTIFYICONDATA m_trayIconData;
    /**
     * @brief æ‰˜ç›˜å›¾æ ‡çš„唯一 ID
     */
    UINT m_nTrayIconID;
    /**
     * @brief æ ‡è®°æ‰˜ç›˜å›¾æ ‡æ˜¯å¦å·²æˆåŠŸåˆ›å»º
     */
    BOOL m_bTrayIconCreated;
    /**
     * @brief æ ‡è®°ç¨‹åºæ˜¯å¦é€šè¿‡æ‰˜ç›˜å›¾æ ‡é€€å‡º
     */
    BOOL m_bExitingFromTray;
    // === PLC ä¿¡å·ç›‘听器 ===
    /**
     * @brief PLC ä¿¡å·ç›‘听器实例,用于处理 PLC ä¿¡å·äº‹ä»¶
     */
    CPLCSignalListener m_plcListener;
};
SourceCode/Bond/SGMeasurement/framework.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
#pragma once
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // ä»Ž Windows å¤´ä¸­æŽ’除极少使用的资料
#endif
#include "targetver.h"
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // æŸäº› CString æž„造函数将是显式的
// å…³é—­ MFC çš„一些常见且经常可放心忽略的隐藏警告消息
#define _AFX_ALL_WARNINGS
#include <afxwin.h>         // MFC æ ¸å¿ƒç»„件和标准组件
#include <afxext.h>         // MFC æ‰©å±•
#include <afxdisp.h>        // MFC è‡ªåŠ¨åŒ–ç±»
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>           // MFC å¯¹ Internet Explorer 4 å…¬å…±æŽ§ä»¶çš„æ”¯æŒ
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>             // MFC å¯¹ Windows å…¬å…±æŽ§ä»¶çš„æ”¯æŒ
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <afxcontrolbars.h>     // MFC æ”¯æŒåŠŸèƒ½åŒºå’ŒæŽ§åˆ¶æ¡
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif
SourceCode/Bond/SGMeasurement/pch.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
// pch.cpp: ä¸Žé¢„编译标头对应的源文件
#include "pch.h"
// å½“使用预编译的头时,需要使用此源文件,编译才能成功。
SourceCode/Bond/SGMeasurement/pch.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
// pch.h: è¿™æ˜¯é¢„编译标头文件。
// ä¸‹æ–¹åˆ—出的文件仅编译一次,提高了将来生成的生成性能。
// è¿™è¿˜å°†å½±å“ IntelliSense æ€§èƒ½ï¼ŒåŒ…括代码完成和许多代码浏览功能。
// ä½†æ˜¯ï¼Œå¦‚果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// è¯·å‹¿åœ¨æ­¤å¤„添加要频繁更新的文件,这将使得性能优势无效。
#ifndef PCH_H
#define PCH_H
// æ·»åŠ è¦åœ¨æ­¤å¤„é¢„ç¼–è¯‘çš„æ ‡å¤´
#include "framework.h"
#endif //PCH_H
SourceCode/Bond/SGMeasurement/res/SGMeasurement.ico
SourceCode/Bond/SGMeasurement/res/SGMeasurement.rc2
Binary files differ
SourceCode/Bond/SGMeasurement/res/menu_close.ico
SourceCode/Bond/SGMeasurement/res/menu_restore.ico
SourceCode/Bond/SGMeasurement/resource.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ ç”Ÿæˆçš„包含文件。
// ä¾› SGMeasurement.rc ä½¿ç”¨
//
#define IDM_ABOUTBOX                    0x0010
#define IDD_ABOUTBOX                    100
#define IDS_ABOUTBOX                    101
#define IDD_SGMEASUREMENT_DIALOG        102
#define IDR_MAINFRAME                   128
#define IDI_ICON_RESTORE                130
#define IDI_ICON_EXIT                   131
#define IDC_IPADDRESS                   1000
#define IDC_BUTTON_CONNECT              1001
#define IDC_BUTTON_DISCONNECT           1002
#define IDC_EDIT_OUT1                   1003
#define IDC_EDIT_OUT2                   1004
#define IDC_EDIT_OUT3                   1005
#define IDC_EDIT_OUT4                   1006
#define IDC_CHECK_USE_TRIGGER           1007
#define IDC_EDIT_STORE_COUNT            1008
#define IDC_COMBO_OUTPUT_PORT           1009
#define IDC_BUTTON_START_STORE          1010
#define IDC_BUTTON_STOP_STORE           1011
#define IDC_BUTTON_CLEAR_STORE          1012
#define IDC_BUTTON_RECEIVE_FROM_CTRL    1013
#define IDC_BUTTON_SEND_TO_CTRL         1014
#define IDC_RICHEDIT_LOG                1015
#define IDC_BUTTON_CLEAR_LOG            1016
#define IDC_EDIT_JUMP_THRESHOLD         1017
#define IDC_EDIT_JUMP_WINDOW            1018
#define IDC_EDIT_VALLEY_MARGIN          1019
#define IDC_EDIT_MIN_GLASS_COUNT        1020
#define IDC_EDIT_FIXED_COUNT            1021
#define IDC_EDIT_MAX_DELTA              1022
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        132
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1023
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
SourceCode/Bond/SGMeasurement/targetver.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
#pragma once
// åŒ…括 SDKDDKVer.h å°†å®šä¹‰å¯ç”¨çš„æœ€é«˜ç‰ˆæœ¬çš„ Windows å¹³å°ã€‚
//如果要为以前的 Windows å¹³å°ç”Ÿæˆåº”用程序,请包括 WinSDKVer.h,并
// å°† _WIN32_WINNT å®è®¾ç½®ä¸ºè¦æ”¯æŒçš„平台,然后再包括 SDKDDKVer.h。
#include <SDKDDKVer.h>
SourceCode/Bond/Servo/PageRecipe.cpp
@@ -22,6 +22,52 @@
{
}
void CPageRecipe::InitListCtrlHeaderForMaster()
{
    m_listPPID.DeleteAllItems();
    while (m_listPPID.DeleteColumn(0));
    CString strIniFile, strItem;
    strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
    int width[12] = { 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 180 };
    for (int i = 0; i < 12; i++) {
        strItem.Format(_T("Col_%d_Width"), i);
        width[i] = GetPrivateProfileInt("PageRecipeListCtrl", strItem, width[i], strIniFile);
    }
    m_listPPID.InsertColumn(0, _T(""), LVCFMT_RIGHT, 0); // éšè—åˆ—
    m_listPPID.InsertColumn(1, _T("No."), LVCFMT_LEFT, width[1]);
    m_listPPID.InsertColumn(2, _T("PPID"), LVCFMT_LEFT, width[2]);
    m_listPPID.InsertColumn(3, _T("真空烘烤"), LVCFMT_LEFT, width[6]);
    m_listPPID.InsertColumn(4, _T("Bonder1"), LVCFMT_LEFT, width[4]);
    m_listPPID.InsertColumn(5, _T("Bonder2"), LVCFMT_LEFT, width[5]);
    m_listPPID.InsertColumn(6, _T("后烘冷却"), LVCFMT_LEFT, width[7]);
    m_listPPID.InsertColumn(7, _T("精度检查"), LVCFMT_LEFT, width[8]);
    m_listPPID.InsertColumn(8, _T("EFEM"), LVCFMT_LEFT, width[3]);
    m_listPPID.InsertColumn(9, _T("创建时间"), LVCFMT_LEFT, width[9]);
    m_listPPID.InsertColumn(10, _T("描述"), LVCFMT_LEFT, width[10]);
}
void CPageRecipe::InitListCtrlHeaderForDevice()
{
    m_listPPID.DeleteAllItems();
    while (m_listPPID.DeleteColumn(0));
    CString strIniFile, strItem;
    strIniFile.Format(_T("%s\\configuration.ini"), (LPCTSTR)theApp.m_strAppDir);
    int width[] = { 0, 60, 150, 150 };
    for (int i = 0; i < 4; i++) {
        strItem.Format(_T("Col_Device_%d_Width"), i);
        width[i] = GetPrivateProfileInt(_T("PageRecipeListCtrl"), strItem, width[i], strIniFile);
    }
    m_listPPID.InsertColumn(0, _T(""), LVCFMT_RIGHT, width[0]);
    m_listPPID.InsertColumn(1, _T("No."), LVCFMT_CENTER, width[1]);
    m_listPPID.InsertColumn(2, _T("Recipe ID"), LVCFMT_CENTER, width[2]);
    m_listPPID.InsertColumn(3, _T("Recipe åç§°"), LVCFMT_CENTER, width[3]);
}
void CPageRecipe::UpdateRecipeByPPID(const CString& strPPID)
{
    if (strPPID.IsEmpty()) {
@@ -168,15 +214,6 @@
{
    CDialogEx::OnInitDialog();
    // è¯»å‡ºåˆ—宽
    CString strIniFile, strItem;
    strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
    int width[12] = { 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 180 };
    for (int i = 0; i < 12; i++) {
        strItem.Format(_T("Col_%d_Width"), i);
        width[i] = GetPrivateProfileInt("PageRecipeListCtrl", strItem, width[i], strIniFile);
    }
    // TODO:  åœ¨æ­¤æ·»åŠ é¢å¤–çš„åˆå§‹åŒ–
    CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID);
    DWORD dwStyle = pListCtrl->GetExtendedStyle();
@@ -186,18 +223,7 @@
    HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1);
    ListView_SetImageList(pListCtrl->GetSafeHwnd(), imageList, LVSIL_SMALL);
    pListCtrl->InsertColumn(0, _T(""), LVCFMT_RIGHT, 0); // éšè—åˆ—
    pListCtrl->InsertColumn(1, _T("No."), LVCFMT_LEFT, width[1]);
    pListCtrl->InsertColumn(2, _T("PPID/Recipe ID"), LVCFMT_LEFT, width[2]);
    pListCtrl->InsertColumn(3, _T("真空烘烤"), LVCFMT_LEFT, width[6]);
    pListCtrl->InsertColumn(4, _T("Bonder1"), LVCFMT_LEFT, width[4]);
    pListCtrl->InsertColumn(5, _T("Bonder2"), LVCFMT_LEFT, width[5]);
    pListCtrl->InsertColumn(6, _T("后烘冷却"), LVCFMT_LEFT, width[7]);
    pListCtrl->InsertColumn(7, _T("精度检查"), LVCFMT_LEFT, width[8]);
    pListCtrl->InsertColumn(8, _T("EFEM"), LVCFMT_LEFT, width[3]);
    pListCtrl->InsertColumn(9, _T("创建时间"), LVCFMT_LEFT, width[9]);
    pListCtrl->InsertColumn(10, _T("描述"), LVCFMT_LEFT, width[10]);
    pListCtrl->SetColumnWidth(10, LVSCW_AUTOSIZE_USEHEADER);
    InitListCtrlHeaderForMaster();
    // èŽ·å–æ‰€æœ‰æ•°æ®
    auto vecData = RecipeManager::getInstance().getAllRecipes();
@@ -255,19 +281,37 @@
void CPageRecipe::OnDestroy()
{
    CDialogEx::OnDestroy();
    CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
    int nSel = pComboBox->GetCurSel();
    SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel);
    // ä¿å­˜åˆ—宽
    CString strIniFile, strItem, strTemp;
    strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
    strIniFile.Format(_T("%s\\configuration.ini"), (LPCTSTR)theApp.m_strAppDir);
    CHeaderCtrl* pHeader = m_listPPID.GetHeaderCtrl();
    if (!pHeader || pHeader->GetItemCount() == 0) {
        return;
    }
    for (int i = 0; i < pHeader->GetItemCount(); i++) {
        RECT rect;
        pHeader->GetItemRect(i, &rect);
        strItem.Format(_T("Col_%d_Width"), i);
        if (!pHeader->GetItemRect(i, &rect)) {
            continue;
        }
        if (pEq == nullptr) {
            strItem.Format(_T("Col_%d_Width"), i);
        }
        else {
            strItem.Format(_T("Col_Device_%d_Width"), i);
        }
        strTemp.Format(_T("%d"), rect.right - rect.left);
        WritePrivateProfileString("PageRecipeListCtrl", strItem, strTemp, strIniFile);
        WritePrivateProfileString(_T("PageRecipeListCtrl"), strItem, strTemp, strIniFile);
    }
    CDialogEx::OnDestroy();
}
void CPageRecipe::OnShowWindow(BOOL bShow, UINT nStatus)
@@ -293,6 +337,10 @@
                pComboBox->InsertString(i,
                    pEq[i] == nullptr ? _T("Master") : pEq[i]->getName().c_str());
                pComboBox->SetItemDataPtr(i, pEq[i]);
                if (pEq[i]) {
                    pEq[i]->masterRecipeListRequest(0, nullptr);
                }
            }
            pComboBox->SetCurSel(0);
        }
@@ -477,6 +525,7 @@
    int nEqSel = pComboBox->GetCurSel();
    int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd());
    GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0);
@@ -488,6 +537,7 @@
    int nEqSel = pComboBox->GetCurSel();
    int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd());
    GetDlgItem(IDC_BUTTON_NEW)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0);
@@ -496,10 +546,12 @@
    SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nEqSel);
    if (pEq == nullptr) {
        InitListCtrlHeaderForMaster();
        auto vecData = RecipeManager::getInstance().getAllRecipes();
        FillDataToListCtrl(vecData);
    }
    else {
        InitListCtrlHeaderForDevice();
        SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
        FillRecipeListToListCtrl(pRecipeList);
    }
SourceCode/Bond/Servo/PageRecipe.h
@@ -1,6 +1,7 @@
#pragma once
#include "afxdialogex.h"
#include "RecipeManager.h"
#include "ListCtrlEx.h"
// CPageRecipe å¯¹è¯æ¡†
@@ -13,6 +14,8 @@
    virtual ~CPageRecipe();
private:
    void InitListCtrlHeaderForMaster();
    void InitListCtrlHeaderForDevice();
    void UpdateRecipeByPPID(const CString& strPPID);
    void FillDataToListCtrl(const std::vector<RecipeInfo>& vecRecipe);
    void FillRecipeListToListCtrl(SERVO::CRecipeList* pList);
@@ -39,5 +42,5 @@
    DECLARE_MESSAGE_MAP()
private:
    CListCtrl m_listPPID;
    CListCtrlEx m_listPPID;
};
SourceCode/Bond/Servo/RecipeManager.cpp
@@ -62,8 +62,7 @@
        );
    )";
    return m_pDB->executeQuery(createRecipeTable)
        && m_pDB->executeQuery(createDeviceTable);
    return m_pDB->executeQuery(createRecipeTable) && m_pDB->executeQuery(createDeviceTable);
}
void RecipeManager::termRecipeTable() {
SourceCode/Bond/Servo/RecipeManager.h
@@ -11,6 +11,7 @@
struct DeviceRecipe {
    int nDeviceID;               // è®¾å¤‡ID
    int nRecipeID;               // å­é…æ–¹ID
    std::string strRecipeName;   // å­é…æ–¹åç§°
    std::string strDeviceName;   // è®¾å¤‡åç§° 
};