mrDarker
2025-08-27 3e0ceaf4e569ea1f57a14de2f6135d1f1a50d080
Merge branch 'clh' into liuyang
已修改18个文件
585 ■■■■■ 文件已修改
Document/Panel Bonder八零联合 SecsTest CheckList_v3.0.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 477 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Configuration.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Configuration.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/TopToolbar.cpp 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/TopToolbar.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/CollectionEventList.txt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/ReportList.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/VariableList.txt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Document/Panel Bonder°ËÁãÁªºÏ SecsTest CheckList_v3.0.xlsx
Binary files differ
SourceCode/Bond/Servo/CEquipment.cpp
@@ -1325,7 +1325,7 @@
        return nullptr;
    }
    CSlot* CEquipment::getProcessedSlot(MaterialsType putSlotType)
    CSlot* CEquipment::getProcessedSlot(MaterialsType putSlotType, BOOL bJobMode/* = FALSE*/)
    {
        for (int i = 0; i < SLOT_MAX; i++) {
            if (!m_slot[i].isEnable()) continue;
@@ -1334,6 +1334,7 @@
            if (!isSlotProcessed(i)) continue;
            if (pGlass == nullptr) continue;
            if (!pGlass->isScheduledForProcessing()) continue;
            if (bJobMode && pGlass->getProcessJob() == nullptr) continue;
            if(pGlass->getInspResult(m_nID, 0) == InspResult::Fail) continue;
            int lsPath = m_slot[i].getLinkSignalPath();
            if(!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
@@ -1654,7 +1655,7 @@
    int CEquipment::decodeVCREventReport(CStep* pStep, const char* pszData, size_t size)
    {
        CVcrEventReport vcrEventReport;
        vcrEventReport.unserialize(pszData, size);
        vcrEventReport.unserialize(pszData, (int)size);
        LOGI("<CEquipment-%s>decodeVCREventReport<Result:%d, GlassId:%s>\n", m_strName.c_str(),
            vcrEventReport.getVcrResult(),
            vcrEventReport.getGlassId().c_str());
SourceCode/Bond/Servo/CEquipment.h
@@ -185,7 +185,7 @@
        CSlot* getNonEmptySlot(MaterialsType type);
        // èŽ·å–ä¸€ä¸ªæŒ‡å®šç‰©æ–™ç±»åž‹(G1,G2,G1&G2)的且已经加工处理的槽位
        CSlot* getProcessedSlot(MaterialsType putSlotType);
        CSlot* getProcessedSlot(MaterialsType putSlotType, BOOL bJobMode = FALSE);
        CSlot* getProcessedSlot2(MaterialsType putSlotType, const std::vector<int>& candidates);
        CSlot* getInspFailSlot();
        CSlot* getProcessedSlotCt(unsigned int slot);
SourceCode/Bond/Servo/CMaster.cpp
@@ -55,9 +55,11 @@
        m_pActiveRobotTask = nullptr;
        m_nLastError = 0;
        m_isCompareMapsBeforeProceeding = FALSE;
        m_bJobMode = FALSE;
        m_bEnableEventReport = true;
        m_bEnableAlarmReport = true;
        m_bContinuousTransfer = false;
        m_bBatch = false;
        m_nContinuousTransferCount = 0;
        m_nContinuousTransferStep = CTStep_Unknow;
        m_pControlJob = nullptr;
@@ -269,6 +271,7 @@
        }
        m_bContinuousTransfer = false;
        m_bBatch = false;
        setState(MASTERSTATE::STARTING);
        m_ullStartTime = GetTickCount64();
@@ -282,6 +285,21 @@
        }
        m_bContinuousTransfer = true;
        m_bBatch = false;
        setState(MASTERSTATE::STARTING);
        m_ullStartTime = GetTickCount64();
        return 0;
    }
    int CMaster::startBatch()
    {
        if (m_state != MASTERSTATE::READY) {
            return -1;
        }
        m_bContinuousTransfer = false;
        m_bBatch = true;
        setState(MASTERSTATE::STARTING);
        m_ullStartTime = GetTickCount64();
@@ -291,12 +309,28 @@
    int CMaster::stop()
    {
        // è¿è¡Œæ—¶é—´ä¸ºç´¯åŠ ç»“æžœï¼Œæœ¬æ¬¡åœæ­¢æ—¶åˆ·æ–°ï¼›
        if (m_state != MASTERSTATE::RUNNING && m_state != MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
        lock();
        if (m_state != MASTERSTATE::RUNNING && m_state != MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER
            && m_state != MASTERSTATE::RUNNING_BATCH) {
            unlock();
            return -1;
        }
        m_ullRunTime += (GetTickCount64() - m_ullStartTime);
        unlock();
        // æ›´æ–°çŠ¶æ€
        setState(MASTERSTATE::STOPPING);
        // ControlJob暂停
        lock();
        if (m_pControlJob != nullptr) {
            m_pControlJob->pause();
            saveState();
        }
        unlock();
        return 0;
    }
@@ -310,7 +344,8 @@
    ULONGLONG CMaster::getRunTime()
    {
        if (m_state == MASTERSTATE::RUNNING || m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER)
        if (m_state == MASTERSTATE::RUNNING || m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER
            || m_state == MASTERSTATE::RUNNING_BATCH)
            return m_ullRunTime + (GetTickCount64() - m_ullStartTime);
        else
            return m_ullRunTime;
@@ -470,18 +505,21 @@
                }
                
                // æ£€æŸ¥çœ‹æ˜¯å¦éƒ½å·²ç»åˆ‡æ¢åˆ°START状态
                /*
                if (!bIomcOk[6]) {
                    unlock();
                    setState(MASTERSTATE::MSERROR);
                    continue;
                }
                */
                unlock();
                if(!m_bContinuousTransfer)
                    setState(MASTERSTATE::RUNNING);
                else
                if(m_bContinuousTransfer)
                    setState(MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER);
                else if (m_bBatch)
                    setState(MASTERSTATE::RUNNING_BATCH);
                else
                    setState(MASTERSTATE::RUNNING);
                continue;
            }
@@ -684,7 +722,7 @@
                    if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                        && (pt == PortType::Loading || pt == PortType::Both)
                        && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                        m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType);
                        m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, 1, m_bJobMode);
                        if (m_pActiveRobotTask != nullptr) {
                            pEFEM->setContext(m_pActiveRobotTask->getContext());
                            goto PORT_GET;
@@ -693,6 +731,233 @@
                }
