1.将OnPanelDataReport相关功能由EFEM移到Aligner;
2.Glass增加最初来源Port和Slot,以便在Aligner检测NG时加退;
3.物流调度增加一个参数,是否检测OK作为调度依据。
4.Alginer检测NG,送回原处;
已修改14个文件
387 ■■■■ 文件已修改
SourceCode/Bond/Servo/CAligner.cpp 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CAligner.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEFEM.cpp 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CGlass.cpp 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CGlass.h 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CLoadPort.cpp 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPath.cpp 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPath.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoCommo.h 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CAligner.cpp
@@ -48,6 +48,34 @@
        m_slot[0].setName("Slot 1");
    }
    void CAligner::initSteps()
    {
        CEquipment::initSteps();
        {
            // Panel Data Report
            CEqReadStep* pStep = new CEqReadStep(0x617f, 386 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodePanelDataReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_PANEL_DATA_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0x15e);
            if (addStep(STEP_ID_PANEL_DATA_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
    }
    void CAligner::onReceiveLBData(const char* pszData, size_t size)
    {
        __super::onReceiveLBData(pszData, size);
        CHECK_READ_STEP_SIGNAL(STEP_ID_PANEL_DATA_REPORT, pszData, size);
    }
    void CAligner::onTimer(UINT nTimerid)
    {
        CEquipment::onTimer(nTimerid);
SourceCode/Bond/Servo/CAligner.h
@@ -16,6 +16,8 @@
        virtual void term();
        virtual void initPins();
        virtual void initSlots();
        virtual void initSteps();
        virtual void onReceiveLBData(const char* pszData, size_t size);
        virtual void onTimer(UINT nTimerid);
        virtual void serialize(CArchive& ar);
        virtual void getAttributeVector(CAttributeVector& attrubutes);
SourceCode/Bond/Servo/CEFEM.cpp
@@ -677,23 +677,6 @@
        }
        {
            // Panel Data Report
            CEqReadStep* pStep = new CEqReadStep(0x617f, 386 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodePanelDataReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
            pStep->setName(STEP_EQ_PANEL_DATA_REPORT);
            pStep->setProp("Port", (void*)1);
            pStep->setWriteSignalDev(0x15e);
            if (addStep(STEP_ID_PANEL_DATA_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        {
            // FAC Data Report
            CEqReadStep* pStep = new CEqReadStep(0x6301, 108 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
@@ -804,6 +787,8 @@
                m_pPort[i]->onReceiveLBData(pszData, size);
            }
        }
        m_pAligner->onReceiveLBData(pszData, size);
        // 更新信号到LoadPort, Robot, Aligner, Fliper
        m_pPort[0]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[0][0]);
SourceCode/Bond/Servo/CEquipment.cpp
@@ -7,22 +7,6 @@
#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)
@@ -1313,6 +1297,7 @@
            CGlass* pGlass = (CGlass*)m_slot[i].getContext();
            if (!isSlotProcessed(i)) continue;
            if (pGlass == nullptr) continue;
            if(pGlass->getInspResult(m_nID, 0) == InspResult::Fail) continue;
            int lsPath = m_slot[i].getLinkSignalPath();
            if(!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
                || m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
@@ -1352,6 +1337,26 @@
                    return &m_slot[i];
                }
            }
        }
        return nullptr;
    }
    CSlot* CEquipment::getInspFailSlot()
    {
        for (int i = 0; i < SLOT_MAX; i++) {
            if (!m_slot[i].isEnable()) continue;
            if (m_slot[i].isLock()) continue;
            CGlass* pGlass = (CGlass*)m_slot[i].getContext();
            if (pGlass == nullptr) continue;
            if (pGlass->getInspResult(m_nID, 0) != InspResult::Fail) continue;
            int lsPath = m_slot[i].getLinkSignalPath();
            if (!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
                || m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
                || !m_bLinkSignalToUpstream[lsPath][SIGNAL_INTERLOCK]
                || !m_bLinkSignalToUpstream[lsPath][SIGNAL_SEND_ABLE]) continue;
            return &m_slot[i];
        }
        return nullptr;
@@ -1634,6 +1639,15 @@
        pStep->addAttribute(new CAttribute("PanelGradeData",
            strPanelGradeData.c_str(), "", weight++));
        // 更新检测结果
        CGlass* pGlass = getGlassWithCassette(cassetteNo, jobSequenceNo);
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>更新Panel Data失败,找不到对应的Glass.cassetteNo=%d, jobSequenceNo=%d",
                getName().c_str(), cassetteNo, jobSequenceNo);
            return -1;
        }
        pGlass->setInspResult(m_nID, 0, judgeStringToInspResult(strPanelJudgeData));
        return 0;
    }
@@ -1974,4 +1988,16 @@
            );
        }
    }
    InspResult CEquipment::judgeStringToInspResult(std::string& strJudge)
    {
        if (strJudge.compare("N") == 0) {
            return InspResult::Fail;
        }
        if (strJudge.compare("G") == 0) {
            return InspResult::Pass;
        }
        return InspResult::NotInspected;
    }
}
SourceCode/Bond/Servo/CEquipment.h
@@ -179,6 +179,7 @@
        // 获取一个指定物料类型(G1,G2,G1&G2)的且已经加工处理的槽位
        CSlot* getProcessedSlot(MaterialsType putSlotType);
        CSlot* getProcessedSlot2(MaterialsType putSlotType, const std::vector<int>& candidates);
        CSlot* getInspFailSlot();
        // 获取玻璃物料
        CGlass* getGlassFromSlot(int slotNo);
