已修改15个文件
708 ■■■■ 文件已修改
SourceCode/Bond/Servo/CCjPage2.cpp 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEFEM.cpp 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqStatusStep.cpp 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqStatusStep.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 187 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PortConfigurationDlg.cpp 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/CollectionEventList.txt 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/DataVariableList.txt 196 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/ReportList.txt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/VariableList.txt 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCjPage2.cpp
@@ -13,6 +13,40 @@
    IDC_BUTTON_PORT3_PROCESS_START,
    IDC_BUTTON_PORT4_PROCESS_START };
namespace {
    void BuildCassetteCtrlMaps(SERVO::CLoadPort* pPort, short (&jobExistence)[12], short& slotProcess)
    {
        slotProcess = 0;
        bool anyScheduled = false;
        // Prefer hardware scan map for job existence (first 16 slots).
        const short scanMap = pPort->getScanCassetteMap();
        if (scanMap != 0) {
            jobExistence[0] = scanMap;
        }
        const int maxSlots = 12 * 16;
        const int totalSlots = (SLOT_MAX < maxSlots) ? SLOT_MAX : maxSlots;
        for (int slot = 1; slot <= totalSlots; ++slot) {
            SERVO::CGlass* pGlass = pPort->getGlassFromSlot(slot);
            if (pGlass == nullptr) continue;
            const int wordIndex = (slot - 1) / 16;
            const int bitIndex = (slot - 1) % 16;
            jobExistence[wordIndex] = (short)(jobExistence[wordIndex] | (1 << bitIndex));
            if (slot <= 16 && pGlass->isScheduledForProcessing()) {
                slotProcess = (short)(slotProcess | (1 << bitIndex));
                anyScheduled = true;
            }
        }
        if (!anyScheduled) {
            slotProcess = jobExistence[0];
        }
    }
}
// CPjPage1 对话框
IMPLEMENT_DYNAMIC(CCjPage2, CCjPageBase)
@@ -452,7 +486,11 @@
{
    auto& master = theApp.m_model.getMaster();
    auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT1);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
    if (port == nullptr) return;
    short jobExistence[12] = { 0 };
    short slotProcess = 0;
    BuildCassetteCtrlMaps(port, jobExistence, slotProcess);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, 0, nullptr, nullptr);
}
@@ -460,21 +498,33 @@
{
    auto& master = theApp.m_model.getMaster();
    auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT2);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
    if (port == nullptr) return;
    short jobExistence[12] = { 0 };
    short slotProcess = 0;
    BuildCassetteCtrlMaps(port, jobExistence, slotProcess);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, 0, nullptr, nullptr);
}
void CCjPage2::OnBnClickedButtonPort3ProcessStart()
{
    auto& master = theApp.m_model.getMaster();
    auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT3);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
    if (port == nullptr) return;
    short jobExistence[12] = { 0 };
    short slotProcess = 0;
    BuildCassetteCtrlMaps(port, jobExistence, slotProcess);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, 0, nullptr, nullptr);
}
void CCjPage2::OnBnClickedButtonPort4ProcessStart()
{
    auto& master = theApp.m_model.getMaster();
    auto port = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT4);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
    if (port == nullptr) return;
    short jobExistence[12] = { 0 };
    short slotProcess = 0;
    BuildCassetteCtrlMaps(port, jobExistence, slotProcess);
    port->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, 0, nullptr, nullptr);
}
SourceCode/Bond/Servo/CEFEM.cpp
@@ -713,14 +713,26 @@
                        // Reserved                    15W
                        short ack = (short)JobDataRequestAck::NG;        // 不存在jobData
                        char szBuffer[1024] = { 0 };
                        LOGI("<CEFEM-%s>JobDataRequest received (code=%d, size=%zu)", m_strName.c_str(), code, size);
                        if (m_pActiveContext != nullptr) {
                            CJobDataS* pJobDataS = ((CGlass*)m_pActiveContext)->getJobDataS();
                            if (pJobDataS != nullptr) {
                                pJobDataS->serialize(szBuffer, 1024);
                                ack = (short)JobDataRequestAck::OK;
                                LOGI("<CEFEM-%s>JobDataRequest OK (CassetteSeq=%d, JobSeq=%d)",
                                    m_strName.c_str(),
                                    pJobDataS->getCassetteSequenceNo(),
                                    pJobDataS->getJobSequenceNo());
                            }
                            else {
                                LOGW("<CEFEM-%s>JobDataRequest NG (JobDataS is null)", m_strName.c_str());
                            }
                        }
                        else {
                            LOGW("<CEFEM-%s>JobDataRequest NG (ActiveContext is null)", m_strName.c_str());
                        }
                        memcpy(&szBuffer[320 * 2], &ack, sizeof(short));
                        LOGI("<CEFEM-%s>JobDataRequest response ack=%d", m_strName.c_str(), (int)ack);
                        ((CEqReadStep*)pFrom)->setReturnData(szBuffer, 336 * 2);
                    }
                    return -1;