PORT_GET:
                CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                unlock();
                continue;
            }
            // æ‰¹å¤„理模式,最终以此为准,但先保留之前的单片模式
            else if (m_state == MASTERSTATE::RUNNING_BATCH) {
                // é¦–选检查有没有CControlJob, çŠ¶æ€ç­‰
                if (m_pControlJob == nullptr) {
                    unlock();
                    continue;
                }
                CJState state = m_pControlJob->state();
                if (state == CJState::Completed || state == CJState::Aborted || state == CJState::Failed) {
                    // ConrolJpb已完成
                    LOGI("<Master>ControlJob已经完成或失败中断");
                    unlock();
                    continue;
                }
                if (m_pControlJob->state() == CJState::NoState) {
                    LOGI("<Master>ControlJob已经进入列队");
                    m_pControlJob->queue();
                }
                if (m_pControlJob->state() == CJState::Queued) {
                    LOGI("<Master>ControlJob已经启动");
                    m_pControlJob->start();
                }
                if (m_pControlJob->state() == CJState::Paused) {
                    LOGI("<Master>ControlJob已经恢复运行");
                    m_pControlJob->resume();
                }
                // å¦‚果当前未选择CProcessJob, é€‰æ‹©ä¸€ä¸ª
                if (m_inProcesJobs.empty()) {
                    auto pj = acquireNextProcessJob();
                    if (pj != nullptr) {
                        m_inProcesJobs.push_back(pj);
                        // è¿™é‡Œä¸ŠæŠ¥PJ Start事件
                        if (m_listener.onPjStart != nullptr) {
                            m_listener.onPjStart(this, pj);
                        }
                    }
                }
                if (m_inProcesJobs.empty()) {
                    LOGI("<Master>选择当前ProcessJob失败!");
                    unlock();
                    continue;
                }
                // å¦‚果当前没有Glass, é€‰æ‹©
                if (m_queueGlasses.empty()) {
                    int nCount = acquireGlassToQueue();
                    LOGI("<Master>已加入 %d å—Glass到工艺列队!", nCount);
                }
                // æ£€æµ‹åˆ¤æ–­robot状态
                RMDATA& rmd = pEFEM->getRobotMonitoringData();
                if (rmd.status != ROBOT_STATUS::Idle && rmd.status != ROBOT_STATUS::Run) {
                    unlock();
                    continue;
                }
                if (m_pActiveRobotTask != nullptr) {
                    if (m_pActiveRobotTask->isPicked()) {
                        m_pActiveRobotTask->place();
                    }
                    unlock();
                    // æ£€æµ‹åˆ°å½“前有正在下午的任务,确保当前任务完成或中止后继续
                    // LOGI("检测到当前有正在下午的任务,确保当前任务完成或中止后继续...");
                    continue;
                }
                // æ­¤å¤„检测优先类型和次要类型(G1或G2)
                // å¦‚果其中一Bonder有单个玻璃,优先取它的配对类型,否则无所谓了
                primaryType = MaterialsType::G1;
                secondaryType = MaterialsType::G2;
                if ((!pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1))
                    && (!pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) {
                    // å¦‚æžœG1和G2都满了,那就看Aligner, å¦‚æžœAligner有玻璃为G1, åˆ™å–G2
                    CGlass* pGlass = pAligner->getGlassFromSlot(1);
                    if (pGlass != nullptr && pGlass->getType() == MaterialsType::G1) {
                        primaryType = MaterialsType::G2;
                        secondaryType = MaterialsType::G1;
                    }
                }
                else if ((pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1))
                    || (pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) {
                    primaryType = MaterialsType::G2;
                    secondaryType = MaterialsType::G1;
                }
                // Measurement -> LoadPort
                if (rmd.armState[0] || rmd.armState[1]) {
                    LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
                        rmd.armState[1] ? _T("不可用") : _T("可用"));
                }
                for (int s = 0; s < 4; s++) {
                    PortType pt = pLoadPorts[s]->getPortType();
                    if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                        && (pt == PortType::Unloading || pt == PortType::Both)
                        && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                        m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType);
                        if (m_pActiveRobotTask != nullptr) {
                            goto BATCH_PORT_PUT;
                        }
                    }
                }
            BATCH_PORT_PUT:
                CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                // Measurement NG -> LoadPort
                // NG回原位
                if (!rmd.armState[1]) {
                    m_pActiveRobotTask = createTransferTask_restore(pMeasurement, pLoadPorts);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // BakeCooling ->Measurement
                if (!rmd.armState[0]) {
                    m_pActiveRobotTask = createTransferTask_bakecooling_to_measurement(pBakeCooling, pMeasurement);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // BakeCooling内部
                // Bake -> Cooling
                if (!rmd.armState[0]) {
                    m_pActiveRobotTask = createTransferTask_bake_to_cooling(pBakeCooling);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // Bonder -> BakeCooling
                if (!rmd.armState[0]) {
                    m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder1, pBakeCooling);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                if (!rmd.armState[0]) {
                    m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder2, pBakeCooling);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // Fliper(G2) -> Bonder
                auto pSrcSlot = pVacuumBake->getProcessedSlot(primaryType);
                if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder1->hasBondClass()) {
                    m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, primaryType, secondaryType, 2);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder2->hasBondClass()) {
                    m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, primaryType, secondaryType, 2);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // VacuumBake(G1) -> Bonder
                if (!rmd.armState[0] && !pBonder1->hasBondClass()) {
                    m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, primaryType, secondaryType);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                if (!rmd.armState[0] && !pBonder2->hasBondClass()) {
                    m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, primaryType, secondaryType);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // Aligner -> Fliper(G2)
                // Aligner -> VacuumBake(G1)
                if (!rmd.armState[1]) {
                    m_pActiveRobotTask = createTransferTask(pAligner, pFliper, primaryType, secondaryType);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                if (!rmd.armState[0]) {
                    m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, primaryType, secondaryType);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // Aligner -> LoadPort
                if (!rmd.armState[1]) {
                    m_pActiveRobotTask = createTransferTask_restore(pAligner, pLoadPorts);
                    CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
                }
                // LoadPort -> Aligner
                for (int s = 0; s < 4; s++) {
                    PortType pt = pLoadPorts[s]->getPortType();
                    if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                        && (pt == PortType::Loading || pt == PortType::Both)
                        && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                        m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, m_bJobMode);
                        if (m_pActiveRobotTask != nullptr) {
                            CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext();
                            pEFEM->setContext(pGlass);
                            pGlass->start();
                            bool bMoved = glassFromQueueToInPorcess(pGlass);
                            if (bMoved) {
                                LOGI("<Master>Glass(%s)从等待列队到工艺列队转移成功.",
                                    pGlass->getID().c_str());
                            }
                            else {
                                LOGE("<Master>Glass(%s)从等待列队到工艺列队转移失败.",
                                    pGlass->getID().c_str());
                            }
                            goto BATCH_PORT_GET;
                        }
                    }
                }
            BATCH_PORT_GET:
                CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
@@ -982,15 +1247,27 @@
            BOOL bOk = FALSE;
            lock();
            if (m_pActiveRobotTask != nullptr) {
                LOGI("<CMaster>onPreFethedOutJob 0001.");
                if (m_pActiveRobotTask->getSrcPosition() == p->getID()) {
                    LOGI("<CMaster>onPreFethedOutJob 0002.");
                    CGlass* pGlass = p->getGlassFromSlot(m_pActiveRobotTask->getSrcSlot());
                    if (pGlass != nullptr) {
                        LOGI("<CMaster>onPreFethedOutJob 0003.");
                        CJobDataS* pJobDataS = pGlass->getJobDataS();
                        if (pJobDataS != nullptr
                            && pJobDataS->getCassetteSequenceNo() == pJobDataB->getCassetteSequenceNo()
                            && pJobDataS->getJobSequenceNo() == pJobDataB->getJobSequenceNo()) {
                            bOk = TRUE;
                            LOGI("<CMaster>onPreFethedOutJob, å·²æ ¡éªŒæ•°æ®ä¸€è‡´æ€§.");
                        }
                        LOGI("<CMaster>onPreFethedOutJob 0004.");
                        if (pJobDataS != nullptr) {
                            LOGI("<CMaster>onPreFethedOutJob 0005. %d,%d,%d,%d",
                                pJobDataS->getCassetteSequenceNo(),
                                pJobDataB->getCassetteSequenceNo(),
                                pJobDataS->getJobSequenceNo(),
                                pJobDataB->getJobSequenceNo()
                                );
                        }
                    }
                }
@@ -1102,6 +1379,34 @@
                    LOGI("放片完成...");
                    // å®Œæˆæ­¤æ¡æ¬é€ä»»åŠ¡ï¼Œä½†è¦æŠŠæ•°æ®å’Œæ¶ˆæ¯ä¸ŠæŠ›åº”ç”¨å±‚
                    // å¦‚果是搬送回从AOI搬送回Port, åˆ™glass工艺完成
                    if (m_pActiveRobotTask->getSrcPosition() == EQ_ID_MEASUREMENT) {
                        CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext();
                        pGlass->complete();
                        bool bMoved = glassFromInPorcessToComplete(pGlass);
                        if (bMoved) {
                            LOGI("<Master>Glass(%s)从工艺列队到完成列队转移成功.",
                                pGlass->getID().c_str());
                        }
                        else {
                            LOGE("<Master>Glass(%s)从工艺列队到完成列队转移失败.",
                                pGlass->getID().c_str());
                        }
                        // æ£€æŸ¥PJ是否已经完成
                        CProcessJob* pJob = getGlassProcessJob((CGlass*)m_pActiveRobotTask->getContext());
                        if (pJob != nullptr && checkAndUpdatePjComplete(pJob)) {
                            LOGE("<Master>ProcessJob(%s)完成.",
                                pJob->id().c_str());
                            if (m_listener.onPjEnd != nullptr) {
                                m_listener.onPjEnd(this, pJob);
                            }
                        }
                    }
                    unlock();
@@ -1403,6 +1708,38 @@
            }
        }
        // æ¨¡æ‹Ÿæµ‹è¯•
        /*
        static int aaa = 0;
        aaa++;
        if (aaa % 30 == 0) {
            if (!m_queueGlasses.empty()) {
                CGlass* pGlass = m_queueGlasses.front();
                pGlass->start();
                glassFromQueueToInPorcess(pGlass);
            }
        }
        if (aaa % 45 == 0) {
            if (!m_inProcesGlasses.empty()) {
                CGlass* pGlass = m_inProcesGlasses.front();
                pGlass->complete();
                glassFromInPorcessToComplete(pGlass);
                CProcessJob* pJob = getGlassProcessJob(pGlass);
                if (pJob != nullptr && checkAndUpdatePjComplete(pJob)) {
                    LOGE("<Master>ProcessJob(%s)完成.",
                        pJob->id().c_str());
                    if (m_listener.onPjEnd != nullptr) {
                        m_listener.onPjEnd(this, pJob);
                    }
                }
            }
        }
        */
    }
    void CMaster::connectEquipments()
