chenluhua1980
9 小时以前 1fac536ec86ccda881c75d751224d353f72234ee
1.手动测试支持,PJ创建,支持多Port
已修改4个文件
308 ■■■■■ 文件已修改
SourceCode/Bond/Servo/CControlJobManagerDlg.cpp 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ProcessJob.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CControlJobManagerDlg.cpp
@@ -12,6 +12,65 @@
bool CControlJobManagerDlg::m_bHasState = false;
CControlJobManagerDlg::State CControlJobManagerDlg::m_state{};
namespace {
    constexpr int kPortCount = 4;
    constexpr int kSlotCount = 8;
    constexpr int kMatG1 = 1;
    constexpr int kMatG2 = 2;
    int NormalizeWarpMaterial(int material)
    {
        return (material == kMatG2) ? kMatG2 : kMatG1;
    }
    void EnsureWarpDefaults(PJWarp& warp)
    {
        bool hasSelectedPort = false;
        for (int p = 0; p < kPortCount; ++p) {
            if (warp.selectedPorts[p]) {
                hasSelectedPort = true;
            }
            for (int s = 0; s < kSlotCount; ++s) {
                warp.materialSlots[p][s] = NormalizeWarpMaterial(warp.materialSlots[p][s]);
            }
        }
        for (int s = 0; s < kSlotCount; ++s) {
            warp.material[s] = NormalizeWarpMaterial(warp.material[s]);
        }
        if (!hasSelectedPort && 0 <= warp.port && warp.port < kPortCount) {
            warp.selectedPorts[warp.port] = TRUE;
            for (int s = 0; s < kSlotCount; ++s) {
                warp.checkSlots[warp.port][s] = warp.checkSlot[s];
                warp.materialSlots[warp.port][s] = NormalizeWarpMaterial(warp.material[s]);
            }
        }
        int firstSelectedPort = -1;
        for (int p = 0; p < kPortCount; ++p) {
            if (warp.selectedPorts[p]) {
                firstSelectedPort = p;
                break;
            }
        }
        warp.port = firstSelectedPort;
        if (firstSelectedPort >= 0) {
            for (int s = 0; s < kSlotCount; ++s) {
                warp.checkSlot[s] = warp.checkSlots[firstSelectedPort][s];
                warp.material[s] = NormalizeWarpMaterial(warp.materialSlots[firstSelectedPort][s]);
            }
        }
        else {
            for (int s = 0; s < kSlotCount; ++s) {
                warp.checkSlot[s] = FALSE;
                warp.material[s] = kMatG1;
            }
        }
    }
}
// CControlJobManagerDlg 对话框
IMPLEMENT_DYNAMIC(CControlJobManagerDlg, CDialogEx)
@@ -373,6 +432,16 @@
        PJWarp pjWarp = {};
        pjWarp.pj = pj;
        pjWarp.port = -1;
        for (int s = 0; s < kSlotCount; ++s) {
            pjWarp.material[s] = kMatG1;
        }
        for (int p = 0; p < kPortCount; ++p) {
            pjWarp.selectedPorts[p] = FALSE;
            for (int s = 0; s < kSlotCount; ++s) {
                pjWarp.checkSlots[p][s] = FALSE;
                pjWarp.materialSlots[p][s] = kMatG1;
            }
        }
        m_pjWarps.push_back(pjWarp);
    }
}
@@ -449,20 +518,19 @@
        return;
    }
    // 先应用
    for (int i = 0; i < 3; i++) {
        if (m_pages[i]->IsWindowVisible()) {
            int ret = m_pages[i]->OnApply();
            if (ret != 0) return ;
            if (ret != 0) return;
        }
    }
    GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(FALSE);
    // 先检查数据正确性
    int checkCount = 0;
    for (auto item : m_pjWarps) {
    for (auto& item : m_pjWarps) {
        EnsureWarpDefaults(item);
        if (!item.addToCj) continue;
        checkCount++;
    }
@@ -471,26 +539,30 @@
        return;
    }
    SERVO::CLoadPort* pPorts[4];
    pPorts[0] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT1);
    pPorts[1] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT2);
    pPorts[2] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT3);
    pPorts[3] = (SERVO::CLoadPort*)master.getEquipment(EQ_ID_LOADPORT4);
    bool bProcessStart[] = {false, false, false, false};
    bool bProcessStart[] = { false, false, false, false };
    std::vector<SERVO::CProcessJob*> pjs;
    for (auto item : m_pjWarps) {
    for (auto& item : m_pjWarps) {
        EnsureWarpDefaults(item);
        if (!item.addToCj) continue;
        if (item.port == -1) continue;
        BOOL bCheck = FALSE;
        for (int i = 0; i < 8; i++) {
            if (item.checkSlot[i]) {
                bCheck = TRUE;
                break;
        bool hasAnyCheckedSlot = false;
        for (int p = 0; p < kPortCount; ++p) {
            if (!item.selectedPorts[p]) continue;
            for (int s = 0; s < kSlotCount; ++s) {
                if (item.checkSlots[p][s]) {
                    hasAnyCheckedSlot = true;
                    break;
                }
            }
            if (hasAnyCheckedSlot) break;
        }
        if (!bCheck) continue;
        if (!hasAnyCheckedSlot) continue;
        SERVO::CProcessJob* pScr = (SERVO::CProcessJob*)item.pj;
        pScr->setPjWarp(item);
@@ -499,7 +571,7 @@
        pScr->setOperationId("OperationId");
        pScr->setRecipe(SERVO::RecipeMethod::NoTuning, pScr->recipeSpec());
        SERVO::CProcessJob * pj = new SERVO::CProcessJob(pScr->id());
        SERVO::CProcessJob* pj = new SERVO::CProcessJob(pScr->id());
        pj->setPjWarp(item);
        pj->setLotId("LotID1");
        pj->setProductId("ProductId1");
@@ -507,24 +579,35 @@
        pj->setRecipe(SERVO::RecipeMethod::NoTuning, pScr->recipeSpec());
        std::vector<SERVO::CarrierSlotInfo> carriers;
        SERVO::CarrierSlotInfo csi;
        csi.carrierId = pPorts[item.port]->getCassetteId();
        for (int i = 0; i < 8; i++) {
            if (item.checkSlot[i]) {
                SERVO::CGlass* pGlass = pPorts[item.port]->getGlassFromSlot(i+1);
        for (int p = 0; p < kPortCount; ++p) {
            if (!item.selectedPorts[p] || pPorts[p] == nullptr) {
                continue;
            }
            SERVO::CarrierSlotInfo csi;
            csi.carrierId = pPorts[p]->getCassetteId();
            for (int s = 0; s < kSlotCount; ++s) {
                if (!item.checkSlots[p][s]) continue;
                SERVO::CGlass* pGlass = pPorts[p]->getGlassFromSlot(s + 1);
                if (pGlass != nullptr) {
                    csi.slots.push_back(i + 1);
                    csi.slots.push_back(s + 1);
                }
            }
            if (!csi.slots.empty()) {
                carriers.push_back(csi);
                bProcessStart[p] = true;
            }
        }
        carriers.push_back(csi);
        if (carriers.empty()) {
            delete pj;
            continue;
        }
        pj->setCarriers(carriers);
        pjs.push_back(pj);
        bProcessStart[item.port] = true;
        m_pControlJob->addPJ(pScr->id());
    }
    if (pjs.empty()) {
        AfxMessageBox(_T("没有需要进行工艺处理的Process Job!\n可能未选择Port或选择任何物料。"));
@@ -583,88 +666,92 @@
        return;
    }
    // 成功后同步到 slot 的 glass
    for (auto& warp : m_pjWarps) {
        EnsureWarpDefaults(warp);
        if (!warp.addToCj) continue;
    // 成功,要判断,同步到slot的glass中,类型等
    for (int p = 0; p < 4; p++) {
        if (m_pjWarps[p].port == -1) continue;
        ASSERT(0 <= m_pjWarps[p].port && m_pjWarps[p].port <= 3);
        SERVO::CProcessJob* pj = (SERVO::CProcessJob*)warp.pj;
        int nRecipeID = RecipeManager::getInstance().getIdByPPID(pj->recipeSpec());
        RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(pj->recipeSpec());
        std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList;
        SERVO::CLoadPort* pLoadPort = pPorts[m_pjWarps[p].port];
        for (int i = 0; i < SLOT_MAX; ++i) {
            SERVO::CSlot* pSlot = pLoadPort->getSlot(i);
            if (!pSlot) continue;
        for (int p = 0; p < kPortCount; ++p) {
            if (!warp.selectedPorts[p]) continue;
            SERVO::CLoadPort* pLoadPort = pPorts[p];
            if (pLoadPort == nullptr) continue;
            SERVO::CGlass* pGlass = dynamic_cast<SERVO::CGlass*>(pSlot->getContext());
            if (pGlass == nullptr) continue;
            for (int s = 0; s < SLOT_MAX; ++s) {
                SERVO::CSlot* pSlot = pLoadPort->getSlot(s);
                if (!pSlot) continue;
            SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
            if (pJobDataS == nullptr) continue;
                SERVO::CGlass* pGlass = dynamic_cast<SERVO::CGlass*>(pSlot->getContext());
                if (pGlass == nullptr) continue;
                SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
                if (pJobDataS == nullptr) continue;
            // 设置 Panel ID 和勾选框
            SERVO::CProcessJob* pj = (SERVO::CProcessJob*)m_pjWarps[p].pj;
            int nRecipeID = RecipeManager::getInstance().getIdByPPID(pj->recipeSpec());
            RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(pj->recipeSpec());
            std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList;
                const BOOL checked = (s < kSlotCount) ? warp.checkSlots[p][s] : FALSE;
                const int mat = (s < kSlotCount) ? NormalizeWarpMaterial(warp.materialSlots[p][s]) : kMatG1;
                pGlass->setScheduledForProcessing(checked);
                pGlass->setType(static_cast<SERVO::MaterialsType>(mat));
            pGlass->setScheduledForProcessing(m_pjWarps[p].checkSlot[i]);
            pGlass->setType(static_cast<SERVO::MaterialsType>(m_pjWarps[p].material[i]));
            pJobDataS->setLotId(pj->getLotId().c_str());
                pJobDataS->setLotId(pj->getLotId().c_str());
                pJobDataS->setProductId(pj->getProductId().c_str());
                pJobDataS->setOperationId(pj->getOperationId().c_str());
                pJobDataS->setMaterialsType(m_pjWarps[p].material[i]);
                pJobDataS->setMaterialsType(mat);
                pJobDataS->setMasterRecipe(nRecipeID);
            for (const auto& info : vecRecipeInfo) {
                const std::string& name = info.strDeviceName;
                short nRecipeID = (short)info.nRecipeID;
                if (name == EQ_NAME_EFEM) {
                    pJobDataS->setDeviceRecipeId(0, nRecipeID);
                }
                else if (name == EQ_NAME_BONDER1) {
                    pJobDataS->setDeviceRecipeId(1, nRecipeID);
                }
                else if (name == EQ_NAME_BONDER2) {
                    pJobDataS->setDeviceRecipeId(2, nRecipeID);
                }
                else if (name == EQ_NAME_BAKE_COOLING) {
                    pJobDataS->setDeviceRecipeId(3, nRecipeID);
                }
                else if (name == EQ_NAME_VACUUMBAKE) {
                    pJobDataS->setDeviceRecipeId(4, nRecipeID);
                }
                else if (name == EQ_NAME_MEASUREMENT) {
                    pJobDataS->setDeviceRecipeId(5, nRecipeID);
                for (const auto& info : vecRecipeInfo) {
                    const std::string& name = info.strDeviceName;
                    short nDeviceRecipeID = (short)info.nRecipeID;
                    if (name == EQ_NAME_EFEM) {
                        pJobDataS->setDeviceRecipeId(0, nDeviceRecipeID);
                    }
                    else if (name == EQ_NAME_BONDER1) {
                        pJobDataS->setDeviceRecipeId(1, nDeviceRecipeID);
                    }
                    else if (name == EQ_NAME_BONDER2) {
                        pJobDataS->setDeviceRecipeId(2, nDeviceRecipeID);
                    }
                    else if (name == EQ_NAME_BAKE_COOLING) {
                        pJobDataS->setDeviceRecipeId(3, nDeviceRecipeID);
                    }
                    else if (name == EQ_NAME_VACUUMBAKE) {
                        pJobDataS->setDeviceRecipeId(4, nDeviceRecipeID);
                    }
                    else if (name == EQ_NAME_MEASUREMENT) {
                        pJobDataS->setDeviceRecipeId(5, nDeviceRecipeID);
                    }
                }
            }
        }
    }
    // process start
    for (int p = 0; p < 4; p++) {
        if (bProcessStart[p]) {
            if (pPorts[p] == nullptr) continue;
            short jobExistence[12] = { 0 };
            short slotProcess = 0;
            const short scanMap = pPorts[p]->getScanCassetteMap();
            if (scanMap != 0) {
                jobExistence[0] = scanMap;
                slotProcess = scanMap;
            }
    for (int p = 0; p < kPortCount; p++) {
        if (!bProcessStart[p]) continue;
        if (pPorts[p] == nullptr) continue;
            bool hasExistence = false;
            for (short w : jobExistence) {
                if (w != 0) { hasExistence = true; break; }
            }
            if (!hasExistence) {
                LOGE("ProcessStart blocked (ControlJob): no JobExistence map (port=%d, portStatus=%d, scanMap=%d).",
                    p + 1, pPorts[p]->getPortStatus(), scanMap);
                continue;
            }
            pPorts[p]->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, 0, nullptr, nullptr);
            Sleep(100);
        short jobExistence[12] = { 0 };
        short slotProcess = 0;
        const short scanMap = pPorts[p]->getScanCassetteMap();
        if (scanMap != 0) {
            jobExistence[0] = scanMap;
            slotProcess = scanMap;
        }
        bool hasExistence = false;
        for (short w : jobExistence) {
            if (w != 0) { hasExistence = true; break; }
        }
        if (!hasExistence) {
            LOGE("ProcessStart blocked (ControlJob): no JobExistence map (port=%d, portStatus=%d, scanMap=%d).",
                p + 1, pPorts[p]->getPortStatus(), scanMap);
            continue;
        }
        pPorts[p]->sendCassetteCtrlCmd(CCC_PROCESS_START, jobExistence, 12, slotProcess, 0, nullptr, nullptr);
        Sleep(100);
    }
}
SourceCode/Bond/Servo/CMaster.cpp
@@ -1710,12 +1710,36 @@
                                pGlass->setProcessJob(pj);
                                PJWarp& jpWarp = pj->getPjWarp();
                                int portIndex = -1;
                                switch (pPort->getID()) {
                                case EQ_ID_LOADPORT1: portIndex = 0; break;
                                case EQ_ID_LOADPORT2: portIndex = 1; break;
                                case EQ_ID_LOADPORT3: portIndex = 2; break;
                                case EQ_ID_LOADPORT4: portIndex = 3; break;
                                default: break;
                                }
                                BOOL scheduled = FALSE;
                                int material = 1; // G1
                                if (1 <= slot && slot <= 8) {
                                    if (0 <= portIndex && portIndex <= 3 && jpWarp.selectedPorts[portIndex]) {
                                        scheduled = jpWarp.checkSlots[portIndex][slot - 1];
                                        material = jpWarp.materialSlots[portIndex][slot - 1];
                                    }
                                    else {
                                        // Backward compatibility for legacy single-port PJWarp.
                                        scheduled = jpWarp.checkSlot[slot - 1];
                                        material = jpWarp.material[slot - 1];
                                    }
                                }
                                material = (material == 2) ? 2 : 1;
                                int nRecipeID = RecipeManager::getInstance().getIdByPPID(pj->recipeSpec());
                                RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(pj->recipeSpec());
                                std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList;
                                pGlass->setScheduledForProcessing(jpWarp.checkSlot[slot-1]);
                                pGlass->setType(static_cast<SERVO::MaterialsType>(jpWarp.material[slot-1]));
                                pGlass->setScheduledForProcessing(scheduled);
                                pGlass->setType(static_cast<SERVO::MaterialsType>(material));
                                SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
                                if (pJobDataS != nullptr) {
@@ -1723,7 +1747,7 @@
                                    pJobDataS->setLotId(pj->getLotId().c_str());
                                    pJobDataS->setProductId(pj->getProductId().c_str());
                                    pJobDataS->setOperationId(pj->getOperationId().c_str());
                                    pJobDataS->setMaterialsType(jpWarp.material[slot - 1]);
                                    pJobDataS->setMaterialsType(material);
                                    pJobDataS->setMasterRecipe(nRecipeID);
                                    for (const auto& info : vecRecipeInfo) {
                                        const std::string& name = info.strDeviceName;
SourceCode/Bond/Servo/ProcessJob.h
@@ -16,6 +16,10 @@
    int port;
    BOOL checkSlot[8];
    int material[8];
    // Multi-port model for PJ editor/runtime.
    BOOL selectedPorts[4];
    BOOL checkSlots[4][8];
    int materialSlots[4][8];
};
namespace SERVO {
SourceCode/Bond/Servo/Servo.rc
@@ -745,10 +745,10 @@
    LTEXT           "主配方:",IDC_LABEL_RECIPE,28,55,30,8
    COMBOBOX        IDC_COMBO_RECIPE,94,53,110,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
    LTEXT           "请选择对应Port并勾选物料",IDC_STATIC,28,86,100,8
    CONTROL         "Port1",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,186,85,60,10
    CONTROL         "Port2",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,256,85,60,10
    CONTROL         "Port3",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,326,85,60,10
    CONTROL         "Port4",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,396,85,60,10
    CONTROL         "Port1",IDC_RADIO1,"Button",BS_AUTOCHECKBOX | WS_GROUP,186,85,60,10
    CONTROL         "Port2",IDC_RADIO2,"Button",BS_AUTOCHECKBOX,256,85,60,10
    CONTROL         "Port3",IDC_RADIO3,"Button",BS_AUTOCHECKBOX,326,85,60,10
    CONTROL         "Port4",IDC_RADIO4,"Button",BS_AUTOCHECKBOX,396,85,60,10
    CONTROL         "",IDC_GRID1,"Static",SS_BLACKFRAME | SS_NOTIFY,28,101,519,144
    PUSHBUTTON      "(Port1) Process Start",IDC_BUTTON_PORT1_PROCESS_START,50,264,88,14
    PUSHBUTTON      "(Port2) Process Start",IDC_BUTTON_PORT2_PROCESS_START,151,264,88,14
@@ -1789,3 +1789,4 @@
/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED