mrDarker
2025-06-26 da96e6da0b677c6a4e96308aaecd3d619a8e4db2
Merge branch 'clh' into liuyang
已修改21个文件
778 ■■■■ 文件已修改
SourceCode/Bond/Servo/CEFEM.cpp 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEFEM.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipmentPage1.cpp 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CLoadPort.cpp 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageGraph2.cpp 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageLinkSignal.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPagePortProperty.cpp 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipeList.cpp 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipesManager.cpp 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipesManager.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogEdit.cpp 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogEdit.h 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/MsgDlg.cpp 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/MsgDlg.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.cpp 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEFEM.cpp
@@ -805,14 +805,23 @@
        }
        // 更新信号到LoadPort, Robot, Aligner, Fliper
        m_pPort[0]->setLinkSignalBlock(0, &m_bLinkSignal[0][0]);
        m_pPort[1]->setLinkSignalBlock(0, &m_bLinkSignal[1][0]);
        m_pPort[2]->setLinkSignalBlock(0, &m_bLinkSignal[2][0]);
        m_pPort[3]->setLinkSignalBlock(0, &m_bLinkSignal[3][0]);
        m_pArmTray[0]->setLinkSignalBlock(0, &m_bLinkSignal[4][0]);
        m_pArmTray[1]->setLinkSignalBlock(0, &m_bLinkSignal[5][0]);
        m_pAligner->setLinkSignalBlock(0, &m_bLinkSignal[6][0]);
        m_pFliper->setLinkSignalBlock(0, &m_bLinkSignal[7][0]);
        m_pPort[0]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[0][0]);
        m_pPort[1]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[1][0]);
        m_pPort[2]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[2][0]);
        m_pPort[3]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[3][0]);
        m_pArmTray[0]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[4][0]);
        m_pArmTray[1]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[5][0]);
        m_pAligner->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[6][0]);
        m_pFliper->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[7][0]);
        m_pPort[0]->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[0][0]);
        m_pPort[1]->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[1][0]);
        m_pPort[2]->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[2][0]);
        m_pPort[3]->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[3][0]);
        m_pArmTray[0]->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[4][0]);
        m_pArmTray[1]->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[5][0]);
        m_pAligner->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[6][0]);
        m_pFliper->setLinkSignalDownstreamBlock(0, &m_bLinkSignalToDownstream[7][0]);
    }
    int CEFEM::onReceivedJob(int port, CJobDataS* pJobDataS)
@@ -870,18 +879,5 @@
    int CEFEM::getIndexerOperationModeBaseValue()
    {
        return 10000;
    }
    void CEFEM::printDebugString001()
    {
        for (int i = 0; i < 8; i++) {
            LOGI("<CEquipment-%s>%d, Signal:%s, %s, %s, %s",
                m_strName.c_str(), i,
                m_bLinkSignal[i][SIGNAL_UPSTREAM_INLINE] ? "ON" : "OFF",
                m_bLinkSignal[i][SIGNAL_UPSTREAM_TROUBLE] ? "ON" : "OFF",
                m_bLinkSignal[i][SIGNAL_INTERLOCK] ? "ON" : "OFF",
                m_bLinkSignal[i][SIGNAL_SEND_ABLE] ? "ON" : "OFF"
            );
        }
    }
}
SourceCode/Bond/Servo/CEFEM.h
@@ -42,7 +42,6 @@
        int robotCmd(ROBOT_CMD_PARAM& robotCmdParam, ONWRITED onWritedBlock = nullptr);
        int robotCmds(ROBOT_CMD_PARAM* robotCmdParam, unsigned int count, ONWRITED onWritedBlock = nullptr);
        RMDATA& getRobotMonitoringData();
        void printDebugString001();
        // 快捷封装
        int robotSendHome(int seq, ONWRITED onWritedBlock = nullptr);
SourceCode/Bond/Servo/CEquipment.cpp
@@ -35,7 +35,8 @@
        m_bLocalAlarm = FALSE;
        m_bAutoRecipeChange = FALSE;
        m_bVCREnable[0] = FALSE;
        memset(m_bLinkSignal, 0, sizeof(m_bLinkSignal));
        memset(m_bLinkSignalToUpstream, 0, sizeof(m_bLinkSignalToUpstream));
        memset(m_bLinkSignalToDownstream, 0, sizeof(m_bLinkSignalToDownstream));
        m_pCclink = nullptr;
        m_nBaseAlarmId = 0;
        m_pArm = nullptr;