@@ -1567,7 +1904,7 @@
    static int taskSeqNo = 0;
    CRobotTask* CMaster::createTransferTask(CEquipment* pSrcEq, CEquipment* pTarEq,
        MaterialsType primaryType/* = MaterialsType::G1*/, MaterialsType secondaryType/* = MaterialsType::G2*/,
        int armNo/* = 1*/)
        int armNo/* = 1*/, BOOL bJobMode/* = FALSE*/)
    {
        if (!pSrcEq->IsEnabled()) { 
            return nullptr;
@@ -1576,10 +1913,10 @@
        CRobotTask* pTask = nullptr;
        CSlot* pSrcSlot, * pTarSlot;
        pTarSlot = pTarEq->getAvailableSlotForGlass(primaryType);
        pSrcSlot = pSrcEq->getProcessedSlot(primaryType);
        pSrcSlot = pSrcEq->getProcessedSlot(primaryType, bJobMode);
        if (pSrcSlot == nullptr || nullptr == pTarSlot) {
            pTarSlot = pTarEq->getAvailableSlotForGlass(secondaryType);
            pSrcSlot = pSrcEq->getProcessedSlot(secondaryType);
            pSrcSlot = pSrcEq->getProcessedSlot(secondaryType, bJobMode);
        }
@@ -1819,6 +2156,11 @@
    void CMaster::setCompareMapsBeforeProceeding(BOOL bCompare)
    {
        m_isCompareMapsBeforeProceeding = bCompare;
    }
    void CMaster::setJobMode(BOOL bJobMode)
    {
        m_bJobMode = bJobMode;
    }
    void CMaster::datetimeSync(SYSTEMTIME& time)
@@ -2089,4 +2431,117 @@
        return true;
    }
    CProcessJob* CMaster::acquireNextProcessJob()
    {
        auto& pjs = m_pControlJob->getPjs();
        for (const auto pj : pjs) {
            if (pj->state() == PJState::Queued) {
                pj->start();
            }
            return pj;
        }
        return nullptr;
    }
    CGlass* CMaster::acquireNextGlass()
    {
        for (auto* pj : m_inProcesJobs) {
            // éåކ PJ çš„ carriers å’Œ slots
            for (auto& cs : pj->carriers()) {
                for (auto ctx : cs.contexts) {
                    CGlass* pGlass = (CGlass*)ctx;
                    if (pGlass->state() == GlsState::NoState) {
                        pGlass->queue();
                        return pGlass;
                    }
                }
            }
        }
        return nullptr; // æ²¡æœ‰å¯åŠ å·¥çš„ Glass
    }
    int CMaster::acquireGlassToQueue()
    {
        int nCount = 0;
        for (auto* pj : m_inProcesJobs) {
            // éåކ PJ çš„ carriers å’Œ slots
            for (auto& cs : pj->carriers()) {
                for (auto ctx : cs.contexts) {
                    CGlass* pGlass = (CGlass*)ctx;
                    if (pGlass->state() == GlsState::NoState) {
                        pGlass->queue();
                        if(addGlassToQueue(pGlass)) nCount++;
                    }
                }
            }
        }
        return nCount;
    }
    bool CMaster::addGlassToQueue(CGlass* pGlass)
    {
        for (auto g : m_queueGlasses) {
            if (g == pGlass) return false;
        }
        m_queueGlasses.push_back(pGlass);
        return true;
    }
    bool CMaster::glassFromQueueToInPorcess(CGlass* pGlass)
    {
        auto it = std::find(m_queueGlasses.begin(), m_queueGlasses.end(), pGlass);
        if (it != m_queueGlasses.end()) {
            m_inProcesGlasses.push_back(*it);
            m_queueGlasses.erase(it);
            return true;
        }
        return false;
    }
    bool CMaster::glassFromInPorcessToComplete(CGlass* pGlass)
    {
        auto it = std::find(m_inProcesGlasses.begin(), m_inProcesGlasses.end(), pGlass);
        if (it != m_inProcesGlasses.end()) {
            m_completeGlasses.push_back(*it);
            m_inProcesGlasses.erase(it);
            return true;
        }
        return false;
    }
    bool CMaster::checkAndUpdatePjComplete(CProcessJob* pJob)
    {
        ASSERT(pJob);
        auto state = pJob->state();
        if (state != PJState::InProcess && state != PJState::Paused) return false;
        for (auto c : pJob->carriers()) {
            for (auto g : c.contexts) {
                CGlass* pGlass = (CGlass*)g;
                if (pGlass->state() != GlsState::Aborted
                    && pGlass->state() != GlsState::Completed
                    && pGlass->state() != GlsState::Failed) return false;
            }
        }
        return pJob->complete();
    }
    CProcessJob* CMaster::getGlassProcessJob(CGlass* pGlass)
    {
        if (m_pControlJob == nullptr) return nullptr;
        for (auto pj : m_pControlJob->getPjs()) {
            for (auto c : pj->carriers()) {
                for (auto g : c.contexts) {
                    if (g == pGlass) return pj;
                }
            }
        }
        return nullptr;
    }
}
SourceCode/Bond/Servo/CMaster.h
@@ -39,6 +39,7 @@
        STARTING,
        RUNNING,
        RUNNING_CONTINUOUS_TRANSFER,
        RUNNING_BATCH,
        STOPPING,
        MSERROR
    };
