SourceCode/Bond/Servo/CMaster.cpp
@@ -51,8 +51,10 @@
      m_state = MASTERSTATE::READY;
      m_pActiveRobotTask = nullptr;
      m_nLastError = 0;
      m_isCompareMapsBeforeProceeding = FALSE;
      m_bEnableEventReport = true;
      m_bEnableAlarmReport = true;
      m_bContinuousTransfer = false;
      InitializeCriticalSection(&m_criticalSection);
   }
@@ -250,6 +252,20 @@
         return -1;
      }
      m_bContinuousTransfer = false;
      setState(MASTERSTATE::STARTING);
      m_ullStartTime = GetTickCount64();
      return 0;
   }
   int CMaster::startContinuousTransfer()
   {
      if (m_state != MASTERSTATE::READY) {
         return -1;
      }
      m_bContinuousTransfer = true;
      setState(MASTERSTATE::STARTING);
      m_ullStartTime = GetTickCount64();
@@ -259,7 +275,7 @@
   int CMaster::stop()
   {
      // 运行时间为累加结果,本次停止时刷新;
      if (m_state != MASTERSTATE::RUNNING) {
      if (m_state != MASTERSTATE::RUNNING && m_state != MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
         return -1;
      }
@@ -446,7 +462,11 @@
            unlock();
            setState(MASTERSTATE::RUNNING);
            if(!m_bContinuousTransfer)
               setState(MASTERSTATE::RUNNING);
            else
               setState(MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER);
            continue;
         }
@@ -547,15 +567,11 @@
               LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
                  rmd.armState[1] ? _T("不可用") : _T("可用"));
            }
            CEquipment* pEqTar[] = { pVacuumBake, pFliper };
            if (primaryType == MaterialsType::G2) {
               pEqTar[0] = pFliper;
               pEqTar[1] = pVacuumBake;
            }
            for (int s = 0; s < 4; s++) {
               PortType pt = pLoadPorts[s]->getPortType();
               if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                  && pLoadPorts[s]->getPortType() == PortType::Unloading
                  && pLoadPorts[s]->getPortMode() == PortMode::ReadyToUnload) {
                  && (pt == PortType::Unloading || pt == PortType::Both)
                  && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                  m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType);
                  if (m_pActiveRobotTask != nullptr) {
                     goto PORT_PUT;
@@ -564,157 +580,65 @@
            }
         PORT_PUT:
            if (m_pActiveRobotTask != nullptr) {
               m_pActiveRobotTask->pick();
               std::string strDescription = m_pActiveRobotTask->getDescription();
               unlock();
               if (m_listener.onRobotTaskEvent != nullptr) {
                  m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
               }
               LOGI("创建新任务<%s>...", strDescription.c_str());
               continue;
            }
            CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            // Measurement NG -> LoadPort
            // NG回原位
            if (!rmd.armState[1]) {
               m_pActiveRobotTask = createTransferTask_restore(pMeasurement, pLoadPorts);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建Measurement回退任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // BakeCooling ->Measurement
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_bakecooling_to_measurement(pBakeCooling, pMeasurement);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            
            // BakeCooling内部
            // Bake -> Cooling
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_bake_to_cooling(pBakeCooling);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Bonder -> BakeCooling
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder1, pBakeCooling);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder2, pBakeCooling);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Fliper(G2) -> Bonder
            // VacuumBake(G1) -> Bonder
            if (!rmd.armState[1] && !pBonder1->hasBondClass()) {
            auto pSrcSlot = pVacuumBake->getProcessedSlot(primaryType);
            if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder1->hasBondClass()) {
               m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, primaryType, secondaryType, 2);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            if (!rmd.armState[1] && !pBonder2->hasBondClass()) {
            if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder2->hasBondClass()) {
               m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, primaryType, secondaryType, 2);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // VacuumBake(G1) -> Bonder
            if (!rmd.armState[0] && !pBonder1->hasBondClass()) {
               m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, primaryType, secondaryType);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            if (!rmd.armState[0] && !pBonder2->hasBondClass()) {
               m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, primaryType, secondaryType);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