@@ -399,14 +400,26 @@
        BOOL bFlag;
        int index = 0;
        for (int i = 0; i < 8; i++) {
            m_bLinkSignal[i][SIGNAL_UPSTREAM_INLINE] = isBitOn(pszData, size, index + 0);
            m_bLinkSignal[i][SIGNAL_UPSTREAM_TROUBLE] = isBitOn(pszData, size, index + 1);
            m_bLinkSignal[i][SIGNAL_INTERLOCK] = isBitOn(pszData, size, index + 2);
            m_bLinkSignal[i][SIGNAL_SEND_ABLE] = isBitOn(pszData, size, index + 3);
            m_bLinkSignalToUpstream[i][SIGNAL_UPSTREAM_INLINE] = isBitOn(pszData, size, index + 0);
            m_bLinkSignalToUpstream[i][SIGNAL_UPSTREAM_TROUBLE] = isBitOn(pszData, size, index + 1);
            m_bLinkSignalToUpstream[i][SIGNAL_INTERLOCK] = isBitOn(pszData, size, index + 2);
            m_bLinkSignalToUpstream[i][SIGNAL_SEND_ABLE] = isBitOn(pszData, size, index + 3);
            index += 0x40;
        }         
        if(m_bLinkSignal[0][SIGNAL_SEND_ABLE]) {
        if(m_bLinkSignalToUpstream[0][SIGNAL_SEND_ABLE]) {
            onSendAble();
        }
        index += 0x40 * 2;
        for (int i = 0; i < 8; i++) {
            m_bLinkSignalToDownstream[i][SIGNAL_UPSTREAM_INLINE] = isBitOn(pszData, size, index + 0);
            m_bLinkSignalToDownstream[i][SIGNAL_UPSTREAM_TROUBLE] = isBitOn(pszData, size, index + 1);
            m_bLinkSignalToDownstream[i][SIGNAL_INTERLOCK] = isBitOn(pszData, size, index + 2);
            m_bLinkSignalToDownstream[i][SIGNAL_RECEIVE_ABLE] = isBitOn(pszData, size, index + 3);
            index += 0x40;
        }
        if (m_bLinkSignalToDownstream[0][SIGNAL_RECEIVE_ABLE]) {
            onReceiveAble();
        }
        // 其它信号及响应
@@ -642,25 +655,47 @@
        return m_bVCREnable[index];
    }
    BOOL CEquipment::isLinkSignalOn(unsigned int path, unsigned int signal)
    BOOL CEquipment::isLinkSignalUpstreamOn(unsigned int path, unsigned int signal)
    {
        if (path >= PATH_MAX) return FALSE;
        if (signal >= SIGNAL_MAX) return FALSE;
        return m_bLinkSignal[path][signal];
        return m_bLinkSignalToUpstream[path][signal];
    }
    void CEquipment::setLinkSignal(unsigned int path, unsigned int signal, BOOL bOn)
    BOOL CEquipment::isLinkSignalDownstreamOn(unsigned int path, unsigned int signal)
    {
        if (path >= PATH_MAX) return FALSE;
        if (signal >= SIGNAL_MAX) return FALSE;
        return m_bLinkSignalToDownstream[path][signal];
    }
    void CEquipment::setLinkSignalUpstream(unsigned int path, unsigned int signal, BOOL bOn)
    {
        if (path >= PATH_MAX) return;
        if (signal >= SIGNAL_MAX) return;
        m_bLinkSignal[path][signal] = bOn;
        m_bLinkSignalToUpstream[path][signal] = bOn;
    }
    void CEquipment::setLinkSignalBlock(unsigned int path, BOOL* pSignal)
    void CEquipment::setLinkSignalUpstreamBlock(unsigned int path, BOOL* pSignal)
    {
        if (path >= PATH_MAX) return;
        for (int i = 0; i < SIGNAL_MAX; i++) {
            m_bLinkSignal[path][i] = pSignal[i];
            m_bLinkSignalToUpstream[path][i] = pSignal[i];
        }
    }
    void CEquipment::setLinkSignalDownstream(unsigned int path, unsigned int signal, BOOL bOn)
    {
        if (path >= PATH_MAX) return;
        if (signal >= SIGNAL_MAX) return;
        m_bLinkSignalToDownstream[path][signal] = bOn;
    }
    void CEquipment::setLinkSignalDownstreamBlock(unsigned int path, BOOL* pSignal)
    {
        if (path >= PATH_MAX) return;
        for (int i = 0; i < SIGNAL_MAX; i++) {
            m_bLinkSignalToDownstream[path][i] = pSignal[i];
        }
    }
@@ -757,6 +792,11 @@
    std::vector<CPin*>& CEquipment::getOutputPins()
    {
        return m_outputPins;
    }
    CRecipeList* CEquipment::getRecipeList(int unitNo)
    {
        return m_recipesManager.getRecipeList(unitNo);
    }
    int CEquipment::recvIntent(CPin* pPin, CIntent* pIntent)
@@ -1111,7 +1151,7 @@
        return 0;
    }
    int CEquipment::masterRecipeListRequest(short unitNo)
    int CEquipment::masterRecipeListRequest(short unitNo, ONSYNCINGSTATECHANGED block)
    {
        SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_MASTER_RECIPE_LIST_REQ);
        if (pStep == nullptr) {
@@ -1119,6 +1159,7 @@
        }
        LOGI("<CEquipment-%s>正在请求单元<%d>主配方列表", m_strName.c_str(), unitNo);
        m_recipesManager.setOnSyncingStateChanged(block);
        if (m_recipesManager.syncing() != 0) {
            return -2;
        }
@@ -1175,6 +1216,28 @@
    }
    CSlot* CEquipment::getAvailableSlotForGlass(MaterialsType type)
    {
        for (int i = 0; i < SLOT_MAX; i++) {
            if (!m_slot[i].isEnable()) continue;
            if (m_slot[i].isLock()) continue;
            if (!m_slot[i].isEmpty()) continue;
            int lsPath = m_slot[i].getLinkSignalPath();
            if (!m_bLinkSignalToDownstream[lsPath][SIGNAL_UPSTREAM_INLINE]
                || m_bLinkSignalToDownstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
                || !m_bLinkSignalToDownstream[lsPath][SIGNAL_INTERLOCK]
                || !m_bLinkSignalToDownstream[lsPath][SIGNAL_RECEIVE_ABLE]) continue;
            MaterialsType slotType = m_slot[i].getType();
            if (type == MaterialsType::G1 && slotType == MaterialsType::G2) continue;
            if (type == MaterialsType::G2 && slotType == MaterialsType::G1) continue;
            return &m_slot[i];
        }
        return nullptr;
    }
    CSlot* CEquipment::getAvailableSlotForGlassExcludeSignal(MaterialsType type)
    {
        for (int i = 0; i < SLOT_MAX; i++) {
            if (!m_slot[i].isEnable()) continue;
@@ -1238,10 +1301,10 @@
            CGlass* pGlass = (CGlass*)m_slot[i].getContext();
            if (pGlass == nullptr) continue;
            int lsPath = m_slot[i].getLinkSignalPath();
            if(!m_bLinkSignal[lsPath][SIGNAL_UPSTREAM_INLINE]
                || m_bLinkSignal[lsPath][SIGNAL_UPSTREAM_TROUBLE]
                || !m_bLinkSignal[lsPath][SIGNAL_INTERLOCK]
                || !m_bLinkSignal[lsPath][SIGNAL_SEND_ABLE] ) continue;
            if(!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
                || m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
                || !m_bLinkSignalToUpstream[lsPath][SIGNAL_INTERLOCK]
                || !m_bLinkSignalToUpstream[lsPath][SIGNAL_SEND_ABLE] ) continue;
            MaterialsType glassType = pGlass->getType();
            if (glassType == MaterialsType::G1 && putSlotType == MaterialsType::G2) continue;
@@ -1263,10 +1326,10 @@
                    CGlass* pGlass = (CGlass*)m_slot[i].getContext();
                    if (pGlass == nullptr) continue;
                    int lsPath = m_slot[i].getLinkSignalPath();
                    if (!m_bLinkSignal[lsPath][SIGNAL_UPSTREAM_INLINE]
                        || m_bLinkSignal[lsPath][SIGNAL_UPSTREAM_TROUBLE]
                        || !m_bLinkSignal[lsPath][SIGNAL_INTERLOCK]
                        || !m_bLinkSignal[lsPath][SIGNAL_SEND_ABLE]) continue;
                    if (!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
                        || m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
                        || !m_bLinkSignalToUpstream[lsPath][SIGNAL_INTERLOCK]
                        || !m_bLinkSignalToUpstream[lsPath][SIGNAL_SEND_ABLE]) continue;
                    MaterialsType glassType = pGlass->getType();
                    if (glassType == MaterialsType::G1 && putSlotType == MaterialsType::G2) continue;
@@ -1634,7 +1697,7 @@
        CJobDataS* pJobDataS = pGlass->getJobDataS();
        ASSERT(pJobDataS);
        if (!compareJobData(pJobDataB, pJobDataS)) {
            LOGE("<CFliper-%s>onPreFetchedOutJob,JobData数据不匹配(JobDataB(%d, %d),JobDataS(%d, %d)), 注意排查风险!", m_strName.c_str(),
            LOGE("<CEquipemnt-%s>onPreFetchedOutJob,JobData数据不匹配(JobDataB(%d, %d),JobDataS(%d, %d)), 注意排查风险!", m_strName.c_str(),
                pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo(),
                pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo());
            return FALSE;
@@ -1642,10 +1705,10 @@
        // 如果没有可用位置,报错
        Lock();
        CSlot* pSlot = getAvailableSlotForGlass((MaterialsType)pJobDataS->getMaterialsType());
        CSlot* pSlot = getAvailableSlotForGlassExcludeSignal((MaterialsType)pJobDataS->getMaterialsType());
        if (pSlot == nullptr) {
            Unlock();
            LOGE("<CFliper-%s>onPreFetchedOutJob,找不到匹配的Slot,不能进料,请注意风险!", m_strName.c_str());
            LOGE("<CEquipemnt-%s>onPreFetchedOutJob,找不到匹配的Slot,不能进料,请注意风险!", m_strName.c_str());
            return FALSE;
        }
        Unlock();
@@ -1703,6 +1766,13 @@
        return 0;
    }
    int CEquipment::onReceiveAble()
    {
        LOGI("<CEquipment-%s>onReceiveAble.", m_strName.c_str());
        return 0;
    }
    int CEquipment::onProcessStateChanged(PROCESS_STATE state)
    {
        return 0;
@@ -1725,4 +1795,26 @@
        return TRUE;
    }
    void CEquipment::printDebugString001()
    {
        for (int i = 0; i < 8; i++) {
            LOGI("<CEquipment-%s>Link Signal to UP stream Path#%d, Signal:%s, %s, %s, %s",
                m_strName.c_str(), i,
                m_bLinkSignalToUpstream[i][SIGNAL_UPSTREAM_INLINE] ? "ON" : "OFF",
                m_bLinkSignalToUpstream[i][SIGNAL_UPSTREAM_TROUBLE] ? "ON" : "OFF",
                m_bLinkSignalToUpstream[i][SIGNAL_INTERLOCK] ? "ON" : "OFF",
                m_bLinkSignalToUpstream[i][SIGNAL_SEND_ABLE] ? "ON" : "OFF"
            );
        }
        for (int i = 0; i < 8; i++) {
            LOGI("<CEquipment-%s>Link Signal to Down stream Path#%d, Signal:%s, %s, %s, %s",
                m_strName.c_str(), i,
                m_bLinkSignalToDownstream[i][SIGNAL_UPSTREAM_INLINE] ? "ON" : "OFF",
                m_bLinkSignalToDownstream[i][SIGNAL_UPSTREAM_TROUBLE] ? "ON" : "OFF",
                m_bLinkSignalToDownstream[i][SIGNAL_INTERLOCK] ? "ON" : "OFF",
                m_bLinkSignalToDownstream[i][SIGNAL_SEND_ABLE] ? "ON" : "OFF"
            );
        }
    }
}
SourceCode/Bond/Servo/CEquipment.h
@@ -43,6 +43,8 @@
#define SIGNAL_UPSTREAM_TROUBLE    1
#define SIGNAL_INTERLOCK        2
#define SIGNAL_SEND_ABLE        3
#define SIGNAL_RECEIVE_ABLE        3
    typedef std::function<void(int writeCode, int retCode)> ONWRITEDRET;
    typedef std::function<void(void* pEiuipment, BOOL bAlive)> ONALIVE;
@@ -112,6 +114,7 @@
        CPin* getPin(char* pszName);
        std::vector<CPin*>& CEquipment::getInputPins();
        std::vector<CPin*>& CEquipment::getOutputPins();
        CRecipeList* getRecipeList(int unitNo);
        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
        virtual int fetchedOutJob(CJobDataB* pJobDataB);
        virtual int storedJob(CJobDataB* pJobDataB, short putSlot);
@@ -123,6 +126,7 @@
        virtual int onStoredJob(int port, CJobDataB* pJobDataB);
        virtual int onProcessData(CProcessData* pProcessData);
        virtual int onSendAble();
        virtual int onReceiveAble();
        virtual int onProcessStateChanged(PROCESS_STATE state);
        virtual int getIndexerOperationModeBaseValue();
        bool isAlarmStep(SERVO::CStep* pStep);
@@ -142,12 +146,12 @@
        int setDateTime(short year, short month, short day, short hour, short minute, short second);
        int setDispatchingMode(DISPATCHING_MODE mode, ONWRITED onWritedBlock = nullptr);
        int indexerOperationModeChange(IDNEXER_OPERATION_MODE mode, ONWRITEDRET onWritedRetBlock);
        void printDebugString001();
        // 请求主配方列表
        // unitNo: 0:local; Others:unit No
        int masterRecipeListRequest(short unitNo);
        int masterRecipeListRequest(short unitNo, ONSYNCINGSTATECHANGED block);
        // 请求配方参数
        // masterRecipeId: 主配方id
@@ -163,6 +167,7 @@
        // 获取一个指定物料类型(G1,G2,G1&G2)的空槽位
        CSlot* getAvailableSlotForGlass(MaterialsType type);
        CSlot* getAvailableSlotForGlassExcludeSignal(MaterialsType type);
        // 在指定的槽列表中,获取一个指定物料类型(G1,G2,G1&G2)的空槽位
        CSlot* getAvailableSlotForGlass2(MaterialsType type, const std::vector<int>& candidates);
@@ -202,11 +207,14 @@
        BOOL isLocalAlarm();
        BOOL isAutoRecipeChange();
        BOOL isVCREnable(unsigned int index);
        BOOL isLinkSignalOn(unsigned int path, unsigned int signal);
        BOOL isLinkSignalUpstreamOn(unsigned int path, unsigned int signal);
        BOOL isLinkSignalDownstreamOn(unsigned int path, unsigned int signal);
        // 只在模拟测试时使用的函数,用于模拟信号
        void setLinkSignal(unsigned int path, unsigned int signal, BOOL bOn);
        void setLinkSignalBlock(unsigned int path, BOOL* pSignal);
        void setLinkSignalUpstream(unsigned int path, unsigned int signal, BOOL bOn);
        void setLinkSignalUpstreamBlock(unsigned int path, BOOL* pSignal);
        void setLinkSignalDownstream(unsigned int path, unsigned int signal, BOOL bOn);
        void setLinkSignalDownstreamBlock(unsigned int path, BOOL* pSignal);
    protected:
        inline void Lock() { EnterCriticalSection(&m_criticalSection); }
@@ -249,7 +257,8 @@
        BOOL m_bLocalAlarm;
        BOOL m_bAutoRecipeChange;
        BOOL m_bVCREnable[VCR_MAX];
        BOOL m_bLinkSignal[PATH_MAX][SIGNAL_MAX];
        BOOL m_bLinkSignalToUpstream[PATH_MAX][SIGNAL_MAX];
        BOOL m_bLinkSignalToDownstream[PATH_MAX][SIGNAL_MAX];
    protected:
        CCCLinkIEControl* m_pCclink;
SourceCode/Bond/Servo/CEquipmentPage1.cpp
@@ -180,7 +180,7 @@
    for (int nRow = 0; nRow < SIGNAL_GRID_ROWS; ++nRow) {
        for (int nCol = 0; nCol < SIGNAL_GRID_COLS; ++nCol) {
            BOOL bCurrentState = m_pEquipment->isLinkSignalOn(nRow, nCol);
            BOOL bCurrentState = m_pEquipment->isLinkSignalUpstreamOn(nRow, nCol);
            UpdateSignalState(nRow, nCol, bCurrentState);
        }
    }
@@ -210,8 +210,8 @@
        int index = nRow * SIGNAL_GRID_COLS + nCol;
        if (index >= 0 && index < (int)m_vSignalList.size() && m_vSignalList[index].bClickable && m_pEquipment != nullptr) {
            // 读取当前状态并切换
            const BOOL bCurrentState = m_pEquipment->isLinkSignalOn(nRow, nCol);
            m_pEquipment->setLinkSignal(nRow, nCol, !bCurrentState);
            const BOOL bCurrentState = m_pEquipment->isLinkSignalUpstreamOn(nRow, nCol);
            m_pEquipment->setLinkSignalUpstream(nRow, nCol, !bCurrentState);
        }
    });
