| | |
| | | |
| | | |
| | | namespace SERVO { |
| | | static inline int64_t now_ms_epoch() { |
| | | using namespace std::chrono; |
| | | return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); |
| | | } |
| | | |
| | | CMaster* g_pMaster = NULL; |
| | | |
| | | unsigned __stdcall DispatchThreadFunction(LPVOID lpParam) |
| | |
| | | } |
| | | m_listEquipment.clear(); |
| | | |
| | | |
| | | if (m_pCollector != nullptr) { |
| | | m_pCollector->stopLoop(); |
| | | delete m_pCollector; |
| | | m_pCollector = nullptr; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | |
| | | |
| | | // 批处理模式,最终以此为准,但先保留之前的单片模式 |
| | | else if (m_state == MASTERSTATE::RUNNING_BATCH) { |
| | | // 首选检查有没有CControlJob, 状态等 |
| | | if (m_pControlJob == nullptr) { |
| | | // 1) 控制作业生命周期保障 |
| | | if (m_pControlJob == nullptr) { unlock(); continue; } |
| | | CJState cjst = m_pControlJob->state(); |
| | | if (cjst == CJState::Completed || cjst == CJState::Aborted || cjst == CJState::Failed) { |
| | | unlock(); |
| | | continue; |
| | | } |
| | | CJState state = m_pControlJob->state(); |
| | | if (state == CJState::Completed || state == CJState::Aborted || state == CJState::Failed) { |
| | | // ConrolJpb已完成 |
| | | LOGE("<Master>ControlJob已经完成或失败中断"); |
| | | unlock(); |
| | | continue; |
| | | } |
| | | |
| | | |
| | | if (m_pControlJob->state() == CJState::NoState) { |
| | | if (cjst == CJState::NoState) { |
| | | LOGI("<Master>ControlJob已经进入列队"); |
| | | m_pControlJob->queue(); |
| | | } |
| | | if (m_pControlJob->state() == CJState::Queued) { |
| | | LOGI("<Master>ControlJob已经启动"); |
| | | m_pControlJob->start(); |
| | | |
| | | if (m_listener.onCjStart != nullptr) { |
| | | m_listener.onCjStart(this, m_pControlJob); |
| | | } |
| | | if (m_listener.onCjStart) m_listener.onCjStart(this, m_pControlJob); |
| | | } |
| | | if (m_pControlJob->state() == CJState::Paused) { |
| | | LOGI("<Master>ControlJob已经恢复运行"); |
| | | m_pControlJob->resume(); |
| | | } |
| | | |
| | | |
| | | // 如果当前未选择CProcessJob, 选择一个 |
| | | // 2) 若当前无 PJ,则选择一个并上报 |
| | | if (m_inProcesJobs.empty()) { |
| | | auto pj = acquireNextProcessJob(); |
| | | if (pj != nullptr) { |
| | | if (auto pj = acquireNextProcessJob()) { |
| | | m_inProcesJobs.push_back(pj); |
| | | |
| | | // 这里上报PJ Start事件 |
| | | if (m_listener.onPjStart != nullptr) { |
| | | m_listener.onPjStart(this, pj); |
| | | } |
| | | if (m_listener.onPjStart) m_listener.onPjStart(this, pj); |
| | | } |
| | | } |
| | | if (m_inProcesJobs.empty()) { |
| | |
| | | continue; |
| | | } |
| | | |
| | | // 如果当前没有Glass, 选择 |
| | | // 3) 若队列无 Glass,拉取到等待队列 |
| | | if (m_queueGlasses.empty()) { |
| | | int nCount = acquireGlassToQueue(); |
| | | LOGI("<Master>已加入 %d 块Glass到工艺列队!", nCount); |
| | | if (nCount > 0) { |
| | | LOGI("<Master>已加入 %d 块Glass到工艺列队!", nCount); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 检测判断robot状态 |
| | | // 4) 机器人状态 |
| | | RMDATA& rmd = pEFEM->getRobotMonitoringData(); |
| | | if (rmd.status != ROBOT_STATUS::Idle && rmd.status != ROBOT_STATUS::Run) { |
| | | unlock(); |
| | | continue; |
| | | unlock(); continue; |
| | | } |
| | | |
| | | // 5) 正在执行的 RobotTask 先让它跑完一拍 |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | if (m_pActiveRobotTask->isPicked()) { |
| | | m_pActiveRobotTask->place(); |
| | | } |
| | | unlock(); |
| | | // 检测到当前有正在下午的任务,确保当前任务完成或中止后继续 |
| | | // LOGI("检测到当前有正在下午的任务,确保当前任务完成或中止后继续..."); |
| | | unlock(); // 等当前任务完成或中止后继续 |
| | | 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; |
| | | // 6) ——关键:全局统计 G1/G2 与组数门限(与单片分支对齐)—— |
| | | auto countG1G2 = [&]() { |
| | | int g1 = 0, g2 = 0; |
| | | if (pBonder1->slotHasGlass(0)) g2++; |
| | | if (pBonder1->slotHasGlass(1)) g1++; |
| | | if (pBonder2->slotHasGlass(0)) g2++; |
| | | if (pBonder2->slotHasGlass(1)) g1++; |
| | | if (pFliper->slotHasGlass(0)) g2++; |
| | | if (pVacuumBake->slotHasGlass(0)) g1++; |
| | | if (pVacuumBake->slotHasGlass(1)) g1++; |
| | | if (auto g = pAligner->getGlassFromSlot(0)) { |
| | | auto t = g->getType(); |
| | | if (t == MaterialsType::G1) g1++; else if (t == MaterialsType::G2) g2++; |
| | | } |
| | | } |
| | | else if ((pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1)) |
| | | || (pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) { |
| | | primaryType = MaterialsType::G2; |
| | | secondaryType = MaterialsType::G1; |
| | | } |
| | | return std::pair<int, int>(g1, g2); |
| | | }; |
| | | |
| | | int g1Count = 0, g2Count = 0; |
| | | std::tie(g1Count, g2Count) = countG1G2(); |
| | | int nGlassGroup = min(g1Count, g2Count); |
| | | int nExtraType = (g1Count == g2Count ? 0 : (g1Count > g2Count ? 1 : 2)); |
| | | |
| | | // Measurement -> LoadPort |
| | | // primary/secondary 统一定义(secondary 默认 G0) |
| | | MaterialsType primaryType = MaterialsType::G1; |
| | | MaterialsType secondaryType = MaterialsType::G0; |
| | | if (nExtraType == 0) primaryType = MaterialsType::G2; // 与单片分支一致 |
| | | else primaryType = MaterialsType::G1; |
| | | |
| | | // 组数门限:≥2 组时不再从 LP 上片,避免堆积(与单片一致) |
| | | bool blockLoadFromLP = (nGlassGroup >= 2); |
| | | |
| | | // 7) Measurement -> LoadPort(固定:G1 优先回 LP) |
| | | if (rmd.armState[0] || rmd.armState[1]) { |
| | | LOGD("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"), |
| | | LOGD("Arm1 %s, Arm2 %s.", |
| | | rmd.armState[0] ? _T("不可用") : _T("可用"), |
| | | rmd.armState[1] ? _T("不可用") : _T("可用")); |
| | | } |
| | | for (int s = 0; s < 4; s++) { |
| | |
| | | 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; |
| | | } |
| | | m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], MaterialsType::G1, secondaryType); |
| | | if (m_pActiveRobotTask != nullptr) { goto BATCH_PORT_PUT; } |
| | | } |
| | | } |
| | | |
| | | BATCH_PORT_PUT: |
| | | BATCH_PORT_PUT: |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | |
| | | |
| | | // Measurement NG -> LoadPort |
| | | // NG回原位 |
| | | // 8) Measurement NG -> LoadPort(原位回退) |
| | | if (!rmd.armState[1]) { |
| | | m_pActiveRobotTask = createTransferTask_restore(pMeasurement, pLoadPorts); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // BakeCooling ->Measurement |
| | | // 9) BakeCooling -> Measurement |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask_bakecooling_to_measurement(pBakeCooling, pMeasurement); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // BakeCooling内部 |
| | | // Bake -> Cooling |
| | | // 10) BakeCooling 内部(Bake -> Cooling) |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask_bake_to_cooling(pBakeCooling); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // Bonder -> BakeCooling |
| | | // 11) 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); |
| | | } |
| | | |
| | | // 12) Fliper(G2) -> Bonder(前置:VacuumBake 有 processed G1;输出 G2 到 Bonder slot0) |
| | | if (auto pSrcSlot = pVacuumBake->getProcessedSlot(MaterialsType::G1)) { |
| | | if (!rmd.armState[1] && pBonder1->canPlaceGlassInSlot(0)) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, MaterialsType::G2, MaterialsType::G0, 2); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | if (!rmd.armState[1] && pBonder2->canPlaceGlassInSlot(0)) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, MaterialsType::G2, MaterialsType::G0, 2); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | } |
| | | |
| | | // Fliper(G2) -> Bonder |
| | | auto pSrcSlot = pVacuumBake->getProcessedSlot(primaryType); |
| | | if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder1->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, primaryType, secondaryType, 2); |
| | | // 13) VacuumBake(G1) -> Bonder(槽级判定:slot0(G2) 已有且 slot1(G1) 为空) |
| | | if (!rmd.armState[0] && pBonder1->slotHasGlass(0) && !pBonder1->slotHasGlass(1)) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, MaterialsType::G1, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder2->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, primaryType, secondaryType, 2); |
| | | if (!rmd.armState[0] && pBonder2->slotHasGlass(0) && !pBonder2->slotHasGlass(1)) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, MaterialsType::G1, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // VacuumBake(G1) -> Bonder |
| | | if (!rmd.armState[0] && !pBonder1->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, primaryType, secondaryType); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | if (!rmd.armState[0] && !pBonder2->hasBondGlass()) { |
| | | m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, primaryType, secondaryType); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // Aligner -> Fliper(G2) |
| | | // Aligner -> VacuumBake(G1) |
| | | // 14) Aligner -> Fliper(G2) 以及 -> VacuumBake(G1)(固定映射) |
| | | if (!rmd.armState[1]) { |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pFliper, primaryType, secondaryType); |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pFliper, MaterialsType::G2, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | if (!rmd.armState[0]) { |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, primaryType, secondaryType); |
| | | m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, MaterialsType::G1, MaterialsType::G0); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | |
| | | // Aligner -> LoadPort |
| | | // 15) Aligner -> LoadPort(restore) |
| | | if (!rmd.armState[1]) { |
| | | m_pActiveRobotTask = createTransferTask_restore(pAligner, pLoadPorts); |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | } |
| | | |
| | | // 16) LoadPort -> Aligner(受组数门限控制;统一 buddy/状态时序) |
| | | if (blockLoadFromLP) { unlock(); continue; } |
| | | |
| | | // 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); |
| | | |
| | | m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, 1, m_bJobMode); |
| | | if (m_pActiveRobotTask != nullptr) { |
| | | CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext(); |
| | | auto* pGlass = static_cast<CGlass*>(m_pActiveRobotTask->getContext()); |
| | | if (pGlass->getBuddy() != nullptr) { |
| | | delete m_pActiveRobotTask; |
| | | m_pActiveRobotTask = nullptr; |
| | | delete m_pActiveRobotTask; m_pActiveRobotTask = nullptr; |
| | | continue; |
| | | } |
| | | |
| | | pEFEM->setContext(pGlass); |
| | | // 统一:queue -> start -> setContext -> move queue→inProcess -> onPanelStart |
| | | pGlass->queue(); |
| | | pGlass->start(); |
| | | pEFEM->setContext(pGlass); |
| | | |
| | | bool bMoved = glassFromQueueToInPorcess(pGlass); |
| | | if (bMoved) { |
| | | LOGI("<Master>Glass(%s)从等待列队到工艺列队转移成功.", |
| | | pGlass->getID().c_str()); |
| | | LOGI("<Master>Glass(%s)从等待列队到工艺列队转移成功.", pGlass->getID().c_str()); |
| | | } |
| | | else { |
| | | LOGE("<Master>Glass(%s)从等待列队到工艺列队转移失败.", |
| | | pGlass->getID().c_str()); |
| | | LOGE("<Master>Glass(%s)从等待列队到工艺列队转移失败.", pGlass->getID().c_str()); |
| | | } |
| | | |
| | | // 这里上报Panel Start事件 |
| | | if (m_listener.onPanelStart != nullptr) { |
| | | m_listener.onPanelStart(this, pGlass); |
| | | } |
| | | |
| | | if (m_listener.onPanelStart) m_listener.onPanelStart(this, pGlass); |
| | | goto BATCH_PORT_GET; |
| | | } |
| | | } |
| | | } |
| | | |
| | | BATCH_PORT_GET: |
| | | BATCH_PORT_GET: |
| | | CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask); |
| | | |
| | | |
| | | unlock(); |
| | | continue; |
| | | } |
| | | |
| | | |
| | | // 千传模式调度逻辑 |
| | | else if (m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) { |
| | |
| | | if (m_listener.onCjEnd != nullptr) { |
| | | m_listener.onCjEnd(this, pJob); |
| | | } |
| | | |
| | | completeControlJob(); |
| | | } |
| | | } |
| | | } |
| | |
| | | unlock(); |
| | | } |
| | | }; |
| | | listener.onProcessStateChanged = [&](void* pEquipment, PROCESS_STATE state) -> void { |
| | | listener.onProcessStateChanged = [&](void* pEquipment, int slotNo, PROCESS_STATE state) -> void { |
| | | ASSERT(1 <= slotNo && slotNo <= 8); |
| | | int eqid = ((CEquipment*)pEquipment)->getID(); |
| | | CGlass* pGlass = ((CEquipment*)pEquipment)->getGlassFromSlot(slotNo); |
| | | LOGI("<Master>onProcessStateChanged<%d>", (int)state); |
| | | if (state == PROCESS_STATE::Processing) { |
| | | if (pGlass != nullptr) { |
| | | m_pCollector->batchStart(eqid, |
| | | pGlass->getID().c_str(), 10 * 60 * 1000ULL); |
| | | } |
| | | } |
| | | else if (state == PROCESS_STATE::Complete) { |
| | | m_pCollector->batchStop(eqid); |
| | | } |
| | | }; |
| | | listener.onMapMismatch = [&](void* pEquipment, short scanMap, short downMap) { |
| | | LOGE("<Master-%s>Port InUse, map(%d!=%d)不一致,请检查。", |
| | |
| | | for (auto pj : pjs) { |
| | | auto carrier = pj->getCarrier(pPort->getCassetteId()); |
| | | if (carrier != nullptr) { |
| | | carrier->contexts.clear(); |
| | | for (auto slot : carrier->slots) { |
| | | CGlass* pGlass = pPort->getGlassFromSlot(slot); |
| | | carrier->contexts.push_back((void*)pGlass); |
| | | if (pGlass != nullptr) { |
| | | pGlass->setProcessJob(pj); |
| | | |
| | | PJWarp& jpWarp = pj->getPjWarp(); |
| | | 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])); |
| | | |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | if (pJobDataS != nullptr) { |
| | | SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS(); |
| | | 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->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); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | if (m_listener.onLoadPortStatusChanged != nullptr) { |
| | |
| | | std::vector<CParam> params; |
| | | ((CEquipment*)pEquipment)->parsingSVData((const char*)rawData.data(), rawData.size(), params); |
| | | |
| | | |
| | | // 以下加入到曲线数据中 |
| | | const int64_t ts = now_ms_epoch(); |
| | | int eqid = ((CEquipment*)pEquipment)->getID(); |
| | | if (eqid == EQ_ID_Bonder1 || eqid == EQ_ID_Bonder2) { |
| | | m_pCollector->buffersPush(eqid, 1, ts, params.at(1).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 2, ts, params.at(2).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 3, ts, params.at(3).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 4, ts, params.at(4).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 5, ts, params.at(5).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 6, ts, params.at(6).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 7, ts, params.at(7).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 8, ts, params.at(8).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 9, ts, params.at(9).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 10, ts, params.at(10).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 11, ts, params.at(11).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 12, ts, params.at(12).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 13, ts, params.at(13).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 14, ts, params.at(14).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 15, ts, params.at(15).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 16, ts, params.at(16).getDoubleValue()); |
| | | } |
| | | else if (eqid == EQ_ID_VACUUMBAKE) { |
| | | m_pCollector->buffersPush(eqid, 1, ts, params.at(1).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 2, ts, params.at(2).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 3, ts, params.at(3).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 4, ts, params.at(4).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 5, ts, params.at(5).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 6, ts, params.at(6).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 7, ts, params.at(7).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 8, ts, params.at(10).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 9, ts, params.at(11).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 10, ts, params.at(12).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 11, ts, params.at(13).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 12, ts, params.at(14).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 13, ts, params.at(15).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 14, ts, params.at(16).getDoubleValue()); |
| | | } |
| | | else if (eqid == EQ_ID_BAKE_COOLING) { |
| | | m_pCollector->buffersPush(eqid, 1, ts, params.at(1).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 2, ts, params.at(2).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 3, ts, params.at(3).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 4, ts, params.at(4).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 5, ts, params.at(5).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 6, ts, params.at(6).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 7, ts, params.at(11).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 8, ts, params.at(12).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 9, ts, params.at(13).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 10, ts, params.at(14).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 11, ts, params.at(15).getDoubleValue()); |
| | | m_pCollector->buffersPush(eqid, 12, ts, params.at(16).getDoubleValue()); |
| | | } |
| | | |
| | | |
| | | // 以下是输出测试 |
| | | std::string strOut; |
| | | char szBuffer[256]; |
| | | for (auto p : params) { |
| | |
| | | |
| | | |
| | | // 模拟测试 |
| | | /* |
| | | static int aaa = 0; |
| | | aaa++; |
| | | if (aaa % 30 == 0) { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | */ |
| | | } |
| | | |
| | | void CMaster::connectEquipments() |
| | |
| | | return 0; |
| | | } |
| | | |
| | | void CMaster::setPortType(unsigned int index, BOOL enable, int type, int mode, |
| | | int cassetteType, int transferMode, BOOL autoChangeEnable) |
| | | void CMaster::setPortType(unsigned int index, int type) |
| | | { |
| | | ASSERT(index < 4); |
| | | int eqid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4}; |
| | | CLoadPort* pPort = (CLoadPort*)getEquipment(eqid[index]); |
| | | pPort->localSetPortType((SERVO::PortType)type); |
| | | } |
| | | |
| | | void CMaster::setPortTypeEx(unsigned int index, BOOL enable, int type, int mode, |
| | | int cassetteType, int transferMode, BOOL autoChangeEnable) |
| | | { |
| | | ASSERT(index < 4); |
| | | int eqid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4 }; |
| | | CLoadPort* pPort = (CLoadPort*)getEquipment(eqid[index]); |
| | | pPort->localEanblePort(enable); |
| | | pPort->localSetPortType((SERVO::PortType)type); |
| | |
| | | int nCount = 0; |
| | | for (auto* pj : m_inProcesJobs) { |
| | | // 遍历 PJ 的 carriers 和 slots |
| | | if (pj->carriers().empty()) continue; |
| | | for (auto& cs : pj->carriers()) { |
| | | for (auto ctx : cs.contexts) { |
| | | CGlass* pGlass = (CGlass*)ctx; |
| | |
| | | } |
| | | |
| | | |
| | | bool CMaster::completeControlJob(std::string description) |
| | | bool CMaster::completeControlJob() |
| | | { |
| | | if (m_pControlJob == nullptr) { |
| | | return false; |
| | | } |
| | | for (auto item : m_processJobs) { |
| | | if (item->state() != PJState::Completed) return false; |
| | | } |
| | | if (m_pControlJob->state() != CJState::Completed) |
| | | return false; |
| | | |
| | | |
| | | |
| | | // 释放Job相关 |
| | | for (auto item : m_processJobs) { |
| | | delete item; |
| | | } |
| | | m_processJobs.clear(); |
| | | if (m_pControlJob != nullptr) { |
| | | delete m_pControlJob; |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | // 注意要释放引用 |
| | | m_inProcesJobs.clear(); |
| | | m_completeProcessJobs.clear(); |
| | | m_queueGlasses.clear(); |
| | | m_inProcesGlasses.clear(); |
| | | m_completeGlasses.clear(); |
| | | |
| | | |
| | | saveState(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CMaster::forceCompleteControlJob(std::string description) |
| | | { |
| | | if (m_pControlJob == nullptr || m_state != SERVO::MASTERSTATE::READY) { |
| | | return false; |
| | |
| | | delete m_pControlJob; |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | // 注意要释放引用 |
| | | m_inProcesJobs.clear(); |
| | | m_completeProcessJobs.clear(); |
| | | m_queueGlasses.clear(); |
| | | m_inProcesGlasses.clear(); |
| | | m_completeGlasses.clear(); |
| | | |
| | | |
| | | saveState(); |
| | | |
| | |
| | | |
| | | return nullptr; |
| | | } |
| | | |
| | | void CMaster::CreateDAQBridgeServer() |
| | | { |
| | | auto connectionStatusCallback = [&](int code, const std::string& status) { |
| | | LOGI("<DAQBridge>status:", status.c_str()); |
| | | }; |
| | | auto rawDataCallback = [](const std::vector<uint8_t>& bytes) { |
| | | |
| | | }; |
| | | |
| | | // 事件:有人连入/断开就上日志 |
| | | auto clieintEventCallback = [](const std::string& ip, uint16_t port, bool connected) { |
| | | LOGI("<DAQBridge>[Client %s] %s:%u", connected ? _T("JOIN") : _T("LEAVE"), ip.c_str(), port); |
| | | }; |
| | | |
| | | if (m_pCollector == nullptr) { |
| | | m_pCollector = new Collector(); |
| | | m_pCollector->setConnectionStatusCallback(connectionStatusCallback); |
| | | m_pCollector->setRawDataCallback(rawDataCallback); |
| | | m_pCollector->setClientEventCallback(clieintEventCallback); |
| | | m_pCollector->createServer(8081); |
| | | m_pCollector->startLoop(10); |
| | | |
| | | // 1) 注册机台(推荐:先注册 id + 机器名称) |
| | | RetentionPolicy defP; defP.mode = RetainMode::ByCount; defP.maxSamples = 200; |
| | | m_pCollector->registryAddMachine(EQ_ID_Bonder1, "Bonder1", defP); |
| | | m_pCollector->registryAddMachine(EQ_ID_Bonder2, "Bonder2", defP); |
| | | m_pCollector->registryAddMachine(EQ_ID_VACUUMBAKE, "前烘烤", defP); |
| | | m_pCollector->registryAddMachine(EQ_ID_BAKE_COOLING, "烘烤冷却", defP); |
| | | |
| | | |
| | | // 2) 为通道设置“曲线名称” |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 1, "气囊压力"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 2, "上腔压力"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 3, "管道真空规值"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 4, "腔体真空规值"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 5, "上腔温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 6, "上腔温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 7, "上腔温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 8, "上腔温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 9, "上腔温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 10, "上腔温度6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 11, "下腔温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 12, "下腔温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 13, "下腔温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 14, "下腔温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 15, "下腔温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder1, 16, "下腔温度6"); |
| | | |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 1, "气囊压力"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 2, "上腔压力"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 3, "管道真空规值"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 4, "腔体真空规值"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 5, "上腔温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 6, "上腔温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 7, "上腔温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 8, "上腔温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 9, "上腔温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 10, "上腔温度6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 11, "下腔温度1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 12, "下腔温度2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 13, "下腔温度3"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 14, "下腔温度4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 15, "下腔温度5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_Bonder2, 16, "下腔温度6"); |
| | | |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 1, "A腔真空规值"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 2, "A腔温控1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 3, "A腔温控2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 4, "A腔温控4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 5, "A腔温控5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 6, "A腔温控6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 7, "A腔温控7"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 8, "B腔真空规值"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 9, "B腔温控1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 10, "B腔温控2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 11, "B腔温控4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 12, "B腔温控5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 13, "B腔温控6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_VACUUMBAKE, 14, "B腔温控7"); |
| | | |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 1, "A烘烤温控1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 2, "A烘烤温控2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 3, "A烘烤温控4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 4, "A烘烤温控5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 5, "A烘烤温控6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 6, "A烘烤温控7"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 7, "B烘烤温控1"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 8, "B烘烤温控2"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 9, "B烘烤温控4"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 10, "B烘烤温控5"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 11, "B烘烤温控6"); |
| | | m_pCollector->buffersSetChannelName(EQ_ID_BAKE_COOLING, 12, "B烘烤温控7"); |
| | | } |
| | | } |
| | | } |