#include "stdafx.h" #include "CEquipment.h" #include "ToolUnits.h" #include #include "CArm.h" #include "CGlassPool.h" #include "Servo.h" #define CHECK_READ_STEP_SIGNAL(addr, data, size) { \ BOOL bFlag = isBitOn(data, size, addr); \ SERVO::CStep* pStep = getStep(addr); \ if (pStep != nullptr) { \ ((CReadStep*)pStep)->onReadSignal(bFlag ? addr : 0); \ } \ } #define CHECK_WRITE_STEP_SIGNAL(addr, data, size) { \ BOOL bFlag = isBitOn(data, size, addr); \ SERVO::CStep* pStep = getStep(addr); \ if (pStep != nullptr) { \ ((CWriteStep*)pStep)->onRecvSignal(bFlag ? addr : 0); \ } \ } namespace SERVO { CEquipment::CEquipment() : m_nID(0), m_strName(""), m_strDescription(""), m_station(0, 255) { m_listener = { nullptr, nullptr, nullptr, nullptr, nullptr }; m_alive = { FALSE, 0, FALSE }; m_bCimState = FALSE; m_bUpstreamInline = FALSE; m_bDownstreamInline = FALSE; m_bLocalAlarm = FALSE; m_bAutoRecipeChange = FALSE; m_bVCREnable[0] = FALSE; m_pCclink = nullptr; m_nBaseAlarmId = 0; m_pArm = nullptr; InitializeCriticalSection(&m_criticalSection); } CEquipment::~CEquipment() { for (auto item : m_glassList) { item->release(); } m_glassList.clear(); for (auto item : m_mapStep) { delete item.second; } m_mapStep.clear(); for (auto item : m_inputPins) { delete item; } m_inputPins.clear(); for (auto item : m_outputPins) { delete item; } m_outputPins.clear(); DeleteCriticalSection(&m_criticalSection); } void CEquipment::setListener(EquipmentListener listener) { m_listener.onAlive = listener.onAlive; m_listener.onCimStateChanged = listener.onCimStateChanged; m_listener.onAlarm = listener.onAlarm; m_listener.onDataChanged = listener.onDataChanged; m_listener.onVcrEventReport = listener.onVcrEventReport; } void CEquipment::setCcLink(CCCLinkIEControl* pCcLink) { m_pCclink = pCcLink; } void CEquipment::setArm(CEquipment* pEquipment) { ASSERT(pEquipment->isArm()); ASSERT(!this->isArm()); m_pArm = pEquipment; } CEquipment* CEquipment::getArm() { return m_pArm; } void CEquipment::setBaseAlarmId(int nBaseId) { m_nBaseAlarmId = nBaseId; } int CEquipment::getBaseAlarmId() { return m_nBaseAlarmId; } void CEquipment::getProperties(std::vector>& container) { container.clear(); // ʾÀý£º½«Ò»Ð©ÊôÐÔÌí¼Óµ½ÈÝÆ÷ container.push_back(std::make_pair("DeviceName", "ServoMotor")); container.push_back(std::make_pair("SerialNumber", "123456789")); container.push_back(std::make_pair("Version", "1.0")); } std::map& CEquipment::getSteps() { return m_mapStep; } CStep* CEquipment::getStep(unsigned int addr) { auto iter = m_mapStep.find(addr); if (iter == m_mapStep.end()) return nullptr; return iter->second; } CStep* CEquipment::getStepWithName(const char* pszName) { for (auto item : m_mapStep) { if (item.second->getName().compare(pszName) == 0) { return item.second; } } return nullptr; } int CEquipment::addStep(unsigned int addr, CStep* pStep) { auto iter = m_mapStep.find(addr); if (iter != m_mapStep.end()) return -1; pStep->setEquipment(this); pStep->setID(addr); pStep->setCcLink(m_pCclink); m_mapStep[addr] = pStep; return 0; } void CEquipment::init() { initPins(); initSteps(); for (auto item : m_mapStep) { item.second->init(); } } void CEquipment::term() { for (auto item : m_mapStep) { item.second->term(); } } void CEquipment::initSteps() { } void CEquipment::setID(int nID) { m_nID = nID; } int CEquipment::getID() { return m_nID; } void CEquipment::setName(const char* pszName) { m_strName = pszName; } std::string& CEquipment::getName() { return m_strName; } void CEquipment::setDescription(const char* pszDescription) { m_strDescription = pszDescription; } std::string& CEquipment::getDescription() { return m_strDescription; } void CEquipment::setStation(int network, int station) { m_station.nNetNo = network; m_station.nStNo = station; } const StationIdentifier& CEquipment::getStation() { return m_station; } void CEquipment::getAttributeVector(CAttributeVector& attrubutes) { attrubutes.clear(); unsigned int weight = 0; attrubutes.addAttribute(new CAttribute("Network", std::to_string(m_station.nNetNo).c_str(), "", weight++)); attrubutes.addAttribute(new CAttribute("Station", std::to_string(m_station.nStNo).c_str(), "", weight++)); attrubutes.addAttribute(new CAttribute("ID", std::to_string(m_nID).c_str(), "", weight++)); attrubutes.addAttribute(new CAttribute("Name", m_strName.c_str(), "", weight++)); attrubutes.addAttribute(new CAttribute("Description", m_strDescription.c_str(), "", weight++)); attrubutes.addAttribute(new CAttribute("Alive", this->isAlive() ? _T("TRUE") : _T("FALSE"), "", weight++)); attrubutes.addAttribute(new CAttribute("CIM State", m_bCimState ? _T("ON") : _T("OFF"), "", weight++)); attrubutes.addAttribute(new CAttribute("Upstream", m_bUpstreamInline ? _T("Inline") : _T("Offline"), "", weight++)); attrubutes.addAttribute(new CAttribute("Downstream", m_bDownstreamInline ? _T("Inline") : _T("Offline"), "", weight++)); attrubutes.addAttribute(new CAttribute("Local Alarm", m_bLocalAlarm ? _T("TRUE") : _T("FALSE"), "", weight++)); attrubutes.addAttribute(new CAttribute("Auto Recipe Change", m_bAutoRecipeChange ? _T("TRUE") : _T("FALSE"), "", weight++)); char szTemp[256]; for (int i = 0; i < VCR_MAX; i++) { sprintf_s(szTemp, 256, "VCR-%d", i + 1); attrubutes.addAttribute(new CAttribute(szTemp, m_bVCREnable[i] ? _T("Enable") : _T("Disable"), "", weight++)); } for (auto item : m_inputPins) { attrubutes.addAttribute(new CAttribute(item->getName().c_str(), std::to_string((int)item->getType()).c_str(), "", weight++)); } for (auto item : m_outputPins) { attrubutes.addAttribute(new CAttribute(item->getName().c_str(), std::to_string((int)item->getType()).c_str(), "", weight++)); } for (auto item : m_glassList) { attrubutes.addAttribute(new CAttribute("Glass", item->getID().c_str(), "", weight++)); } } void CEquipment::setReadBitBlock(unsigned int start, unsigned int end) { m_blockReadBit.type = (unsigned int)DeviceType::B; m_blockReadBit.start = start; m_blockReadBit.end = end; m_blockReadBit.size = (m_blockReadBit.end - m_blockReadBit.start + 1) / 8; ASSERT(m_blockReadBit.size < BLOCK_BUFFER_MAX); } MemoryBlock& CEquipment::getReadBitBlock() { return m_blockReadBit; } void CEquipment::setWriteBitBlock(unsigned int start, unsigned int end) { m_blockWriteBit.type = (unsigned int)DeviceType::LB; m_blockWriteBit.start = start; m_blockWriteBit.end = end; m_blockWriteBit.size = (m_blockWriteBit.end - m_blockWriteBit.start + 1) / 8; } MemoryBlock& CEquipment::getWriteBitBlock() { return m_blockWriteBit; } void CEquipment::onTimer(UINT nTimerid) { // ÿ¸ôÒ»Ã룬¼ì²éÒ»ÏÂALIVE״̬ static int tick = 0; tick++; if (tick % (4 * 1) == 0) { m_alive.count++; if (m_alive.alive && m_alive.count > ALIVE_TIMEOUT) { m_alive.alive = FALSE; if (m_listener.onAlive != nullptr) { m_listener.onAlive(this, m_alive.alive); } } } } void CEquipment::serialize(CArchive& ar) { if (ar.IsStoring()) { Lock(); int count = (int)m_glassList.size(); ar << count; for (auto item : m_glassList) { item->serialize(ar); } Unlock(); } else { // addGlassToListǰ²»ÐèÒªÉÏËø£¬ÒòÆäÄÚ²¿ÓÐËø int count; ar >> count; for (int i = 0; i < count; i++) { CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass(); pGlass->serialize(ar); addGlassToList(pGlass); } // ÊáÀí¸÷²£Á§Ö®¼äµÄ°ó¶¨¹ØÏµ Lock(); std::list list = m_glassList; for (auto item : list) { std::string& strBuddyId = item->getBuddyId(); if (!strBuddyId.empty()) { for (auto item2 : m_glassList) { if (strBuddyId.compare(item2->getID()) == 0) { item->setBuddy(item2); TRACE("°ó¶¨¹ØÏµ: %s <- %s\n", item->getID().c_str(), item2->getID().c_str()); } } } } Unlock(); } } void CEquipment::onReceiveLBData(const char* pszData, size_t size) { /* TRACE("%s onReceiveLBData: %d bytes\n", m_strName.c_str(), size); for (unsigned int i = 0; i < size; i++) { if (pszData[i] != 0) TRACE("%d[%x]\n", i, pszData[i]); } */ // ÒÔϽâÊͺʹ¦ÀíÊý¾Ý BOOL bFlag; int index = 0x540; // alive bFlag = isBitOn(pszData, size, index); if (!equalBool(m_alive.flag, bFlag)) { m_alive.flag = bFlag; m_alive.count = 0; // ״̬ if (!m_alive.alive) { m_alive.alive = TRUE; if (m_listener.onAlive != nullptr) { m_listener.onAlive(this, m_alive.alive); } } } // CIM State bFlag = isBitOn(pszData, size, ++index); if (!equalBool(m_bCimState, bFlag)) { m_bCimState = bFlag; if (m_listener.onCimStateChanged != nullptr) { m_listener.onCimStateChanged(this, m_bCimState); } } // UpstreamInline bFlag = isBitOn(pszData, size, ++index); if (!equalBool(m_bUpstreamInline, bFlag)) { m_bUpstreamInline = bFlag; } // DownstreamInline bFlag = isBitOn(pszData, size, ++index); if (!equalBool(m_bDownstreamInline, bFlag)) { m_bDownstreamInline = bFlag; } // LocalAlarm bFlag = isBitOn(pszData, size, ++index); if (!equalBool(m_bLocalAlarm, bFlag)) { m_bLocalAlarm = bFlag; } // AutoRecipeChange bFlag = isBitOn(pszData, size, ++index); if (!equalBool(m_bAutoRecipeChange, bFlag)) { m_bAutoRecipeChange = bFlag; } // VCR Enable bFlag = isBitOn(pszData, size, ++index); if (!equalBool(m_bVCREnable[0], bFlag)) { m_bVCREnable[0] = bFlag; } // ÒÔϸù¾ÝÐźÅ×öÁ÷³Ì´¦Àí for (int i = 0; i < 7; i++) { CHECK_READ_STEP_SIGNAL(STEP_ID_EQMODE_CHANGED + i, pszData, size); } // process data report CHECK_READ_STEP_SIGNAL(STEP_ID_PROCESS_DATA_REPORT, pszData, size); // Åä·½¸Ä±ä CHECK_READ_STEP_SIGNAL(STEP_ID_CURRENT_RECIPE_CHANGE_REPORT, pszData, size); // Ö÷Åä·½Éϱ¨ CHECK_READ_STEP_SIGNAL(STEP_ID_MASTER_RECIPE_LIST_REPORT, pszData, size); // CIM Mode CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pszData, size); // CIM Message Set cmd reply CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIM_MSG_SET_CMD_REPLY, pszData, size); // CIM Message Clear cmd reply CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIM_MSG_CLEAR_CMD_REPLY, pszData, size); // Datetime set cmd reply CHECK_WRITE_STEP_SIGNAL(STEP_ID_DATETIME_SET_CMD_REPLY, pszData, size); // vcr enable cmd reply CHECK_WRITE_STEP_SIGNAL(STEP_ID_VCR_ENABLE_CMD_REPLY, pszData, size); // EQ mode change cmd reply CHECK_WRITE_STEP_SIGNAL(STEP_ID_EQMODE_CHANGE_CMD_REPLY, pszData, size); // EQ Master recipe request cmd reply CHECK_WRITE_STEP_SIGNAL(STEP_ID_MASTER_RECIPE_LIST_CMD_REPLY, pszData, size); // CIM Message Confirm CHECK_READ_STEP_SIGNAL(STEP_ID_CIM_MSG_CONFIRM_REPORT, pszData, size); // VCR1 Event report CHECK_READ_STEP_SIGNAL(STEP_ID_VCR1_EVENT_REPORT, pszData, size); // EQ Job Event CHECK_READ_STEP_SIGNAL(STEP_ID_RECIVE_JOB_UPS1, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_RECIVE_JOB_UPS2, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_SENT_OUT_JOB_DOWNS1, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_SENT_OUT_JOB_DOWNS2, pszData, size); // Store Job Report #1~15 CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT1, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT2, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT3, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT4, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT5, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT6, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT7, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT8, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT9, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT10, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT11, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT12, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT13, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT14, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_STORE_JOB_REPORT15, pszData, size); // Fetched Out Job Report #1~15 CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT1, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT2, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT3, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT4, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT5, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT6, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT7, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT8, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT9, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT10, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT11, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT12, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT13, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT14, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_FETCHED_OUT_JOB_REPORT15, pszData, size); // CEqCassetteTranserStateStep CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_EMPTY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_LOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_LOADED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_INUSE, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_UNLOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_BLOCKED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_EMPTY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_LOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_LOADED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_INUSE, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_UNLOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_BLOCKED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_EMPTY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_LOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_LOADED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_INUSE, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_UNLOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_BLOCKED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_EMPTY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_LOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_LOADED, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_INUSE, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_UNLOAD_READY, pszData, size); CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_BLOCKED, pszData, size); } BOOL CEquipment::isBitOn(const char* pszData, size_t size, int index) { int byteIndex, bitIndex; byteIndex = (index) / 8; bitIndex = (index) % 8; return CToolUnits::getBit(pszData[byteIndex], bitIndex); } BOOL CEquipment::equalBool(BOOL b1, BOOL b2) { return (b1 && b2) || (!b1 && !b2); } BOOL CEquipment::isAlive() { return m_alive.alive; } BOOL CEquipment::isCimOn() { return m_bCimState; } BOOL CEquipment::isUpstreamInline() { return m_bUpstreamInline; } BOOL CEquipment::isDownstreamInline() { return m_bDownstreamInline; } BOOL CEquipment::isLocalAlarm() { return m_bLocalAlarm; } BOOL CEquipment::isAutoRecipeChange() { return m_bAutoRecipeChange; } BOOL CEquipment::isVCREnable(unsigned int index) { if (index >= VCR_MAX) return FALSE; return m_bVCREnable[index]; } int CEquipment::onStepEvent(CStep* pStep, int code) { if (code == STEP_EVENT_READDATA) { if (isAlarmStep(pStep)) { SERVO::CEqAlarmStep* pEqAlarmStep = (SERVO::CEqAlarmStep*)pStep; int state = pEqAlarmStep->getAlarmState(); ASSERT(state == 0 || state == 1); if (m_listener.onAlarm != nullptr) { m_listener.onAlarm(this, state, pEqAlarmStep->getAlarmId(), pEqAlarmStep->getUnitId(), pEqAlarmStep->getAlarmLevel()); } return 1; } else if (isCimMessageConfirmStep(pStep)) { SERVO::CEqReadIntStep* pEqReadIntStep = (SERVO::CEqReadIntStep*)pStep; int value = pEqReadIntStep->getValue(); // ´Ë´¦½«value°´¸ßµÍλ²ð·ÖΪmessage idºÍpanel no. // ¿ÉÄÜ»¹ÐèÒªÉϱ¨µ½cim short msgId, panelNo; msgId = (value & 0xffff0000 >> 16); panelNo = (value & 0xffff); LOGI("Cim Message Confirm(msgID = %d, panel no.=%d).", msgId, panelNo); } /* else if (isVcrEventStep(pStep)) { SERVO::CEqVcrEventStep* pEqVcrEventStep = (SERVO::CEqVcrEventStep*)pStep; CVcrEventReport* pVcrEventReport = pEqVcrEventStep->getVcrEventReport(); ASSERT(pVcrEventReport); if (m_listener.onVcrEventReport != nullptr) { m_listener.onVcrEventReport(this, pVcrEventReport); } // 0426, Ïȹ̶¨·µ»Ø1(OK) pEqVcrEventStep->setReturnCode(1); return 1; } */ } return 0; } CPin* CEquipment::addPin(PinType type, char* pszName) { // ²»ÔÊÐíÃû×ÖÌí¼ÓÖØ¸´µÄpin CPin* pPin = getPin(pszName); if (pPin != nullptr) return nullptr; // Ìí¼Óµ½PinÁÐ±í£¬¿´ÊÇÊäÈëpin»òÊä³öpin if (type == PinType::INPUT) { pPin = new CPin(this, type, pszName); m_inputPins.push_back(pPin); return pPin; } else if (type == PinType::OUTPUT) { pPin = new CPin(this, type, pszName); m_outputPins.push_back(pPin); return pPin; } return nullptr; } CPin* CEquipment::getPin(char* pszName) { for (auto item : m_inputPins) { if (item->getName().compare(pszName) == 0) { return item; } } for (auto item : m_outputPins) { if (item->getName().compare(pszName) == 0) { return item; } } return nullptr; } std::vector& CEquipment::getInputPins() { return m_inputPins; } std::vector& CEquipment::getOutputPins() { return m_outputPins; } int CEquipment::recvIntent(CPin* pPin, CIntent* pIntent) { ASSERT(pPin); CPin* pFromPin = pPin->getConnectedPin(); ASSERT(pFromPin); CEquipment* pFromEq = pFromPin->getEquipment(); ASSERT(pFromEq); LOGI("<%s-%s>ÊÕµ½À´×Ô<%s.%s>µÄIntent<%d,%s,0x%x>", this->getName().c_str(), pPin->getName().c_str(), pFromEq->getName().c_str(), pFromPin->getName().c_str(), pIntent->getCode(), pIntent->getMsg(), pIntent->getContext()); // ÒÔϽâÊÍ´¦ÀíÊý¾Ý int code = pIntent->getCode(); // ²âÊÔ if (code == FLOW_TEST) { AfxMessageBox(pIntent->getMsg()); return FLOW_ACCEPT; } // ÐźŠif (code == FLOW_SIGNAL) { return FLOW_ACCEPT; } // Êý¾Ý if (code == FLOW_SIGNAL) { return FLOW_ACCEPT; } // ÎïÁÏ if (code == FLOW_MOVE_MATERIAL) { CGlass* pGlass = (CGlass*)pIntent->getContext(); ASSERT(pGlass); if (!glassWillArrive(pGlass)) { return FLOW_REJECT; } return glassArrived(pGlass); } return FLOW_ACCEPT; } int CEquipment::outputGlass(int port) { CPin* pOutPin = nullptr; if (port == 0) { pOutPin = getPin("Out"); if (pOutPin == nullptr) { pOutPin = getPin("Out1"); } } else if (port == 1) { pOutPin = getPin("Out2"); } if (pOutPin == nullptr) { return -1; } // Ä£ÄâÈ¡³öµÚÒ»ÕÅPanel,´«Ë͵½ÏÂÒ»»·½Ú ULONGLONG time = CToolUnits::getTimestamp(); Lock(); if (m_glassList.empty()) { Unlock(); return -2; } CGlass* pContext = m_glassList.front(); pContext->addRef(); CIntent intent(FLOW_MOVE_MATERIAL, "", pContext); int nRet = pOutPin->sendIntent(&intent); if (nRet == FLOW_REJECT) { LOGE("¶Ô·½¾Ü¾ø½ÓÊÕIntent."); } else if (nRet == FLOW_ACCEPT) { CPath* pPath = pContext->getPathWithSiteID(m_nID); if (pPath != nullptr) { pPath->setOutTime(time); } m_glassList.pop_front(); pContext->release(); // Ìí¼Óµ½ÁжÓʱaddRef, È¡³öʱrelease if (m_listener.onDataChanged != nullptr) { m_listener.onDataChanged(this, 0); } } pContext->release(); Unlock(); return 0; } BOOL CEquipment::glassWillArrive(CGlass* pGlass) { return TRUE; } int CEquipment::glassArrived(CGlass* pGlass) { Lock(); pGlass->addPath(m_nID); pGlass->addRef(); m_glassList.push_back(pGlass); Unlock(); if (m_listener.onDataChanged != nullptr) { m_listener.onDataChanged(this, 0); } return FLOW_ACCEPT; } void CEquipment::addGlassToList(CGlass* pGlass) { ASSERT(pGlass); Lock(); pGlass->addRef(); m_glassList.push_back(pGlass); Unlock(); if (m_listener.onDataChanged != nullptr) { m_listener.onDataChanged(this, 0); } } CGlass* CEquipment::getGlassFromList(const char* pszId) { CGlass* pGlass = nullptr; Lock(); for (auto item : m_glassList) { if (item->getID().compare(pszId) == 0) { pGlass = item; break; } } Unlock(); return pGlass; } BOOL CEquipment::removeClass(CGlass* pGlass) { Lock(); bool bExist = std::find(m_glassList.begin(), m_glassList.end(), pGlass) != m_glassList.end(); if (bExist) { pGlass->addPath(EQ_ID_OPERATOR_REMOVE); pGlass->release(); m_glassList.remove(pGlass); } Unlock(); if (bExist && m_listener.onDataChanged != nullptr) { m_listener.onDataChanged(this, 0); } return bExist; } void CEquipment::getGlassList(std::list& list) { Lock(); for (auto item : m_glassList) { item->addRef(); list.push_back(item); } Unlock(); } CGlass* CEquipment::getFrontGlass() { CGlass* pGlass = nullptr; Lock(); if (!m_glassList.empty()) { pGlass = m_glassList.front(); } Unlock(); return pGlass; } int CEquipment::fetchedOutJob(CJobDataB* pJobDataB) { if (m_pArm == nullptr) { return -1; } // ÕÒµ½Ö¸¶¨µÄglass id, Lock(); if (m_glassList.empty()) { Unlock(); return -2; } CGlass* pContext = nullptr; for (auto iter = m_glassList.begin(); iter != m_glassList.end(); iter++) { if ((*iter)->getID().compare(pJobDataB->getGlassId()) == 0) { pContext = (*iter); m_glassList.erase(iter); break; } } if (pContext == nullptr) { Unlock(); return -3; } // Èç¹û´Ë²£Á§ÒѾ­ÌùºÏ£¬ÌùºÏµÄ²£Á§Ò²Òª´ÓÁбíÖÐÒÆ³ý CGlass* pBuddy = pContext->getBuddy(); if (pBuddy != nullptr) { for (auto iter = m_glassList.begin(); iter != m_glassList.end(); iter++) { if ((*iter)->getID().compare(pBuddy->getID()) == 0) { (*iter)->release(); m_glassList.erase(iter); break; } } } ((CArm*)m_pArm)->tempStore(pContext); pContext->release(); Unlock(); if (m_listener.onDataChanged != nullptr) { m_listener.onDataChanged(this, 0); } return 0; } int CEquipment::storedJob(CJobDataB* pJobDataB) { if (m_pArm == nullptr) { return -1; } CGlass* pGlass = nullptr; if (((CArm*)m_pArm)->tempFetchOut(pGlass) != 0) { return -2; } ASSERT(pGlass); Lock(); pGlass->addPath(m_nID); pGlass->addRef(); // ¼ÓÈëlist,addRef m_glassList.push_back(pGlass); pGlass->release(); // tempFetchOutÐèÒªµ÷ÓÃÒ»´Îrelease Unlock(); // Èç¹û´Ë²£Á§ÒѾ­ÌùºÏ£¬ÌùºÏµÄ²£Á§Ò²Òª´Ó¼ÓÈëµ½ÁбíÖÐ CGlass* pBuddy = pGlass->getBuddy(); if (pBuddy != nullptr) { Lock(); pBuddy->addPath(m_nID); pBuddy->addRef(); // ¼ÓÈëlist,addRef m_glassList.push_back(pBuddy); Unlock(); } if (m_listener.onDataChanged != nullptr) { m_listener.onDataChanged(this, 0); } return 0; } BOOL CEquipment::isGlassListEmpty() { return m_glassList.empty(); } bool CEquipment::isAlarmStep(SERVO::CStep* pStep) { return CToolUnits::startsWith(pStep->getName(), STEP_ALARM_START); } bool CEquipment::isPortTypeStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+Type$"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isPortModeStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+Mode$"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isPortCassetteTypeStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+CassetteType$"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isPortTransferModeStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+TransferMode$"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isPortEnableStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+Enable$"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isPortTypeAutoChangeEnableStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+CassetteType$"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isCassetteTransferStateStep(SERVO::CStep* pStep) { std::regex pattern("^EQPort\\d+Cassette.*"); return std::regex_match(pStep->getName(), pattern); } bool CEquipment::isCimMessageConfirmStep(SERVO::CStep* pStep) { return pStep->getName().compare(STEP_EQ_CIM_MESSAGE_CONFIRM) == 0; } bool CEquipment::isVcrEventStep(SERVO::CStep* pStep) { return pStep->getName().compare(STEP_EQ_VCR1_EVENT_REPORT) == 0; } int CEquipment::setEqMode(short mode) { SERVO::CEqModeChangeStep* pStep = (SERVO::CEqModeChangeStep*)getStepWithName(STEP_EQ_MODE_CHANGE); if (pStep == nullptr) { return -1; } return pStep->setEqMode(mode); } int CEquipment::setCimMode(BOOL bOn) { SERVO::CEqCimModeChangeStep* pStep = (SERVO::CEqCimModeChangeStep*)getStepWithName(STEP_CIM_MODE_CHANGE); if (pStep == nullptr) { return -1; } if (bOn) return pStep->cimOn(); else return pStep->cimOff(); } int CEquipment::setCimMessage(const char* pszMessage, short id, short nTouchPanelNo) { SERVO::CEqCimMessageCmdStep* pStep = (SERVO::CEqCimMessageCmdStep*)getStepWithName(STEP_CIM_MESSAGE_CMD); if (pStep == nullptr) { return -1; } return pStep->setCimMessage(pszMessage, id, nTouchPanelNo); } int CEquipment::clearCimMessage(short id, short nTouchPanelNo) { SERVO::CEqCimMessageClearStep* pStep = (SERVO::CEqCimMessageClearStep*)getStepWithName(STEP_CIM_MESSAGE_CLEAR); if (pStep == nullptr) { return -1; } return pStep->clearCimMessage(id, nTouchPanelNo); } int CEquipment::setDateTime(short year, short month, short day, short hour, short minute, short second) { SERVO::CEqDateTimeSetCmdStep* pStep = (SERVO::CEqDateTimeSetCmdStep*)getStepWithName(STEP_DATETIME_SET_CMD); if (pStep == nullptr) { return -1; } return pStep->setDateTime(year, month, day, hour, minute, second); } int CEquipment::setDispatchingMode(DISPATCHING_MODE mode, ONWRITED onWritedBlock/* = nullptr*/) { SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_DISPATCHINT_MODE_CHANGE); if (pStep == nullptr) { return -1; } LOGI("×¼±¸ÉèÖÃDispatchingMode<%d>", m_strName.c_str(), (int)mode); if (onWritedBlock != nullptr) { pStep->writeShort((short)mode, onWritedBlock); } else { pStep->writeShort((short)mode, [&, mode](int code) -> int { if (code == WOK) { LOGI("ÉèÖÃDispatchingMode³É¹¦.", m_strName.c_str()); } else { LOGI("ÉèÖÃDispatchingModeʧ°Ü£¬code:%d", m_strName.c_str(), code); } return 0; }); } return 0; } int CEquipment::indexerOperationModeChange(IDNEXER_OPERATION_MODE mode, ONWRITED onWritedBlock/* = nullptr*/) { SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EFEM_IN_OP_MODE_CHANGE); if (pStep == nullptr) { return -1; } unsigned short operationMode = (unsigned short)(mode + getIndexerOperationModeBaseValue()); LOGI("×¼±¸ÉèÖÃindexerOperationMode<%d>", m_strName.c_str(), (int)mode); if (onWritedBlock != nullptr) { pStep->writeShort(operationMode, onWritedBlock); } else { pStep->writeShort(operationMode, [&, mode](int code) -> int { if (code == WOK) { LOGI("ÉèÖÃindexerOperationMode³É¹¦.", m_strName.c_str()); } else { LOGI("ÉèÖÃindexerOperationModeʧ°Ü£¬code:%d", m_strName.c_str(), code); } return 0; }); } return 0; } int CEquipment::masterRecipeListRequest(short unitNo) { SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_MASTER_RECIPE_LIST_REQ); if (pStep == nullptr) { return -1; } LOGI("ÕýÔÚÇëÇóµ¥Ôª<%d>Ö÷Åä·½Áбí", m_strName.c_str(), unitNo); if (m_recipesManager.syncing() != 0) { return -2; } pStep->writeShort(unitNo, [&, unitNo](int code) -> int { if (code == WOK) { LOGI("ÇëÇóµ¥Ôª<%d>Ö÷Åä·½Áбí³É¹¦£¬ÕýÔڵȴýÊý¾Ý.", m_strName.c_str(), unitNo); } else { m_recipesManager.syncFailed(); LOGI("ÇëÇóµ¥Ôª<%d>Ö÷Åä·½Áбíʧ°Ü£¬code:%d", m_strName.c_str(), unitNo, code); } return 0; }); return 0; } int CEquipment::recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo) { SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_MASTER_RECIPE_LIST_REQ); if (pStep == nullptr) { return -1; } LOGI("ÕýÔÚÇëÇóµ¥Ôª<%d>Ö÷Åä·½Áбí", m_strName.c_str(), unitNo); if (m_recipesManager.syncing() != 0) { return -2; } pStep->writeShort(unitNo, [&, unitNo](int code) -> int { if (code == WOK) { LOGI("ÇëÇóµ¥Ôª<%d>Ö÷Åä·½Áбí³É¹¦£¬ÕýÔڵȴýÊý¾Ý.", m_strName.c_str(), unitNo); } else { m_recipesManager.syncFailed(); LOGI("ÇëÇóµ¥Ôª<%d>Ö÷Åä·½Áбíʧ°Ü£¬code:%d", m_strName.c_str(), unitNo, code); } return 0; }); return 0; } short CEquipment::decodeRecipeListReport(const char* pszData, size_t size) { return m_recipesManager.decodeRecipeListReport(pszData, size); } short CEquipment::decodeRecipeParameterReport(const char* pszData, size_t size) { return m_recipesManager.decodeRecipeParameterReport(pszData, size); } int CEquipment::decodeProcessDataReport(CStep* pStep, const char* pszData, size_t size) { CProcessData processData; int nRet = processData.unserialize(&pszData[0], (int)size); if (nRet < 0) return nRet; // »º´æAttribute£¬ÓÃÓÚµ÷ÊÔʱÏÔʾÐÅÏ¢ unsigned int weight = 201; CAttributeVector attrubutes; processData.getAttributeVector(attrubutes, weight); pStep->addAttributeVector(attrubutes); onProcessData(&processData); return nRet; } int CEquipment::decodeReceivedJobReport(CStep* pStep, int port, const char* pszData, size_t size) { CJobDataS jobDataS; int nRet = jobDataS.unserialize(&pszData[0], (int)size); if (nRet < 0) return nRet; // »º´æAttribute£¬ÓÃÓÚµ÷ÊÔʱÏÔʾÐÅÏ¢ unsigned int weight = 201; CAttributeVector attrubutes; jobDataS.getAttributeVector(attrubutes, weight); pStep->addAttributeVector(attrubutes); onReceivedJob(port, &jobDataS); return nRet; } int CEquipment::onReceivedJob(int port, CJobDataS* pJobDataS) { LOGI("onReceivedJob.", m_strName.c_str()); addJobDataS(pJobDataS); return 0; } int CEquipment::decodeSentOutJobReport(CStep* pStep, int port, const char* pszData, size_t size) { CJobDataS jobDataS; int nRet = jobDataS.unserialize(&pszData[0], (int)size); if (nRet < 0) return nRet; // »º´æAttribute£¬ÓÃÓÚµ÷ÊÔʱÏÔʾÐÅÏ¢ unsigned int weight = 201; CAttributeVector attrubutes; jobDataS.getAttributeVector(attrubutes, weight); pStep->addAttributeVector(attrubutes); onReceivedJob(port, &jobDataS); return nRet; } int CEquipment::onSentOutJob(int port, CJobDataS* pJobDataS) { LOGI("onSentOutJob.", m_strName.c_str()); int count = removeJobDataS(pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo()); if (count == 1) { LOGI("onSentOutJob,ɾ³ýÊý¾Ý %d Ìõ", m_strName.c_str(), count); } else { LOGE("onSentOutJob,ɾ³ýÊý¾Ý %d Ìõ£¬×¢ÒâÅŲé·çÏÕ", m_strName.c_str(), count); } return 0; } int CEquipment::decodeFetchedOutJobReport(CStep* pStep, int port, const char* pszData, size_t size) { int index = 0; short unitOrPort, unitOrPortNo, subUnitNo, subSlotNo; CJobDataB jobDataB; int nRet = jobDataB.unserialize(&pszData[index], (int)size); if (nRet < 0) return nRet; index += nRet; memcpy(&unitOrPort, &pszData[index], sizeof(short)); index += sizeof(short); memcpy(&unitOrPortNo, &pszData[index], sizeof(short)); index += sizeof(short); memcpy(&subUnitNo, &pszData[index], sizeof(short)); index += sizeof(short); memcpy(&subSlotNo, &pszData[index], sizeof(short)); index += sizeof(short); // »º´æAttribute£¬ÓÃÓÚµ÷ÊÔʱÏÔʾÐÅÏ¢ unsigned int weight = 201; pStep->addAttribute(new CAttribute("UnitOrPort", std::to_string(unitOrPort).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("UnitOrPortNo", std::to_string(unitOrPortNo).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("SubUnitNo", std::to_string(subUnitNo).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("SubSlotNo", std::to_string(subSlotNo).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("CassetteSequenceNo", std::to_string(jobDataB.getCassetteSequenceNo()).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("JobSequenceNo", std::to_string(jobDataB.getJobSequenceNo()).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("GlassId", jobDataB.getGlassId().c_str(), "", weight++)); onFetchedOutJob(port, &jobDataB); return index; } int CEquipment::onPreFetchedOutJob(int port, CJobDataB* pJobDataB) { LOGI("onPreFetchedOutJob:port:%d|GlassId:%s", m_strName.c_str(), port, pJobDataB->getGlassId().c_str()); return TRUE; } int CEquipment::onFetchedOutJob(int port, CJobDataB* pJobDataB) { LOGI("onFetchedOutJob:port:%d|GlassId:%s", m_strName.c_str(), port, pJobDataB->getGlassId().c_str()); BOOL bCheck = onPreFetchedOutJob(port, pJobDataB); if (bCheck) { return fetchedOutJob(pJobDataB); } // Êý¾ÝÒì³££¬´¦Àí»òÏÔʾ LOGI("onFetchedOutJob Error.ort:%d|GlassId:%s", m_strName.c_str(), port, pJobDataB->getGlassId().c_str()); return -1; } int CEquipment::decodeStoredJobReport(CStep* pStep, int port, const char* pszData, size_t size) { int index = 0; short unitOrPort, unitOrPortNo, subUnitNo, subSlotNo; CJobDataB jobDataB; int nRet = jobDataB.unserialize(&pszData[index], (int)size); if (nRet < 0) return nRet; index += nRet; memcpy(&unitOrPort, &pszData[index], sizeof(short)); index += sizeof(short); memcpy(&unitOrPortNo, &pszData[index], sizeof(short)); index += sizeof(short); memcpy(&subUnitNo, &pszData[index], sizeof(short)); index += sizeof(short); memcpy(&subSlotNo, &pszData[index], sizeof(short)); index += sizeof(short); // »º´æAttribute£¬ÓÃÓÚµ÷ÊÔʱÏÔʾÐÅÏ¢ unsigned int weight = 201; pStep->addAttribute(new CAttribute("UnitOrPort", std::to_string(unitOrPort).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("UnitOrPortNo", std::to_string(unitOrPortNo).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("SubUnitNo", std::to_string(subUnitNo).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("SubSlotNo", std::to_string(subSlotNo).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("CassetteSequenceNo", std::to_string(jobDataB.getCassetteSequenceNo()).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("JobSequenceNo", std::to_string(jobDataB.getJobSequenceNo()).c_str(), "", weight++)); pStep->addAttribute(new CAttribute("GlassId", jobDataB.getGlassId().c_str(), "", weight++)); onStoredJob(port, &jobDataB); return index; } int CEquipment::decodeVCREventReport(CStep* pStep, const char* pszData, size_t size) { CVcrEventReport vcrEventReport; vcrEventReport.unserialize(pszData, size); LOGI("decodeVCREventReport\n", m_strName.c_str(), vcrEventReport.getVcrResult(), vcrEventReport.getGlassId().c_str()); // »º´æAttribute£¬ÓÃÓÚµ÷ÊÔʱÏÔʾÐÅÏ¢ unsigned int weight = 201; CAttributeVector attrubutes; vcrEventReport.getAttributeVector(attrubutes, weight); pStep->addAttributeVector(attrubutes); // 0426, Ïȹ̶¨·µ»Ø1(OK) ((CReadStep*)pStep)->setReturnCode((short)VCR_Reply_Code::OK); return 0; } int CEquipment::onPreStoredJob(int port, CJobDataB* pJobDataB) { LOGI("onPreStoredJob:port:%d|GlassId:%s", m_strName.c_str(), port, pJobDataB->getGlassId().c_str()); return TRUE; } int CEquipment::onStoredJob(int port, CJobDataB* pJobDataB) { LOGI("onStore:port:%d|GlassId:%s", m_strName.c_str(), port, pJobDataB->getGlassId().c_str()); BOOL bCheck = onPreStoredJob(port, pJobDataB); if (bCheck) { addJobDataB(pJobDataB); return storedJob(pJobDataB); } // Êý¾ÝÒì³££¬´¦Àí»òÏÔʾ LOGI("onStoredJob Error.ort:%d|GlassId:%s", m_strName.c_str(), port, pJobDataB->getGlassId().c_str()); return -1; } int CEquipment::onProcessData(CProcessData* pProcessData) { LOGI("onProcessData.", m_strName.c_str()); return 0; } int CEquipment::getIndexerOperationModeBaseValue() { return 0; } int CEquipment::addJobDataB(CJobDataB* pJobDataB) { // Ìí¼Ó֮ǰÏÈɾ³ý¾ÉµÄ£¬ÒÔÃâÊý¾ÝÖØ¸´ Lock(); int count = removeJobDataB(pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo()); if (count > 0) { LOGE("addJobDataB,ɾ³ýÖØ¸´Êý¾Ý %d Ìõ£¬×¢ÒâÅŲé·çÏÕ", m_strName.c_str(), count); } m_listJobDataB.push_back(std::move(*pJobDataB)); Unlock(); return (int)m_listJobDataB.size(); } int CEquipment::removeJobDataB(int nCassetteSequenceNo, int nJobSequenceNo) { int count = 0; for (auto it = m_listJobDataB.begin(); it != m_listJobDataB.end(); ) { if ((*it).getCassetteSequenceNo() == nCassetteSequenceNo && (*it).getJobSequenceNo() == nJobSequenceNo) { it = m_listJobDataB.erase(it); count++; } else { ++it; } } return count; } CJobDataB* CEquipment::getJobDataB(int nCassetteSequenceNo, int nJobSequenceNo) { for (auto& item : m_listJobDataB) { if (item.getCassetteSequenceNo() == nCassetteSequenceNo && item.getJobSequenceNo() == nJobSequenceNo) { return &item; } } return nullptr; } int CEquipment::addJobDataS(CJobDataS* pJobDataS) { // Ìí¼Ó֮ǰÏÈɾ³ý¾ÉµÄ£¬ÒÔÃâÊý¾ÝÖØ¸´ Lock(); int count = removeJobDataS(pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo()); if (count > 0) { LOGE("addJobDataS,ɾ³ýÖØ¸´Êý¾Ý %d Ìõ£¬×¢ÒâÅŲé·çÏÕ", m_strName.c_str(), count); } m_listJobDataS.push_back(std::move(*pJobDataS)); Unlock(); return (int)m_listJobDataB.size(); } int CEquipment::removeJobDataS(int nCassetteSequenceNo, int nJobSequenceNo) { int count = 0; Lock(); for (auto it = m_listJobDataS.begin(); it != m_listJobDataS.end(); ) { if ((*it).getCassetteSequenceNo() == nCassetteSequenceNo && (*it).getJobSequenceNo() == nJobSequenceNo) { it = m_listJobDataS.erase(it); count++; } else { ++it; } } Unlock(); return count; } CJobDataS* CEquipment::getJobDataS(int nCassetteSequenceNo, int nJobSequenceNo) { for (auto& item : m_listJobDataS) { if (item.getCassetteSequenceNo() == nCassetteSequenceNo && item.getJobSequenceNo() == nJobSequenceNo) { return &item; } } return nullptr; } }