@@ -52,6 +53,7 @@
    typedef std::function<void(void* pMaster, CRobotTask* pTask, int code)> ONROBOTTASKEVENT;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, short status, __int64 data)> ONLOADPORTSTATUSCHANGED;
    typedef std::function<void(void* pMaster, int round)> ONCTROUNDEND;
    typedef std::function<void(void* pMaster, void* pj)> ONPJSTART;
    typedef struct _MasterListener
    {
        ONMASTERSTATECHANGED    onMasterStateChanged;
@@ -63,6 +65,8 @@
        ONROBOTTASKEVENT        onRobotTaskEvent;
        ONLOADPORTSTATUSCHANGED    onLoadPortStatusChanged;
        ONCTROUNDEND            onCTRoundEnd;
        ONPJSTART               onPjStart;
        ONPJSTART               onPjEnd;
    } MasterListener;
    class CMaster : public IResourceView
@@ -79,6 +83,7 @@
        int term();
        int start();
        int startContinuousTransfer();
        int startBatch();
        int stop();
        void clearError();
        ULONGLONG getRunTime();
@@ -98,6 +103,7 @@
        void setPortCassetteType(unsigned int index, SERVO::CassetteType type);
        void setPortEnable(unsigned int index, BOOL bEnable);
        void setCompareMapsBeforeProceeding(BOOL bCompare);
        void setJobMode(BOOL bJobMode);
        void datetimeSync(SYSTEMTIME& time);
        void enableEventReport(bool bEnable);
        void enableAlarmReport(bool bEnable);