SourceCode/Bond/Servo/CEqStatusStep.cpp
@@ -8,6 +8,7 @@
    CEqStatusStep::CEqStatusStep() : CReadStep()
    {
        m_nStatusDev = 0;
        m_nUnitId = 0;
        for (int i = 0; i < STATUS_MAX; i++) {
            m_nStatus[i] = 0;
            m_nReasonCode[i] = 0;
@@ -49,6 +50,20 @@
        return -1;
    }
    int CEqStatusStep::getReasonCode(unsigned int uint) const
    {
        if (uint < STATUS_MAX) {
            return m_nReasonCode[uint];
        }
        return -1;
    }
    unsigned int CEqStatusStep::getUnitId() const
    {
        return m_nUnitId;
    }
    int CEqStatusStep::onReadData()
    {
        CReadStep::onReadData();
@@ -60,10 +75,11 @@
            return -1;
        }
        unsigned int unitId = (unsigned int)CToolUnits::toInt16(&szBuffer[0]);
        const unsigned int unitId = (unsigned int)CToolUnits::toInt16(&szBuffer[0]);
        if (unitId >= STATUS_MAX) {
            return -2;
        }
        m_nUnitId = unitId;
        if (unitId == 0) {
            m_nStatus[unitId] = CToolUnits::toInt16(&szBuffer[2 + unitId * 4]);
SourceCode/Bond/Servo/CEqStatusStep.h
@@ -18,11 +18,14 @@
        virtual int onComplete();
        virtual int onTimeout();
        void setStatusDev(int nDev);
        unsigned int getUnitId() const;
        int getStatus(unsigned int uint);
        int getReasonCode(unsigned int uint) const;
        std::string& getStatusDescription(unsigned int unid, std::string& strDescription);
    private:
        int m_nStatusDev;
        unsigned int m_nUnitId;
        int m_nStatus[STATUS_MAX];
        int m_nReasonCode[STATUS_MAX];
    };
SourceCode/Bond/Servo/CEquipment.cpp
@@ -779,6 +779,16 @@
                return 1;
            }
            else if (pStep->getName().compare(STEP_STATUS) == 0) {
                SERVO::CEqStatusStep* pEqStatusStep = (SERVO::CEqStatusStep*)pStep;
                if (m_listener.onEqStatusChanged != nullptr) {
                    const unsigned int unitId = pEqStatusStep->getUnitId();
                    const int status = pEqStatusStep->getStatus(unitId);
                    const int reason = pEqStatusStep->getReasonCode(unitId);
                    m_listener.onEqStatusChanged(this, (int)unitId, status, reason);
                }
                return 1;
            }
            else if (isCimMessageConfirmStep(pStep)) {
                SERVO::CEqReadIntStep* pEqReadIntStep = (SERVO::CEqReadIntStep*)pStep;
                int value = pEqReadIntStep->getValue();
SourceCode/Bond/Servo/CEquipment.h
@@ -61,6 +61,7 @@
    typedef std::function<void(void* pEiuipment, const std::vector<CParam>& params)> ONPROCESSDATAREPORT;
    typedef std::function<void(void* pEiuipment, int port, CJobDataS* pJobDataS)> ONRECEIVEDJOB;
    typedef std::function<void(void* pEiuipment, int port, CJobDataS* pJobDataS)> ONSENTOUTJOB;
    typedef std::function<void(void* pEiuipment, int unitId, int status, int reason)> ONEQSTATUSCHANGED;
    
    typedef struct _EquipmentListener
    {
@@ -79,6 +80,7 @@
        ONPROCESSDATAREPORT    onProcessDataReport;
        ONRECEIVEDJOB        onReceivedJob;
        ONSENTOUTJOB        onSentOutJob;
        ONEQSTATUSCHANGED    onEqStatusChanged;
    } EquipmentListener;
SourceCode/Bond/Servo/CMaster.cpp
@@ -1935,6 +1935,11 @@
                m_listener.onJobSentOut(this, (CEquipment*)pEquipment, port, pJobDataS);
            }
        };
        listener.onEqStatusChanged = [&](void* pEquipment, int unitId, int status, int reason) {
            if (m_listener.onEqStatusChanged != nullptr) {
                m_listener.onEqStatusChanged(this, (CEquipment*)pEquipment, unitId, status, reason);
            }
        };
        pEquipment->setListener(listener);
        pEquipment->setCcLink(&m_cclink);
        m_listEquipment.push_back(pEquipment);
@@ -2902,7 +2907,40 @@
        static int pid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4};
        CLoadPort* pPort = (CLoadPort*)getEquipment(pid[port]);
        pPort->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
        if (pPort == nullptr) return -1;
        short jobExistence[12] = { 0 };
        short slotProcess = 0;
        short jobCount = 0; // 0 = Process All Glass
        bool anyScheduled = false;
        // Prefer hardware scan map for job existence (first 16 slots).
        const short scanMap = pPort->getScanCassetteMap();
        if (scanMap != 0) {
            jobExistence[0] = scanMap;
        }
        const int maxSlots = 12 * 16;
        const int totalSlots = (SLOT_MAX < maxSlots) ? SLOT_MAX : maxSlots;
        for (int slot = 1; slot <= totalSlots; ++slot) {
            CGlass* pGlass = pPort->getGlassFromSlot(slot);
            if (pGlass == nullptr) continue;
            const int wordIndex = (slot - 1) / 16;
            const int bitIndex = (slot - 1) % 16;
            jobExistence[wordIndex] = (short)(jobExistence[wordIndex] | (1 << bitIndex));
            if (slot <= 16 && pGlass->isScheduledForProcessing()) {
                slotProcess = (short)(slotProcess | (1 << bitIndex));
                anyScheduled = true;
            }
        }
        if (!anyScheduled) {
            slotProcess = jobExistence[0];
        }
        pPort->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, jobCount, nullptr, nullptr);
        return 0;
    }
@@ -3490,6 +3528,11 @@
        }
        m_pControlJob->abort(description);
        // 先上报一次状态变化(便于 PrJobAbort 触发)
        if (m_listener.onControlJobChanged) {
            notifyControlJobChanged();
        }
        // 释放Job相关
        for (auto item : m_processJobs) {
SourceCode/Bond/Servo/CMaster.h
@@ -72,6 +72,7 @@
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, const std::vector<CParam>& params)> ONSVDATAREPORT;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int port, CJobDataS* pJobDataS)> ONJOBRECEIVED;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int port, CJobDataS* pJobDataS)> ONJOBSENTOUT;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int unitId, int status, int reason)> ONEQSTATUSCHANGEDEX;
    typedef std::function<void(void* pMaster, int round)> ONCTROUNDEND;
    typedef std::function<void(void* pMaster, void* pj)> ONPJSTART;
    typedef std::function<void(void* pMaster)> ONCONTROLJOBCHANGED;
@@ -90,6 +91,7 @@
        ONPROCESSDATAREPORTEX   onProcessDataReport;
        ONJOBRECEIVED           onJobReceived;
        ONJOBSENTOUT            onJobSentOut;
        ONEQSTATUSCHANGEDEX       onEqStatusChanged;
        ONCTROUNDEND            onCTRoundEnd;
        ONPJSTART               onCjStart;
        ONPJSTART               onCjEnd;
SourceCode/Bond/Servo/Model.cpp
@@ -41,8 +41,118 @@
{
    // 1) 刷新派生 SV
    refreshDerivedSVs();
    // 2) 上报 CJ 状态事件(同一 CJID,RPTID=31000)
    static SERVO::CJState s_prevState = SERVO::CJState::NoState;
    static std::string s_prevCjId;
    SERVO::CControlJob* pCj = m_master.getControlJob();
    if (pCj == nullptr) {
        if (!s_prevCjId.empty()) {
            m_hsmsPassive.withVariableLock([&] {
                m_hsmsPassive.setVariableValue("CJID", s_prevCjId.c_str());
                m_hsmsPassive.requestEventReportSend("CJobDeleted");
            });
            s_prevCjId.clear();
            s_prevState = SERVO::CJState::NoState;
        }
    }
    else {
        const std::string& cjId = pCj->id();
        const SERVO::CJState state = pCj->state();
        if (s_prevCjId != cjId) {
            s_prevCjId = cjId;
            s_prevState = SERVO::CJState::NoState;
        }
        if (state != s_prevState) {
            m_hsmsPassive.withVariableLock([&] {
                m_hsmsPassive.setVariableValue("CJID", cjId.c_str());
                if (state == SERVO::CJState::Queued) {
                    m_hsmsPassive.requestEventReportSend("CJobQueued");
                }
                else if (state == SERVO::CJState::Executing) {
                    if (s_prevState == SERVO::CJState::Paused) {
                        m_hsmsPassive.requestEventReportSend("CJobResume");
                    }
                    else {
                        m_hsmsPassive.requestEventReportSend("CJobExecuting");
                    }
                }
                else if (state == SERVO::CJState::Paused) {
                    m_hsmsPassive.requestEventReportSend("CJobPaused");
                }
                else if (state == SERVO::CJState::Completed) {
                    m_hsmsPassive.requestEventReportSend("CJobCompleted");
                }
                else if (state == SERVO::CJState::Aborted || state == SERVO::CJState::Failed) {
                    m_hsmsPassive.requestEventReportSend("CJobAbort");
                }
            });
            s_prevState = state;
        }
    }
    // 3) 上报 PJ 状态事件(PrJob*)
    emitPjStateEvents();
    // 2) 通知上层 UI(RX_CODE_CONTROLJOB_CHANGED)
    notify(RX_CODE_CONTROLJOB_CHANGED);
}
void CModel::emitPjStateEvents()
{
    // 当前 PJ 列表
    std::map<std::string, SERVO::PJState> current;
    for (auto pj : m_master.getProcessJobs()) {
        if (pj == nullptr) continue;
        current[pj->id()] = pj->state();
    }
    // 已删除的 PJ
    for (auto it = m_prevPjStates.begin(); it != m_prevPjStates.end(); ) {
        if (current.find(it->first) == current.end()) {
            const std::string pjId = it->first;
            m_hsmsPassive.withVariableLock([&] {
                m_hsmsPassive.setVariableValue("PJID", pjId.c_str());
                m_hsmsPassive.requestEventReportSend("PrJobDeleted");
            });
            it = m_prevPjStates.erase(it);
            continue;
        }
        ++it;
    }
    // 状态变更事件
    for (const auto& kv : current) {
        const std::string& pjId = kv.first;
        const SERVO::PJState state = kv.second;
        auto prevIt = m_prevPjStates.find(pjId);
        if (prevIt == m_prevPjStates.end()) {
            // 新 PJ:由 onPRJobMultiCreate 负责上报 PrJobPooled,这里只缓存
            m_prevPjStates[pjId] = state;
            continue;
        }
        const SERVO::PJState prevState = prevIt->second;
        if (state == prevState) continue;
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJID", pjId.c_str());
            if (state == SERVO::PJState::InProcess) {
                if (prevState == SERVO::PJState::Paused) {
                    m_hsmsPassive.requestEventReportSend("PrJobResume");
                }
                else {
                    m_hsmsPassive.requestEventReportSend("PrJobProcessing");
                }
            }
            else if (state == SERVO::PJState::Paused) {
                m_hsmsPassive.requestEventReportSend("PrJobPaused");
            }
            else if (state == SERVO::PJState::Completed) {
                m_hsmsPassive.requestEventReportSend("PrJobCompleted");
            }
            else if (state == SERVO::PJState::Aborted || state == SERVO::PJState::Failed || state == SERVO::PJState::Aborting) {
                m_hsmsPassive.requestEventReportSend("PrJobAbort");
            }
        });
        m_prevPjStates[pjId] = state;
    }
}
bool CModel::raiseSoftAlarm(int alarmId,
@@ -398,6 +508,12 @@
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJQueued", vars);
            m_hsmsPassive.requestEventReportSend_PJ_Queued();
            for (auto pj : processJobs) {
                if (pj == nullptr) continue;
                m_hsmsPassive.setVariableValue("PJID", pj->id().c_str());
                m_hsmsPassive.requestEventReportSend("PrJobPooled");
                m_prevPjStates[pj->id()] = pj->state();
            }
        });
        return nRet;
    };
@@ -645,10 +761,20 @@
                glassId = g2;
            }
            const int slotNo = pJobDataS->getTargetSlotNo();
            const int sourceSlotNo = pJobDataS->getSourceSlotNo();
            const int sourcePortNo = pJobDataS->getSourcePortNo();
            std::string sourceCarrier;
            if (sourcePortNo > 0) {
                if (auto* pLoadPort = (SERVO::CLoadPort*)m_master.getEquipment(EQ_ID_LOADPORT1 + sourcePortNo - 1)) {
                    sourceCarrier = pLoadPort->getCassetteId();
                }
            }
            m_hsmsPassive.withVariableLock([&] {
                m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
                m_hsmsPassive.setVariableValue("SubEqpSlot", slotNo);
                m_hsmsPassive.setVariableValue("MaterialId", glassId.c_str());
                m_hsmsPassive.setVariableValue("SourceCarrier", sourceCarrier.c_str());
                m_hsmsPassive.setVariableValue("SourceSlot", (__int64)sourceSlotNo);
                m_hsmsPassive.setVariableValue("SourcePanelID", glassId.c_str());
                m_hsmsPassive.requestEventReportSend("GlassReceivedJob");
            });
        }
@@ -701,10 +827,20 @@
            glassId = g2;
        }
        const int slotNo = pJobDataS->getSourceSlotNo();
        const int targetSlotNo = pJobDataS->getTargetSlotNo();
        const int targetPortNo = pJobDataS->getTargetPortNo();
        std::string targetCarrier;
        if (targetPortNo > 0) {
            if (auto* pLoadPort = (SERVO::CLoadPort*)m_master.getEquipment(EQ_ID_LOADPORT1 + targetPortNo - 1)) {
                targetCarrier = pLoadPort->getCassetteId();
            }
        }
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
            m_hsmsPassive.setVariableValue("SubEqpSlot", slotNo);
            m_hsmsPassive.setVariableValue("MaterialId", glassId.c_str());
            m_hsmsPassive.setVariableValue("TargetCarrier", targetCarrier.c_str());
            m_hsmsPassive.setVariableValue("TargetSlot", (__int64)targetSlotNo);
            m_hsmsPassive.setVariableValue("TargetPanelID", glassId.c_str());
            m_hsmsPassive.requestEventReportSend("GlassSentOutJob");
        });
    };