@@ -199,6 +200,12 @@
        // 手动移除物料
        int removeGlass(int slotNo);
        // 字符串检测结果转换
        InspResult judgeStringToInspResult(std::string& strJudge);
    // 以下为从CC-Link读取到的Bit标志位检测函数
    public:
        BOOL isAlive();
SourceCode/Bond/Servo/CGlass.cpp
@@ -8,6 +8,8 @@
        m_pPath = nullptr;
        m_type = MaterialsType::G1;
        m_pBuddy = nullptr;
        m_nOriginPort = 0;
        m_nOriginSlot = 0;
    }
    CGlass::~CGlass()
@@ -66,6 +68,18 @@
        return m_strID;
    }
    void CGlass::setOriginPort(int port, int slot)
    {
        m_nOriginPort = port;
        m_nOriginSlot = slot;
    }
    void CGlass::getOrginPort(int& port, int& slot)
    {
        port = m_nOriginPort;
        slot = m_nOriginSlot;
    }
    CPath* CGlass::getPath()
    {
        return m_pPath;
@@ -103,6 +117,8 @@
            Lock();
            ar << (int)m_type;
            WriteString(ar, m_strID);
            ar << m_nOriginPort;
            ar << m_nOriginSlot;
            ar << (ULONGLONG)m_pPath;
            if (m_pPath != nullptr) {
                m_pPath->serialize(ar);
@@ -123,6 +139,8 @@
            ar >> type;
            m_type = (MaterialsType)type;
            ReadString(ar, m_strID);
            ar >> m_nOriginPort;
            ar >> m_nOriginSlot;
            ar >> ullPath;
            if (ullPath != 0) {
                m_pPath = new CPath();
@@ -182,12 +200,13 @@
        return m_strBuddyId;
    }
    void CGlass::processEnd(unsigned int nEqId, unsigned int nUnit)
    int CGlass::processEnd(unsigned int nEqId, unsigned int nUnit)
    {
        CPath* pPath = getPathWithEq(nEqId, nUnit);
        if (pPath != nullptr) {
            pPath->processEnd();
        }
        if (pPath == nullptr) return -1;
        pPath->processEnd();
        return 0;
    }
    BOOL CGlass::isProcessed(unsigned int nEqId, unsigned int nUnit)
@@ -197,4 +216,21 @@
        return pPath->isProcessEnd();
    }
    int CGlass::setInspResult(unsigned int nEqId, unsigned int nUnit, InspResult result)
    {
        CPath* pPath = getPathWithEq(nEqId, nUnit);
        if (pPath == nullptr) return -1;
        pPath->setInspResult(result);
        return 0;
    }
    InspResult CGlass::getInspResult(unsigned int nEqId, unsigned int nUnit)
    {
        CPath* pPath = getPathWithEq(nEqId, nUnit);
        if (pPath == nullptr) return InspResult::NotInspected;
        return pPath->getInspResult();
    }
}
SourceCode/Bond/Servo/CGlass.h
@@ -24,6 +24,8 @@
        void setType(MaterialsType type);
        void setID(const char* pszID);
        std::string& getID();
        void setOriginPort(int port, int slot);
        void getOrginPort(int& port, int& slot);
        CPath* getPathWithEq(unsigned int nEqId, unsigned int nUnit);
        CPath* getPath();
        void addPath(unsigned int nEqId, unsigned int nUnit);