SourceCode/Bond/Servo/CLoadPort.cpp
@@ -12,6 +12,14 @@
    }                                                                        \
}
#define CHECK_WRITE_STEP_SIGNAL2(addr, data, size) {                            \
    BOOL bFlag = isBitOn(data, size, addr);                                    \
    SERVO::CStep* pStep = getStep(addr);                                    \
    if (pStep != nullptr) {                                                    \
        ((CWriteStep*)pStep)->onRecvSignal(bFlag ? addr : 0);                \
    }                                                                        \
}
namespace SERVO {
    CLoadPort::CLoadPort() : CEquipment()
    {
@@ -867,12 +875,12 @@
        static int cassetteTypeReply[] = { STEP_ID_PROT1_CASSETTE_TYPE_CHANGE_REPLY, STEP_ID_PROT2_CASSETTE_TYPE_CHANGE_REPLY,
            STEP_ID_PROT3_CASSETTE_TYPE_CHANGE_REPLY, STEP_ID_PROT4_CASSETTE_TYPE_CHANGE_REPLY };
        CHECK_READ_STEP_SIGNAL2(typeReply[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(modeReply[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(transferModeReply[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(enableModeReply[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(typeAutoReply[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(cassetteTypeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(typeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(modeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(transferModeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(enableModeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(typeAutoReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(cassetteTypeReply[m_nIndex], pszData, size);
    }
    int CLoadPort::decodePortStatusReport(CStep* pStep, const char* pszData, size_t size)
SourceCode/Bond/Servo/CPageGraph2.cpp
@@ -265,14 +265,14 @@
        else if (nCmd == ID_EQSGRAPHITEM_TEST4) {
            SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
            if (pEquipment != nullptr) {
                pEquipment->setLinkSignal(0, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignal(0, SIGNAL_UPSTREAM_TROUBLE, FALSE);
                pEquipment->setLinkSignal(0, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignal(0, SIGNAL_SEND_ABLE, TRUE);
                pEquipment->setLinkSignal(1, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignal(1, SIGNAL_UPSTREAM_TROUBLE, FALSE);
                pEquipment->setLinkSignal(1, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignal(1, SIGNAL_SEND_ABLE, TRUE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_UPSTREAM_TROUBLE, FALSE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_SEND_ABLE, TRUE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_UPSTREAM_TROUBLE, FALSE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_SEND_ABLE, TRUE);
            }
            if (pEquipment != nullptr && (pEquipment->getID() == EQ_ID_Bonder1
@@ -288,14 +288,14 @@
        else if (nCmd == ID_EQSGRAPHITEM_TEST5) {
            SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
            if (pEquipment != nullptr) {
                pEquipment->setLinkSignal(0, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignal(0, SIGNAL_UPSTREAM_TROUBLE, TRUE);
                pEquipment->setLinkSignal(0, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignal(0, SIGNAL_SEND_ABLE, FALSE);
                pEquipment->setLinkSignal(1, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignal(1, SIGNAL_UPSTREAM_TROUBLE, TRUE);
                pEquipment->setLinkSignal(1, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignal(1, SIGNAL_SEND_ABLE, FALSE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_UPSTREAM_TROUBLE, TRUE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignalUpstream(0, SIGNAL_SEND_ABLE, FALSE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_UPSTREAM_INLINE, TRUE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_UPSTREAM_TROUBLE, TRUE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_INTERLOCK, TRUE);
                pEquipment->setLinkSignalUpstream(1, SIGNAL_SEND_ABLE, FALSE);
            }
        }
        else if (nCmd == ID_EQSGRAPHITEM_TEST6) {
@@ -379,7 +379,7 @@
            // 请求主配方列表
            if (pEquipment != nullptr) {
                pEquipment->masterRecipeListRequest(0);
                pEquipment->masterRecipeListRequest(0, nullptr);
            }            
        }
SourceCode/Bond/Servo/CPageLinkSignal.cpp
@@ -158,7 +158,7 @@
    for (int nRow = 0; nRow < 8; ++nRow) {
        for (int nCol = 0; nCol < 8; ++nCol) {
            BOOL bCurrentState = m_pEquipment->isLinkSignalOn(nRow, nCol);
            BOOL bCurrentState = m_pEquipment->isLinkSignalUpstreamOn(nRow, nCol);
            UpdateSignalState(nRow, nCol, bCurrentState);
        }
    }
SourceCode/Bond/Servo/CPagePortProperty.cpp
@@ -9,6 +9,9 @@
#include "MsgDlg.h"
#define DELAY_CLOSE        2000
// CPagePortProperty 对话框
IMPLEMENT_DYNAMIC(CPagePortProperty, CHMPropertyPage)
@@ -130,6 +133,7 @@
    // TODO: 在此处添加消息处理程序代码
}
int g_nMsgDlgShow = 0;
void CPagePortProperty::OnBnClickedCheckEnable()
{
    BOOL bCheck = ((CButton*)GetDlgItem(IDC_CHECK_ENABLE))->GetCheck() == BST_CHECKED;
@@ -137,6 +141,7 @@
    // enable port
    g_nMsgDlgShow = 0;
    CMsgDlg msgDlg("请等待", "正在操作,请等待...");
    ASSERT(m_pPort != nullptr);
@@ -146,28 +151,29 @@
        if (code == WOK) {
            LOGI("%s Port 成功.", bCheck ? _T("enable") : _T("disable"));
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("%s Port 成功."), bCheck ? _T("enable") : _T("disable"));
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_SUCCEED);
            msgDlg.SetTitle(_T("操作成功"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(0);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("%s Port 成功."), bCheck ? _T("enable") : _T("disable"));
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
        }
        else {
            LOGI("%s Port 失败,code:%d", bCheck ? _T("enable") : _T("disable"), code);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("%s Port 失败,code:%d"), bCheck ? _T("enable") : _T("disable"), code);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_ERROR);
            msgDlg.SetTitle(_T("操作失败"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(-1);
            
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("%s Port 失败,code:%d"), bCheck ? _T("enable") : _T("disable"), code);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
            // 还原控件状态
            EnableCtrls(!bCheck);
            ((CButton*)GetDlgItem(IDC_CHECK_ENABLE))->SetCheck(!bCheck ? BST_CHECKED : BST_UNCHECKED);
@@ -177,10 +183,12 @@
        });
    msgDlg.DoModal();
    g_nMsgDlgShow = 1;
}
void CPagePortProperty::OnCbnSelchangeComboPortType()
{
    g_nMsgDlgShow = 0;
    CMsgDlg msgDlg("请等待", "正在操作,请等待...");
    msgDlg.SetData((DWORD_PTR)this);
@@ -193,36 +201,40 @@
        if (code == WOK) {
            LOGI("设置Port Type(%d)成功.", index + 1);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Port Type(%d)成功"), index + 1);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_SUCCEED);
            msgDlg.SetTitle(_T("操作成功"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(0);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Port Type(%d)成功"), index + 1);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
        }
        else {
            LOGI("设置Port Type(%d)失败,code:%d", index + 1, code);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Port Type(%d)失败,code:%d"), index + 1, code);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_ERROR);
            msgDlg.SetTitle(_T("操作失败"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(-1);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Port Type(%d)失败,code:%d"), index + 1, code);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
        }
        return 0;
    });
    msgDlg.DoModal();
    g_nMsgDlgShow = 1;
}
void CPagePortProperty::OnCbnSelchangeComboPortMode()
{
    g_nMsgDlgShow = 0;
    CMsgDlg msgDlg("请等待", "正在操作,请等待...");
    msgDlg.SetData((DWORD_PTR)this);
@@ -235,126 +247,137 @@
        if (code == WOK) {
            LOGI("设置Port Mode(%d)成功.", index);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Port Mode(%d)成功"), index);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_SUCCEED);
            msgDlg.SetTitle(_T("操作成功"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(0);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Port Mode(%d)成功"), index);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
        }
        else {
            LOGI("设置Port Mode(%d)失败,code:%d", index, code);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Port Mode(%d)失败,code:%d"), index, code);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_ERROR);
            msgDlg.SetTitle(_T("操作失败"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(-1);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Port Mode(%d)失败,code:%d"), index, code);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
        }
        return 0;
        });
    msgDlg.DoModal();
    g_nMsgDlgShow = 1;
}
void CPagePortProperty::OnCbnSelchangeComboPortCassertType()
{
    g_nMsgDlgShow = 0;
    CMsgDlg msgDlg("请等待", "正在操作,请等待...");
    msgDlg.SetData((DWORD_PTR)this);
    ASSERT(m_pPort != nullptr);
    int index = ((CComboBox*)GetDlgItem(IDC_COMBO_PORT_CASSERT_TYPE))->GetCurSel();
    m_pPort->setPortMode(SERVO::PortMode(index + 1), [&](int code) -> int {
    m_pPort->setCassetteType(SERVO::CassetteType(index + 1), [&](int code) -> int {
        Sleep(100);
        CString strMsg;
        if (code == WOK) {
            LOGI("设置Cassette type(%d)成功.", index + 1);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Cassette type(%d)成功"), index + 1);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_SUCCEED);
            msgDlg.SetTitle(_T("操作成功"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(0);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Cassette type(%d)成功"), index + 1);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
        }
        else {
            LOGI("设置Cassette type(%d)失败,code:%d", index + 1, code);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Cassette type(%d)失败,code:%d"), index + 1, code);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_ERROR);
            msgDlg.SetTitle(_T("操作失败"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(-1);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Cassette type(%d)失败,code:%d"), index + 1, code);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
        }
        return 0;
        });
    msgDlg.DoModal();
    g_nMsgDlgShow = 1;
}
void CPagePortProperty::OnCbnSelchangeComboPortTransferMode()
{
    // TODO: 在此添加控件通知处理程序代码
    g_nMsgDlgShow = 0;
    CMsgDlg msgDlg("请等待", "正在操作,请等待...");
    msgDlg.SetData((DWORD_PTR)this);
    ASSERT(m_pPort != nullptr);
    int index = ((CComboBox*)GetDlgItem(IDC_COMBO_PORT_TRANSFER_MODE))->GetCurSel();
    m_pPort->setPortMode(SERVO::PortMode(index + 1), [&](int code) -> int {
    m_pPort->setTransferMode(SERVO::TransferMode(index + 1), [&](int code) -> int {
        Sleep(100);
        CString strMsg;
        if (code == WOK) {
            LOGI("设置Transfer mode(%d)成功.", index + 1);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Transfer mode(%d)成功"), index + 1);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_SUCCEED);
            msgDlg.SetTitle(_T("操作成功"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(0);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Transfer mode(%d)成功"), index + 1);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
        }
        else {
            LOGI("设置Transfer mode(%d)失败,code:%d", index + 1, code);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("设置Transfer mode(%d)失败,code:%d"), index + 1, code);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_ERROR);
            msgDlg.SetTitle(_T("操作失败"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(-1);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("设置Transfer mode(%d)失败,code:%d"), index + 1, code);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
        }
        return 0;
        });
    msgDlg.DoModal();
    g_nMsgDlgShow = 1;
}
void CPagePortProperty::OnBnClickedCheckAutoChange()
{
    BOOL bCheck = ((CButton*)GetDlgItem(IDC_CHECK_AUTO_CHANGE))->GetCheck() == BST_CHECKED;
    EnableCtrls(bCheck);
    // enable port
    g_nMsgDlgShow = 0;
    CMsgDlg msgDlg("请等待", "正在操作,请等待...");
    ASSERT(m_pPort != nullptr);
@@ -365,26 +388,28 @@
        if (code == WOK) {
            LOGI("%s Auto Change 成功.", bCheck ? _T("enable") : _T("disable"));
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("%s Auto Change 成功."), bCheck ? _T("enable") : _T("disable"));
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_SUCCEED);
            msgDlg.SetTitle(_T("操作成功"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(0);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("%s Auto Change 成功."), bCheck ? _T("enable") : _T("disable"));
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
        }
        else {
            LOGI("%s Auto Change 失败,code:%d", bCheck ? _T("enable") : _T("disable"), code);
            msgDlg.DelayClose(3000);
            strMsg.Format(_T("%s Auto Change 失败,code:%d"), bCheck ? _T("enable") : _T("disable"), code);
            msgDlg.DelayClose(3000);
            msgDlg.SetIcon(MSG_BOX_ERROR);
            msgDlg.SetTitle(_T("操作失败"));
            msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
            msgDlg.SetMarquee(FALSE, 0);
            msgDlg.SetCompleteCode(-1);
            if (g_nMsgDlgShow == 0 && ::IsWindow(msgDlg.GetSafeHwnd())) {
                strMsg.Format(_T("%s Auto Change 失败,code:%d"), bCheck ? _T("enable") : _T("disable"), code);
                msgDlg.DelayClose(DELAY_CLOSE);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
            // 还原控件状态
            ((CButton*)GetDlgItem(IDC_CHECK_AUTO_CHANGE))->SetCheck(!bCheck ? BST_CHECKED : BST_UNCHECKED);
@@ -394,6 +419,7 @@
        });
    msgDlg.DoModal();
    g_nMsgDlgShow = 1;
}
void CPagePortProperty::EnableCtrls(BOOL bEnable)
SourceCode/Bond/Servo/CRecipeList.cpp
@@ -33,6 +33,9 @@
            reset();
            return MRLRC_GROUP_COUNT_NG;
        }
        if (currentGroup == 0) {
            reset();
        }
        if (m_nCurrentGroupCount + 1 > currentGroup) {
            return MRLRC_DUPLICATION_GROUP_COUNT_NG;
        }
SourceCode/Bond/Servo/CRecipesManager.cpp
@@ -20,6 +20,7 @@
        m_hWorkStop = nullptr;
        m_hWorkThreadHandle = nullptr;
        m_nTimeoutCount = 0;
        m_onSyncingStateChanged = nullptr;
        ::InitializeCriticalSection(&m_cs);
    }
@@ -62,6 +63,9 @@
        m_nTimeoutCount = 0;
        unlock();
        if (m_onSyncingStateChanged != nullptr) {
            m_onSyncingStateChanged(m_nSyncStatus);
        }
        if (m_hWorkStop == nullptr) {
            m_hWorkStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -78,6 +82,11 @@
        m_nSyncStatus = SS_FAILED;
        m_nTimeoutCount = 0;
        unlock();
        if (m_onSyncingStateChanged != nullptr) {
            m_onSyncingStateChanged(m_nSyncStatus);
        }
    }
    short CRecipesManager::decodeRecipeListReport(const char* pszData, size_t size)
@@ -144,17 +153,19 @@
            int nRet = pRecipeList->addRecipePacket(toatlGroupCount, currentGroupCount, pszIdsData, 250 * 2);
            if (MRLRC_CURRENT_RECIPE_COMPLETE == nRet) {
                lock();
                if (m_nTotalMasterRecipeCount == m_mapRecipesTemp.size()) {
                    for (auto item : m_mapRecipes) {
                        delete item.second;
                    }
                    m_mapRecipes = m_mapRecipesTemp;
                    m_mapRecipesTemp.clear();
                    m_nSyncStatus = SS_COMPLETE;
                    unlock();
                    return MRLRC_OK;
                for (auto item : m_mapRecipes) {
                    delete item.second;
                }
                m_mapRecipes = m_mapRecipesTemp;
                m_mapRecipesTemp.clear();
                m_nSyncStatus = SS_COMPLETE;
                unlock();
                if (m_onSyncingStateChanged != nullptr) {
                    m_onSyncingStateChanged(m_nSyncStatus);
                }
                return MRLRC_OK;
            }
            else if (MRLRC_CONTINUE == nRet) {
                return MRLRC_CONTINUE;
@@ -268,6 +279,18 @@
        return iter->second;
    }
    CRecipeList* CRecipesManager::getRecipeList(int unitNo)
    {
        auto iter = m_mapRecipes.find(unitNo);
        if (iter == m_mapRecipes.end()) return nullptr;
        return iter->second;
    }
    void CRecipesManager::setOnSyncingStateChanged(ONSYNCINGSTATECHANGED block)
    {
        m_onSyncingStateChanged = block;
    }
    unsigned CRecipesManager::TimeoutCheckWorkingProc()
    {
        while (1) {
SourceCode/Bond/Servo/CRecipesManager.h
@@ -1,6 +1,7 @@
#pragma once
#include <map>
#include "CRecipeList.h"
#include <functional>
#define SS_NONE                    0
@@ -10,6 +11,8 @@
#define SS_FAILED                4
namespace SERVO {
    typedef std::function<void(int state)> ONSYNCINGSTATECHANGED;
    class CRecipesManager
    {
    public:
@@ -17,12 +20,14 @@
        virtual ~CRecipesManager();
    public:
        void setOnSyncingStateChanged(ONSYNCINGSTATECHANGED block);
        unsigned TimeoutCheckWorkingProc();
        int syncing();
        void syncFailed();
        short decodeRecipeListReport(const char* pszData, size_t size);
        short decodeRecipeParameterReport(const char* pszData, size_t size);
        CRecipeList* getRecipeListFromTemp(int unitNo);
        CRecipeList* getRecipeList(int unitNo);
    public:
        inline void lock() { ::EnterCriticalSection(&m_cs); };
@@ -39,6 +44,7 @@
        int m_nTotalParameterCount;
        std::map<int, CRecipeList*> m_mapRecipes;
        std::map<int, CRecipeList*> m_mapRecipesTemp;
        ONSYNCINGSTATECHANGED m_onSyncingStateChanged;
    };
}
SourceCode/Bond/Servo/LogEdit.cpp
@@ -8,7 +8,9 @@
CLogEdit::CLogEdit()
{
    m_nMaxLineCount = 0xffff;
    m_nMaxLines = 0xffff;
    m_nTrimLines = 100;
    m_bAutoScroll = TRUE;
}
@@ -18,11 +20,13 @@
BEGIN_MESSAGE_MAP(CLogEdit, CEdit)
    ON_WM_CONTEXTMENU()
    ON_WM_VSCROLL()
END_MESSAGE_MAP()
void CLogEdit::SetMaxLineCount(int line)
{
    m_nMaxLineCount = line;
    m_nMaxLines = line;
    m_nTrimLines = min(m_nMaxLines, 100);
}
void CLogEdit::OnContextMenu(CWnd* pWnd, CPoint point)
@@ -49,39 +53,47 @@
    }
}
void CLogEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // 每次滚动时检查是否还在底部
    m_bAutoScroll = IsScrollBarAtBottom();
    CEdit::OnVScroll(nSBCode, nPos, pScrollBar);
}
BOOL CLogEdit::IsScrollBarAtBottom()
{
    SCROLLINFO si = { sizeof(si), SIF_ALL };
    GetScrollInfo(SB_VERT, &si);
    return (si.nPos + (int)si.nPage >= si.nMax);
}
void CLogEdit::AppendText(const char* pszText)
{
    // 获取选择范围以便恢复
    int nStart, nEnd;
    GetSel(nStart, nEnd);
    SetRedraw(FALSE);
    // 裁剪逻辑
    int totalLines = GetLineCount();
    if (totalLines > m_nMaxLines) {
        // 获取要删除的字符范围
        int startChar = LineIndex(0);            // 第0行首字符位置
        int endChar = LineIndex(m_nTrimLines);    // 第N行首字符位置
    // 超过指定行数则删除最前面的行
    int nLineCount = GetLineCount();
    while (nLineCount > m_nMaxLineCount) {
        int nLin1End = LineIndex(1);
        nStart -= nLin1End;
        if (nStart < 0) nStart = 0;
        nEnd -= nLin1End;
        if (nEnd < 0) nEnd = 0;
        SetSel(0, nLin1End);
        ReplaceSel(_T(""));
        nLineCount = GetLineCount();
        if (startChar >= 0 && endChar > startChar) {
            SetSel(startChar, endChar);
            ReplaceSel(_T("")); // 删除前面行
        }
    }
    // 追加到最后
    int length = GetWindowTextLength();
    SetSel(length, length);
    int len = GetWindowTextLength();
    SetSel(len, len);
    ReplaceSel(pszText);
    PostMessage(WM_VSCROLL, SB_BOTTOM, 0);
    // 恢复
    if (nStart == 0 && nEnd == 0) {
        nStart = GetWindowTextLength();
        nEnd = nStart;
    if (m_bAutoScroll) {
        LineScroll(GetLineCount());
    }
    SetSel(nStart, nEnd);
}
    SetRedraw(TRUE);
    Invalidate();
    UpdateWindow();
}
SourceCode/Bond/Servo/LogEdit.h
@@ -10,12 +10,15 @@
public:
    void SetMaxLineCount(int line);
    void AppendText(const char* pszText);
    BOOL IsScrollBarAtBottom();
private:
    int m_nMaxLineCount;
    int m_nMaxLines;
    int m_nTrimLines;
    BOOL m_bAutoScroll;        // 是否自动滚动
    DECLARE_MESSAGE_MAP()
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
};
SourceCode/Bond/Servo/MsgDlg.cpp
@@ -22,6 +22,7 @@
    m_crTitle = CR_MSGBOX_TITLE;
    m_crMessage = CR_MSGBOX_MESSAGE;
    m_nIcon = MSG_BOX_TIP;
    m_bDelayClose = FALSE;
}
CMsgDlg::CMsgDlg(CString strTitle, CString strMessage)
@@ -169,7 +170,10 @@
void CMsgDlg::DelayClose(int nDelay)
{
    SetTimer(1, nDelay, NULL);
    if (!m_bDelayClose) {
        m_bDelayClose = TRUE;
        SetTimer(1, nDelay, NULL);
    }
}
void CMsgDlg::ShowCloseButton(BOOL bVisible)
SourceCode/Bond/Servo/MsgDlg.h
@@ -52,6 +52,7 @@
    int m_nCompleteCode;
    DWORD_PTR m_dwData;
    DWORD_PTR m_dwDataEx;
    BOOL m_bDelayClose;
// 对话框数据
SourceCode/Bond/Servo/PageRecipe.cpp
@@ -5,6 +5,8 @@
#include "Servo.h"
#include "afxdialogex.h"
#include "PageRecipe.h"
#include "MsgDlg.h"
// CPageRecipe 对话框
@@ -22,7 +24,7 @@
void CPageRecipe::FillDataToListCtrl(const std::vector<RecipeInfo>& vecRecipe) {
    CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID);
    if (pListCtrl == nullptr || pListCtrl->m_hWnd == nullptr) {
    if (pListCtrl == nullptr || !::IsWindow(pListCtrl->m_hWnd)) {
        return;
    }
@@ -49,6 +51,33 @@
    m_listPPID.SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER);
}
void CPageRecipe::FillRecipeListToListCtrl(SERVO::CRecipeList* pList)
{
    CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID);
    if (pListCtrl == nullptr || !::IsWindow(pListCtrl->m_hWnd)) {
        return;
    }
    // 清空当前CListCtrl中的所有项
    pListCtrl->DeleteAllItems();
    if (pList == nullptr) {
        return;
    }
    // 遍历数据并插入到CListCtrl中
    std::map<int, short>& ids = pList->getIds();
    for (auto item : ids) {
        int index = m_listPPID.InsertItem(m_listPPID.GetItemCount(), _T(""));
        m_listPPID.SetItemText(index, 1, std::to_string(item.first).c_str());
        m_listPPID.SetItemText(index, 2, std::to_string(item.second).c_str());
    }
    // 获取列数
    int nColCount = m_listPPID.GetHeaderCtrl()->GetItemCount();
    m_listPPID.SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER);
}
void CPageRecipe::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
@@ -65,6 +94,8 @@
    ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CPageRecipe::OnBnClickedButtonRefresh)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_PPID, &CPageRecipe::OnLvnItemChangedListPPID)
    ON_WM_DESTROY()
    ON_CBN_SELCHANGE(IDC_COMBO_EQUIPMENT, &CPageRecipe::OnCbnSelchangeComboEquipment)
    ON_WM_SHOWWINDOW()
END_MESSAGE_MAP()
@@ -95,10 +126,11 @@
    ListView_SetImageList(pListCtrl->GetSafeHwnd(), imageList, LVSIL_SMALL);
    pListCtrl->InsertColumn(0, _T(""), LVCFMT_RIGHT, 0); // 隐藏列
    pListCtrl->InsertColumn(1, _T("No."), LVCFMT_LEFT, width[1]);
    pListCtrl->InsertColumn(2, _T("PPID"), LVCFMT_LEFT, width[2]);
    pListCtrl->InsertColumn(2, _T("PPID/Recipe ID"), LVCFMT_LEFT, width[2]);
    pListCtrl->InsertColumn(3, _T("描述"), LVCFMT_LEFT, width[3]);
    pListCtrl->InsertColumn(4, _T("创建时间"), LVCFMT_LEFT, width[4]);
    pListCtrl->SetColumnWidth(4, LVSCW_AUTOSIZE_USEHEADER);
    // 获取所有数据
    auto vecData = RecipeManager::getInstance().getAllRecipes();
@@ -139,10 +171,10 @@
    // 按钮竖直排列在右侧
    CWnd* buttons[] = {
        GetDlgItem(IDC_BUTTON_MODIFY),
        GetDlgItem(IDC_BUTTON_REFRESH),
        GetDlgItem(IDC_BUTTON_DELETE),
        GetDlgItem(IDC_BUTTON_DELETE_ALL),
        GetDlgItem(IDC_BUTTON_REFRESH)
        GetDlgItem(IDC_BUTTON_MODIFY)
    };
    for (auto pBtn : buttons) {
@@ -272,9 +304,42 @@
void CPageRecipe::OnBnClickedButtonRefresh()
{
    // TODO: 在此添加控件通知处理程序代码
    auto vecData = RecipeManager::getInstance().getAllRecipes();
    FillDataToListCtrl(vecData);
    CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
    int nSel = pComboBox->GetCurSel();
    SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel);
    if (pEq == nullptr) {
        // 获取master配方(本地)
        auto vecData = RecipeManager::getInstance().getAllRecipes();
        FillDataToListCtrl(vecData);
    }
    else {
        // enable port
        CMsgDlg msgDlg("请等待", "正在获取配方...");
        pEq->masterRecipeListRequest(0, [&](int status) -> void {
            if (status == SS_FAILED) {
                CString strMsg;
                strMsg.Format(_T("获取配方失败!"));
                msgDlg.DelayClose(3000);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
            else if (status == SS_COMPLETE) {
                CString strMsg;
                strMsg.Format(_T("获取配方完成!"));
                msgDlg.DelayClose(3000);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
            }
            });
        msgDlg.DoModal();
    }
}
void CPageRecipe::OnLvnItemChangedListPPID(NMHDR* pNMHDR, LRESULT* pResult)
@@ -282,11 +347,41 @@
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    *pResult = 0;
    CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
    int nEqSel = pComboBox->GetCurSel();
    int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd());
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(selectedCount > 0);
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0);
}
void CPageRecipe::OnCbnSelchangeComboEquipment()
{
    CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
    int nEqSel = pComboBox->GetCurSel();
    int selectedCount = ListView_GetSelectedCount(m_listPPID.GetSafeHwnd());
    GetDlgItem(IDC_BUTTON_MODIFY)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_BUTTON_DELETE_ALL)->EnableWindow(nEqSel == 0 && selectedCount > 0);
    GetDlgItem(IDC_EDIT_KEYWORD)->EnableWindow(nEqSel == 0);
    GetDlgItem(IDC_BUTTON_SEARCH)->EnableWindow(nEqSel == 0);
    SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nEqSel);
    if (pEq == nullptr) {
        auto vecData = RecipeManager::getInstance().getAllRecipes();
        FillDataToListCtrl(vecData);
    }
    else {
        SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
        FillRecipeListToListCtrl(pRecipeList);
    }
}
void CPageRecipe::OnDestroy()
{
@@ -304,3 +399,33 @@
        WritePrivateProfileString("PageRecipeListCtrl", strItem, strTemp, strIniFile);
    }
}
void CPageRecipe::OnShowWindow(BOOL bShow, UINT nStatus)
{
    CDialogEx::OnShowWindow(bShow, nStatus);
    if (bShow) {
        CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
        if (pComboBox->GetCount() == 0) {
            SERVO::CMaster& master = theApp.m_model.getMaster();
            SERVO::CEquipment* pEq[] = {
                nullptr,
                master.getEquipment(EQ_ID_EFEM),
                master.getEquipment(EQ_ID_Bonder1),
                master.getEquipment(EQ_ID_Bonder2),
                master.getEquipment(EQ_ID_BAKE_COOLING),
                master.getEquipment(EQ_ID_VACUUMBAKE),
                master.getEquipment(EQ_ID_MEASUREMENT),
            };
            CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
            for (int i = 0; i < sizeof(pEq) / sizeof(pEq[0]); i++) {
                pComboBox->InsertString(i,
                    pEq[i] == nullptr ? _T("Master") : pEq[i]->getName().c_str());
                pComboBox->SetItemDataPtr(i, pEq[i]);
            }
            pComboBox->SetCurSel(0);
        }
    }
}
SourceCode/Bond/Servo/PageRecipe.h
@@ -14,6 +14,7 @@
private:
    void FillDataToListCtrl(const std::vector<RecipeInfo>& vecRecipe);
    void FillRecipeListToListCtrl(SERVO::CRecipeList* pList);
// 对话框数据
#ifdef AFX_DESIGN_TIME
@@ -36,4 +37,6 @@
    CListCtrl m_listPPID;
public:
    afx_msg void OnDestroy();
    afx_msg void OnCbnSelchangeComboEquipment();
    afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
};
SourceCode/Bond/Servo/Servo.rc
Binary files differ
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -898,8 +898,12 @@
        dlg.DoModal();
    }
    else if (id == IDC_BUTTON_SETTINGS) {
        SERVO::CEFEM* pEFEM = (SERVO::CEFEM*)theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
        pEFEM->printDebugString001();
        SERVO::CEquipment* pEq = theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
        pEq->printDebugString001();
        pEq = theApp.m_model.m_master.getEquipment(EQ_ID_Bonder1);
        pEq->printDebugString001();
        pEq = theApp.m_model.m_master.getEquipment(EQ_ID_Bonder2);
        pEq->printDebugString001();
    }
    else if (id == IDC_BUTTON_OPERATOR) {
        int menuId = (int)wParam;
SourceCode/Bond/Servo/resource.h
Binary files differ