@@ -722,55 +646,28 @@
            // Aligner -> VacuumBake(G1)
            if (!rmd.armState[1]) {
               m_pActiveRobotTask = createTransferTask(pAligner, pFliper, primaryType, secondaryType);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, primaryType, secondaryType);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建新任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Aligner -> LoadPort
            if (!rmd.armState[1]) {
               m_pActiveRobotTask = createTransferTask_restore(pAligner, pLoadPorts);
               if (m_pActiveRobotTask != nullptr) {
                  m_pActiveRobotTask->pick();
                  std::string strDescription = m_pActiveRobotTask->getDescription();
                  unlock();
                  if (m_listener.onRobotTaskEvent != nullptr) {
                     m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
                  }
                  LOGI("创建Aligner回退任务<%s>...", strDescription.c_str());
                  continue;
               }
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // LoadPort -> Aligner
            for (int s = 0; s < 4; s++) {
               PortType pt = pLoadPorts[s]->getPortType();
               if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                  && pLoadPorts[s]->getPortType() == PortType::Loading
                  && pLoadPorts[s]->getPortMode() == PortMode::ReadyToLoad) {
                  && (pt == PortType::Loading || pt == PortType::Both)
                  && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                  m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType);
                  if (m_pActiveRobotTask != nullptr) {
                     pEFEM->setContext(m_pActiveRobotTask->getContext());
@@ -780,20 +677,138 @@
            }
PORT_GET:
            if (m_pActiveRobotTask != nullptr) {
               m_pActiveRobotTask->pick();
               std::string strDescription = m_pActiveRobotTask->getDescription();
            CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            unlock();
            continue;
         }
         // 千传模式调度逻辑
         else if (m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
            // 检测判断robot状态
            RMDATA& rmd = pEFEM->getRobotMonitoringData();
            if (rmd.status != ROBOT_STATUS::Idle && rmd.status != ROBOT_STATUS::Run) {
               unlock();
               if (m_listener.onRobotTaskEvent != nullptr) {
                  m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
               }
               LOGI("创建新任务<%s>...", strDescription.c_str());
               continue;
            }
            unlock();
            if (m_pActiveRobotTask != nullptr) {
               if (m_pActiveRobotTask->isPicked()) {
                  m_pActiveRobotTask->place();
               }
               unlock();
               // 检测到当前有正在下午的任务,确保当前任务完成或中止后继续
               // LOGI("检测到当前有正在下午的任务,确保当前任务完成或中止后继续...");
               continue;
            }
            // Measurement -> LoadPort
            for (int s = 0; s < 4; s++) {
               PortType pt = pLoadPorts[s]->getPortType();
               if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                  && (pt == PortType::Unloading || pt == PortType::Both)
                  && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                  for (int slot = 0; slot < SLOT_MAX; slot++) {
                     m_pActiveRobotTask = createTransferTask_continuous_transfer(pMeasurement,
                        0, pLoadPorts[s], slot);
                     if (m_pActiveRobotTask != nullptr) {
                        goto CT_PORT_PUT;
                     }
                  }
               }
            }
         CT_PORT_PUT:
            CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            // BakeCooling ->Measurement
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
                  3, pMeasurement, 0);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // BakeCooling内部
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
                  2, pBakeCooling, 3);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
                  1, pBakeCooling, 2);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
                  0, pBakeCooling, 1);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Bonder2 -> BakeCooling
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pBonder2,
                  0, pBakeCooling, 0);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Bonder1 -> Bonder2
            if (!rmd.armState[0] && !pBonder2->hasBondClass()) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pBonder1,
                  0, pBonder2, 0);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // VacuumBake(G1) -> Bonder1
            if (!rmd.armState[0] && !pBonder1->hasBondClass()) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pVacuumBake,
                  0, pBonder1, 0);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Fliper(G2) -> VacuumBake(G1)
            if (!rmd.armState[0]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pFliper,
                  0, pVacuumBake, 0);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // Aligner -> Fliper(G2)
            if (!rmd.armState[1]) {
               m_pActiveRobotTask = createTransferTask_continuous_transfer(pAligner,
                  0, pFliper, 0);
               CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            }
            // LoadPort -> Aligner
            for (int s = 0; s < 4; s++) {
               PortType pt = pLoadPorts[s]->getPortType();
               if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                  && (pt == PortType::Loading || pt == PortType::Both)
                  && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
                  for (int slot = 0; slot < SLOT_MAX; slot++) {
                     m_pActiveRobotTask = createTransferTask_continuous_transfer(pLoadPorts[s],
                        slot, pAligner, 0);
                     if (m_pActiveRobotTask != nullptr) {
                        pEFEM->setContext(m_pActiveRobotTask->getContext());
                        goto CT_PORT_GET;
                     }
                  }
               }
            }
         CT_PORT_GET:
            CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
            unlock();
            continue;
         }
         unlock();
      }
@@ -1018,6 +1033,12 @@
         LOGE("<Master-%s>Port InUse, map(%d!=%d)不一致,请检查。",
            ((CEquipment*)pEquipment)->getName().c_str(), scanMap, downMap);
      };
      listener.onPortStatusChanged = [&](void* pEquipment, short status, __int64 data) {
         LOGE("<Master-%s>Port InUse。status=%d, data=%lld", ((CEquipment*)pEquipment)->getName().c_str(), status);
         if (m_listener.onLoadPortStatusChanged != nullptr) {
            m_listener.onLoadPortStatusChanged(this, (CEquipment*)pEquipment, status, data);
         }
      };
      pEquipment->setListener(listener);
      pEquipment->setCcLink(&m_cclink);
      m_listEquipment.push_back(pEquipment);
@@ -1055,6 +1076,7 @@
      pEquipment->setID(EQ_ID_LOADPORT1 + index);
      pEquipment->setName(szName);
      pEquipment->setDescription(szName);
      pEquipment->setCompareMapsBeforeProceeding(m_isCompareMapsBeforeProceeding);
      addToEquipmentList(pEquipment);