@@ -811,34 +947,37 @@
            m_hsmsPassive.setVariableValue("CurrentProcessState", (__int64)state);
            m_hsmsPassive.requestEventReportSend("ProcessStateChanged");
            // SubEqp events (per equipment, ignore slot distinction except payload)
            static std::map<int, SERVO::PROCESS_STATE> s_prevSubEqpState;
            const auto prevEqState = s_prevSubEqpState[eqId];
            if (prevEqState != state) {
                // state change
                m_hsmsPassive.requestEventReportSend("SubEqpStateChange");
            }
            if (state == SERVO::PROCESS_STATE::Processing) {
                m_hsmsPassive.requestEventReportSend_SubEqpStart();
            }
            else if (state == SERVO::PROCESS_STATE::Complete) {
                m_hsmsPassive.requestEventReportSend_SubEqpEnd();
            }
            s_prevSubEqpState[eqId] = state;
            // Unit events (per equipment slot)
            static std::map<int, std::map<int, SERVO::PROCESS_STATE>> s_prevUnitState;
            const auto prevUnitState = s_prevUnitState[eqId][slotNo];
            if (prevUnitState != state) {
                m_hsmsPassive.requestEventReportSend("UnitStateChange");
                std::string panelId;
                if (pEquipment != nullptr && slotNo > 0) {
                    if (auto* pGlass = pEquipment->getGlassFromSlot(slotNo)) {
                        panelId = pGlass->getID();
                    }
                }
                if (state == SERVO::PROCESS_STATE::Processing) {
                    m_hsmsPassive.setVariableValue("PanelStartID", panelId.c_str());
                    m_hsmsPassive.requestEventReportSend("UnitStart");
                }
                else if (state == SERVO::PROCESS_STATE::Complete) {
                    m_hsmsPassive.setVariableValue("PanelEndID", panelId.c_str());
                    m_hsmsPassive.requestEventReportSend("UnitEnd");
                }
                s_prevUnitState[eqId][slotNo] = state;
            }
        });
    };
    masterListener.onEqStatusChanged = [&](void* pMaster, SERVO::CEquipment* pEquipment, int unitId, int status, int reason) {
        (void)pMaster;
        if (pEquipment == nullptr) return;
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
            m_hsmsPassive.setVariableValue("SubEqpSlot", (__int64)unitId);
            m_hsmsPassive.setVariableValue("EquipmentStatus", (__int64)status);
            m_hsmsPassive.requestEventReportSend("SubEqpStateChange");
        });
    };
    masterListener.onSVDataReport = [&](void* pMaster, SERVO::CEquipment* pEquipment, const std::vector<CParam>& params) {
@@ -851,7 +990,7 @@
                if (pEquipment != nullptr) {
                    m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
                }
                m_hsmsPassive.setVariableValue("SubEqpSlot", 0);
                m_hsmsPassive.setVariableValue("SubEqpSlot", (__int64)0);
                m_hsmsPassive.setVariableValue("Clock", CToolUnits::getCurrentTimeString().c_str());
                for (size_t idx = 0; idx < count; ++idx) {
                    const std::string val = formatParamValue(params[idx]);
@@ -897,7 +1036,7 @@
                if (pEquipment != nullptr) {
                    m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
                }
                m_hsmsPassive.setVariableValue("SubEqpSlot", 0);
                m_hsmsPassive.setVariableValue("SubEqpSlot", (__int64)0);
                m_hsmsPassive.setVariableValue("Clock", CToolUnits::getCurrentTimeString().c_str());
                for (size_t idx = 0; idx < count; ++idx) {
                    const std::string val = formatParamValue(params[idx]);
@@ -932,13 +1071,13 @@
    };
    masterListener.onCjStart = [&](void* pMaster, void* pj) {
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("CJStartID", ((SERVO::CControlJob*)pj)->id().c_str());
            m_hsmsPassive.setVariableValue("CJID", ((SERVO::CControlJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_CJ_Start();
        });
    };
    masterListener.onCjEnd = [&](void* pMaster, void* pj) {
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("CJEndID", ((SERVO::CControlJob*)pj)->id().c_str());
            m_hsmsPassive.setVariableValue("CJID", ((SERVO::CControlJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_CJ_End();
        });
@@ -947,15 +1086,17 @@
    };
    masterListener.onPjStart = [&](void* pMaster, void* pj) {
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJStartID", ((SERVO::CProcessJob*)pj)->id().c_str());
            m_hsmsPassive.setVariableValue("PJID", ((SERVO::CProcessJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_PJ_Start();
        });
        emitPjStateEvents();
    };
    masterListener.onPjEnd = [&](void* pMaster, void* pj) {
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJEndID", ((SERVO::CProcessJob*)pj)->id().c_str());
            m_hsmsPassive.setVariableValue("PJID", ((SERVO::CProcessJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_PJ_End();
        });
        emitPjStateEvents();
    };
    masterListener.onPanelStart = [&](void* pMaster, void* pPanel) {
        m_hsmsPassive.withVariableLock([&] {
SourceCode/Bond/Servo/Model.h
@@ -3,7 +3,9 @@
#include "HsmsPassive.h"
#include "CMaster.h"
#include "CGlassPool.h"
#include "ProcessJob.h"
#include <cstdint>
#include <map>
#include <string>
enum class ControlState : uint8_t {
@@ -46,6 +48,7 @@
private:
    void refreshDerivedSVs();
    void notifyControlJobChanged();
    void emitPjStateEvents();
public:
    int notify(int code);
@@ -75,4 +78,5 @@
private:
    ControlState m_currentControlState{ ControlState::OfflineEquipment };
    std::map<std::string, SERVO::PJState> m_prevPjStates;
};
SourceCode/Bond/Servo/PortConfigurationDlg.cpp
@@ -451,7 +451,40 @@
    constexpr short cmd = CCC_PROCESS_START;
    LOGI("ProcessStart request: port=%d, cmd=%d", selPort + 1, cmd);
    int ret = pPort->sendCassetteCtrlCmd(cmd, nullptr, 0, 0, 0, nullptr,
    short jobExistence[12] = { 0 };
    short slotProcess = 0;
    short jobCount = 0; // 0 = Process All Glass (per spec)
    bool anyScheduled = false;
    // Prefer hardware scan map for job existence (first 16 slots).
    const short scanMap = pPort->getScanCassetteMap();
    if (scanMap != 0) {
        jobExistence[0] = scanMap;
    }
    // Build existence/selected maps from current glass list (up to 192 slots).
    const int maxSlots = 12 * 16;
    const int totalSlots = (SLOT_MAX < maxSlots) ? SLOT_MAX : maxSlots;
    for (int slot = 1; slot <= totalSlots; ++slot) {
        SERVO::CGlass* pGlass = pPort->getGlassFromSlot(slot);
        if (pGlass == nullptr) continue;
        const int wordIndex = (slot - 1) / 16;
        const int bitIndex = (slot - 1) % 16;
        jobExistence[wordIndex] = (short)(jobExistence[wordIndex] | (1 << bitIndex));
        if (slot <= 16 && pGlass->isScheduledForProcessing()) {
            slotProcess = (short)(slotProcess | (1 << bitIndex));
            anyScheduled = true;
        }
    }
    // If no slot explicitly selected, default to all existing in the first word.
    if (!anyScheduled) {
        slotProcess = jobExistence[0];
    }
    int ret = pPort->sendCassetteCtrlCmd(cmd, jobExistence, 12, slotProcess, jobCount, nullptr,
        [selPort](int code) -> int {
            if (code == WOK) {
                LOGI("ProcessStart write complete: port=%d, code=WOK", selPort + 1);
SourceCode/Bond/x64/Debug/CollectionEventList.txt
@@ -4,8 +4,6 @@
600,ControlStateChanged,,(600)
700,ProcessStateChanged,,(700)
10018,ProcessDataReport,,(33)
10015,SubEqpStart,,(10015)
10016,SubEqpEnd,,(10016)
10017,SubEqpStateChange,,(10017)
10000,RecipeChanged,,(10000)
10030,CarrierArrived,,(10300)
@@ -29,29 +27,29 @@
20000,GlassSlotStart,,(20000)
20001,GlassSlotCompleted,,(20000)
30000,PrJobPooled,,(30000)
30001,PrJobAbort,,(30000)
30010,PrJobProcessing,,(30000)
30011,PrJobCompleted,,(30000)
30013,PrJobPaused,,(30000)
30014,PrJobResume,,(30000)
30020,PrJobDeleted,,(30000)
30001,PJ_Queued,,(50001)
30002,PJ_Start,,(50002)
30003,PrJobProcessing,,(30000)
30004,PrJobPaused,,(30000)
30005,PrJobResume,,(30000)
30006,PrJobCompleted,,(30000)
30007,PJ_End,,(50003)
30008,PrJobAbort,,(30000)
30009,PrJobDeleted,,(30000)
31000,CJobQueued,,(31000)
31001,CJobAbort,,(31000)
31010,CJobExecuting,,(31000)
31020,CJobCompleted,,(31000)
31021,CJobDeleted,,(31000)
31031,CJobPaused,,(31000)
31032,CJobResume,,(31000)
31001,CJ_Start,,(31000)
31002,CJobExecuting,,(31000)
31003,CJobPaused,,(31000)
31004,CJobResume,,(31000)
31005,CJobCompleted,,(31000)
31006,CJ_End,,(31000)
31007,CJobAbort,,(31000)
31008,CJobDeleted,,(31000)
40000,E90_SPSM_NoState_To_NeedsProcessing,,(40000)
40001,E90_SPSM_InProcess_To_ProcessCompleted,,(40000)
50000,CarrierID_Readed,,(50000)
50001,PJ_Queued,,(50001)
50002,PJ_Start,,(50002)
50003,PJ_End,,(50003)
50004,Panel_Start,,(50004)
50005,Panel_End,,(50005)
50006,CJ_Start,,(50006)
50007,CJ_End,,(50007)
50008,Port_Unload_Ready,,(50008)
50009,Port_Load_Ready,,(50009)
50010,Port_Blocked,,(50010)
SourceCode/Bond/x64/Debug/DataVariableList.txt
@@ -1,98 +1,98 @@
DVID,DV Name,DV Format,DV Remark
6000,Bonder_SV_ProcessStep,A20,Bonder SV: 工艺运行步骤
6001,Bonder_SV_BladderPressure,A20,Bonder SV: 气囊压力当前
6002,Bonder_SV_UpperChamberPressure,A20,Bonder SV: 上腔压力合计
6003,Bonder_SV_PipeVacuumGauge,A20,Bonder SV: 管道真空表
6004,Bonder_SV_ChamberVacuumGauge,A20,Bonder SV: 腔体真空表
6005,Bonder_SV_UpperTemp1,A20,Bonder SV: 上腔温度1
6006,Bonder_SV_UpperTemp2,A20,Bonder SV: 上腔温度2
6007,Bonder_SV_UpperTemp3,A20,Bonder SV: 上腔温度3
6008,Bonder_SV_UpperTemp4,A20,Bonder SV: 上腔温度4
6009,Bonder_SV_UpperTemp5,A20,Bonder SV: 上腔温度5
6010,Bonder_SV_UpperTemp6,A20,Bonder SV: 上腔温度6
6011,Bonder_SV_LowerTemp1,A20,Bonder SV: 下腔温度1
6012,Bonder_SV_LowerTemp2,A20,Bonder SV: 下腔温度2
6013,Bonder_SV_LowerTemp3,A20,Bonder SV: 下腔温度3
6014,Bonder_SV_LowerTemp4,A20,Bonder SV: 下腔温度4
6015,Bonder_SV_LowerTemp5,A20,Bonder SV: 下腔温度5
6016,Bonder_SV_LowerTemp6,A20,Bonder SV: 下腔温度6
6017,Bonder_SV_HeatingRemaining,A20,Bonder SV: 加热剩余时间
6018,Bonder_SV_PressingRemaining,A20,Bonder SV: 压合剩余时间
6100,Bonder_PD_AlignDelay,A20,Bonder PD: 对位延时
6101,Bonder_PD_DwellTime,A20,Bonder PD: 保压时间
6102,Bonder_PD_BreakVacuumDelay,A20,Bonder PD: 破真空延时
6103,Bonder_PD_TurboPumpStartDelay,A20,Bonder PD: 分子泵启动延时
6104,Bonder_PD_AttachVacuumDelay,A20,Bonder PD: 抽真空延时
6105,Bonder_PD_HeatingWaitDelay,A20,Bonder PD: 等待加热延时
6106,Bonder_PD_BladderPressureSet,A20,Bonder PD: 气囊压力设定
6107,Bonder_PD_BladderPressurizeRate,A20,Bonder PD: 气囊加压速率
6108,Bonder_PD_BladderDepressurizeRate,A20,Bonder PD: 气囊泄压速率
6109,Bonder_PD_AttachPressureLimit,A20,Bonder PD: 贴合压力上限
6110,Bonder_PD_UpperZTorqueSpeed,A20,Bonder PD: 上腔Z预贴合速度
6111,Bonder_PD_UpperTempSet,A20,Bonder PD: 上腔温度设定
6112,Bonder_PD_LowerTempSet,A20,Bonder PD: 下腔温度设定
6113,Bonder_PD_PreAttachSpeed,A20,Bonder PD: 预贴合速度
6114,Bonder_PD_AttachSpeed,A20,Bonder PD: 贴合速度
6115,Bonder_PD_UpperHeatDistance,A20,Bonder PD: 上腔加热距离
6116,Bonder_PD_AttachPressIn,A20,Bonder PD: 贴合压入力
6117,Bonder_PD_UpperBreakVacuumDist,A20,Bonder PD: 上腔破真空距离
6118,Bonder_PD_LowerPinBreakVacuumDist,A20,Bonder PD: 下顶针破真空距离
6119,Bonder_PD_LowerPinHeatDistance,A20,Bonder PD: 下顶针加热距离
6120,Bonder_PD_PumpGaugeSet,A20,Bonder PD: 真空泵真空设定
6121,Bonder_PD_TurboReachSet,A20,Bonder PD: 分子泵到达设定
6200,VacuumBake_SV_A_ProcessStep,A20,VacuumBake SV A: 工艺运行步骤
6201,VacuumBake_SV_A_ChamberVacuum,A20,VacuumBake SV A: 腔体真空
6202,VacuumBake_SV_A_Temp1,A20,VacuumBake SV A: 温度1
6203,VacuumBake_SV_A_Temp2,A20,VacuumBake SV A: 温度2
6204,VacuumBake_SV_A_Temp4,A20,VacuumBake SV A: 温度4
6205,VacuumBake_SV_A_Temp5,A20,VacuumBake SV A: 温度5
6206,VacuumBake_SV_A_Temp6,A20,VacuumBake SV A: 温度6
6207,VacuumBake_SV_A_Temp7,A20,VacuumBake SV A: 温度7
6208,VacuumBake_SV_A_BakeRemaining,A20,VacuumBake SV A: 烘烤剩余时间
6209,VacuumBake_SV_B_ProcessStep,A20,VacuumBake SV B: 工艺运行步骤
6210,VacuumBake_SV_B_ChamberVacuum,A20,VacuumBake SV B: 腔体真空
6211,VacuumBake_SV_B_Temp1,A20,VacuumBake SV B: 温度1
6212,VacuumBake_SV_B_Temp2,A20,VacuumBake SV B: 温度2
6213,VacuumBake_SV_B_Temp4,A20,VacuumBake SV B: 温度4
6214,VacuumBake_SV_B_Temp5,A20,VacuumBake SV B: 温度5
6215,VacuumBake_SV_B_Temp6,A20,VacuumBake SV B: 温度6
6216,VacuumBake_SV_B_Temp7,A20,VacuumBake SV B: 温度7
6217,VacuumBake_SV_B_BakeRemaining,A20,VacuumBake SV B: 烘烤剩余时间
6300,VacuumBake_PD_ParamIndex,A20,VacuumBake PD: 参数序号
6301,VacuumBake_PD_HeatTime,A20,VacuumBake PD: 加热时间
6302,VacuumBake_PD_BreakVacuumTime,A20,VacuumBake PD: 破真空时间
6303,VacuumBake_PD_VacuumReach,A20,VacuumBake PD: 真空达到值
6304,VacuumBake_PD_TempSet,A20,VacuumBake PD: 主控温度设定
6400,BakeCooling_SV_A_BakeStep,A20,BakeCooling SV A: 烘烤步骤
6401,BakeCooling_SV_A_Temp1,A20,BakeCooling SV A: 温度1
6402,BakeCooling_SV_A_Temp2,A20,BakeCooling SV A: 温度2
6403,BakeCooling_SV_A_Temp4,A20,BakeCooling SV A: 温度4
6404,BakeCooling_SV_A_Temp5,A20,BakeCooling SV A: 温度5
6405,BakeCooling_SV_A_Temp6,A20,BakeCooling SV A: 温度6
6406,BakeCooling_SV_A_Temp7,A20,BakeCooling SV A: 温度7
6407,BakeCooling_SV_A_BakeRemaining,A20,BakeCooling SV A: 烘烤剩余时间
6408,BakeCooling_SV_A_CoolStep,A20,BakeCooling SV A: 冷却步骤
6409,BakeCooling_SV_A_CoolRemaining,A20,BakeCooling SV A: 冷却剩余时间
6410,BakeCooling_SV_B_BakeStep,A20,BakeCooling SV B: 烘烤步骤
6411,BakeCooling_SV_B_Temp1,A20,BakeCooling SV B: 温度1
6412,BakeCooling_SV_B_Temp2,A20,BakeCooling SV B: 温度2
6413,BakeCooling_SV_B_Temp4,A20,BakeCooling SV B: 温度4
6414,BakeCooling_SV_B_Temp5,A20,BakeCooling SV B: 温度5
6415,BakeCooling_SV_B_Temp6,A20,BakeCooling SV B: 温度6
6416,BakeCooling_SV_B_Temp7,A20,BakeCooling SV B: 温度7
6417,BakeCooling_SV_B_BakeRemaining,A20,BakeCooling SV B: 烘烤剩余时间
6418,BakeCooling_SV_B_CoolStep,A20,BakeCooling SV B: 冷却步骤
6419,BakeCooling_SV_B_CoolRemaining,A20,BakeCooling SV B: 冷却剩余时间
6500,BakeCooling_PD_ParamIndex,A20,BakeCooling PD: 参数序号
6501,BakeCooling_PD_TimeOrTemp1,A20,BakeCooling PD: 时间/温度1
6502,BakeCooling_PD_TimeOrTemp2,A20,BakeCooling PD: 时间/温度2
6503,BakeCooling_PD_Reserved,A20,BakeCooling PD: 预留
6600,Measurement_SV_ProcessStep,A20,Measurement SV: 工艺运行步骤
6601,Measurement_SV_AOIScore,A20,Measurement SV: AOI分数
6700,Measurement_PD_ParamIndex,A20,Measurement PD: 参数序号
6701,Measurement_PD_Time,A20,Measurement PD: 时间
6702,Measurement_PD_Value1,A20,Measurement PD: 测量值1
6703,Measurement_PD_Value2,A20,Measurement PD: 测量值2
10200,SlotMap,U1,SlotMap(Scan)
10201,SlotMapScan,U1,SlotMap(Scan)
10202,SlotMapDownload,U1,SlotMap(Download)
DVID,DV Name,DV Format,DV Remark
6000,Bonder_SV_ProcessStep,A20,Bonder SV: 工艺运行步骤
6001,Bonder_SV_BladderPressure,A20,Bonder SV: 气囊压力当前
6002,Bonder_SV_UpperChamberPressure,A20,Bonder SV: 上腔压力合计
6003,Bonder_SV_PipeVacuumGauge,A20,Bonder SV: 管道真空表
6004,Bonder_SV_ChamberVacuumGauge,A20,Bonder SV: 腔体真空表
6005,Bonder_SV_UpperTemp1,A20,Bonder SV: 上腔温度1
6006,Bonder_SV_UpperTemp2,A20,Bonder SV: 上腔温度2
6007,Bonder_SV_UpperTemp3,A20,Bonder SV: 上腔温度3
6008,Bonder_SV_UpperTemp4,A20,Bonder SV: 上腔温度4
6009,Bonder_SV_UpperTemp5,A20,Bonder SV: 上腔温度5
6010,Bonder_SV_UpperTemp6,A20,Bonder SV: 上腔温度6
6011,Bonder_SV_LowerTemp1,A20,Bonder SV: 下腔温度1
6012,Bonder_SV_LowerTemp2,A20,Bonder SV: 下腔温度2
6013,Bonder_SV_LowerTemp3,A20,Bonder SV: 下腔温度3
6014,Bonder_SV_LowerTemp4,A20,Bonder SV: 下腔温度4
6015,Bonder_SV_LowerTemp5,A20,Bonder SV: 下腔温度5
6016,Bonder_SV_LowerTemp6,A20,Bonder SV: 下腔温度6
6017,Bonder_SV_HeatingRemaining,A20,Bonder SV: 加热剩余时间
6018,Bonder_SV_PressingRemaining,A20,Bonder SV: 压合剩余时间
6100,Bonder_PD_AlignDelay,A20,Bonder PD: 对位延时
6101,Bonder_PD_DwellTime,A20,Bonder PD: 保压时间
6102,Bonder_PD_BreakVacuumDelay,A20,Bonder PD: 破真空延时
6103,Bonder_PD_TurboPumpStartDelay,A20,Bonder PD: 分子泵启动延时
6104,Bonder_PD_AttachVacuumDelay,A20,Bonder PD: 抽真空延时
6105,Bonder_PD_HeatingWaitDelay,A20,Bonder PD: 等待加热延时
6106,Bonder_PD_BladderPressureSet,A20,Bonder PD: 气囊压力设定
6107,Bonder_PD_BladderPressurizeRate,A20,Bonder PD: 气囊加压速率
6108,Bonder_PD_BladderDepressurizeRate,A20,Bonder PD: 气囊泄压速率
6109,Bonder_PD_AttachPressureLimit,A20,Bonder PD: 贴合压力上限
6110,Bonder_PD_UpperZTorqueSpeed,A20,Bonder PD: 上腔Z预贴合速度
6111,Bonder_PD_UpperTempSet,A20,Bonder PD: 上腔温度设定
6112,Bonder_PD_LowerTempSet,A20,Bonder PD: 下腔温度设定
6113,Bonder_PD_PreAttachSpeed,A20,Bonder PD: 预贴合速度
6114,Bonder_PD_AttachSpeed,A20,Bonder PD: 贴合速度
6115,Bonder_PD_UpperHeatDistance,A20,Bonder PD: 上腔加热距离
6116,Bonder_PD_AttachPressIn,A20,Bonder PD: 贴合压入力
6117,Bonder_PD_UpperBreakVacuumDist,A20,Bonder PD: 上腔破真空距离
6118,Bonder_PD_LowerPinBreakVacuumDist,A20,Bonder PD: 下顶针破真空距离
6119,Bonder_PD_LowerPinHeatDistance,A20,Bonder PD: 下顶针加热距离
6120,Bonder_PD_PumpGaugeSet,A20,Bonder PD: 真空泵真空设定
6121,Bonder_PD_TurboReachSet,A20,Bonder PD: 分子泵到达设定
6200,VacuumBake_SV_A_ProcessStep,A20,VacuumBake SV A: 工艺运行步骤
6201,VacuumBake_SV_A_ChamberVacuum,A20,VacuumBake SV A: 腔体真空
6202,VacuumBake_SV_A_Temp1,A20,VacuumBake SV A: 温度1
6203,VacuumBake_SV_A_Temp2,A20,VacuumBake SV A: 温度2
6204,VacuumBake_SV_A_Temp4,A20,VacuumBake SV A: 温度4
6205,VacuumBake_SV_A_Temp5,A20,VacuumBake SV A: 温度5
6206,VacuumBake_SV_A_Temp6,A20,VacuumBake SV A: 温度6
6207,VacuumBake_SV_A_Temp7,A20,VacuumBake SV A: 温度7
6208,VacuumBake_SV_A_BakeRemaining,A20,VacuumBake SV A: 烘烤剩余时间
6209,VacuumBake_SV_B_ProcessStep,A20,VacuumBake SV B: 工艺运行步骤
6210,VacuumBake_SV_B_ChamberVacuum,A20,VacuumBake SV B: 腔体真空
6211,VacuumBake_SV_B_Temp1,A20,VacuumBake SV B: 温度1
6212,VacuumBake_SV_B_Temp2,A20,VacuumBake SV B: 温度2
6213,VacuumBake_SV_B_Temp4,A20,VacuumBake SV B: 温度4
6214,VacuumBake_SV_B_Temp5,A20,VacuumBake SV B: 温度5
6215,VacuumBake_SV_B_Temp6,A20,VacuumBake SV B: 温度6
6216,VacuumBake_SV_B_Temp7,A20,VacuumBake SV B: 温度7
6217,VacuumBake_SV_B_BakeRemaining,A20,VacuumBake SV B: 烘烤剩余时间
6300,VacuumBake_PD_ParamIndex,A20,VacuumBake PD: 参数序号
6301,VacuumBake_PD_HeatTime,A20,VacuumBake PD: 加热时间
6302,VacuumBake_PD_BreakVacuumTime,A20,VacuumBake PD: 破真空时间
6303,VacuumBake_PD_VacuumReach,A20,VacuumBake PD: 真空达到值
6304,VacuumBake_PD_TempSet,A20,VacuumBake PD: 主控温度设定
6400,BakeCooling_SV_A_BakeStep,A20,BakeCooling SV A: 烘烤步骤
6401,BakeCooling_SV_A_Temp1,A20,BakeCooling SV A: 温度1
6402,BakeCooling_SV_A_Temp2,A20,BakeCooling SV A: 温度2
6403,BakeCooling_SV_A_Temp4,A20,BakeCooling SV A: 温度4
6404,BakeCooling_SV_A_Temp5,A20,BakeCooling SV A: 温度5
6405,BakeCooling_SV_A_Temp6,A20,BakeCooling SV A: 温度6
6406,BakeCooling_SV_A_Temp7,A20,BakeCooling SV A: 温度7
6407,BakeCooling_SV_A_BakeRemaining,A20,BakeCooling SV A: 烘烤剩余时间
6408,BakeCooling_SV_A_CoolStep,A20,BakeCooling SV A: 冷却步骤
6409,BakeCooling_SV_A_CoolRemaining,A20,BakeCooling SV A: 冷却剩余时间
6410,BakeCooling_SV_B_BakeStep,A20,BakeCooling SV B: 烘烤步骤
6411,BakeCooling_SV_B_Temp1,A20,BakeCooling SV B: 温度1
6412,BakeCooling_SV_B_Temp2,A20,BakeCooling SV B: 温度2
6413,BakeCooling_SV_B_Temp4,A20,BakeCooling SV B: 温度4
6414,BakeCooling_SV_B_Temp5,A20,BakeCooling SV B: 温度5
6415,BakeCooling_SV_B_Temp6,A20,BakeCooling SV B: 温度6
6416,BakeCooling_SV_B_Temp7,A20,BakeCooling SV B: 温度7
6417,BakeCooling_SV_B_BakeRemaining,A20,BakeCooling SV B: 烘烤剩余时间
6418,BakeCooling_SV_B_CoolStep,A20,BakeCooling SV B: 冷却步骤
6419,BakeCooling_SV_B_CoolRemaining,A20,BakeCooling SV B: 冷却剩余时间
6500,BakeCooling_PD_ParamIndex,A20,BakeCooling PD: 参数序号
6501,BakeCooling_PD_TimeOrTemp1,A20,BakeCooling PD: 时间/温度1
6502,BakeCooling_PD_TimeOrTemp2,A20,BakeCooling PD: 时间/温度2
6503,BakeCooling_PD_Reserved,A20,BakeCooling PD: 预留
6600,Measurement_SV_ProcessStep,A20,Measurement SV: 工艺运行步骤
6601,Measurement_SV_AOIScore,A20,Measurement SV: AOI分数
6700,Measurement_PD_ParamIndex,A20,Measurement PD: 参数序号
6701,Measurement_PD_Time,A20,Measurement PD: 时间
6702,Measurement_PD_Value1,A20,Measurement PD: 测量值1
6703,Measurement_PD_Value2,A20,Measurement PD: 测量值2
10200,SlotMap,U1,SlotMap(Scan)
10201,SlotMapScan,U1,SlotMap(Scan)
10202,SlotMapDownload,U1,SlotMap(Download)
SourceCode/Bond/x64/Debug/ReportList.txt
@@ -18,17 +18,15 @@
10072,(1,10000,10001,10002,10003,10100,10203,20000,20001)
10080,(1,10000,10001,10002,10003,10100)
20000,(1,5018,5019,10000,10001,10002,10003,10203)
30000,(1,30000,30001)
31000,(1,31000,31001)
30000,(5004)
31000,(5008)
40000,(1,10203,20000)
50000,(5000)
50001,(5003)
50002,(5004)
50003,(5005)
50003,(5004)
50004,(5006)
50005,(5007)
50006,(5008)
50007,(5009)
50008,(5022)
50009,(5022)
50010,(5022)
@@ -37,8 +35,8 @@
50013,(5022)
50014,(5022)
50020,(500,5022,5021)
50021,(5018,5019,5023)
50022,(5018,5019,5023)
50021,(5018,5019,5028,5029,5030)
50022,(5018,5019,5025,5026,5027)
60000,(500,5018,5019,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018)
61000,(500,5018,5019,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118,6119,6120,6121)
62000,(500,5018,5019,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217)
@@ -47,10 +45,8 @@
65000,(500,5018,5019,6500,6501,6502,6503)
66000,(500,5018,5019,6600,6601)
67000,(500,5018,5019,6700,6701,6702,6703)
10015,(5018,5019)
10016,(5018,5019)
10017,(500,5018,5019)
12000,(500,5018,5019)
10017,(500,5018,5019,5024)
12000,(500,5018,5019,5006)
12001,(500,5018,5019)
12002,(500,5018,5019)
12002,(500,5018,5019,5007)
SourceCode/Bond/x64/Debug/VariableList.txt
@@ -1,42 +1,38 @@
SVID,SV Name,SV Format,SV Remark
10000,CarrierID_P1,A50,Carrier ID for Port 1
10001,CarrierID_P2,A50,Carrier ID for Port 2
10002,CarrierID_P3,A50,Carrier ID for Port 3
10003,CarrierID_P4,A50,Carrier ID for Port 4
100,PortTransferState_P1,U1,1=LoadReady;2=Loaded;3=InUse;4=UnloadReady;5=Empty;6=Blocked
101,PortTransferState_P2,U1,1=LoadReady;2=Loaded;3=InUse;4=UnloadReady;5=Empty;6=Blocked
102,PortTransferState_P3,U1,1=LoadReady;2=Loaded;3=InUse;4=UnloadReady;5=Empty;6=Blocked
103,PortTransferState_P4,U1,1=LoadReady;2=Loaded;3=InUse;4=UnloadReady;5=Empty;6=Blocked
300,AccessMode_P1,U1,0=OutOfService;1=TransferBlocked;2=ReadyToLoad;3=ReadyToUnload;4=InService;5=TransferReady
301,AccessMode_P2,U1,0=OutOfService;1=TransferBlocked;2=ReadyToLoad;3=ReadyToUnload;4=InService;5=TransferReady
302,AccessMode_P3,U1,0=OutOfService;1=TransferBlocked;2=ReadyToLoad;3=ReadyToUnload;4=InService;5=TransferReady
303,AccessMode_P4,U1,0=OutOfService;1=TransferBlocked;2=ReadyToLoad;3=ReadyToUnload;4=InService;5=TransferReady
500,Clock,A50,Current timestamp string
600,CurrentControlState,U1,0=OfflineEquipment;1=OfflineAttempt;2=Online;3=OfflineHost;4=OnlineLocal;5=OnlineRemote
601,PreviousControlState,U1,Previous control state (same code set as CurrentControlState)
700,CurrentProcessState,U1,0=Ready;1=Processing;2=Complete;3=Error
701,PreviousProcessState,U1,Previous process state (0=Ready;1=Processing;2=Complete;3=Error)
800,EFEMPPExecName,A20,Current PPExec name from EFEM
801,EQPPExecName,A20,Current PPExec name from equipment
8100,Bonder1CurrentRecipe,A50,Current recipe for Bonder1
8101,Bonder2CurrentRecipe,A50,Current recipe for Bonder2
8102,VacuumBakeCurrentRecipe,A50,Current recipe for VacuumBake
8103,BakeCoolingCurrentRecipe,A50,Current recipe for BakeCooling
8104,MeasurementCurrentRecipe,A50,Current recipe for Measurement
8105,EFEMCurrentRecipe,A50,Current recipe for EFEM
5001,CJobSpace,U1,CJ Space
5002,PJobSpace,U1,PJ Space
5003,PJQueued,L,PJ queued list (IDs)
5004,PJStartID,A20,PJ start ID
5005,PJEndID,A20,PJ end ID
5006,PanelStartID,A20,Panel start ID
5007,PanelEndID,A20,Panel end ID
5008,CJStartID,A20,CJ start ID
5009,CJEndID,A20,CJ end ID
5014,VCRPanelID,A20,Panel ID from reader
5017,ProcessDataReportText,A50,EV_PROCESS_DATA_REPORT payload (placeholder)
5018,SubEqpName,A20,Sub equipment name (SubEqp/Unit/Process/SV/ProcessData events)
5019,SubEqpSlot,U1,Slot number for SubEqp/Unit; 0 when not applicable
5021,PortState,U1,Port transfer/state code for PortStateChange
5022,PortId,U1,Unified port ID for all Port events
5023,MaterialId,A50,Material/Glass ID for Received/SentOut events
SVID,SV Name,SV Format,SV Remark
300,AccessMode_P1,U1,0=OutOfService;1=TransferBlocked;2=ReadyToLoad;3=ReadyToUnload;4=InService;5=TransferReady
500,Clock,A50,Current timestamp string
600,CurrentControlState,U1,0=OfflineEquipment;1=OfflineAttempt;2=Online;3=OfflineHost;4=OnlineLocal;5=OnlineRemote
601,PreviousControlState,U1,Previous control state (same code set as CurrentControlState)
700,CurrentProcessState,U1,0=Ready;1=Processing;2=Complete;3=Error
701,PreviousProcessState,U1,Previous process state (0=Ready;1=Processing;2=Complete;3=Error)
801,EQPPExecName,A20,Current PPExec name from equipment
5001,CJobSpace,U1,CJ Space
5002,PJobSpace,U1,PJ Space
5003,PJQueued,L,PJ queued list (IDs)
5004,PJID,A20,Process job ID (PJ)
5006,PanelStartID,A20,Panel start ID
5007,PanelEndID,A20,Panel end ID
5008,CJID,A20,Control job ID (CJ)
5014,VCRPanelID,A20,Panel ID from reader
5017,ProcessDataReportText,A50,EV_PROCESS_DATA_REPORT payload (placeholder)
5018,SubEqpName,A20,Sub equipment name (SubEqp/Unit/Process/SV/ProcessData events)
5019,SubEqpSlot,U1,Slot number for SubEqp/Unit; 0 when not applicable
5021,PortState,U1,Port transfer/state code for PortStateChange
5022,PortId,U1,Unified port ID for all Port events
5024,EquipmentStatus,U1,Equipment status (SubEqpStateChange): 1=PM;2=Down(BM);3=Pause;4=Idle;5=Run;6=Job Change;7=ETC
5025,TargetCarrier,A50,Target carrier ID for SentOutJob
5026,TargetSlot,U1,Target slot number for SentOutJob
5027,TargetPanelID,A50,Target panel/glass ID for SentOutJob
5028,SourceCarrier,A50,Source carrier ID for ReceivedJob
5029,SourceSlot,U1,Source slot number for ReceivedJob
5030,SourcePanelID,A50,Source panel/glass ID for ReceivedJob
8100,Bonder1CurrentRecipe,A50,Current recipe for Bonder1
8101,Bonder2CurrentRecipe,A50,Current recipe for Bonder2
8102,VacuumBakeCurrentRecipe,A50,Current recipe for VacuumBake
8103,BakeCoolingCurrentRecipe,A50,Current recipe for BakeCooling
8104,MeasurementCurrentRecipe,A50,Current recipe for Measurement
8105,EFEMCurrentRecipe,A50,Current recipe for EFEM
10000,CarrierID_P1,A50,Carrier ID for Port 1
10001,CarrierID_P2,A50,Carrier ID for Port 2
10002,CarrierID_P3,A50,Carrier ID for Port 3
10003,CarrierID_P4,A50,Carrier ID for Port 4