已修改21个文件
502 ■■■■ 文件已修改
SourceCode/Bond/Servo/BlButton.cpp 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/BlButton.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBakeCooling.cpp 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBakeCooling.h 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBonder.cpp 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMeasurement.cpp 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRobotTask.cpp 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CVacuumBake.cpp 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Configuration.cpp 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Configuration.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogEdit.cpp 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogEdit.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageLog.cpp 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageLog.h 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Res/logcat_include.ico 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/BlButton.cpp
@@ -36,6 +36,7 @@
    m_hIcon[1] = nullptr;
    m_nIconWidth = 0;
    m_nFlashState = 0;
    m_bTextRight = FALSE;
}
@@ -159,6 +160,11 @@
    return m_nFlashState != 0;
}
void CBlButton::SetTextRight()
{
    m_bTextRight = TRUE;
}
void CBlButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    HDC hDC = lpDrawItemStruct->hDC;
@@ -200,15 +206,24 @@
    HICON hIcon = this->IsWindowEnabled() ? m_hIcon[0] : m_hIcon[01];
    if (hIcon != nullptr) {
        int xIcon = (rcClient.right - rcClient.top - m_nIconWidth) / 2;
        if (m_bTextRight) {
            xIcon = 15;
        }
        if (m_hMenu != nullptr) xIcon -= 10;
        int yIcon = (rcClient.bottom - rcClient.top - m_nIconWidth) / 2;
        if (nTextLen != 0) {
        if (nTextLen != 0 && !m_bTextRight) {
            yIcon -= 8;
        }
        DrawIconEx(hDC, xIcon, yIcon,
            hIcon, m_nIconWidth, m_nIconWidth, 0, 0, DI_NORMAL);
        rcText.top = yIcon + m_nIconWidth + 2;
        if (m_bTextRight) {
            rcText.left = xIcon + m_nIconWidth + 2;
        }
        else {
            rcText.top = yIcon + m_nIconWidth + 2;
        }
    }
@@ -223,18 +238,19 @@
    ::SetBkMode(hDC, TRANSPARENT);
    ::SetTextColor(hDC, m_crText[state]);
    UINT format1 = m_bTextRight ? DT_LEFT : DT_CENTER;
    if ((BS_MULTILINE & GetStyle()) == BS_MULTILINE) {
        CRect rcBound;
        int height = DrawTextA(hDC, szText, (int)strlen(szText), &rcBound,  DT_CENTER | DT_CALCRECT | DT_EDITCONTROL);
        rcText.top = rcBound.top + (rcClient.bottom - rcClient.top - height) / 2;
        rcText.bottom = rcText.top + height;
        DrawTextA(hDC, szText, (int)strlen(szText), &rcText,  DT_CENTER | DT_EDITCONTROL);
        DrawTextA(hDC, szText, (int)strlen(szText), &rcText, format1 | DT_EDITCONTROL);
    }
    else {
        if (m_hMenu != nullptr) {
            rcText.right -= (10);
        }
        DrawTextA(hDC, szText, (int)strlen(szText), &rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
        DrawTextA(hDC, szText, (int)strlen(szText), &rcText, format1 | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
    }
    ::SelectObject(hDC, hOldFont);
SourceCode/Bond/Servo/BlButton.h
@@ -53,6 +53,7 @@
    void Flash(int ms);
    void StopFlash();
    BOOL IsFlash();
    void SetTextRight();
private:
    BOOL CustomBitBlt(HDC hDC, LPRECT lprc, CString& strBkgndBmp, int nFrame, int nAllFrame,
@@ -78,6 +79,7 @@
    HICON m_hIcon[2];
    int m_nIconWidth;
    int m_nFlashState;        // 闪烁状态,0:不闪;1和2为闪烁切换中
    BOOL m_bTextRight;
public:
    virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
SourceCode/Bond/Servo/CBakeCooling.cpp
@@ -239,7 +239,7 @@
        {
            // Received Job Report Upstream #1~9
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 4; i++) {
                CEqReadStep* pStep = new CEqReadStep(0x10c90 + 320 * i, 320 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
@@ -263,13 +263,13 @@
        {
            // Sent Out Job Report Downstream #1~9
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 4; i++) {
                CEqReadStep* pStep = new CEqReadStep(0x10000 + 320 * i, 320 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
                            int port = (int)(__int64)((CEqReadStep*)pFrom)->getProp("Port");
                            if (port > 0) {
                                decodeReceivedJobReport((CStep*)pFrom, port, pszData, size);
                                decodeSentOutJobReport((CStep*)pFrom, port, pszData, size);
                            }
                        }
                        return -1;
@@ -287,7 +287,7 @@
        {
            // Fetched Out Job Report #1~15
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 4; i++) {
                CEqReadStep* pStep = new CEqReadStep(0x11c31 + 18 * i, 18 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
@@ -311,7 +311,7 @@
        {
            // Stored Job Report #1~15
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 4; i++) {
                CEqReadStep* pStep = new CEqReadStep(0x11b23 + 18 * i, 18 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
@@ -331,6 +331,38 @@
                }
            }
        }
        // process start/end report
        {
            CEqReadStep* pStep = new CEqReadStep(0x11D3F, 13 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodeJobProcessStartReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_JOB_PROCESS_START_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0x933);
            if (addStep(STEP_ID_JOB_PROCESS_START_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        {
            CEqReadStep* pStep = new CEqReadStep(0x11D4C, 13 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodeJobProcessEndReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_JOB_PROCESS_END_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0x934);
            if (addStep(STEP_ID_JOB_PROCESS_END_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
    }
    // 必须要实现的虚函数,在此初始化Slot信息
@@ -344,18 +376,18 @@
        m_slot[1].enable();
        m_slot[1].setPosition(m_nID);
        m_slot[1].setNo(2);
        m_slot[1].setName("Bake 2");
        m_slot[1].setLinkSignalPath(0);
        m_slot[1].setName("Cooling 1");
        m_slot[1].setLinkSignalPath(1);
        m_slot[2].enable();
        m_slot[2].setPosition(m_nID);
        m_slot[2].setNo(3);
        m_slot[2].setName("Cooling 1");
        m_slot[2].setLinkSignalPath(1);
        m_slot[2].setName("Bake 2");
        m_slot[2].setLinkSignalPath(2);
        m_slot[3].enable();
        m_slot[3].setPosition(m_nID);
        m_slot[3].setNo(4);
        m_slot[3].setName("Cooling 2");
        m_slot[3].setLinkSignalPath(1);
        m_slot[3].setLinkSignalPath(3);
    }
    void CBakeCooling::onTimer(UINT nTimerid)
@@ -382,4 +414,11 @@
    {
        return 25000;
    }
    bool CBakeCooling::isSlotProcessed(int slot)
    {
        CGlass* pGlass = getGlassFromSlot(slot);
        if (pGlass == nullptr) return false;
        return pGlass->isProcessed(m_nID, getSlotUnit(slot));
    }
}
SourceCode/Bond/Servo/CBakeCooling.h
@@ -22,7 +22,8 @@
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
        virtual int getIndexerOperationModeBaseValue();
        virtual short getSlotUnit(short slot) { return slot <= 2 ? 0 : 1; };
        virtual short getSlotUnit(short slotNo) { return slotNo % 2 == 1 ? 0 : 1; };
        virtual bool isSlotProcessed(int slot);
    };
}
SourceCode/Bond/Servo/CBonder.cpp
@@ -244,7 +244,7 @@
        {
            // Received Job Report Upstream #1~9
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 2; i++) {
                CEqReadStep* pStep = new CEqReadStep((m_nIndex == 0 ? 0x8c90 : 0xcc90) + 320 * i, 320 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
@@ -267,13 +267,13 @@
        {
            // Sent Out Job Report Downstream #1~9
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 2; i++) {
                CEqReadStep* pStep = new CEqReadStep((m_nIndex == 0 ? 0x8000 : 0xc000) + 320 * i, 320 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
                            int port = (int)(__int64)((CEqReadStep*)pFrom)->getProp("Port");
                            if (port > 0) {
                                decodeReceivedJobReport((CStep*)pFrom, port, pszData, size);
                                decodeSentOutJobReport((CStep*)pFrom, port, pszData, size);
                            }
                        }
                        return -1;
@@ -291,7 +291,7 @@
        {
            // Fetched Out Job Report #1~15
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 2; i++) {
                CEqReadStep* pStep = new CEqReadStep((m_nIndex == 0 ? 0x9c31 : 0xdc31) + 18 * i, 18 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
@@ -315,7 +315,7 @@
        {
            // Stored Job Report #1~15
            char szBuffer[256];
            for (int i = 0; i < 1; i++) {
            for (int i = 0; i < 2; i++) {
                CEqReadStep* pStep = new CEqReadStep((m_nIndex == 0 ? 0x9b23 : 0xdb23) + 18 * i, 18 * 2,
                    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                        if (code == ROK && pszData != nullptr && size > 0) {
@@ -422,11 +422,13 @@
        m_slot[0].setPosition(m_nID);
        m_slot[0].setNo(1);
        m_slot[0].setName("Slot 1(G2)");
        m_slot[0].setLinkSignalPath(0);
        m_slot[0].setType(MaterialsType::G2);
        m_slot[1].enable();
        m_slot[1].setPosition(m_nID);
        m_slot[1].setNo(2);
        m_slot[1].setName("Slot 2(G1)");
        m_slot[1].setLinkSignalPath(1);
        m_slot[1].setType(MaterialsType::G1);
    }
SourceCode/Bond/Servo/CEquipment.cpp
@@ -406,10 +406,12 @@
            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_bLinkSignalToUpstream[i][SIGNAL_SEND_ABLE]) {
                onSendAble(i+1);
            }
        }         
        if(m_bLinkSignalToUpstream[0][SIGNAL_SEND_ABLE]) {
            onSendAble();
        }
        index += 0x40 * 2;
        for (int i = 0; i < 8; i++) {
@@ -418,10 +420,12 @@
            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(i + 1);
            }
        }
        if (m_bLinkSignalToDownstream[0][SIGNAL_RECEIVE_ABLE]) {
            onReceiveAble();
        }
        // 其它信号及响应
        index = 0x540;
@@ -836,7 +840,7 @@
        return 0;
    }
    int CEquipment::fetchedOutJob(CJobDataB* pJobDataB)
    int CEquipment::fetchedOutJob(int port, CJobDataB* pJobDataB)
    {
        if (m_pArm == nullptr) {
            return -1;
@@ -859,7 +863,6 @@
            return -3;
        }
        ((CArm*)m_pArm)->tempStore(pContext);
        pContext->release();
        Unlock();
@@ -876,7 +879,7 @@
        return 0;
    }
    int CEquipment::storedJob(CJobDataB* pJobDataB, short putSlot)
    int CEquipment::storedJob(int port, CJobDataB* pJobDataB, short putSlot)
    {
        if (m_pArm == nullptr) {
            return -1;
@@ -902,7 +905,7 @@
        if (m_listener.onDataChanged != nullptr) {
            m_listener.onDataChanged(this, EDCC_STORED_JOB);
        }
        return 0;
    }
@@ -950,7 +953,6 @@
    CGlass* CEquipment::getGlassWithCassette(int cassetteSequenceNo, int jobSequenceNo)
    {
        CSlot* pSlot = nullptr;
        for (int i = 0; i < SLOT_MAX; i++) {
            if (!m_slot[i].isEnable()) continue;
            CGlass* pGlass = (CGlass*)m_slot[i].getContext();
@@ -1304,6 +1306,7 @@
            if (!m_slot[i].isEnable()) continue;
            if (m_slot[i].isLock()) continue;
            CGlass* pGlass = (CGlass*)m_slot[i].getContext();
            if (!isSlotProcessed(i)) continue;
            if (pGlass == nullptr) continue;
            int lsPath = m_slot[i].getLinkSignalPath();
            if(!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
@@ -1330,6 +1333,7 @@
                    if (m_slot[i].isLock()) continue;
                    CGlass* pGlass = (CGlass*)m_slot[i].getContext();
                    if (pGlass == nullptr) continue;
                    if (!isSlotProcessed(i+1)) continue;
                    int lsPath = m_slot[i].getLinkSignalPath();
                    if (!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
                        || m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
@@ -1434,6 +1438,17 @@
    int CEquipment::onReceivedJob(int port, CJobDataS* pJobDataS)
    {
        LOGI("<CEquipment-%s>onReceivedJob.", m_strName.c_str());
        // 可以在此更新JobDataS数据了
        CGlass* pGlass = getGlassFromSlot(port);
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>onSentOutJob,没有找到对应的Glass(CassetteSequenceNo:%d, JobSequenceNo:%d, ID=%s),请检查数据,注意风险。",
                m_strName.c_str(), pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo(),
                pJobDataS->getGlass1Id().c_str());
            return -1;
        }
        pGlass->updateJobDataS(pJobDataS);
        return 0;
    }
@@ -1455,17 +1470,6 @@
    int CEquipment::onSentOutJob(int port, CJobDataS* pJobDataS)
    {
        LOGI("<CEquipment-%s>onSentOutJob.", m_strName.c_str());
        // 可以在此更新JobDataS数据了
        CGlass* pGlass = getGlass(pJobDataS->getGlass1Id().c_str());
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>onSentOutJob,没有找到对应的Glass(CassetteSequenceNo:%d, JobSequenceNo:%d, ID=%s),请检查数据,注意风险。",
                m_strName.c_str(), pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo(),
                pJobDataS->getGlass1Id().c_str());
            return -1;
        }
        pGlass->updateJobDataS(pJobDataS);
        return 0;
    }
@@ -1517,7 +1521,7 @@
        LOGI("<CEquipment-%s>onPreFetchedOutJob:port:%d|GlassId:%s",
            m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
        if (m_listener.onPreFethedOutJob != nullptr) {
            return m_listener.onPreFethedOutJob(this, pJobDataB);
            return m_listener.onPreFethedOutJob(this, port, pJobDataB);
        }
        return TRUE;
@@ -1530,7 +1534,7 @@
        BOOL bCheck = onPreFetchedOutJob(port, pJobDataB);
        if (bCheck) {
            return fetchedOutJob(pJobDataB);
            return fetchedOutJob(port, pJobDataB);
        }
        // 数据异常,处理或显示
@@ -1678,7 +1682,9 @@
    int CEquipment::decodeJobProcessStartReport(CStep* pStep, const char* pszData, size_t size)
    {
        LOGI("<CEquipment-%s>decodeJobProcessStartReport", getName().c_str());
        int port = (int)(__int64)pStep->getProp("Port");
        LOGI("<CEquipment-%s>decodeJobProcessStartReport, port:%d", getName().c_str(), port);
        short cassetteNo, jobSequenceNo, unitNo, subUnitNo, slotNo;
        int year, month, day, hour, minute, second;
@@ -1718,6 +1724,10 @@
            );
        if (m_processState != PROCESS_STATE::Processing) {
            setProcessState(PROCESS_STATE::Processing);
        }
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
@@ -1740,7 +1750,8 @@
    int CEquipment::decodeJobProcessEndReport(CStep* pStep, const char* pszData, size_t size)
    {
        LOGI("<CEquipment-%s>decodeJobProcessEndReport", getName().c_str());
        int port = (int)(__int64)pStep->getProp("Port");
        LOGI("<CEquipment-%s>decodeJobProcessEndReport, port:%d", getName().c_str(), port);
        short cassetteNo, jobSequenceNo, unitNo, subUnitNo, slotNo;
        int year, month, day, hour, minute, second;
@@ -1782,6 +1793,32 @@
        );
        if (m_processState != PROCESS_STATE::Complete) {
            setProcessState(PROCESS_STATE::Complete);
        }
        CGlass* pGlass = getGlassFromSlot(slotNo);
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>decodeJobProcessEndReport, 找不到对应glass", getName().c_str());
        }
        else {
            CJobDataS* pJs = pGlass->getJobDataS();
            if (pJs->getCassetteSequenceNo() == cassetteNo
                && pJs->getJobSequenceNo() == jobSequenceNo) {
                pGlass->processEnd(m_nID, getSlotUnit(slotNo));
                if (m_processState != PROCESS_STATE::Complete) {
                    setProcessState(PROCESS_STATE::Complete);
                }
            }
            else {
                LOGE("<CEquipment-%s>decodeJobProcessEndReport, jobSequenceNo或jobSequenceNo不匹配",
                    getName().c_str());
            }
        }
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("CassetteNo",
@@ -1817,7 +1854,7 @@
        CJobDataS* pJobDataS = pGlass->getJobDataS();
        ASSERT(pJobDataS);
        if (!compareJobData(pJobDataB, pJobDataS)) {
            LOGE("<CEquipemnt-%s>onPreFetchedOutJob,JobData数据不匹配(JobDataB(%d, %d),JobDataS(%d, %d)), 注意排查风险!", m_strName.c_str(),
            LOGE("<CEquipemnt-%s>onPreStoredJob,JobData数据不匹配(JobDataB(%d, %d),JobDataS(%d, %d)), 注意排查风险!", m_strName.c_str(),
                pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo(),
                pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo());
            return FALSE;
@@ -1825,17 +1862,18 @@
        // 如果没有可用位置,报错
        Lock();
        CSlot* pSlot = getAvailableSlotForGlassExcludeSignal((MaterialsType)pJobDataS->getMaterialsType());
        if (pSlot == nullptr) {
        CSlot* pSlot = getSlot(putSlot - 1);
        ASSERT(pSlot);
        if (pSlot->getContext() != nullptr) {
            Unlock();
            LOGE("<CEquipemnt-%s>onPreFetchedOutJob,找不到匹配的Slot,不能进料,请注意风险!", m_strName.c_str());
            LOGE("<CEquipemnt-%s>onPreStoredJob,指定slot(port:%d)有料,请注意风险!", m_strName.c_str(), port);
            return FALSE;
        }
        Unlock();
        if (m_listener.onPreStoredJob != nullptr) {
            if (!m_listener.onPreStoredJob(this, pJobDataB, putSlot)) {
            if (!m_listener.onPreStoredJob(this, port, pJobDataB, putSlot)) {
                return FALSE;
            }
@@ -1855,11 +1893,11 @@
        short putSlot = 0;
        BOOL bCheck = onPreStoredJob(port, pJobDataB, putSlot);
        if (bCheck) {
            return storedJob(pJobDataB, putSlot);
            return storedJob(port, pJobDataB, putSlot);
        }
        // 数据异常,处理或显示
        LOGI("<CEquipment-%s>onStoredJob Error.ort:%d|GlassId:%s",
        LOGI("<CEquipment-%s>onStoredJob Error.port:%d|GlassId:%s",
            m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
        return -1;
    }
@@ -1875,20 +1913,16 @@
     * 当从CC-Link检测到设备Send Able为On时调用此函数
     * 可能会多次重复调用(根据扫描频率), 注意防呆
     */
    int CEquipment::onSendAble()
    int CEquipment::onSendAble(int port)
    {
        LOGI("<CEquipment-%s>onSendAble.", m_strName.c_str());
        if (m_processState != PROCESS_STATE::Complete) {
            setProcessState(PROCESS_STATE::Complete);
        }
        LOGI("<CEquipment-%s>onSendAble.port:%d", m_strName.c_str(), port);
        return 0;
    }
    int CEquipment::onReceiveAble()
    int CEquipment::onReceiveAble(int port)
    {
        LOGI("<CEquipment-%s>onReceiveAble.", m_strName.c_str());
        LOGI("<CEquipment-%s>onReceiveAble.port:%d", m_strName.c_str(), port);
        return 0;
    }
SourceCode/Bond/Servo/CEquipment.h
@@ -51,8 +51,8 @@
    typedef std::function<void(void* pEiuipment, int code)> ONDATACHANGED;
    typedef std::function<void(void* pEiuipment, int state, int alarmId, int unitId, int level)> ONALARM;
    typedef std::function<void(void* pEiuipment, void* pReport)> ONVCREVENTREPORT;
    typedef std::function<BOOL(void* pEiuipment, CJobDataB* pJobDataB)> ONPREFETCHEDOUTJOB;
    typedef std::function<BOOL(void* pEiuipment, CJobDataB* pJobDataB, short& putSlot)> ONPRESTOREDJOB;
    typedef std::function<BOOL(void* pEiuipment, int port, CJobDataB* pJobDataB)> ONPREFETCHEDOUTJOB;
    typedef std::function<BOOL(void* pEiuipment, int port, CJobDataB* pJobDataB, short& putSlot)> ONPRESTOREDJOB;
    typedef std::function<void(void* pEiuipment, PROCESS_STATE state)> ONPROCESSSTATE;
    typedef struct _EquipmentListener
    {
@@ -110,14 +110,14 @@
        virtual void onReceiveLBData(const char* pszData, size_t size);
        virtual int onStepEvent(CStep* pStep, int code);
        virtual CPin* addPin(PinType type, char* pszName);
        virtual short getSlotUnit(short slot) { return 0; };
        virtual short getSlotUnit(short slotNo) { return 0; };
        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);
        virtual int fetchedOutJob(int port, CJobDataB* pJobDataB);
        virtual int storedJob(int port, CJobDataB* pJobDataB, short putSlot);
        virtual int onReceivedJob(int port, CJobDataS* pJobDataS);
        virtual int onSentOutJob(int port, CJobDataS* pJobDataS);
        virtual BOOL onPreFetchedOutJob(int port, CJobDataB* pJobDataB);
@@ -125,10 +125,11 @@
        virtual BOOL onPreStoredJob(int port, CJobDataB* pJobDataB, short& putSlot);
        virtual int onStoredJob(int port, CJobDataB* pJobDataB);
        virtual int onProcessData(CProcessData* pProcessData);
        virtual int onSendAble();
        virtual int onReceiveAble();
        virtual int onSendAble(int port);
        virtual int onReceiveAble(int port);
        virtual int onProcessStateChanged(PROCESS_STATE state);
        virtual int getIndexerOperationModeBaseValue();
        virtual bool isSlotProcessed(int slot) { return true; };
        bool isAlarmStep(SERVO::CStep* pStep);
        bool isVcrEventStep(SERVO::CStep* pStep);
        bool isCassetteTransferStateStep(SERVO::CStep* pStep);
SourceCode/Bond/Servo/CMaster.cpp
@@ -825,7 +825,7 @@
                m_listener.onEqVcrEventReport(this, p, p2);
            }
        };
        listener.onPreFethedOutJob = [&](void* pEquipment, CJobDataB* pJobDataB) -> BOOL {
        listener.onPreFethedOutJob = [&](void* pEquipment, int port, CJobDataB* pJobDataB) -> BOOL {
            CEquipment* p = (CEquipment*)pEquipment;
@@ -858,7 +858,7 @@
            return bOk;
        };
        listener.onPreStoredJob = [&](void* pEquipment, CJobDataB* pJobDataB, short& slot) -> BOOL {
        listener.onPreStoredJob = [&](void* pEquipment, int port, CJobDataB* pJobDataB, short& slot) -> BOOL {
            CEquipment* p = (CEquipment*)pEquipment;
@@ -890,7 +890,7 @@
                else if (m_pActiveRobotTask->isRestoring() &&
                    m_pActiveRobotTask->getSrcPosition() == p->getID()) {
                    CGlass* pGlass = p->getGlassFromSlot(m_pActiveRobotTask->getSrcSlot());
                    if (pGlass == nullptr) {
                    if (pGlass == nullptr && m_pActiveRobotTask->getSrcSlot() == port) {
                        bOk = TRUE;
                        slot = m_pActiveRobotTask->getSrcSlot();
                        LOGI("<CMaster>onPreFethedOutJob, 已校验数据一致性.");
@@ -1392,7 +1392,7 @@
    CRobotTask* CMaster::createTransferTask_bonder_to_bakecooling(CEquipment* pSrcEq, CEquipment* pTarEq)
    {
        std::vector<int> slots = {1, 2};
        std::vector<int> slots = {1, 3};
        CRobotTask* pTask = nullptr;
        CSlot* pSrcSlot, * pTarSlot;
@@ -1413,8 +1413,8 @@
    CRobotTask* CMaster::createTransferTask_bake_to_cooling(CEquipment* pSrcEq)
    {
        std::vector<int> slotsTar = { 3, 4 };
        std::vector<int> slotsSrc = { 1, 2 };
        std::vector<int> slotsTar = { 2, 4 };
        std::vector<int> slotsSrc = { 1, 3 };
        CRobotTask* pTask = nullptr;
        CSlot* pSrcSlot, * pTarSlot;
@@ -1435,7 +1435,7 @@
    CRobotTask* CMaster::createTransferTask_bakecooling_to_measurement(CEquipment* pSrcEq, CEquipment* pTarEq)
    {
        std::vector<int> slots = { 3, 4 };
        std::vector<int> slots = { 2, 4 };
        CRobotTask* pTask = nullptr;
        CSlot* pSrcSlot, * pTarSlot;
SourceCode/Bond/Servo/CMeasurement.cpp
@@ -269,7 +269,7 @@
                        if (code == ROK && pszData != nullptr && size > 0) {
                            int port = (int)(__int64)((CEqReadStep*)pFrom)->getProp("Port");
                            if (port > 0) {
                                decodeReceivedJobReport((CStep*)pFrom, port, pszData, size);
                                decodeSentOutJobReport((CStep*)pFrom, port, pszData, size);
                            }
                        }
                        return -1;
@@ -331,6 +331,38 @@
                }
            }
        }
        // process start/end report
        {
            CEqReadStep* pStep = new CEqReadStep(0x19D3F, 13 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodeJobProcessStartReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_JOB_PROCESS_START_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0xf33);
            if (addStep(STEP_ID_JOB_PROCESS_START_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        {
            CEqReadStep* pStep = new CEqReadStep(0x19D4C, 13 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodeJobProcessEndReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_JOB_PROCESS_END_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0xf34);
            if (addStep(STEP_ID_JOB_PROCESS_END_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
    }
    // 必须要实现的虚函数,在此初始化Slot信息
SourceCode/Bond/Servo/CRobotTask.cpp
@@ -359,6 +359,9 @@
        case EQ_ID_LOADPORT2:
        case EQ_ID_LOADPORT3:
        case EQ_ID_LOADPORT4:
            tarPos = srcPos;
            tarSlot = srcSlot;
            break;
        case EQ_ID_ARM_TRAY1:
        case EQ_ID_ARM_TRAY2:
        case EQ_ID_ALIGNER:
SourceCode/Bond/Servo/CVacuumBake.cpp
@@ -269,7 +269,7 @@
                        if (code == ROK && pszData != nullptr && size > 0) {
                            int port = (int)(__int64)((CEqReadStep*)pFrom)->getProp("Port");
                            if (port > 0) {
                                decodeReceivedJobReport((CStep*)pFrom, port, pszData, size);
                                decodeSentOutJobReport((CStep*)pFrom, port, pszData, size);
                            }
                        }
                        return -1;
@@ -331,6 +331,38 @@
                }
            }
        }
        // process start/end report
        {
            CEqReadStep* pStep = new CEqReadStep(0x15D3F, 13 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodeJobProcessStartReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_JOB_PROCESS_START_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0xc33);
            if (addStep(STEP_ID_JOB_PROCESS_START_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        {
            CEqReadStep* pStep = new CEqReadStep(0x15D4C, 13 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodeJobProcessEndReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_JOB_PROCESS_END_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0xc34);
            if (addStep(STEP_ID_JOB_PROCESS_END_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
    }
    // 必须要实现的虚函数,在此初始化Slot信息
SourceCode/Bond/Servo/Configuration.cpp
@@ -92,6 +92,17 @@
    return (int)texts.size();    
}
void CConfiguration::setFilterMode(int mode)
{
    WritePrivateProfileString(_T("Logcat"), _T("FilterMode"),
        std::to_string(mode).c_str(), m_strFilepath);
}
int CConfiguration::getFilterMode()
{
    return GetPrivateProfileInt(_T("Logcat"), _T("FilterMode"), 0, m_strFilepath);
}
int CConfiguration::getP2RemoteEqReconnectInterval()
{
    return GetPrivateProfileInt(_T("P2"), _T("RemoteEqReconnectInterval"), 20, m_strFilepath);
SourceCode/Bond/Servo/Configuration.h
@@ -20,6 +20,8 @@
    void setLogcatIncludeRegex(BOOL bRegex);
    BOOL isLogcatIncludeRegex();
    int getCustomLogcatIncludeTexts(std::vector<std::string>& texts);
    void setFilterMode(int mode);
    int getFilterMode();
    BOOL getPortParms(unsigned int index, BOOL& bEnable, int& type, int& mode,
        int& cassetteType, int& transferMode, BOOL& bAutoChangeEnable);
SourceCode/Bond/Servo/LogEdit.cpp
@@ -21,12 +21,13 @@
BEGIN_MESSAGE_MAP(CLogEdit, CEdit)
    ON_WM_CONTEXTMENU()
    ON_WM_VSCROLL()
    ON_WM_MOUSEWHEEL()
END_MESSAGE_MAP()
void CLogEdit::SetMaxLineCount(int line)
{
    m_nMaxLines = line;
    m_nTrimLines = min(m_nMaxLines, 100);
    m_nTrimLines = min(m_nMaxLines, 4000);
}
void CLogEdit::OnContextMenu(CWnd* pWnd, CPoint point)
@@ -60,6 +61,13 @@
    CEdit::OnVScroll(nSBCode, nPos, pScrollBar);
}
BOOL CLogEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
    // 每次滚动时检查是否还在底部
    m_bAutoScroll = IsScrollBarAtBottom();
    return CEdit::OnMouseWheel(nFlags, zDelta, pt);
}
BOOL CLogEdit::IsScrollBarAtBottom()
{
    SCROLLINFO si = { sizeof(si), SIF_ALL };
@@ -69,31 +77,41 @@
void CLogEdit::AppendText(const char* pszText)
{
    SetRedraw(FALSE);
    SetRedraw(FALSE);
    // 裁剪逻辑
    int totalLines = GetLineCount();
    if (totalLines > m_nMaxLines) {
        // 获取要删除的字符范围
        int startChar = LineIndex(0);            // 第0行首字符位置
        int endChar = LineIndex(m_nTrimLines);    // 第N行首字符位置
    // 剪切过多行
    int totalLines = GetLineCount();
    if (totalLines > m_nMaxLines) {
        int startChar = LineIndex(0);
        int endChar = LineIndex(m_nTrimLines);
        if (startChar >= 0 && endChar > startChar) {
            SetSel(startChar, endChar);
            ReplaceSel(_T(""));
        }
    }
        if (startChar >= 0 && endChar > startChar) {
            SetSel(startChar, endChar);
            ReplaceSel(_T("")); // 删除前面行
        }
    }
    // 保存当前选择
    int start, end;
    GetSel(start, end);
    bool hasSelection = (start != end);
    int endPos = GetWindowTextLength();
    SetSel(endPos, endPos);
    ReplaceSel(pszText);
    int len = GetWindowTextLength();
    SetSel(len, len);
    ReplaceSel(pszText);
    if (m_bAutoScroll && !hasSelection) {
        LineScroll(GetLineCount());
    }
    if (m_bAutoScroll) {
        LineScroll(GetLineCount());
    }
    // 恢复选择
    if (hasSelection) {
        SetSel(start, end);
    }
    SetRedraw(TRUE);
    Invalidate();
    UpdateWindow();
}
    SetRedraw(TRUE);
    if (m_bAutoScroll && !hasSelection) {
        Invalidate();
        UpdateWindow();
    }
}
SourceCode/Bond/Servo/LogEdit.h
@@ -20,5 +20,7 @@
    DECLARE_MESSAGE_MAP()
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
public:
    afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
};
SourceCode/Bond/Servo/Model.cpp
@@ -190,8 +190,16 @@
        }
        // 任务描述与 ID 用于日志
        SERVO::CGlass* pGlass = (SERVO::CGlass*)pTask->getContext();
        const std::string& strDesc = pTask->getDescription();
        const std::string& strClassID = pTask->getId();
        std::string strClassID;
        if (pGlass != nullptr) {
            strClassID = pGlass->getID();
            if (pGlass->getBuddy() != nullptr) {
                strClassID += "/";
                strClassID += pGlass->getBuddy()->getID();
            }
        }
        // 日志输出与状态处理
        switch (code) {
@@ -245,23 +253,26 @@
        // 状态映射
        static const char* STATUS_STR[] = {
            "Unknown", "Ready", "Running", "Picking", "Placing", "Restoring", "Error", "Abort", "Completed"
            "Ready", "Running", "Picking", "Picked", "Placing", "Restoring", "Error", "Abort", "Restored", "Completed"
        };
        auto state = pTask->getState();
        int index = static_cast<int>(state);
        if (index > 0 && index < static_cast<int>(std::size(STATUS_STR))) {
        if (index >= 0 && index < static_cast<int>(std::size(STATUS_STR))) {
            data.strStatus = STATUS_STR[index];
        }
        else {
            data.strStatus = STATUS_STR[0];
            data.strStatus = "Unknown";
        }
        // 写入数据库
        int nRecordId = 0;
        TransferManager::getInstance().addTransferRecord(data, nRecordId);
        if (code == ROBOT_EVENT_FINISH || code == ROBOT_EVENT_ERROR
            || code == ROBOT_EVENT_ABORT || code == ROBOT_EVENT_RESTORE) {
            int nRecordId = 0;
            TransferManager::getInstance().addTransferRecord(data, nRecordId);
            LOGI("<CModel>onRobotTaskEvent: 任务记录已保存,RecordID=%d", nRecordId);
        }
        notifyPtrAndInt(RX_CODE_EQ_ROBOT_TASK, pTask, nullptr, code);
        LOGI("<CModel>onRobotTaskEvent: 任务记录已保存,RecordID=%d", nRecordId);
    };
    m_master.setListener(masterListener);
SourceCode/Bond/Servo/PageLog.cpp
@@ -20,8 +20,9 @@
    m_hbrBkgnd = nullptr;
    m_pObserver = nullptr;
    m_nLevel = 0;
    m_strIncludeText = _T("");
    m_bIncludeRegex = FALSE;
    m_strFilterText = _T("");
    m_bRegex = FALSE;
    m_filterMode = FilterMode::Include;
}
CPageLog::~CPageLog()
@@ -70,19 +71,24 @@
                    && pAny->getIntValue("exCode", level)) {
                    if (level >= m_nLevel) {
                        CString strText = pszLogMsg;
                        BOOL bInclude = TRUE;
                        if (!m_strIncludeText.IsEmpty()) {
                            if (!m_bIncludeRegex) {
                                bInclude = (strText.Find(m_strIncludeText) >= 0);
                        BOOL bMatch = TRUE;
                        if (!m_strFilterText.IsEmpty()) {
                            if (!m_bRegex) {
                                bMatch = (strText.Find(m_strFilterText) >= 0);
                            }
                            else {
                                bInclude = std::regex_search((LPTSTR)(LPCTSTR)strText,
                                    std::regex((LPTSTR)(LPCTSTR)m_strIncludeText));
                                CString strTemp = strText;
                                strTemp.TrimRight();
                                bMatch = std::regex_match((LPTSTR)(LPCTSTR)strTemp,
                                    std::regex((LPTSTR)(LPCTSTR)m_strFilterText));
                            }
                            if (m_filterMode == FilterMode::Exclude) {
                                bMatch = !bMatch;
                            }
                        }
                        if (bInclude) {
                        if (bMatch) {
                            strText.Replace("\n", "\r\n");
                            AppendLog(level, (LPTSTR)(LPCTSTR)strText);
                        }
@@ -110,9 +116,12 @@
    // 缓存
    m_nLevel = theApp.m_model.m_configuration.getLogcatLevel();
    theApp.m_model.m_configuration.getLogcatIncludeText(m_strIncludeText);
    m_bIncludeRegex = theApp.m_model.m_configuration.isLogcatIncludeRegex();
    theApp.m_model.m_configuration.getLogcatIncludeText(m_strFilterText);
    m_bRegex = theApp.m_model.m_configuration.isLogcatIncludeRegex();
    theApp.m_model.m_configuration.getCustomLogcatIncludeTexts(m_customIncludeTexts);
    m_customIncludeTexts.clear();
    m_customIncludeTexts.push_back("包含");
    m_customIncludeTexts.push_back("排除");
    // Level
@@ -135,6 +144,9 @@
        strIcon1, IMAGE_ICON, 24, 24,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    m_btnInclude.SetIcon(hIcon, hIcon, 24);
    m_filterMode = (FilterMode)theApp.m_model.m_configuration.getFilterMode();
    m_btnInclude.SetTextRight();
    m_btnInclude.SetWindowText(m_filterMode == FilterMode::Include ? "包含" : "排除");
    {
        HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCEA(IDR_MENU_INCLUDE));
@@ -143,19 +155,19 @@
        int i = 0;
        for (auto& item : m_customIncludeTexts) {
            i++;
            InsertMenu(hSubMenu, 0, MF_BYPOSITION, 0x1998 + i, item.c_str());
            InsertMenu(hSubMenu, i, MF_BYPOSITION, 0x1998 + i, item.c_str());
            m_btnInclude.SetMenu(hMenu);
        }
    }
    SetDlgItemText(IDC_EDIT_INCLUDE, m_strIncludeText);
    SetDlgItemText(IDC_EDIT_INCLUDE, m_strFilterText);
    CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
    pCheckBox->SetCheck(m_bIncludeRegex ? BST_CHECKED : BST_UNCHECKED);
    pCheckBox->SetCheck(m_bRegex ? BST_CHECKED : BST_UNCHECKED);
    // 内容
    m_logEdit.SetMaxLineCount(500);
    m_logEdit.SetMaxLineCount(6000);
    m_logEdit.SetLimitText(-1);
    Resize();
@@ -290,28 +302,22 @@
void CPageLog::OnButtonIncludeMenuClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
    BLBUTTON_NMHDR* pblbNmhdr = reinterpret_cast<BLBUTTON_NMHDR*>(pNMHDR);
    int position = (int)pblbNmhdr->dwData;
    std::string& strInclude = m_customIncludeTexts.at(position);
    SetDlgItemText(IDC_EDIT_INCLUDE, strInclude.c_str());
    CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
    m_bIncludeRegex = FALSE;
    pCheckBox->SetCheck(BST_UNCHECKED);
    theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bIncludeRegex);
    theApp.m_model.m_configuration.setLogcatIncludeText(m_strIncludeText);
    m_filterMode = (FilterMode)pblbNmhdr->dwData;
    theApp.m_model.m_configuration.setFilterMode((int)m_filterMode);
    m_btnInclude.SetWindowText(m_filterMode == FilterMode::Include ? "包含" : "排除");
    *pResult = 0;
}
void CPageLog::OnEnChangeEditInclude()
{
    GetDlgItemText(IDC_EDIT_INCLUDE, m_strIncludeText);
    theApp.m_model.m_configuration.setLogcatIncludeText(m_strIncludeText);
    GetDlgItemText(IDC_EDIT_INCLUDE, m_strFilterText);
    theApp.m_model.m_configuration.setLogcatIncludeText(m_strFilterText);
}
void CPageLog::OnBnClickedCheckRegex()
{
    CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
    m_bIncludeRegex = pCheckBox->GetCheck();
    theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bIncludeRegex);
    m_bRegex = pCheckBox->GetCheck();
    theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bRegex);
}
SourceCode/Bond/Servo/PageLog.h
@@ -7,6 +7,12 @@
#define ID_MSG_LOGDLG_HIDE        WM_USER + 1023
enum class FilterMode {
    Include,  // 只保留匹配行
    Exclude   // 排除匹配行
};
// CPageLog 对话框
class CPageLog : public CDialogEx
@@ -29,14 +35,15 @@
    HBRUSH m_hbrBkgnd;
    IObserver* m_pObserver;
    int m_nLevel;
    CString m_strIncludeText;
    BOOL m_bIncludeRegex;
    CString m_strFilterText;
    BOOL m_bRegex;
    std::vector<std::string> m_customIncludeTexts;
private:
    CBlButton m_btnLevel;
    CBlButton m_btnInclude;
    CLogEdit m_logEdit;
    FilterMode m_filterMode;
// 对话框数据
SourceCode/Bond/Servo/Servo.rc
Binary files differ
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -285,6 +285,10 @@
    SetIcon(m_hIcon, FALSE);        // 设置小图标
    // model init
    theApp.m_model.init();
    // 菜单
    CMenu menu;
    menu.LoadMenu(IDR_MENU_APP);
@@ -353,9 +357,6 @@
    int height = GetSystemMetrics(SM_CYSCREEN);
    MoveWindow((width - rcWnd.Width()) / 2, 0, rcWnd.Width(), rcWnd.Height(), TRUE);
    // model init
    theApp.m_model.init();
    SetTimer(TIMER_ID_CREATE_TERMINAL, 3000, nullptr);
SourceCode/Bond/x64/Debug/Res/logcat_include.ico