@@ -1411,6 +1433,10 @@
      MaterialsType primaryType/* = MaterialsType::G1*/, MaterialsType secondaryType/* = MaterialsType::G2*/,
      int armNo/* = 1*/)
   {
      if (!pSrcEq->IsEnabled()) {
         return nullptr;
      }
      CRobotTask* pTask = nullptr;
      CSlot* pSrcSlot, * pTarSlot;
      pTarSlot = pTarEq->getAvailableSlotForGlass(primaryType);
@@ -1435,6 +1461,10 @@
   CRobotTask* CMaster::createTransferTask_bonder_to_bakecooling(CEquipment* pSrcEq, CEquipment* pTarEq)
   {
      if (!pSrcEq->IsEnabled()) {
         return nullptr;
      }
      std::vector<int> slots = {1, 3};
      CRobotTask* pTask = nullptr;
@@ -1456,6 +1486,10 @@
   CRobotTask* CMaster::createTransferTask_bake_to_cooling(CEquipment* pSrcEq)
   {
      if (!pSrcEq->IsEnabled()) {
         return nullptr;
      }
      std::vector<int> slotsTar = { 2, 4 };
      std::vector<int> slotsSrc = { 1, 3 };
@@ -1478,6 +1512,10 @@
   CRobotTask* CMaster::createTransferTask_bakecooling_to_measurement(CEquipment* pSrcEq, CEquipment* pTarEq)
   {
      if (!pSrcEq->IsEnabled()) {
         return nullptr;
      }
      std::vector<int> slots = { 2, 4 };
      CRobotTask* pTask = nullptr;
@@ -1499,6 +1537,10 @@
   CRobotTask* CMaster::createTransferTask_restore(CEquipment* pEqSrc, CLoadPort** pPorts)
   {
      if (!pEqSrc->IsEnabled()) {
         return nullptr;
      }
      CRobotTask* pTask = nullptr;
      CSlot* pSrcSlot, * pTarSlot = nullptr, * pTempSlot;
      pSrcSlot = pEqSrc->getInspFailSlot();
@@ -1529,6 +1571,31 @@
      return pTask;
   }
   CRobotTask* CMaster::createTransferTask_continuous_transfer(CEquipment* pSrcEq, int nSrcSlot,
      CEquipment* pTarEq, int nTarSlot, int armNo/* = 1*/)
   {
      if (!pSrcEq->IsEnabled()) {
         return nullptr;
      }
      if (!pTarEq->IsEnabled()) {
         return nullptr;
      }
      CRobotTask* pTask = nullptr;
      CSlot* pTarSlot = pTarEq->isSlotAvailable(nTarSlot);
      CSlot* pSrcSlot = pSrcEq->getProcessedSlotCt(nSrcSlot);
      if (pSrcSlot != nullptr && nullptr != pTarSlot) {
         pTask = new CRobotTask();
         pTask->setContext(pSrcSlot->getContext());
         pTask->setEFEM((CEFEM*)getEquipment(EQ_ID_EFEM));
         taskSeqNo = pTask->setRobotTransferParam(taskSeqNo, armNo, pSrcSlot->getPosition(),
            pTarSlot->getPosition(), pSrcSlot->getNo(), pTarSlot->getNo());
      }
      return pTask;
   }
   int CMaster::abortCurrentTask()
   {
      lock();
@@ -1549,7 +1616,8 @@
      unlock();
      // 当前任务手动中止后,停止调度,需要操作员在解决问题后,重新启动
      stop();
      // 25年7月23日后修改为不停止任务
      // stop();
      return 0;
   }
@@ -1559,6 +1627,18 @@
      lock();
      if (m_pActiveRobotTask != nullptr) {
         m_pActiveRobotTask->restore();
      }
      unlock();
      return 0;
   }
   int CMaster::resendCurrentTask()
   {
      lock();
      if (m_pActiveRobotTask != nullptr) {
         m_pActiveRobotTask->resend();
      }
      unlock();
@@ -1580,6 +1660,27 @@
      pPort->localAutoChangeEnable(autoChangeEnable);
   }
   void CMaster::setPortCassetteType(unsigned int index, SERVO::CassetteType 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->localSetCessetteType(type);
   }
   void CMaster::setPortEnable(unsigned int index, BOOL bEnable)
   {
      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(bEnable);
   }
   void CMaster::setCompareMapsBeforeProceeding(BOOL bCompare)
   {
      m_isCompareMapsBeforeProceeding = bCompare;
   }
   void CMaster::datetimeSync(SYSTEMTIME& time)
   {
      for (auto item : m_listEquipment) {
@@ -1597,4 +1698,29 @@
   {
      m_bEnableAlarmReport = bEnable;
   }
   bool CMaster::isAlarmReportEnable()
   {
      return m_bEnableAlarmReport;
   }
   int CMaster::proceedWithCarrier(unsigned int port)
   {
      if (port >= 4) return -1;
      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);
      return 0;
   }
   int CMaster::carrierRelease(unsigned int port)
   {
      if (port >= 4) return -1;
      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_CANCEL, nullptr, 0, 0, 0, nullptr, nullptr);
      return 0;
   }
}