LAPTOP-SNT8I5JK\Boounion
2025-02-14 2fc5bbfe88adefb0d2f8ba55d800fe074264a539
Merge branch 'liuyang' into clh
已添加9个文件
已修改5个文件
3503 ■■■■■ 文件已修改
Document/VID 表格.zip 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/MELSECSDK/include/Mdfunc.h 392 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/MELSECSDK/lib/MdFunc32.lib 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp 1355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h 465 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/SECSRuntimeManager.cpp 682 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/SECSRuntimeManager.h 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.cpp 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/stdafx.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Document/VID ±í¸ñ.zip
Binary files differ
SourceCode/Bond/MELSECSDK/include/Mdfunc.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,392 @@
#ifndef WINAPI
    #define WINAPI
#endif
#ifdef __cplusplus
extern "C" {
#endif
    SHORT WINAPI mdOpen( SHORT, SHORT, LPLONG );
    SHORT WINAPI mdClose( LONG );
    SHORT WINAPI mdSend( LONG, SHORT, SHORT, SHORT, PSHORT, LPVOID );
    SHORT WINAPI mdReceive( LONG, SHORT, SHORT, SHORT, PSHORT, LPVOID );
    SHORT WINAPI mdDevSet( LONG, SHORT, SHORT, SHORT );
    SHORT WINAPI mdDevRst( LONG, SHORT, SHORT, SHORT );
    SHORT WINAPI mdRandW( LONG, SHORT, LPVOID, LPVOID, SHORT );
    SHORT WINAPI mdRandR( LONG, SHORT, LPVOID, LPVOID, SHORT );
    SHORT WINAPI mdControl( LONG, SHORT, SHORT );
    SHORT WINAPI mdTypeRead( LONG, SHORT, PSHORT );
    SHORT WINAPI mdBdLedRead( LONG, PSHORT );
    SHORT WINAPI mdBdModRead( LONG, PSHORT );
    SHORT WINAPI mdBdModSet( LONG, SHORT );
    SHORT WINAPI mdBdRst( LONG );
    SHORT WINAPI mdBdSwRead( LONG, PSHORT );
    SHORT WINAPI mdBdVerRead( LONG, PSHORT );
    SHORT WINAPI mdInit( LONG );
    SHORT WINAPI mdWaitBdEvent( LONG, PSHORT, LONG, PSHORT, PSHORT );
    LONG WINAPI mdSendEx( LONG, LONG, LONG, LONG, LONG, LPLONG, LPVOID );
    LONG WINAPI mdReceiveEx( LONG, LONG, LONG, LONG, LONG, LPLONG, LPVOID );
    LONG WINAPI mdDevSetEx( LONG, LONG, LONG, LONG, LONG );
    LONG WINAPI mdDevRstEx( LONG, LONG, LONG, LONG, LONG );
    LONG WINAPI mdRandWEx( LONG, LONG, LONG, LPVOID, LPVOID, LONG );
    LONG WINAPI mdRandREx( LONG, LONG, LONG, LPVOID, LPVOID, LONG );
    LONG WINAPI mdRemBufWriteEx(  LONG, LONG, LONG, LONG, LPLONG, LPVOID );
    LONG WINAPI mdRemBufReadEx(  LONG, LONG, LONG, LONG, LPLONG, LPVOID );
    LONG WINAPI mdRemBufWriteIPEx(  LONG, LONG, LONG, LPLONG, LPVOID );
    LONG WINAPI mdRemBufReadIPEx(  LONG, LONG, LONG, LPLONG, LPVOID );
#ifdef __cplusplus
}
#endif
#define    mdopen            mdOpen
#define    mdclose            mdClose
#define    mdsend            mdSend
#define    mdreceive        mdReceive
#define    mddevset        mdDevSet
#define    mddevrst        mdDevRst
#define    mdrandw            mdRandW
#define    mdrandr            mdRandR
#define    mdcontrol        mdControl
#define    mdtyperead        mdTypeRead
#define    mdsendex        mdSendEx
#define    mdreceiveex        mdReceiveEx
#define    mddevsetex        mdDevSetEx
#define    mddevrstex        mdDevRstEx
#define    mdrandwex        mdRandWEx
#define    mdrandrex        mdRandREx
#define    DevX        (1)
#define    DevLX(x)    (DevX*1000+(x))
#define    DevY        (2)
#define    DevLY(x)    (DevY*1000+(x))
#define    DevL        (3)
#define    DevM        (4)
#define    DevSM        (5)
#define    DevF        (6)
#define    DevTT        (7)
#define    DevTC        (8)
#define    DevCT        (9)
#define    DevCC        (10)
#define    DevTN        (11)
#define    DevCN        (12)
#define    DevD        (13)
#define    DevSD        (14)
#define    DevTM        (15)
#define    DevTS        (16)
#define    DevTS2        (16002)
#define    DevTS3        (16003)
#define    DevCM        (17)
#define    DevCS        (18)
#define    DevCS2        (18002)
#define    DevCS3        (18003)
#define    DevA        (19)
#define    DevZ        (20)
#define    DevV        (21)
#define    DevR        (22)
#define    DevZR        (220)
#define    DevB        (23)
#define    DevLB(x)    (DevB*1000+(x))
#define    DevW        (24)
#define    DevLW(x)    (DevW*1000+(x))
#define    DevQSB        (25)
#define    DevLSB(x)    (DevQSB*1000+(x))
#define    DevSTT        (26)
#define    DevSTC        (27)
#define    DevQSW        (28)
#define    DevLSW(x)    (DevQSW*1000+(x))
#define    DevSPG(x)    (29*1000+(x))
#define    DevQV        (30)
#define    DevMRB        (33)
#define    DevMAB        (34)
#define    DevSTN        (35)
#define    DevWw        (36)
#define    DevWr        (37)
#define    DevLZ        (38)
#define    DevRD        (39)
#define DevFS        (40)
#define    DevLTT        (41)
#define    DevLTC        (42)
#define    DevLTN        (43)
#define    DevLCT        (44)
#define    DevLCC        (45)
#define    DevLCN        (46)
#define    DevLSTT        (47)
#define    DevLSTC        (48)
#define    DevLSTN        (49)
#define    DevSPB        (50)
#define    DevSPB1        (501)
#define    DevSPB2        (502)
#define    DevSPB3        (503)
#define    DevSPB4        (504)
#define    DevSPX        (51)
#define    DevSPY        (52)
#define    DevUSER        (100)
#define    DevMAIL        (101)
#define    DevMAILNC    (102)
#define    DevER0        (22000)
#define    DevER1        (22001)
#define    DevER2        (22002)
#define    DevER3        (22003)
#define    DevER4        (22004)
#define    DevER5        (22005)
#define    DevER6        (22006)
#define    DevER7        (22007)
#define    DevER8        (22008)
#define    DevER9        (22009)
#define    DevER10        (22010)
#define    DevER11        (22011)
#define    DevER12        (22012)
#define    DevER13        (22013)
#define    DevER14        (22014)
#define    DevER15        (22015)
#define    DevER16        (22016)
#define    DevER17        (22017)
#define    DevER18        (22018)
#define    DevER19        (22019)
#define    DevER20        (22020)
#define    DevER21        (22021)
#define    DevER22        (22022)
#define    DevER23        (22023)
#define    DevER24        (22024)
#define    DevER25        (22025)
#define    DevER26        (22026)
#define    DevER27        (22027)
#define    DevER28        (22028)
#define    DevER29        (22029)
#define    DevER30        (22030)
#define    DevER31        (22031)
#define    DevER32        (22032)
#define    DevER33        (22033)
#define    DevER34        (22034)
#define    DevER35        (22035)
#define    DevER36        (22036)
#define    DevER37        (22037)
#define    DevER38        (22038)
#define    DevER39        (22039)
#define    DevER40        (22040)
#define    DevER41        (22041)
#define    DevER42        (22042)
#define    DevER43        (22043)
#define    DevER44        (22044)
#define    DevER45        (22045)
#define    DevER46        (22046)
#define    DevER47        (22047)
#define    DevER48        (22048)
#define    DevER49        (22049)
#define    DevER50        (22050)
#define    DevER51        (22051)
#define    DevER52        (22052)
#define    DevER53        (22053)
#define    DevER54        (22054)
#define    DevER55        (22055)
#define    DevER56        (22056)
#define    DevER57        (22057)
#define    DevER58        (22058)
#define    DevER59        (22059)
#define    DevER60        (22060)
#define    DevER61        (22061)
#define    DevER62        (22062)
#define    DevER63        (22063)
#define    DevER64        (22064)
#define    DevER65        (22065)
#define    DevER66        (22066)
#define    DevER67        (22067)
#define    DevER68        (22068)
#define    DevER69        (22069)
#define    DevER70        (22070)
#define    DevER71        (22071)
#define    DevER72        (22072)
#define    DevER73        (22073)
#define    DevER74        (22074)
#define    DevER75        (22075)
#define    DevER76        (22076)
#define    DevER77        (22077)
#define    DevER78        (22078)
#define    DevER79        (22079)
#define    DevER80        (22080)
#define    DevER81        (22081)
#define    DevER82        (22082)
#define    DevER83        (22083)
#define    DevER84        (22084)
#define    DevER85        (22085)
#define    DevER86        (22086)
#define    DevER87        (22087)
#define    DevER88        (22088)
#define    DevER89        (22089)
#define    DevER90        (22090)
#define    DevER91        (22091)
#define    DevER92        (22092)
#define    DevER93        (22093)
#define    DevER94        (22094)
#define    DevER95        (22095)
#define    DevER96        (22096)
#define    DevER97        (22097)
#define    DevER98        (22098)
#define    DevER99        (22099)
#define    DevER100    (22100)
#define    DevER101    (22101)
#define    DevER102    (22102)
#define    DevER103    (22103)
#define    DevER104    (22104)
#define    DevER105    (22105)
#define    DevER106    (22106)
#define    DevER107    (22107)
#define    DevER108    (22108)
#define    DevER109    (22109)
#define    DevER110    (22110)
#define    DevER111    (22111)
#define    DevER112    (22112)
#define    DevER113    (22113)
#define    DevER114    (22114)
#define    DevER115    (22115)
#define    DevER116    (22116)
#define    DevER117    (22117)
#define    DevER118    (22118)
#define    DevER119    (22119)
#define    DevER120    (22120)
#define    DevER121    (22121)
#define    DevER122    (22122)
#define    DevER123    (22123)
#define    DevER124    (22124)
#define    DevER125    (22125)
#define    DevER126    (22126)
#define    DevER127    (22127)
#define    DevER128    (22128)
#define    DevER129    (22129)
#define    DevER130    (22130)
#define    DevER131    (22131)
#define    DevER132    (22132)
#define    DevER133    (22133)
#define    DevER134    (22134)
#define    DevER135    (22135)
#define    DevER136    (22136)
#define    DevER137    (22137)
#define    DevER138    (22138)
#define    DevER139    (22139)
#define    DevER140    (22140)
#define    DevER141    (22141)
#define    DevER142    (22142)
#define    DevER143    (22143)
#define    DevER144    (22144)
#define    DevER145    (22145)
#define    DevER146    (22146)
#define    DevER147    (22147)
#define    DevER148    (22148)
#define    DevER149    (22149)
#define    DevER150    (22150)
#define    DevER151    (22151)
#define    DevER152    (22152)
#define    DevER153    (22153)
#define    DevER154    (22154)
#define    DevER155    (22155)
#define    DevER156    (22156)
#define    DevER157    (22157)
#define    DevER158    (22158)
#define    DevER159    (22159)
#define    DevER160    (22160)
#define    DevER161    (22161)
#define    DevER162    (22162)
#define    DevER163    (22163)
#define    DevER164    (22164)
#define    DevER165    (22165)
#define    DevER166    (22166)
#define    DevER167    (22167)
#define    DevER168    (22168)
#define    DevER169    (22169)
#define    DevER170    (22170)
#define    DevER171    (22171)
#define    DevER172    (22172)
#define    DevER173    (22173)
#define    DevER174    (22174)
#define    DevER175    (22175)
#define    DevER176    (22176)
#define    DevER177    (22177)
#define    DevER178    (22178)
#define    DevER179    (22179)
#define    DevER180    (22180)
#define    DevER181    (22181)
#define    DevER182    (22182)
#define    DevER183    (22183)
#define    DevER184    (22184)
#define    DevER185    (22185)
#define    DevER186    (22186)
#define    DevER187    (22187)
#define    DevER188    (22188)
#define    DevER189    (22189)
#define    DevER190    (22190)
#define    DevER191    (22191)
#define    DevER192    (22192)
#define    DevER193    (22193)
#define    DevER194    (22194)
#define    DevER195    (22195)
#define    DevER196    (22196)
#define    DevER197    (22197)
#define    DevER198    (22198)
#define    DevER199    (22199)
#define    DevER200    (22200)
#define    DevER201    (22201)
#define    DevER202    (22202)
#define    DevER203    (22203)
#define    DevER204    (22204)
#define    DevER205    (22205)
#define    DevER206    (22206)
#define    DevER207    (22207)
#define    DevER208    (22208)
#define    DevER209    (22209)
#define    DevER210    (22210)
#define    DevER211    (22211)
#define    DevER212    (22212)
#define    DevER213    (22213)
#define    DevER214    (22214)
#define    DevER215    (22215)
#define    DevER216    (22216)
#define    DevER217    (22217)
#define    DevER218    (22218)
#define    DevER219    (22219)
#define    DevER220    (22220)
#define    DevER221    (22221)
#define    DevER222    (22222)
#define    DevER223    (22223)
#define    DevER224    (22224)
#define    DevER225    (22225)
#define    DevER226    (22226)
#define    DevER227    (22227)
#define    DevER228    (22228)
#define    DevER229    (22229)
#define    DevER230    (22230)
#define    DevER231    (22231)
#define    DevER232    (22232)
#define    DevER233    (22233)
#define    DevER234    (22234)
#define    DevER235    (22235)
#define    DevER236    (22236)
#define    DevER237    (22237)
#define    DevER238    (22238)
#define    DevER239    (22239)
#define    DevER240    (22240)
#define    DevER241    (22241)
#define    DevER242    (22242)
#define    DevER243    (22243)
#define    DevER244    (22244)
#define    DevER245    (22245)
#define    DevER246    (22246)
#define    DevER247    (22247)
#define    DevER248    (22248)
#define    DevER249    (22249)
#define    DevER250    (22250)
#define    DevER251    (22251)
#define    DevER252    (22252)
#define    DevER253    (22253)
#define    DevER254    (22254)
#define    DevER255    (22255)
#define    DevER256    (22256)
#define    DevRBM        (-32768)
#define    DevRAB        (-32736)
#define    DevRX        (-32735)
#define    DevRY        (-32734)
#define    DevRW        (-32732)
#define    DevARB        (-32704)
#define    DevSB        (-32669)
#define    DevSW        (-32668)
#define    DevEM(x)    (31*1000+(x))
#define    DevED(x)    (32*1000+(x))
SourceCode/Bond/MELSECSDK/lib/MdFunc32.lib
Binary files differ
SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
#include "stdafx.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; // æ ¡éªŒé€šè¿‡
}
SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
#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);
private:
    static CCLinkIEControlMode ConvertToCCLinkIEControlMode(short nMode);
    static int ValidateBoardStatus(const BoardStatus& status);
};
#endif //CCLINKIECONTROL_H
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1355 @@
// PerformanceMelsec.cpp: implementation of the CPerformanceMelsec class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.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 short nDevType, const short nDevNo, short nSize, std::vector<short>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nSize);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // åˆå§‹åŒ–读取缓冲区
    vecData.clear();
    vecData.resize(nSize);
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        short* pData = vecData.data();
        nRet = mdReceive(m_nPath, CombineStation(station), nDevType, 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;
    }
    // è®¡ç®—需要读取的字节大小(按位对齐为字节数)
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>((nBitCount + 7) / 8);     // å‘上取整
    std::vector<short> vecTempBuffer((nSize + 1) / 2, 0); // ä¸´æ—¶ç¼“冲区,字节对齐
    nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
    if (nRet == 0) {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToUint8(vecTempBuffer, vecData);
    }
    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 short nDevType, const short nDevNo, short 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);
        nRet = mdSend(m_nPath, CombineStation(station), 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) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    const int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // è®¡ç®—需要写入的字节数(位数据需要按 8 ä½å¯¹é½ä¸ºå­—节数)
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>((vecData.size() + 7) / 8);
    std::vector<short> vecBuffer(vecData.size() / 2 + vecData.size() % 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertUint8ToShort(vecData, vecBuffer);
    }
    return WriteData(station, nDevType, nDevNo, nSize, vecBuffer.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() * sizeof(uint16_t));
    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(uint32_t));
    std::vector<short> vecBuffer(vecData.size() * 2, 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;
    }
    vecData.resize(nSize);
    long nActualSize = (nSize + 1) / 2;
    std::vector<short> vecBuffer(nActualSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &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 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());
    std::vector<short> vecBuffer((nSize + 1) / 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::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, long nDevType, long nDevNo) {
    std::lock_guard<std::mutex> lock(m_mtx);
    // æ£€æŸ¥å‚数有效性
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    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, long nDevType, long nDevNo) {
    std::lock_guard<std::mutex> lock(m_mtx);
    // æ£€æŸ¥å‚数有效性
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    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/Servo/CCLinkPerformance/PerformanceMelsec.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,465 @@
#ifndef PERFORMANCE_MELSEC_H
#define PERFORMANCE_MELSEC_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 = 0x03E9,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输入) (0x03E9~0x04E7) (位)
    LY = 0x07D1,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输出) (0x07D1~0x08CF) (位)
    LB = 0x59D9,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接继电器) (0x59D9~0x5AD7) (位)
    LW = 0x5DC1,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接寄存器) (0x5DC1~0x5EBF) (字)
    LSB = 0x61A9,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊继电器) (0x61A9~0x62A7) (位)
    LSW = 0x6D61,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊寄存器) (0x6D61~0x6E5F) (字)
    SPG = 0x7148,    // æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ (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) {}
    // å°†â€œç½‘络号”和“站点号”组合成一个最终编码
    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<uint8_t>;        // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 8 ä¸ªä½
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, short nDevType, short nDevNo, short 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, short nDevType, short nDevNo, short 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 WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& 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, long nDevType, long nDevNo);
    long ResetBitDeviceEx(const StationIdentifier& station, long nDevType, 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/Servo/SECSRuntimeManager.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,682 @@
#include "stdafx.h"
#include "SECSRuntimeManager.h"
// å¸¸é‡
const std::string DATABASE_FILE = R"(SECSDataManager.db)";
// é™æ€æˆå‘˜åˆå§‹åŒ–
std::mutex SECSRuntimeManager::m_mutex;
// èŽ·å–å•ä¾‹å®žä¾‹
SECSRuntimeManager& SECSRuntimeManager::getInstance() {
    static SECSRuntimeManager instance;
    return instance;
}
// æž„造函数
SECSRuntimeManager::SECSRuntimeManager() {
    m_pDB = new BL::SQLiteDatabase();
}
// æžæž„函数
SECSRuntimeManager::~SECSRuntimeManager() {
    termRuntimeSetting();
    if (m_pDB != nullptr) {
        delete m_pDB;
        m_pDB = nullptr;
    }
}
// ä»Žæ•°æ®åº“中获取整数
int SECSRuntimeManager::getIntFromDB(const std::string& query) {
    auto results = m_pDB->fetchResults(query);
    if (!results.empty() && !results[0].empty()) {
        // è½¬æ¢ç¬¬ä¸€ä¸ªæŸ¥è¯¢ç»“果为整数
        return std::stoi(results[0][0]);
    }
    return 0;
}
// åˆ¤æ–­VID是否重复
bool SECSRuntimeManager::isIDDuplicate(int nID) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return false;
    }
    // å®šä¹‰è¦æ£€æŸ¥çš„表
    std::vector<std::string> tables = { "SystemSV", "EqpSV", "SystemDV", "EqpDV", "SystemEC", "EqpEC" };
    // éåŽ†è¡¨ï¼Œæ£€æŸ¥æ˜¯å¦æœ‰é‡å¤çš„ ID
    for (const auto& table : tables) {
        // åˆ›å»º SQL æŸ¥è¯¢
        std::string checkSQL = "SELECT COUNT(*) FROM " + table + " WHERE ID = " + std::to_string(nID) + ";";
        // æ‰§è¡ŒæŸ¥è¯¢
        auto results = m_pDB->fetchResults(checkSQL);
        int count = (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
        // å¦‚果找到了重复的 ID,则返回 true
        if (count > 0) {
            return true;
        }
    }
    // å¦‚果没有重复,返回 false
    return false;
}
// åˆ¤æ–­åç§°æ˜¯å¦é‡å¤
bool SECSRuntimeManager::isNameDuplicate(const std::string& sName) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return false;
    }
    // å®šä¹‰è¦æ£€æŸ¥çš„表
    std::vector<std::string> tables = { "SystemSV", "EqpSV", "SystemDV", "EqpDV", "SystemEC", "EqpEC" };
    // éåŽ†è¡¨ï¼Œæ£€æŸ¥æ˜¯å¦æœ‰é‡å¤çš„ Name
    for (const auto& table : tables) {
        // åˆ›å»º SQL æŸ¥è¯¢
        std::string checkSQL = "SELECT COUNT(*) FROM " + table + " WHERE Name = '" + sName + "';";
        // æ‰§è¡ŒæŸ¥è¯¢
        auto results = m_pDB->fetchResults(checkSQL);
        int count = (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
        // å¦‚果找到了重复的 Name,则返回 true
        if (count > 0) {
            return true;
        }
    }
    // å¦‚果没有重复,返回 false
    return false;
}
// è®¾ç½®æ•°æ®åº“连接
void SECSRuntimeManager::setDatabase(BL::Database* db) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_pDB = db;
}
// åˆå§‹åŒ–SECS设置管理库
bool SECSRuntimeManager::initRuntimeSetting() {
    char path[MAX_PATH];
    GetModuleFileName(NULL, path, MAX_PATH);
    std::string exePath(path);
    std::string dbFileDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB";
    if (!CreateDirectory(dbFileDir.c_str(), NULL) && ERROR_ALREADY_EXISTS != GetLastError()) {
        throw std::runtime_error("Failed to create database directory.");
    }
    std::string dbFilePath = dbFileDir + "\\" + DATABASE_FILE;
    if (!m_pDB->connect(dbFilePath, true)) {
        return false;
    }
    // åˆå§‹åŒ– SystemSV è¡¨
    initSystemSVTable();
    // åˆå§‹åŒ– EqpSV è¡¨
    initEqpSVTable();
    // åˆå§‹åŒ– SystemDV è¡¨
    initSystemDVTable();
    // åˆå§‹åŒ– EqpDV è¡¨
    initEqpDVTable();
    // åˆå§‹åŒ– SystemEC è¡¨
    initSystemECTable();
    // åˆå§‹åŒ– EqpEC è¡¨
    initEqpECTable();
    // åˆå§‹åŒ– SystemECID è¡¨
    initSystemEventTable();
    // åˆå§‹åŒ– EqpECID è¡¨
    initEqpEventTable();
    // åˆå§‹åŒ– SystemEventLink è¡¨
    initEventLinkTable();
    // åˆå§‹åŒ– PPID è¡¨
    initPPIDTable();
    // åˆå§‹åŒ– RPTID è¡¨
    initRPTIDTable();
    return true;
}
// é”€æ¯SECS设置管理库
void SECSRuntimeManager::termRuntimeSetting() {
    if (m_pDB != nullptr) {
        m_pDB->disconnect();
    }
}
// åˆå§‹åŒ– SystemSV è¡¨
void SECSRuntimeManager::initSystemSVTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º SystemSV è¡¨ï¼ˆå¦‚果不存在)
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS SystemSV ("
        "ID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "DataType TEXT NOT NULL, "
        "Length INTEGER NULL, "
        "Unit TEXT NULL, "
        "Remark TEXT, "
        "SystemID INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create SystemSV table.");
    }
    // é¢„定义的 SV æ•°æ®
    std::vector<std::tuple<int, std::string, std::string, int, std::string, std::string, int>> svData = {
        {1, "SYS_LICENSE_CODE", "ASCII", 0, "NULL", "License code (Formal; Evaluation; NoLicense)", 1},
        {2, "SYS_LICENSE_STATUS", "UINT_1", 0, "NULL", "License status(0:Unauthorized; 1:Authorized; 2:Evaluation; 3:Evaluation Expiring; 4:Trial; 5:Trial End)", 2},
        {3, "GEM_CLOCK", "ASCII", 0, "NULL", "System Clock", 3},
        {4, "SYS_SECS_COMM_MODE", "UINT_1", 0, "NULL", "SECS Communication Mode(0:HSMS Mode; 1:SECSI Mode)", 4},
        {5, "SYS_SECS_DRIVER_CONNECT_STATE", "UINT_1", 0, "NULL", "Initial SECS Driver Connect State(0:Stop; 1:Start)", 5}
    };
    for (const auto& entry : svData) {
        int nID, nLength, nSystemID;
        std::string sName, sDataType, sRemark, sUnit;
        std::tie(nID, sName, sDataType, nLength, sUnit, sRemark, nSystemID) = entry;
        // æ£€æŸ¥ Name æ˜¯å¦å·²å­˜åœ¨
        int count = getIntFromDB("SELECT COUNT(*) FROM SystemSV WHERE Name = '" + sName + "';");
        if (count == 0) {
            // æ’入数据
            std::string insertSQL = "INSERT INTO SystemSV (ID, Name, DataType, Length, Unit, Remark, SystemID) VALUES ("
                + std::to_string(nID) + ", '"
                + sName + "', '"
                + sDataType + "', "
                + (nLength > 0 ? std::to_string(nLength) : "NULL") + ", "
                + ((sUnit == "NULL") ? "NULL" : "'" + sUnit + "'") + ", '"
                + sRemark + "', "
                + std::to_string(nSystemID) + ");";
            if (!m_pDB->executeQuery(insertSQL)) {
                throw std::runtime_error("Failed to insert SystemSV data.");
            }
        }
    }
}
// æ·»åŠ  SystemSV æ•°æ®
int SECSRuntimeManager::addSystemSV(int nID, const std::string& sName, const std::string& sDataType, int nLength, const std::string& sUnit, const std::string& sRemark, int nSystemID) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return 1;
    }
    if (isIDDuplicate(nID)) {
        return 2;
    }
    if (isNameDuplicate(sName)) {
        return 3;
    }
    // å¦‚æžœ Unit æ˜¯ "NULL" å­—符串或者为空,则插入 NULL å€¼
    std::string insertSQL = "INSERT INTO SystemSV (ID, Name, DataType, Length, Unit, Remark, SystemID) VALUES ("
        + std::to_string(nID) + ", '"
        + sName + "', '"
        + sDataType + "', "
        + (nLength > 0 ? std::to_string(nLength) : "NULL") + ", "
        + ((sUnit == "NULL" || sUnit.empty()) ? "NULL" : "'" + sUnit + "'") + ", '"
        + sRemark + "', "
        + std::to_string(nSystemID) + ");";
    if (!m_pDB->executeQuery(insertSQL)) {
        return 4;
    }
    return 0;
}
// æ›´æ–°æŒ‡å®š ID çš„ SystemSV æ•°æ®
int SECSRuntimeManager::updateIDSystemSV(int nID, int sNewID) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return 1;
    }
    // æ£€æŸ¥æ˜¯å¦å­˜åœ¨è¯¥ ID
    if (!isIDDuplicate(nID)) {
        return 2;
    }
    if (isIDDuplicate(sNewID)) {
        return 3;
    }
    // æž„建更新的 SQL è¯­å¥
    std::string updateSQL = "UPDATE SystemSV SET ID = " + std::to_string(sNewID) + " WHERE ID = " + std::to_string(nID) + ";";
    if (!m_pDB->executeQuery(updateSQL)) {
        return 4;
    }
    return 0;
}
// æ›´æ–°æ‰€æœ‰ SystemSV æ•°æ®
int SECSRuntimeManager::updateAllSystemSV(int nID, int sNewID, const std::string& sName, const std::string& sDataType, int nLength, const std::string& sUnit, const std::string& sRemark, int nSystemID) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return 1;
    }
    // æ£€æŸ¥æ˜¯å¦å­˜åœ¨è¯¥ ID
    if (!isIDDuplicate(nID)) {
        return 2;
    }
    // æ£€æŸ¥æ–°çš„ ID æ˜¯å¦å·²å­˜åœ¨ï¼Œå¦‚果已存在,则返回错误代码 3。
    if (isIDDuplicate(sNewID)) {
        return 3;
    }
    // æž„建更新的 SQL è¯­å¥
    std::string updateSQL = "UPDATE SystemSV SET ";
    bool firstField = true;
    // å¦‚果新的 ID è¢«æä¾›ï¼Œæ›´æ–° ID
    if (sNewID > 0) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "ID = " + std::to_string(sNewID);
        firstField = false;
    }
    // æ›´æ–° Name
    if (!sName.empty()) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "Name = '" + sName + "'";
        firstField = false;
    }
    // æ›´æ–° DataType
    if (!sDataType.empty()) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "DataType = '" + sDataType + "'";
        firstField = false;
    }
    // æ›´æ–° Length
    if (nLength > 0) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "Length = " + std::to_string(nLength);
        firstField = false;
    }
    // æ›´æ–° Unit
    if (sUnit != "NULL" && !sUnit.empty()) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "Unit = '" + sUnit + "'";
        firstField = false;
    }
    else if (sUnit == "NULL") {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "Unit = NULL";
        firstField = false;
    }
    // æ›´æ–° Remark
    if (!sRemark.empty()) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "Remark = '" + sRemark + "'";
        firstField = false;
    }
    // æ›´æ–° SystemID
    if (nSystemID > 0) {
        if (!firstField) {
            updateSQL += ", ";
        }
        updateSQL += "SystemID = " + std::to_string(nSystemID);
    }
    // æ·»åŠ  WHERE å­å¥æ¥æŒ‡å®šæ›´æ–°å“ªä¸ªè®°å½•
    updateSQL += " WHERE ID = " + std::to_string(nID) + ";";
    // æ‰§è¡Œæ›´æ–°æ“ä½œ
    if (!m_pDB->executeQuery(updateSQL)) {
        return 4;
    }
    return 0;
}
// åˆ é™¤æŒ‡å®š ID çš„ SystemSV æ•°æ®
int SECSRuntimeManager::deleteSystemSVByID(int nID) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return 1;
    }
    // æ£€æŸ¥æ˜¯å¦å­˜åœ¨è¯¥ ID
    if (!isIDDuplicate(nID)) {
        return 2;
    }
    // æž„建删除的 SQL è¯­å¥
    std::string deleteSQL = "DELETE FROM SystemSV WHERE ID = " + std::to_string(nID) + ";";
    if (!m_pDB->executeQuery(deleteSQL)) {
        return 3;
    }
    return 0;
}
int SECSRuntimeManager::deleteAllSystemSV() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return 1;
    }
    // æž„建删除所有数据的 SQL è¯­å¥
    std::string deleteSQL = "DELETE FROM SystemSV;";
    if (!m_pDB->executeQuery(deleteSQL)) {
        return 2;
    }
    return 0; // åˆ é™¤æˆåŠŸï¼Œè¿”å›ž 0 è¡¨ç¤ºæ“ä½œæˆåŠŸå®Œæˆã€‚
}
// åˆå§‹åŒ– EqpSV è¡¨
void SECSRuntimeManager::initEqpSVTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º EqpSV è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS EqpSV ("
        "ID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "DataType TEXT NOT NULL, "
        "Length INTEGER NULL, "
        "Unit TEXT NULL, "
        "Remark TEXT, "
        "SeqNo INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create EqpSV table.");
    }
}
// æ·»åŠ  EqpSV æ•°æ®
int SECSRuntimeManager::addEqpSV(int nID, const std::string& sName, const std::string& sDataType, int nLength, const std::string& sUnit, const std::string& sRemark, int nSeqNo) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        return 1;
    }
    if (isIDDuplicate(nID)) {
        return 2;
    }
    if (isNameDuplicate(sName)) {
        return 3;
    }
    // æž„建 SQL æ’入语句,插入数据到 EqpSV è¡¨ä¸­ã€‚
    std::string insertSQL = "INSERT INTO EqpSV (ID, Name, DataType, Length, Unit, Remark, SeqNo) VALUES ("
        + std::to_string(nID) + ", '"
        + sName + "', '"
        + sDataType + "', "
        + ((nLength <= 0) ? "NULL" : std::to_string(nLength))+", "
        + ((sUnit == "NULL" || sUnit.empty()) ? "NULL" : "'" + sUnit + "'")+", '"
        + sRemark + "', "
        + std::to_string(nSeqNo) + ");";
    // æ‰§è¡Œæ’入操作,若失败则抛出异常。
    if (!m_pDB->executeQuery(insertSQL)) {
        return 4;
    }
    return 0; // æ’入成功,返回 0 è¡¨ç¤ºæ“ä½œæˆåŠŸå®Œæˆã€‚
}
// åˆå§‹åŒ– SystemDV è¡¨
void SECSRuntimeManager::initSystemDVTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º SystemDV è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS SystemDV ("
        "ID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "DataType TEXT NOT NULL, "
        "Length INTEGER NULL, "
        "Unit TEXT NULL, "
        "Remark TEXT, "
        "SystemID INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create SystemDV table.");
    }
}
// åˆå§‹åŒ– EqpDV è¡¨
void SECSRuntimeManager::initEqpDVTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º EqpDV è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS EqpDV ("
        "ID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "DataType TEXT NOT NULL, "
        "Length INTEGER NULL, "
        "Unit TEXT NULL, "
        "Remark TEXT, "
        "SeqNo INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create EqpDV table.");
    }
}
// åˆå§‹åŒ– SystemEC è¡¨
void SECSRuntimeManager::initSystemECTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º SystemEC è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS SystemEC ("
        "ID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "DataType TEXT NOT NULL, "
        "MinValue INTEGER NULL, "
        "MaxValue INTEGER NULL, "
        "DefaultVal INTEGER NULL, "
        "Unit TEXT NULL, "
        "Remark TEXT, "
        "SystemID INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create SystemEC table.");
    }
}
// åˆå§‹åŒ– EqpEC è¡¨
void SECSRuntimeManager::initEqpECTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º EqpEC è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS EqpEC ("
        "ID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "DataType TEXT NOT NULL, "
        "MinValue INTEGER NULL, "
        "MaxValue INTEGER NULL, "
        "DefaultValue INTEGER NULL, "
        "Unit TEXT NULL, "
        "Remark TEXT, "
        "SeqNo INTEGER NOT NULL, "
        "Length INTEGER NOT NULL, "
        "CanUpdateByHost INTEGER NOT NULL);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create EqpEC table.");
    }
}
// åˆå§‹åŒ– SystemEvent è¡¨
void SECSRuntimeManager::initSystemEventTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º SystemEvent è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS SystemEvent ("
        "CEID INTEGER PRIMARY KEY, "
        "Name TEXT UNIQUE NOT NULL, "
        "Remark TEXT, "
        "SystemID INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create SystemEvent table.");
    }
}
// åˆå§‹åŒ– EqpEvent è¡¨
void SECSRuntimeManager::initEqpEventTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º EqpEvent è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS EqpEvent ("
        "CEID INTEGER PRIMARY KEY AUTOINCREMENT, "
        "Name TEXT UNIQUE NOT NULL, "
        "Remark TEXT, "
        "BitNo INTEGER);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create EqpEvent table.");
    }
}
// åˆå§‹åŒ– EventLink è¡¨
void SECSRuntimeManager::initEventLinkTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º EventLink è¡¨
    std::string createEventLinkSQL =
        "CREATE TABLE IF NOT EXISTS EventLink ("
        "CEID INTEGER, "
        "RPTID INTEGER, "
        "FOREIGN KEY (CEID) REFERENCES EqpEvent(CEID));";
    if (!m_pDB->executeQuery(createEventLinkSQL)) {
        throw std::runtime_error("Failed to create EventLink table.");
    }
}
// åˆå§‹åŒ– PPID è¡¨
void SECSRuntimeManager::initPPIDTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º EqpPPID è¡¨
    std::string createTableSQL =
        "CREATE TABLE IF NOT EXISTS EqpPPID ("
        "BitNo INTEGER PRIMARY KEY AUTOINCREMENT, "
        "PPID INTEGER NULL);";
    if (!m_pDB->executeQuery(createTableSQL)) {
        throw std::runtime_error("Failed to create EqpPPID table.");
    }
    // å…ˆæ£€æŸ¥è¡¨æ˜¯å¦ä¸ºç©º
    int nCount = getIntFromDB("SELECT COUNT(*) FROM EqpPPID;");
    if (nCount == 0) {
        // æ’入初始数据(512 è¡Œï¼‰
        for (int nBitNo = 0; nBitNo < 512; ++nBitNo) {
            std::string insertSQL = "INSERT INTO EqpPPID (BitNo) VALUES (" + std::to_string(nBitNo) + ");";
            if (!m_pDB->executeQuery(insertSQL)) {
                throw std::runtime_error("Failed to insert data into EqpPPID table.");
            }
        }
    }
}
// åˆå§‹åŒ– RPTID è¡¨
void SECSRuntimeManager::initRPTIDTable() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pDB == nullptr) {
        throw std::runtime_error("Database not connected.");
    }
    // åˆ›å»º RPTID ç›¸å…³è¡¨
    std::string createReportTableSQL =
        "CREATE TABLE IF NOT EXISTS Report ("
        "RPTID INTEGER PRIMARY KEY);";
    std::string createReportVIDsTableSQL =
        "CREATE TABLE IF NOT EXISTS ReportVIDs ("
        "ID INTEGER PRIMARY KEY AUTOINCREMENT, "
        "RPTID INTEGER NOT NULL, "
        "VID INTEGER NOT NULL, "
        "FOREIGN KEY (RPTID) REFERENCES Report(RPTID));";
    if (!m_pDB->executeQuery(createReportTableSQL)) {
        throw std::runtime_error("Failed to create Report table.");
    }
    if (!m_pDB->executeQuery(createReportVIDsTableSQL)) {
        throw std::runtime_error("Failed to create ReportVIDs table.");
    }
}
SourceCode/Bond/Servo/SECSRuntimeManager.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,221 @@
#ifndef SECS_RUNTIME_MANAGER_H
#define SECS_RUNTIME_MANAGER_H
#include <string>
#include <vector>
#include <mutex>
#include "Database.h"
class SECSRuntimeManager {
public:
    /**
     * èŽ·å–å•ä¾‹å®žä¾‹
     * @return SECSRuntimeManager实例的引用
     */
    static SECSRuntimeManager& getInstance();
    /**
     * è®¾ç½®æ•°æ®åº“连接
     * @param db æ•°æ®åº“连接的指针
     */
    void setDatabase(BL::Database* db);
    /**
     * åˆå§‹åŒ–SECS运行设置管理库
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool initRuntimeSetting();
    /**
    * é”€æ¯SECS运行设置管理库
    */
    void termRuntimeSetting();
    /**
    * åˆå§‹åŒ–SystemSV表
    */
    void initSystemSVTable();
    /**
     * æ·»åŠ  SystemSV æ•°æ®
     * @param nID: éœ€è¦æ·»åŠ çš„ SystemSV çš„ ID,必须是唯一的。
     * @param sName: éœ€è¦æ·»åŠ çš„ SystemSV çš„名称,必须是唯一的。
     * @param sDataType: æ•°æ®ç±»åž‹ï¼Œè¡¨ç¤ºè¯¥ç³»ç»Ÿå€¼çš„类型,例如 "ASCII"、"UINT_1" ç­‰ã€‚
     * @param nLength: ç³»ç»Ÿå€¼çš„æ•°æ®é•¿åº¦ï¼Œé€šå¸¸ä¸ºä¸€ä¸ªæ­£æ•´æ•°ï¼Œç”¨äºŽè¡¨ç¤ºè¯¥æ•°æ®çš„长度。
     * @param sUnit: ç³»ç»Ÿå€¼çš„单位。如果为空或者为 "NULL",则插入数据库中的 NULL å€¼ã€‚
     * @param sRemark: å¤‡æ³¨ä¿¡æ¯ï¼Œæè¿°è¯¥ç³»ç»Ÿå€¼çš„其他信息,可用于说明该字段的用途或特性。
     * @param nSystemID: è¯¥æ•°æ®æ‰€å±žçš„系统 ID,用于与其他表进行关联。
     * @return 1: æ•°æ®åº“未连接。
     * @return 2: ID é‡å¤ï¼Œæ— æ³•插入数据。
     * @return 3: Name é‡å¤ï¼Œæ— æ³•插入数据。
     * @return 4: æ’入数据失败。
     * @return 0: æ’入成功,数据已添加到 SystemSV è¡¨ä¸­ã€‚
     *
     * æ­¤å‡½æ•°ç”¨äºŽå°†ä¸€æ¡æ–°çš„æ•°æ®æ’入到 SystemSV è¡¨ä¸­ã€‚它首先会检查传入的 `ID` å’Œ `Name` æ˜¯å¦å·²å­˜åœ¨äºŽè¡¨ä¸­ï¼Œ
     * å¦‚果存在则返回相应的错误代码。如果 `Unit` å‚数为 "NULL" æˆ–者为空,函数会将其转换为数据库中的 NULL å€¼ã€‚
     * ç„¶åŽï¼Œæž„造一个 SQL æ’入语句并执行插入操作。如果插入失败,则抛出异常。
     * å¦‚果一切顺利,返回 0 è¡¨ç¤ºæ•°æ®æˆåŠŸæ’å…¥ã€‚
     */
    int addSystemSV(int nID, const std::string& sName, const std::string& sDataType, int nLength, const std::string& sUnit, const std::string& sRemark, int nSystemID);
    /**
     * æ›´æ–°æŒ‡å®š ID çš„ SystemSV æ•°æ®
     * @param nID: éœ€è¦æ›´æ–°çš„ SystemSV çš„当前 ID。
     * @param sNewID: è¦æ›´æ–°ä¸ºçš„æ–° ID。
     * @return 1: æ•°æ®åº“未连接。
     * @return 2: æœªæ‰¾åˆ°æŒ‡å®šçš„ ID。
     * @return 3: æ–°çš„ ID å·²ç»å­˜åœ¨ï¼Œæ— æ³•更新。
     * @return 4: æ›´æ–°æ“ä½œå¤±è´¥ã€‚
     * @return 0: æ›´æ–°æˆåŠŸã€‚
     *
     * æ­¤å‡½æ•°ç”¨äºŽæ›´æ–° `SystemSV` è¡¨ä¸­æŒ‡å®š `nID` çš„记录,将其 `ID` å­—段更新为 `sNewID`。
     * åœ¨æ‰§è¡Œæ›´æ–°å‰ï¼Œå‡½æ•°ä¼šæ£€æŸ¥ï¼š
     * 1. å½“前的 `nID` æ˜¯å¦å­˜åœ¨äºŽè¡¨ä¸­ã€‚
     * 2. æ–°çš„ `sNewID` æ˜¯å¦å·²ç»å­˜åœ¨äºŽè¡¨ä¸­ï¼Œå¦‚果存在,则无法进行更新。
     *
     * å¦‚æžœ `nID` ä¸å­˜åœ¨ï¼Œåˆ™è¿”回错误代码 2。如果 `sNewID` å·²ç»å­˜åœ¨ï¼Œåˆ™è¿”回错误代码 3。
     * å¦‚果数据库更新失败,则返回错误代码 4。成功时,返回 0 è¡¨ç¤ºæ“ä½œæˆåŠŸã€‚
     */
    int updateIDSystemSV(int nID, int sNewID);
    /**
     * æ›´æ–°æ‰€æœ‰ SystemSV æ•°æ®
     * @param nID: éœ€è¦æ›´æ–°çš„ SystemSV çš„当前 ID。
     * @param sNewID: è¦æ›´æ–°ä¸ºçš„æ–° ID,如果为空或为 -1,则不更新 ID。
     * @param sName: æ–°çš„名称,如果为空,则不更新。
     * @param sDataType: æ–°çš„æ•°æ®ç±»åž‹ï¼Œå¦‚果为空,则不更新。
     * @param nLength: æ–°çš„æ•°æ®é•¿åº¦ï¼Œå¦‚果为负值或零,则不更新。
     * @param sUnit: æ–°çš„单位,如果为空或 "NULL",则不更新。
     * @param sRemark: æ–°çš„备注,如果为空,则不更新。
     * @param nSystemID: æ–°çš„系统 ID,如果为负值,则不更新。
     * @return 1: æ•°æ®åº“未连接。
     * @return 2: æ²¡æœ‰æ‰¾åˆ°è¯¥ ID å¯¹åº”的记录。
     * @return 3: æ–°çš„ ID å·²ç»å­˜åœ¨ï¼Œæ— æ³•更新。
     * @return 4: æ›´æ–°æ“ä½œå¤±è´¥ã€‚
     * @return 0: æ›´æ–°æˆåŠŸã€‚
     *
     * æ­¤å‡½æ•°ç”¨äºŽæ›´æ–°æŒ‡å®š `ID` çš„ `SystemSV` æ•°æ®ã€‚如果某个字段为空,则跳过该字段的更新。
     * å¦‚果给定的 `ID` ä¸å­˜åœ¨ï¼Œåˆ™è¿”回错误代码 2。如果新的 `ID` å·²ç»å­˜åœ¨ï¼Œåˆ™è¿”回错误代码 3。
     *
     * å¦‚果字段为空,跳过该字段的更新。
     */
    int updateAllSystemSV(int nID, int sNewID, const std::string& sName, const std::string& sDataType, int nLength, const std::string& sUnit, const std::string& sRemark, int nSystemID);
    /**
     * åˆ é™¤æŒ‡å®š ID çš„ SystemSV æ•°æ®
     * @param nID: éœ€è¦åˆ é™¤çš„ SystemSV çš„ ID。
     * @return 1: æ•°æ®åº“未连接。
     * @return 2: æœªæ‰¾åˆ°æŒ‡å®šçš„ ID å¯¹åº”的记录。
     * @return 3: åˆ é™¤æ“ä½œå¤±è´¥ã€‚
     * @return 0: åˆ é™¤æˆåŠŸã€‚
     *
     * æ­¤å‡½æ•°ç”¨äºŽåˆ é™¤ `SystemSV` è¡¨ä¸­æŒ‡å®š `nID` çš„记录。如果给定的 `nID` ä¸å­˜åœ¨ï¼Œåˆ™è¿”回错误代码 2。
     * åˆ é™¤æ“ä½œæˆåŠŸåŽï¼Œè¿”å›ž 0 è¡¨ç¤ºåˆ é™¤æˆåŠŸã€‚
     */
    int deleteSystemSVByID(int nID);
    /**
     * åˆ é™¤æ‰€æœ‰ SystemSV æ•°æ®
     * @return 1: æ•°æ®åº“未连接。
     * @return 2: åˆ é™¤æ“ä½œå¤±è´¥ã€‚
     * @return 0: åˆ é™¤æˆåŠŸã€‚
     *
     * æ­¤å‡½æ•°ç”¨äºŽåˆ é™¤ `SystemSV` è¡¨ä¸­çš„æ‰€æœ‰è®°å½•。如果数据库未连接,则返回错误代码 1。
     * å¦‚果删除操作失败,则返回错误代码 2。删除成功后,返回 0 è¡¨ç¤ºåˆ é™¤æˆåŠŸã€‚
     */
    int deleteAllSystemSV();
    /**
    * åˆå§‹åŒ–Eqp表
    */
    void initEqpSVTable();
    /**
     * æ·»åŠ  EqpSV æ•°æ®
     * @param nID: éœ€è¦æ·»åŠ çš„ EqpSV çš„ ID,必须是唯一的。
     * @param sName: éœ€è¦æ·»åŠ çš„ EqpSV çš„名称,必须是唯一的。
     * @param sDataType: æ•°æ®ç±»åž‹ï¼Œè¡¨ç¤ºè¯¥è®¾å¤‡å€¼çš„类型,例如 "ASCII"、"UINT_1" ç­‰ã€‚
     * @param nLength: è®¾å¤‡å€¼çš„æ•°æ®é•¿åº¦ï¼Œé€šå¸¸ä¸ºä¸€ä¸ªæ­£æ•´æ•°ï¼Œç”¨äºŽè¡¨ç¤ºè¯¥æ•°æ®çš„长度。
     * @param sUnit: è®¾å¤‡å€¼çš„单位。如果为空或者为 "NULL",则插入数据库中的 NULL å€¼ã€‚
     * @param sRemark: å¤‡æ³¨ä¿¡æ¯ï¼Œæè¿°è¯¥è®¾å¤‡å€¼çš„其他信息,可用于说明该字段的用途或特性。
     * @param nSeqNo: è¯¥æ•°æ®çš„序号,用于排序。
     * @return 1: æ•°æ®åº“未连接。
     * @return 2: ID é‡å¤ï¼Œæ— æ³•插入数据。
     * @return 3: Name é‡å¤ï¼Œæ— æ³•插入数据。
     * @return 4: æ’入数据失败。
     * @return 0: æ’入成功,数据已添加到 EqpSV è¡¨ä¸­ã€‚
     *
     * æ­¤å‡½æ•°ç”¨äºŽå°†ä¸€æ¡æ–°çš„æ•°æ®æ’入到 EqpSV è¡¨ä¸­ã€‚它首先会检查传入的 `ID` å’Œ `Name` æ˜¯å¦å·²å­˜åœ¨äºŽè¡¨ä¸­ï¼Œ
     * å¦‚果存在则返回相应的错误代码。如果 `Unit` å‚数为 "NULL" æˆ–者为空,函数会将其转换为数据库中的 NULL å€¼ã€‚
     * ç„¶åŽï¼Œæž„造一个 SQL æ’入语句并执行插入操作。如果插入失败,则抛出异常。
     * å¦‚果一切顺利,返回 0 è¡¨ç¤ºæ•°æ®æˆåŠŸæ’å…¥ã€‚
     */
    int addEqpSV(int nID, const std::string& sName, const std::string& sDataType, int nLength, const std::string& sUnit, const std::string& sRemark, int nSeqNo);
    /**
    * åˆå§‹åŒ–SystemDV表
    */
    void initSystemDVTable();
    /**
    * åˆå§‹åŒ–EqpDV表
    */
    void initEqpDVTable();
    /**
    * åˆå§‹åŒ–SystemEC表
    */
    void initSystemECTable();
    /**
    * åˆå§‹åŒ–EqpEC表
    */
    void initEqpECTable();
    /**
    * åˆå§‹åŒ–SystemEvent表
    */
    void initSystemEventTable();
    /**
    * åˆå§‹åŒ–EqpEvent表
    */
    void initEqpEventTable();
    /**
    * åˆå§‹åŒ–EventLink表
    */
    void initEventLinkTable();
    /**
     * åˆå§‹åŒ–PPID表
     */
    void initPPIDTable();
    /**
    * åˆå§‹åŒ–RPTID表
    */
    void initRPTIDTable();
private:
    SECSRuntimeManager();
    ~SECSRuntimeManager();
    // ç¦æ­¢æ‹·è´å’Œèµ‹å€¼
    SECSRuntimeManager(const SECSRuntimeManager&) = delete;
    SECSRuntimeManager& operator=(const SECSRuntimeManager&) = delete;
    // ä»Žæ•°æ®åº“中获取整数
    int getIntFromDB(const std::string& query);
    // åˆ¤æ–­VID是否重复
    bool isIDDuplicate(int nID);
    // åˆ¤æ–­åç§°æ˜¯å¦é‡å¤
    bool isNameDuplicate(const std::string& sName);
    BL::Database* m_pDB;
    static std::mutex m_mutex;
};
#endif // SECS_RUNTIME_MANAGER_H
SourceCode/Bond/Servo/Servo.cpp
@@ -7,6 +7,7 @@
#include "ServoDlg.h"
#include "ServoGraph.h"
#include "AlarmManager.h"
#include "SECSRuntimeManager.h"
// å£°æ˜Žå…¨å±€å˜é‡ï¼Œç”¨äºŽç®¡ç† GDI+ åˆå§‹åŒ–
ULONG_PTR g_diplusToken;
@@ -117,6 +118,21 @@
    }
    // åˆå§‹åŒ–SECS运行设置管理库
    try {
        if (!SECSRuntimeManager::getInstance().initRuntimeSetting()) {
            AfxMessageBox("初始化SECS运行设置失败!");
            return FALSE;
        }
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("初始化SECS运行设置失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
        return FALSE;
    }
    CServoDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
@@ -159,6 +175,9 @@
    // é”€æ¯æŠ¥è­¦è¡¨
    AlarmManager::getInstance().termAlarmTable();
    // é”€æ¯SECS运行设置管理库
    SECSRuntimeManager::getInstance().termRuntimeSetting();
    return CWinApp::ExitInstance();
}
SourceCode/Bond/Servo/Servo.vcxproj
@@ -21,7 +21,7 @@
  <PropertyGroup Label="Globals">
    <ProjectGuid>{66ADACE5-3166-4D1F-B30B-DE5E01FB01A2}</ProjectGuid>
    <RootNamespace>Servo</RootNamespace>
    <WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
    <Keyword>MFCProj</Keyword>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -115,7 +115,7 @@
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
@@ -169,7 +169,7 @@
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
@@ -194,6 +194,8 @@
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
    <ClInclude Include="BlButton.h" />
    <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h" />
    <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h" />
    <ClInclude Include="Common.h" />
    <ClInclude Include="Configuration.h" />
    <ClInclude Include="Context.h" />
@@ -204,6 +206,7 @@
    <ClInclude Include="LogEdit.h" />
    <ClInclude Include="Model.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="SECSRuntimeManager.h" />
    <ClInclude Include="SecsTestDlg.h" />
    <ClInclude Include="Servo.h" />
    <ClInclude Include="ServoDlg.h" />
@@ -215,6 +218,8 @@
  <ItemGroup>
    <ClCompile Include="AlarmManager.cpp" />
    <ClCompile Include="BlButton.cpp" />
    <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp" />
    <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp" />
    <ClCompile Include="Configuration.cpp" />
    <ClCompile Include="Context.cpp" />
    <ClCompile Include="HsmsAction.cpp" />
@@ -223,6 +228,7 @@
    <ClCompile Include="LogDlg.cpp" />
    <ClCompile Include="LogEdit.cpp" />
    <ClCompile Include="Model.cpp" />
    <ClCompile Include="SECSRuntimeManager.cpp" />
    <ClCompile Include="SecsTestDlg.cpp" />
    <ClCompile Include="Servo.cpp" />
    <ClCompile Include="ServoDlg.cpp" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -1,144 +1,80 @@
<?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;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="头文件">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;hm;inl;inc;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>
    <Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
  </ItemGroup>
  <ItemGroup>
    <Manifest Include="res\application.exe.manifest" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="AlarmManager.cpp" />
    <ClCompile Include="BlButton.cpp" />
    <ClCompile Include="Configuration.cpp" />
    <ClCompile Include="Context.cpp" />
    <ClCompile Include="HsmsAction.cpp" />
    <ClCompile Include="HsmsPassive.cpp" />
    <ClCompile Include="Log.cpp" />
    <ClCompile Include="LogDlg.cpp" />
    <ClCompile Include="LogEdit.cpp" />
    <ClCompile Include="Model.cpp" />
    <ClCompile Include="SecsTestDlg.cpp" />
    <ClCompile Include="Servo.cpp" />
    <ClCompile Include="ServoDlg.cpp" />
    <ClCompile Include="ServoGraph.cpp" />
    <ClCompile Include="stdafx.cpp" />
    <ClCompile Include="TerminalDisplayDlg.cpp" />
    <ClCompile Include="SECSRuntimeManager.cpp" />
    <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp">
      <Filter>CCLinkPerformance</Filter>
    </ClCompile>
    <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp">
      <Filter>CCLinkPerformance</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
    <ClInclude Include="BlButton.h" />
    <ClInclude Include="Common.h" />
    <ClInclude Include="Configuration.h" />
    <ClInclude Include="Context.h" />
    <ClInclude Include="HsmsAction.h" />
    <ClInclude Include="HsmsPassive.h" />
    <ClInclude Include="Log.h" />
    <ClInclude Include="LogDlg.h" />
    <ClInclude Include="LogEdit.h" />
    <ClInclude Include="Model.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="SecsTestDlg.h" />
    <ClInclude Include="Servo.h" />
    <ClInclude Include="ServoDlg.h" />
    <ClInclude Include="ServoGraph.h" />
    <ClInclude Include="stdafx.h" />
    <ClInclude Include="targetver.h" />
    <ClInclude Include="TerminalDisplayDlg.h" />
    <ClInclude Include="SECSRuntimeManager.h" />
    <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h">
      <Filter>CCLinkPerformance</Filter>
    </ClInclude>
    <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h">
      <Filter>CCLinkPerformance</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc" />
  </ItemGroup>
  <ItemGroup>
    <Image Include="res\Servo.ico" />
  </ItemGroup>
  <ItemGroup>
    <None Include="packages.config" />
    <None Include="res\Servo.rc2" />
  </ItemGroup>
  <ItemGroup>
    <Text Include="ReadMe.txt" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="Servo.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="ServoDlg.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="stdafx.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="targetver.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Resource.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="ServoGraph.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Model.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="BlButton.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Common.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="LogDlg.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="LogEdit.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Configuration.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Log.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="HsmsPassive.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="HsmsAction.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Context.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="SecsTestDlg.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="TerminalDisplayDlg.h">
    <ClInclude Include="AlarmManager.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Servo.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="ServoDlg.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="stdafx.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="ServoGraph.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Model.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="BlButton.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="LogDlg.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="LogEdit.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Configuration.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Log.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="HsmsPassive.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="HsmsAction.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Context.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="SecsTestDlg.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="TerminalDisplayDlg.cpp">
    <ClCompile Include="AlarmManager.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc">
      <Filter>资源文件</Filter>
    </ResourceCompile>
  </ItemGroup>
  <ItemGroup>
    <None Include="res\Servo.rc2">
      <Filter>资源文件</Filter>
    </None>
    <None Include="packages.config" />
  </ItemGroup>
  <ItemGroup>
    <Image Include="res\Servo.ico">
      <Filter>资源文件</Filter>
    </Image>
  </ItemGroup>
  <ItemGroup>
    <Manifest Include="res\application.exe.manifest" />
    <Filter Include="CCLinkPerformance">
      <UniqueIdentifier>{77338295-9841-4706-8816-a958b1b5c465}</UniqueIdentifier>
    </Filter>
  </ItemGroup>
</Project>
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -9,7 +9,6 @@
#include "Common.h"
#include "Log.h"
#include "SecsTestDlg.h"
#include "AlarmManager.h"
#include <chrono>
#include <thread>
#include <cmath>
SourceCode/Bond/Servo/stdafx.h
@@ -38,6 +38,9 @@
#include <gdiplus.h>
using namespace Gdiplus;
// CC-LINK模块
#include "..\MELSECSDK\include\Mdfunc.h"
#pragma comment(lib, "..\\MELSECSDK\\lib\\MdFunc32.lib")
// æ•°æ®åº“模块
#include "..\DatabaseSDK\include\Database.h"