@@ -35,8 +37,10 @@
        BOOL forceSetBuddy(CGlass* pGlass);
        CGlass* getBuddy();
        std::string& getBuddyId();
        void processEnd(unsigned int nEqId, unsigned int nUnit);
        int processEnd(unsigned int nEqId, unsigned int nUnit);
        BOOL isProcessed(unsigned int nEqId, unsigned int nUnit);
        int setInspResult(unsigned int nEqId, unsigned int nUnit, InspResult result);
        InspResult getInspResult(unsigned int nEqId, unsigned int nUnit);
    private:
        MaterialsType m_type;
@@ -45,6 +49,8 @@
        CJobDataS m_jobDataS;
        CGlass* m_pBuddy;
        std::string m_strBuddyId;
        int m_nOriginPort;
        int m_nOriginSlot;
    };
}
SourceCode/Bond/Servo/CLoadPort.cpp
@@ -2,23 +2,8 @@
#include "CLoadPort.h"
#include "CGlassPool.h"
#include "Servo.h"
#include "ServoCommo.h"
#define CHECK_READ_STEP_SIGNAL2(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_SIGNAL2(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 {
    CLoadPort::CLoadPort() : CEquipment()
@@ -429,15 +414,18 @@
        SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getCassetteCtrlCmdStep();
        ASSERT(pStep);
        ASSERT(jobExistenceSize == 12);
        ASSERT(pJobDataA);
        char szBuffer[1024] = { 0 };
        memcpy(&szBuffer[0], &cmd, sizeof(short));
        memcpy(&szBuffer[2], jobExistence, sizeof(short) * jobExistenceSize);
        if (jobExistence != nullptr && jobExistenceSize == 12) {
            memcpy(&szBuffer[2], jobExistence, sizeof(short) * jobExistenceSize);
        }
        memcpy(&szBuffer[26], &slotProcess, sizeof(short));
        memcpy(&szBuffer[36], &jopCount, sizeof(short));
        int nLen = pJobDataA->serialize(&szBuffer[38], 1024 - 38);
        if (pJobDataA != nullptr) {
            pJobDataA->serialize(&szBuffer[38], 1024 - 38);
        }
        return pStep->writeDataEx(szBuffer, 352 * 2, onWritedBlock);
    }