@@ -137,7 +143,7 @@
        void setState(MASTERSTATE state);
        CRobotTask* createTransferTask(CEquipment* pSrcEq, CEquipment* pTarEq,
            MaterialsType primaryType = MaterialsType::G1, MaterialsType secondaryType = MaterialsType::G2,
            int armNo = 1);
            int armNo = 1, BOOL bJobMode = FALSE);
        CRobotTask* createTransferTask_bonder_to_bakecooling(CEquipment* pSrcEq, CEquipment* pTarEq);
        CRobotTask* createTransferTask_bake_to_cooling(CEquipment* pSrcEq);
        CRobotTask* createTransferTask_bakecooling_to_measurement(CEquipment* pSrcEq, CEquipment* pTarEq);
@@ -153,6 +159,18 @@
        bool slotUsable(const std::string& carrierId, uint16_t slot) const override;
        bool ceidDefined(uint32_t ceid) const override;
    public:
        // æ–°å¢žå‡½æ•°
        CProcessJob* acquireNextProcessJob();
        CGlass* acquireNextGlass();
        int acquireGlassToQueue();
        bool addGlassToQueue(CGlass* pGlass);
        bool glassFromQueueToInPorcess(CGlass* pGlass);
        bool glassFromInPorcessToComplete(CGlass* pGlass);
        bool checkAndUpdatePjComplete(CProcessJob* pJob);
        CProcessJob* getGlassProcessJob(CGlass* pGlass);
    private:
        CRITICAL_SECTION m_criticalSection;
        MasterListener m_listener;
@@ -161,6 +179,7 @@
        std::string m_strFilepath;
        BOOL m_bDataModify;
        bool m_bContinuousTransfer;
        bool m_bBatch;
    private:
        /* ç›‘控比特位的线程*/
@@ -189,11 +208,19 @@
        // åœ¨å¼€å§‹å·¥è‰ºå‰æ˜¯å¦å…ˆéœ€è¦å…ˆæ¯”较map
        BOOL m_isCompareMapsBeforeProceeding;
        BOOL m_bJobMode;
        // åƒä¼ åœˆæ•°è®¡æ•°
        int m_nContinuousTransferCount;
        int m_nContinuousTransferStep;
        // æ–°å¢žå·²ç»å¼€å§‹å¤„理的ProcessJob列表
        std::vector<CProcessJob*> m_inProcesJobs;
        std::vector<CGlass*> m_queueGlasses;
        std::vector<CGlass*> m_inProcesGlasses;
        std::vector<CGlass*> m_completeGlasses;
    private:
        bool m_bEnableEventReport;
        bool m_bEnableAlarmReport;