@@ -860,12 +848,12 @@
        static int autoType[] = { STEP_ID_PORT1_TYPE_AUTO_CHANGE, STEP_ID_PORT2_TYPE_AUTO_CHANGE,
            STEP_ID_PORT3_TYPE_AUTO_CHANGE, STEP_ID_PORT4_TYPE_AUTO_CHANGE };
        CHECK_READ_STEP_SIGNAL2(type[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(mode[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(cassetteType[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(transferMode[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(enable[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL2(autoType[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL(type[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL(mode[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL(cassetteType[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL(transferMode[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL(enable[m_nIndex], pszData, size);
        CHECK_READ_STEP_SIGNAL(autoType[m_nIndex], pszData, size);
        static int typeReply[] = { STEP_ID_PROT1_TYPE_CHANGE_REPLY, STEP_ID_PROT2_TYPE_CHANGE_REPLY,
@@ -881,12 +869,12 @@
        static int cassetteTypeReply[] = { STEP_ID_PROT1_CASSETTE_TYPE_CHANGE_REPLY, STEP_ID_PROT2_CASSETTE_TYPE_CHANGE_REPLY,
            STEP_ID_PROT3_CASSETTE_TYPE_CHANGE_REPLY, STEP_ID_PROT4_CASSETTE_TYPE_CHANGE_REPLY };
        CHECK_WRITE_STEP_SIGNAL2(typeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(modeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(transferModeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(enableModeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(typeAutoReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL2(cassetteTypeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL(typeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL(modeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL(transferModeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL(enableModeReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL(typeAutoReply[m_nIndex], pszData, size);
        CHECK_WRITE_STEP_SIGNAL(cassetteTypeReply[m_nIndex], pszData, size);
    }
    int CLoadPort::decodePortStatusReport(CStep* pStep, const char* pszData, size_t size)
@@ -895,6 +883,11 @@
        int nRet = portStatusReport.unserialize(&pszData[0], (int)size);
        if (nRet < 0) return nRet;
        m_portStatusReport.copyEx(portStatusReport);
        if (m_portStatusReport.getPortStatus() == PORT_INUSE) {
            this->sendCassetteCtrlCmd(5, nullptr, 0, 0, 0, nullptr, nullptr);
        }
        // 缓存Attribute,用于调试时显示信息
@@ -909,6 +902,8 @@
            LOGI("<CCassetteTranserStateStep>InUse<JobExistenceSlot:%d>",
                m_portStatusReport.getJobExistenceSlot());
        }
        return nRet;
    }
@@ -1144,6 +1139,7 @@
            js.setMaterialsType((int)type);
            CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
            pGlass->setOriginPort(m_nIndex, i);
            pGlass->addPath(m_nID, 0);
            pGlass->processEnd(m_nID, 0);
            pGlass->setID(szBuffer);
@@ -1182,6 +1178,7 @@
            js.setGlass1Id(szBuffer);
            CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
            pGlass->setOriginPort(m_nIndex, nSlotIndex);
            pGlass->addPath(m_nID, 0);
            pGlass->processEnd(m_nID, 0);
            pGlass->setID(szBuffer);
SourceCode/Bond/Servo/CMaster.cpp
@@ -297,11 +297,12 @@
        // 各种机器
        CLoadPort* pLoadPorts[4];
        CEFEM* pEFEM = (CEFEM*)getEquipment(EQ_ID_EFEM);
        CLoadPort* pLoadPort1 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT1);
        CLoadPort* pLoadPort2 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT2);
        CLoadPort* pLoadPort3 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT3);
        CLoadPort* pLoadPort4 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT4);
        pLoadPorts[0] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT1);
        pLoadPorts[1] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT2);
        pLoadPorts[2] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT3);
        pLoadPorts[3] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT4);
        CFliper* pFliper = (CFliper*)getEquipment(EQ_ID_FLIPER);
        CVacuumBake* pVacuumBake = (CVacuumBake*)getEquipment(EQ_ID_VACUUMBAKE);
        CAligner* pAligner = (CAligner*)getEquipment(EQ_ID_ALIGNER);
@@ -311,10 +312,10 @@
        CMeasurement* pMeasurement = (CMeasurement*)getEquipment(EQ_ID_MEASUREMENT);
        ASSERT(pEFEM);
        ASSERT(pLoadPort1);
        ASSERT(pLoadPort2);
        ASSERT(pLoadPort3);
        ASSERT(pLoadPort4);
        ASSERT(pLoadPorts[0]);
        ASSERT(pLoadPorts[1]);
        ASSERT(pLoadPorts[2]);
        ASSERT(pLoadPorts[3]);
        ASSERT(pFliper);
        ASSERT(pVacuumBake);
        ASSERT(pAligner);
@@ -544,17 +545,16 @@
                    LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
                        rmd.armState[1] ? _T("不可用") : _T("可用"));
                }
                CLoadPort* pEqLoadPort[] = { pLoadPort1, pLoadPort2, pLoadPort3, pLoadPort4 };
                CEquipment* pEqTar[] = { pVacuumBake, pFliper };
                if (primaryType == MaterialsType::G2) {
                    pEqTar[0] = pFliper;
                    pEqTar[1] = pVacuumBake;
                }
                for (int s = 0; s < 4; s++) {
                    if (!rmd.armState[0] && pEqLoadPort[s]->isEnable()
                        && pEqLoadPort[s]->getPortType() == PortType::Unloading
                        && pEqLoadPort[s]->getPortMode() == PortMode::ReadyToUnload) {
                        m_pActiveRobotTask = createTransferTask(pMeasurement, pEqLoadPort[s], primaryType, secondaryType);
                    if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                        && pLoadPorts[s]->getPortType() == PortType::Unloading
                        && pLoadPorts[s]->getPortMode() == PortMode::ReadyToUnload) {
                        m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType);
                        if (m_pActiveRobotTask != nullptr) {
                            goto PORT_PUT;
                        }
@@ -572,6 +572,25 @@
                    LOGI("创建新任务<%s>...", strDescription.c_str());
                    continue;
                }
                // 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;
                    }
                }
                // BakeCooling ->Measurement
@@ -727,12 +746,30 @@
                    }
                }
                // 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;
                    }
                }
                // LoadPort -> Aligner
                for (int s = 0; s < 4; s++) {
                    if (!rmd.armState[0] && pEqLoadPort[s]->isEnable()
                        && pEqLoadPort[s]->getPortType() == PortType::Loading
                        && pEqLoadPort[s]->getPortMode() == PortMode::ReadyToLoad) {
                        m_pActiveRobotTask = createTransferTask(pEqLoadPort[s], pAligner, primaryType, secondaryType);
                    if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
                        && pLoadPorts[s]->getPortType() == PortType::Loading
                        && pLoadPorts[s]->getPortMode() == PortMode::ReadyToLoad) {
                        m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType);
                        if (m_pActiveRobotTask != nullptr) {
                            pEFEM->setContext(m_pActiveRobotTask->getContext());
                            goto PORT_GET;
@@ -1454,6 +1491,38 @@
        return pTask;
    }
    CRobotTask* CMaster::createTransferTask_restore(CEquipment* pEqSrc, CLoadPort** pPorts)
    {
        CRobotTask* pTask = nullptr;
        CSlot* pSrcSlot, * pTarSlot = nullptr, * pTempSlot;
        pSrcSlot = pEqSrc->getInspFailSlot();
        if (pSrcSlot != nullptr) {
            CGlass* pGlass = (CGlass*)pSrcSlot->getContext();
            ASSERT(pGlass);
            int port, slot;
            pGlass->getOrginPort(port, slot);
            pGlass->setInspResult(pPorts[port]->getID(), 0, InspResult::Fail);
            ASSERT(0 <= port && port < 4);
            ASSERT(0 <= slot && slot < 8);
            pTempSlot = pPorts[port]->getSlot(slot);
            if (pTempSlot->getContext() == nullptr) {
                pTarSlot = pTempSlot;
            }
        }
        if (pSrcSlot != nullptr && nullptr != pTarSlot) {
            pTask = new CRobotTask();
            pTask->setContext(pSrcSlot->getContext());
            pTask->setEFEM((CEFEM*)getEquipment(EQ_ID_EFEM));
            taskSeqNo = pTask->setRobotTransferParam(taskSeqNo, 1, pSrcSlot->getPosition(),
                pTarSlot->getPosition(), pSrcSlot->getNo(), pTarSlot->getNo());
        }
        return pTask;
    }
    int CMaster::abortCurrentTask()
    {
        lock();
SourceCode/Bond/Servo/CMaster.h
@@ -96,7 +96,8 @@
        CRobotTask* createTransferTask_bonder_to_bakecooling(CEquipment* pSrcEq, CEquipment* pTarEq);
        CRobotTask* createTransferTask_bake_to_cooling(CEquipment* pSrcEq);
        CRobotTask* createTransferTask_bakecooling_to_measurement(CEquipment* pSrcEq, CEquipment* pTarEq);
        CRobotTask* createTransferTask_restore(CEquipment* pEqSrc, CLoadPort** pPorts);
    private:
        CRITICAL_SECTION m_criticalSection;
        MasterListener m_listener;
SourceCode/Bond/Servo/CPath.cpp
@@ -10,6 +10,7 @@
        m_timeOut = 0;
        m_timeIn = CToolUnits::getTimestamp();
        m_bProcessed = FALSE;
        m_inspResult = InspResult::NotInspected;
        m_pPrev = nullptr;
        m_pNext = nullptr;
    }
@@ -20,9 +21,10 @@
        m_nUnit = nUnit;
        m_timeOut = 0;
        m_timeIn = CToolUnits::getTimestamp();
        m_bProcessed = FALSE;
        m_inspResult = InspResult::NotInspected;
        m_pPrev = nullptr;
        m_pNext = nullptr;
        m_bProcessed = FALSE;
    }
    CPath::~CPath()
@@ -52,17 +54,21 @@
            ar << m_timeIn;
            ar << m_timeOut;
            ar << m_bProcessed;
            ar << (int)m_inspResult;
            ar << (ULONGLONG)m_pNext;
            if (m_pNext != nullptr) {
                m_pNext->serialize(ar);
            }
        }
        else {
            int temp;
            ar >> m_nEqID;
            ar >> m_nUnit;
            ar >> m_timeIn;
            ar >> m_timeOut;
            ar >> m_bProcessed;
            ar >> temp; m_inspResult = (InspResult)temp;
            ULONGLONG ulNext;
            ar >> ulNext;
            if ((CPath*)ulNext != nullptr) {
@@ -109,6 +115,16 @@
        return m_bProcessed;
    }
    void CPath::setInspResult(InspResult result)
    {
        m_inspResult = result;
    }
    InspResult CPath::getInspResult()
    {
        return m_inspResult;
    }
    CPath* CPath::getPrev()
    {
        return m_pPrev;
SourceCode/Bond/Servo/CPath.h
@@ -1,4 +1,5 @@
#pragma once
#include "ServoCommo.h"
namespace SERVO {
@@ -24,6 +25,8 @@
        ULONGLONG getOutTime();
        void processEnd();
        BOOL isProcessEnd();
        void setInspResult(InspResult result);
        InspResult getInspResult();
    private:    
        unsigned int m_nEqID;
@@ -31,6 +34,7 @@
        ULONGLONG m_timeIn;
        ULONGLONG m_timeOut;
        BOOL m_bProcessed;
        InspResult m_inspResult;
        CPath* m_pPrev;
        CPath* m_pNext;
    };
SourceCode/Bond/Servo/Servo.vcxproj
@@ -135,8 +135,8 @@
    </ResourceCompile>
    <PostBuildEvent>
      <Command>if exist "\\DESKTOP-IODBVIQ\Servo\Debug\" (
    xcopy /Y /D "$(OutDir)*.exe" "\\DESKTOP-IODBVIQ\Servo\Debug\"
    xcopy /Y /D "$(OutDir)*.pdb" "\\DESKTOP-IODBVIQ\Servo\Debug\"
    xcopy /Y /D "$(OutDir)Servo.exe" "\\DESKTOP-IODBVIQ\Servo\Debug\"
    xcopy /Y /D "$(OutDir)Servo.pdb" "\\DESKTOP-IODBVIQ\Servo\Debug\"
)</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
SourceCode/Bond/Servo/ServoCommo.h
@@ -2,6 +2,23 @@
#include <string>
#include <vector>
#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 {
#define BLOCK_BUFFER_MAX            1024
#define ALIVE_TIMEOUT                15
@@ -14,7 +31,14 @@
        OK = 1,
        NG,
    };
    typedef RET JobDataRequestAck;
    using JobDataRequestAck = RET;
    enum class InspResult
    {
        NotInspected = 0,  // 初始化状态,尚未检测
        Pass,              // 检测合格
        Fail               // 检测不合格
    };
    enum class PortType {
        Loading = 1,