SourceCode/Bond/Servo/Configuration.cpp
@@ -160,6 +160,11 @@
    return GetPrivateProfileInt(_T("Master"), _T("CompareMapsBeforeProceeding"), 0, m_strFilepath);
}
BOOL CConfiguration::isJobMode()
{
    return GetPrivateProfileInt(_T("Master"), _T("JobMode"), 0, m_strFilepath);
}
void CConfiguration::setContinuousTransferCount(int round)
{
    WritePrivateProfileString(_T("Master"), _T("CTRound"),
SourceCode/Bond/Servo/Configuration.h
@@ -27,6 +27,7 @@
    BOOL setPortCassetteType(unsigned int index, int cassetteType);
    BOOL setPortEnable(unsigned int index, BOOL bEnable);
    BOOL isCompareMapsBeforeProceeding();
    BOOL isJobMode();
    void setContinuousTransferCount(int round);
    int getContinuousTransferCount();
SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -1879,6 +1879,16 @@
    return requestEventReportSend("PJ_Queued");
}
int CHsmsPassive::requestEventReportSend_PJ_Start()
{
    return requestEventReportSend("PJ_Start");
}
int CHsmsPassive::requestEventReportSend_PJ_End()
{
    return requestEventReportSend("PJ_End");
}
SourceCode/Bond/Servo/HsmsPassive.h
@@ -192,6 +192,8 @@
    int requestEventReportSend(const char* pszEventName);
    int requestEventReportSend_CarrierID_Readed();
    int requestEventReportSend_PJ_Queued();
    int requestEventReportSend_PJ_Start();
    int requestEventReportSend_PJ_End();
private:
    void replyAck(int s, int f, unsigned int systemBytes, BYTE ack, const char* pszAckName);
SourceCode/Bond/Servo/Model.cpp
@@ -387,6 +387,14 @@
    masterListener.onCTRoundEnd = [&](void* pMaster, int round) {
        m_configuration.setContinuousTransferCount(round);
    };
    masterListener.onPjStart = [&](void* pMaster, void* pj) {
        m_hsmsPassive.setVariableValue("PJStartID", ((SERVO::CProcessJob*)pj)->id().c_str());
        m_hsmsPassive.requestEventReportSend_PJ_Start();
    };
    masterListener.onPjEnd = [&](void* pMaster, void* pj) {
        m_hsmsPassive.setVariableValue("PJEndID", ((SERVO::CProcessJob*)pj)->id().c_str());
        m_hsmsPassive.requestEventReportSend_PJ_End();
    };
    m_master.setListener(masterListener);
    m_master.setContinuousTransferCount(m_configuration.getContinuousTransferCount());
@@ -396,6 +404,7 @@
    strMasterDataFile.Format(_T("%s\\Master.dat"), (LPTSTR)(LPCTSTR)m_strWorkDir);
    m_master.setCacheFilepath((LPTSTR)(LPCTSTR)strMasterDataFile);
    m_master.setCompareMapsBeforeProceeding(m_configuration.isCompareMapsBeforeProceeding());
    m_master.setJobMode(m_configuration.isJobMode());
    // åŠ æˆªJob
    strMasterDataFile.Format(_T("%s\\MasterState.dat"), (LPTSTR)(LPCTSTR)m_strWorkDir);
SourceCode/Bond/Servo/Servo.rc
Binary files differ
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -192,6 +192,7 @@
                SERVO::MASTERSTATE state = theApp.m_model.getMaster().getState();
                if (state == SERVO::MASTERSTATE::READY) {
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(TRUE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(TRUE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
                    m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_NORMAL);
@@ -208,14 +209,17 @@
                }
                else if (state == SERVO::MASTERSTATE::MSERROR) {
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(TRUE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(TRUE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(TRUE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
                    m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_ALARM);
                    m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
                    m_pMyStatusbar->setRunTimeText("启动失败.");
                }
                else if (state == SERVO::MASTERSTATE::RUNNING || state == SERVO::MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
                else if (state == SERVO::MASTERSTATE::RUNNING || state == SERVO::MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER
                    || state == SERVO::MASTERSTATE::RUNNING_BATCH) {
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(FALSE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(FALSE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(FALSE);
                    m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(TRUE);
                    m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_RUNNING);
@@ -959,6 +963,19 @@
        else {
            if (theApp.m_model.getMaster().start() == 0) {
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(FALSE);
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(FALSE);
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(FALSE);
            }
        }
    }
    else if (id == IDC_BUTTON_RUN_BATCH) {
        if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) {
            AfxMessageBox("当前有机台发生错误,不能启动,请确认解决问题后再尝试重新启动!");
        }
        else {
            if (theApp.m_model.getMaster().startBatch() == 0) {
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(FALSE);
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(FALSE);
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(FALSE);
            }
        }
@@ -970,6 +987,7 @@
        else {
            if (theApp.m_model.getMaster().startContinuousTransfer() == 0) {
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN)->EnableWindow(FALSE);
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_BATCH)->EnableWindow(FALSE);
                m_pTopToolbar->GetBtn(IDC_BUTTON_RUN_CT)->EnableWindow(FALSE);
            }
        }
@@ -1099,6 +1117,9 @@
    else if (state == SERVO::MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
        strText.Format(_T("千传模式:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
    }
    else if (state == SERVO::MASTERSTATE::RUNNING_BATCH) {
        strText.Format(_T("JOB模式:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
    }
    else {
        strText.Format(_T("已运行:%02d:%02d:%02d   %s"), h, m, s, pszSuffix);
    }
SourceCode/Bond/Servo/TopToolbar.cpp
@@ -8,6 +8,9 @@
#include "Common.h"
#define SHOW_BATCH    1
#define SHOW_CT        1
// CTopToolbar å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CTopToolbar, CDialogEx)
@@ -27,6 +30,7 @@
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BUTTON_RUN, m_btnRun);
    DDX_Control(pDX, IDC_BUTTON_RUN_BATCH, m_btnRunBatch);
    DDX_Control(pDX, IDC_BUTTON_RUN_CT, m_btnRunCt);
    DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop);
    DDX_Control(pDX, IDC_BUTTON_JOBS, m_btnCJobs);
@@ -54,6 +58,7 @@
    CDialogEx::OnInitDialog();
    InitBtn(m_btnRun, "Run_High_32.ico", "Run_Gray_32.ico");
    InitBtn(m_btnRunBatch, "Run_High_32.ico", "Run_Gray_32.ico");
    InitBtn(m_btnRunCt, "RunCt_High_32.ico", "RunCt_Gray_32.ico");
    InitBtn(m_btnStop, "Stop_High_32.ico", "Stop_Gray_32.ico");
    InitBtn(m_btnAlarm, "Alarm_o_32.ico", "Alarm_gray_32.ico");
@@ -120,10 +125,19 @@
    x += BTN_WIDTH;
    x += 2;
#ifdef SHOW_BATCH
    pItem = GetDlgItem(IDC_BUTTON_RUN_BATCH);
    pItem->MoveWindow(x, y, BTN_WIDTH, nBthHeight);
    x += BTN_WIDTH;
    x += 2;
#endif
#ifdef SHOW_CT
    pItem = GetDlgItem(IDC_BUTTON_RUN_CT);
    pItem->MoveWindow(x, y, BTN_WIDTH, nBthHeight);
    x += BTN_WIDTH;
    x += 2;
#endif
    pItem = GetDlgItem(IDC_BUTTON_STOP);
    pItem->MoveWindow(x, y, BTN_WIDTH, nBthHeight);
@@ -204,6 +218,7 @@
{
    switch (LOWORD(wParam)) {
    case IDC_BUTTON_RUN:
    case IDC_BUTTON_RUN_BATCH:
    case IDC_BUTTON_RUN_CT:
    case IDC_BUTTON_STOP:
    case IDC_BUTTON_JOBS:
SourceCode/Bond/Servo/TopToolbar.h
@@ -31,6 +31,7 @@
private:
    CBlButton m_btnRun;
    CBlButton m_btnRunBatch;
    CBlButton m_btnRunCt;
    CBlButton m_btnStop;
    CBlButton m_btnCJobs;
SourceCode/Bond/Servo/resource.h
Binary files differ
SourceCode/Bond/x64/Debug/CollectionEventList.txt
@@ -39,3 +39,5 @@
40001,E90_SPSM_InProcess_To_ProcessCompleted,,(40000)
50000,CarrierID_Readed,,(50000)
50001,PJ_Queued,,(50001)
50002,PJ_Start,,(50002)
50002,PJ_End,,(50003)
SourceCode/Bond/x64/Debug/ReportList.txt
@@ -17,4 +17,5 @@
40000,(1,10203,20000)
50000,(5000)
50001,(5003)
50002,(5004)
SourceCode/Bond/x64/Debug/VariableList.txt
@@ -37,4 +37,5 @@
5000,CarrierID,A20,卡匣ID
5001,CJobSpace,U1,CJ Space
5002,PJobSpace,U1,PJ Space
5003,PJQueued,L,PJ Queued
5003,PJQueued,L,PJ Queued
5004,PJStartID,A20,PJStartID