chenluhua1980
2026-01-09 570e812442a64360239f558ae4b55c0d204a5523
1.继续完善通讯;
已修改11个文件
684 ■■■■■ 文件已修改
SourceCode/Bond/Servo/CBonder.cpp 236 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBonder.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 141 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.cpp 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/CollectionEventList.txt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/ReportList.txt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBonder.cpp
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "CBonder.h"
@@ -29,10 +29,10 @@
        CEquipment::term();
    }
    // 必须要实现的虚函数,在此初始化Pin列表
    // 必须要实现的虚函数,在此初始化Pin列表
    void CBonder::initPins()
    {
        // 加入Pin初始化代码
        // 加入Pin初始化代码
        LOGI("<CBonder>initPins");
        addPin(SERVO::PinType::INPUT, _T("In1"));
        addPin(SERVO::PinType::INPUT, _T("In2"));
@@ -137,8 +137,8 @@
        {
            // CIM Message Confirm
            // 要将int32的值拆分为两个short, 分别为msg id和panel id
            // 65538, 2Ϊmsg id, 1Ϊpanel id
            // 要将int32的值拆分为两个short, 分别为msg id和panel id
            // 65538, 2为msg id, 1为panel id
            CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, m_nIndex == 0 ? 0x9d80 : 0xdd80);
            pStep->setName(STEP_EQ_CIM_MESSAGE_CONFIRM);
            pStep->setWriteSignalDev(m_nIndex == 0 ? 0x349 : 0x649);
@@ -178,7 +178,7 @@
        }
        {
            // 请求主配方列表的step
            // 请求主配方列表的step
            CEqWriteStep* pStep = new CEqWriteStep();
            pStep->setName(STEP_EQ_MASTER_RECIPE_LIST_REQ);
            pStep->setWriteSignalDev(m_nIndex == 0 ? 0x366 : 0x666);
@@ -195,7 +195,7 @@
                    CEqReadStep* pTmpStep = (CEqReadStep*)pFrom;
                    short ret = MRLRC_OK;
                    if (code == ROK && pszData != nullptr && size > 0) {
                        // 此处解释配方数据
                        // 此处解释配方数据
                        ret = decodeRecipeListReport(pszData, size);
                    }
                    pTmpStep->setReturnCode(ret);
@@ -210,7 +210,7 @@
        }
        {
            // 请求配方参数
            // 请求配方参数
            CEqWriteStep* pStep = new CEqWriteStep();
            pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            pStep->setWriteSignalDev(m_nIndex == 0 ? 0x367 : 0x667);
@@ -227,7 +227,7 @@
                    CEqReadStep* pTmpStep = (CEqReadStep*)pFrom;
                    short ret = MRLRC_OK;
                    if (code == ROK && pszData != nullptr && size > 0) {
                        // 此处解释配方数据
                        // 此处解释配方数据
                        ret = decodeRecipeParameterReport(pszData, size);
                    }
                    pTmpStep->setReturnCode(ret);
@@ -241,7 +241,7 @@
            }
        }
        // 使用CEqReadStep替换CEqJobEventStep
        // 使用CEqReadStep替换CEqJobEventStep
        {
            // Received Job Report Upstream #1~9
            char szBuffer[256];
@@ -404,7 +404,7 @@
        }
    }
    // 必须要实现的虚函数,在此初始化Slot信息
    // 必须要实现的虚函数,在此初始化Slot信息
    void CBonder::initSlots()
    {
        m_slot[0].enable();
@@ -487,35 +487,35 @@
        return 0;
    }
    int CBonder::onProcessStateChanged(int slotNo, PROCESS_STATE state)
    int CBonder::onProcessStateChanged(int slotNo, PROCESS_STATE prevState, PROCESS_STATE state)
    {
        CEquipment::onProcessStateChanged(slotNo, state);
        CEquipment::onProcessStateChanged(slotNo, prevState, state);
        if (state == PROCESS_STATE::Complete) {
            // 检查数据,当前两片玻璃,一片为G1, 一片为G2, 且pProcessData中的id能匹配G1或G2
            // 检查数据,当前两片玻璃,一片为G1, 一片为G2, 且pProcessData中的id能匹配G1或G2
            Lock();
            CGlass* pGlass2 = getGlassFromSlot(1);
            CGlass* pGlass1 = getGlassFromSlot(2);
            if (pGlass1 == nullptr || pGlass2 == nullptr) {
                LOGE("<CBonder-%s>onProcessData,错误!不满足两片玻璃且分别为G1与G2的条件,请检查数据是否正确!", m_strName.c_str());
                LOGE("<CBonder-%s>onProcessData,错误!不满足两片玻璃且分别为G1与G2的条件,请检查数据是否正确!", m_strName.c_str());
                Unlock();
                return -1;
            }
            if (pGlass1->getBuddy() != nullptr) {
                LOGE("<CBonder-%s>onProcessData,错误!玻璃较早前已被绑定,请检查数据是否正确!", m_strName.c_str());
                LOGE("<CBonder-%s>onProcessData,错误!玻璃较早前已被绑定,请检查数据是否正确!", m_strName.c_str());
                Unlock();
                return -1;
            }
            if (pGlass1->getType() != MaterialsType::G1 || pGlass2->getType() != MaterialsType::G2) {
                LOGE("<CBonder-%s>onProcessData,错误!两片玻璃未匹配,必须分别为G1和G2类型,请检查数据是否正确!", m_strName.c_str());
                LOGE("<CBonder-%s>onProcessData,错误!两片玻璃未匹配,必须分别为G1和G2类型,请检查数据是否正确!", m_strName.c_str());
                Unlock();
                return -1;
            }
            pGlass1->setBuddy(pGlass2);
            getSlot(0)->setContext(nullptr);
            LOGE("<CBonder-%s>onProcessStateChanged,%s和%s已贴合!", m_strName.c_str(),
            LOGE("<CBonder-%s>onProcessStateChanged,%s和%s已贴合!", m_strName.c_str(),
                pGlass1->getID().c_str(), pGlass2->getID().c_str());
            Unlock();
        }
@@ -535,112 +535,112 @@
        int i = 0, v;
        // 1.校正对位延时
        // 1.校正对位延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("校正对位延时", "", this->getName().c_str(), v * 0.01f));
        params.push_back(CParam("校正对位延时", "", this->getName().c_str(), v * 0.01f));
        i += 2;
        // 2.保压时间
        // 2.保压时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("保压时间", "", this->getName().c_str(), v * 0.01f));
        params.push_back(CParam("保压时间", "", this->getName().c_str(), v * 0.01f));
        i += 2;
        // 3.腔体破真空延时
        // 3.腔体破真空延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("腔体破真空延时", "", this->getName().c_str(), v * 0.01f));
        params.push_back(CParam("腔体破真空延时", "", this->getName().c_str(), v * 0.01f));
        i += 2;
        // 4.腔体分子泵启动延时
        // 4.腔体分子泵启动延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("腔体分子泵启动延时", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("腔体分子泵启动延时", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 5.腔体贴附抽真空延时
        // 5.腔体贴附抽真空延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("腔体贴附抽真空延时", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("腔体贴附抽真空延时", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 6.加热等待延时
        // 6.加热等待延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("加热等待延时", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("加热等待延时", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 7.气囊压力设定
        // 7.气囊压力设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("气囊压力设定", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("气囊压力设定", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 8.气囊加压速率
        // 8.气囊加压速率
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("气囊加压速率", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("气囊加压速率", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 9.气囊泄压速率
        // 9.气囊泄压速率
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("气囊泄压速率", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("气囊泄压速率", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 10.贴附压力上限
        // 10.贴附压力上限
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("贴附压力上限", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("贴附压力上限", "", this->getName().c_str(), v * 0.1f));
        i += 4;
        // 11.Z轴转矩速度设定
        // 11.Z轴转矩速度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("上腔Z轴转矩速度设定", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("上腔Z轴转矩速度设定", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 12.上腔温度设定
        // 12.上腔温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度设定", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度设定", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 13.下腔温度设定
        // 13.下腔温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度设定", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度设定", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 14.上腔Z轴预贴合位速度
        // 14.上腔Z轴预贴合位速度
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("上腔Z轴预贴合位速度", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("上腔Z轴预贴合位速度", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 15.上腔Z轴贴附位速度
        // 15.上腔Z轴贴附位速度
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("上腔Z轴贴附位速度", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("上腔Z轴贴附位速度", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 16.上腔Z上腔加热位间距
        // 16.上腔Z上腔加热位间距
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("上腔Z上腔加热位间距", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("上腔Z上腔加热位间距", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 17.上腔贴附位压入量
        // 17.上腔贴附位压入量
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("上腔贴附位压入量", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("上腔贴附位压入量", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 18.上腔Z轴破真空距离
        // 18.上腔Z轴破真空距离
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("上腔Z轴破真空距离", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("上腔Z轴破真空距离", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 19.下顶Pin破真空距离
        // 19.下顶Pin破真空距离
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("下顶Pin破真空距离", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("下顶Pin破真空距离", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 20.下顶Pin加热位间距
        // 20.下顶Pin加热位间距
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("下顶Pin加热位间距", "", this->getName().c_str(), v * 0.001f));
        params.push_back(CParam("下顶Pin加热位间距", "", this->getName().c_str(), v * 0.001f));
        i += 4;
        // 21.腔体真空泵真空规设定值
        params.push_back(CParam("腔体真空泵真空规设定值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        // 21.腔体真空泵真空规设定值
        params.push_back(CParam("腔体真空泵真空规设定值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        i += 4;
        // 22.腔体分子泵到达设定值
        params.push_back(CParam("腔体分子泵到达设定值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        // 22.腔体分子泵到达设定值
        params.push_back(CParam("腔体分子泵到达设定值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        i += 4;
@@ -655,24 +655,24 @@
    int CBonder::parsingSVData(const char* pszData, size_t size, std::vector<CParam>& params)
    {
        /*
        1    工艺运行步骤    1Word    123456
            2    气囊压力当前    2Word    12345.6
            3    上腔压力合计    1Word    1234.56
            4    管道真空规值    FLOAT    123.456
            5    腔体真空规值    FLOAT    123.456
            6    上腔温度1    1Word    12345.6
            7    上腔温度2    1Word    12345.6
            8    上腔温度3    1Word    12345.6
            9    上腔温度4    1Word    12345.6
            10    上腔温度5    1Word    12345.6
            11    上腔温度6    1Word    12345.6
            12    下腔温度1    1Word    12345.6
            13    下腔温度2    1Word    12345.6
            14    下腔温度3    1Word    12345.6
            15    下腔温度4    1Word    12345.6
            16    下腔温度5    1Word    12345.6
            17    下腔温度6    1Word    12345.6
            18    压合剩余时间    1Word    1234.56
        1    工艺运行步骤    1Word    123456
            2    气囊压力当前    2Word    12345.6
            3    上腔压力合计    1Word    1234.56
            4    管道真空规值    FLOAT    123.456
            5    腔体真空规值    FLOAT    123.456
            6    上腔温度1    1Word    12345.6
            7    上腔温度2    1Word    12345.6
            8    上腔温度3    1Word    12345.6
            9    上腔温度4    1Word    12345.6
            10    上腔温度5    1Word    12345.6
            11    上腔温度6    1Word    12345.6
            12    下腔温度1    1Word    12345.6
            13    下腔温度2    1Word    12345.6
            14    下腔温度3    1Word    12345.6
            15    下腔温度4    1Word    12345.6
            16    下腔温度5    1Word    12345.6
            17    下腔温度6    1Word    12345.6
            18    压合剩余时间    1Word    1234.56
*/
        ASSERT(pszData);
@@ -680,97 +680,97 @@
        int i = 0, v;
        // 1.工艺运行步骤
        // 1.工艺运行步骤
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("工艺运行步骤", "", this->getName().c_str(), v));
        params.push_back(CParam("工艺运行步骤", "", this->getName().c_str(), v));
        i += 2;
        // 2.气囊压力当前
        // 2.气囊压力当前
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        params.push_back(CParam("气囊压力当前", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("气囊压力当前", "", this->getName().c_str(), v * 0.1f));
        i += 4;
        // 3.上腔压力合计
        // 3.上腔压力合计
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔压力合计", "", this->getName().c_str(), ((short)v) * 0.01f));
        params.push_back(CParam("上腔压力合计", "", this->getName().c_str(), ((short)v) * 0.01f));
        i += 2;
        // 4.管道真空规值
        params.push_back(CParam("管道真空规值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        // 4.管道真空规值
        params.push_back(CParam("管道真空规值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        i += 4;
        // 5.腔体真空规值
        params.push_back(CParam("腔体真空规值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        // 5.腔体真空规值
        params.push_back(CParam("腔体真空规值", "", this->getName().c_str(), (double)toFloat(&pszData[i])));
        i += 4;
        // 6.上腔温度1
        // 6.上腔温度1
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度1", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度1", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 7.上腔温度2
        // 7.上腔温度2
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度2", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度2", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 8.上腔温度3
        // 8.上腔温度3
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度3", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度3", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 9.上腔温度4
        // 9.上腔温度4
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度4", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度4", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 10.上腔温度5
        // 10.上腔温度5
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度5", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度5", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 11.上腔温度6
        // 11.上腔温度6
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("上腔温度6", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("上腔温度6", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 12.下腔温度1
        // 12.下腔温度1
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度1", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度1", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 13.下腔温度2
        // 13.下腔温度2
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度2", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度2", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 14.下腔温度3
        // 14.下腔温度3
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度3", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度3", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 15.下腔温度4
        // 15.下腔温度4
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度4", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度4", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 16.下腔温度5
        // 16.下腔温度5
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度5", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度5", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 17.下腔温度6
        // 17.下腔温度6
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("下腔温度6", "", this->getName().c_str(), v * 0.1f));
        params.push_back(CParam("下腔温度6", "", this->getName().c_str(), v * 0.1f));
        i += 2;
        // 18.加热剩余时间
        // 18.加热剩余时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("加热剩余时间", "", this->getName().c_str(), v * 0.01f));
        params.push_back(CParam("加热剩余时间", "", this->getName().c_str(), v * 0.01f));
        i += 2;
        // 19.压合剩余时间
        // 19.压合剩余时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        params.push_back(CParam("压合剩余时间", "", this->getName().c_str(), v * 0.01f));
        params.push_back(CParam("压合剩余时间", "", this->getName().c_str(), v * 0.01f));
        i += 2;
        return (int)params.size();
SourceCode/Bond/Servo/CBonder.h
@@ -22,7 +22,7 @@
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
        virtual int onProcessData(CProcessData* pProcessData);
        virtual int onProcessStateChanged(int slotNo, PROCESS_STATE state);
        virtual int onProcessStateChanged(int slotNo, PROCESS_STATE prevState, PROCESS_STATE state);
        virtual int getIndexerOperationModeBaseValue();
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms);
        virtual int parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& parsms);
SourceCode/Bond/Servo/CEquipment.cpp
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "CEquipment.h"
#include "ToolUnits.h"
#include <regex>
@@ -103,7 +103,7 @@
    void CEquipment::getProperties(std::vector<std::pair<std::string, std::string>>& 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"));
@@ -147,11 +147,12 @@
    {
        if (nSlotNo <= 0 || nSlotNo > 8) return;
        const auto prevState = m_processState[nSlotNo - 1];
        m_processState[nSlotNo - 1] = state;
        onProcessStateChanged(nSlotNo, m_processState[nSlotNo - 1]);
        onProcessStateChanged(nSlotNo, prevState, m_processState[nSlotNo - 1]);
        if (m_listener.onProcessStateChanged != nullptr) {
            m_listener.onProcessStateChanged(this, nSlotNo, m_processState[nSlotNo - 1]);
            m_listener.onProcessStateChanged(this, nSlotNo, prevState, m_processState[nSlotNo - 1]);
        }
    }
@@ -315,7 +316,7 @@
    void CEquipment::onTimer(UINT nTimerid)
    {
        // 每隔一秒,检查一下ALIVE状态
        // 每隔一秒,检查一下ALIVE状态
        static int tick = 0;
        tick++;
@@ -379,7 +380,7 @@
                }
            }
            // 梳理各玻璃之间的绑定关系
            // 梳理各玻璃之间的绑定关系
            /*
            Lock();
            for (int i = 0; i < SLOT_MAX; i++) {
@@ -391,7 +392,7 @@
                            CGlass* pBudy = (CGlass*)m_slot[j].getContext();
                            if (pBudy != nullptr && strBuddyId.compare(pBudy->getID()) == 0) {
                                pGlass->setBuddy(pBudy);
                                TRACE("绑定关系: %s <- %s\n", pGlass->getID().c_str(), pBudy->getID().c_str());
                                TRACE("绑定关系: %s <- %s\n", pGlass->getID().c_str(), pBudy->getID().c_str());
                            }
                        }
                    }
@@ -412,7 +413,7 @@
        }
        */
        // 连接信号解释和保存
        // 连接信号解释和保存
        BOOL bFlag;
        int index = 0;
        for (int i = 0; i < 8; i++) {
@@ -442,7 +443,7 @@
        }
        // 其它信号及响应
        // 其它信号及响应
        index = 0x540;
@@ -452,7 +453,7 @@
            m_alive.flag = bFlag;
            m_alive.count = 0;
            // ״̬
            // 状态
            if (!m_alive.alive) {
                m_alive.alive = TRUE;
                if (m_listener.onAlive != nullptr) {
@@ -501,7 +502,7 @@
        }
        // 以下根据信号做流程处理
        // 以下根据信号做流程处理
        for (int i = 0; i < 7; i++) {
            CHECK_READ_STEP_SIGNAL(STEP_ID_EQMODE_CHANGED + i, pszData, size);
        }
@@ -519,13 +520,13 @@
        }
        // 配方改变
        // 配方改变
        CHECK_READ_STEP_SIGNAL(STEP_ID_CURRENT_RECIPE_CHANGE_REPORT, pszData, size);
        
        // 主配方上报
        // 主配方上报
        CHECK_READ_STEP_SIGNAL(STEP_ID_MASTER_RECIPE_LIST_REPORT, pszData, size);
        // 配方参数
        // 配方参数
        CHECK_WRITE_STEP_SIGNAL(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pszData, size);
        CHECK_READ_STEP_SIGNAL(STEP_ID_RECIPE_PARAMETER_REPORT, pszData, size);
        
@@ -766,8 +767,8 @@
            else if (isCimMessageConfirmStep(pStep)) {
                SERVO::CEqReadIntStep* pEqReadIntStep = (SERVO::CEqReadIntStep*)pStep;
                int value = pEqReadIntStep->getValue();
                // 此处将value按高低位拆分为message id和panel no.
                // 可能还需要上报到cim
                // 此处将value按高低位拆分为message id和panel no.
                // 可能还需要上报到cim
                short msgId, panelNo;
                msgId = (value & 0xffff0000 >> 16);
                panelNo = (value & 0xffff);
@@ -782,7 +783,7 @@
                    m_listener.onVcrEventReport(this, pVcrEventReport);
                }
                // 0426, 先固定返回1(OK)
                // 0426, 先固定返回1(OK)
                pEqVcrEventStep->setReturnCode(1);        
                return 1;
            }
@@ -795,12 +796,12 @@
    CPin* CEquipment::addPin(PinType type, char* pszName)
    {
        // 不允许名字添加重复的pin
        // 不允许名字添加重复的pin
        CPin* pPin = getPin(pszName);
        if (pPin != nullptr) return nullptr;
        // 添加到Pin列表,看是输入pin或输出pin
        // 添加到Pin列表,看是输入pin或输出pin
        if (type == PinType::INPUT) {
            pPin = new CPin(this, type, pszName);
            m_inputPins.push_back(pPin);
@@ -865,7 +866,7 @@
        CEquipment* pFromEq = pFromPin->getEquipment();
        ASSERT(pFromEq);
        LOGD("<CEquipment><%s-%s>收到来自<%s.%s>的Intent<%d,%s,0x%x>",
        LOGD("<CEquipment><%s-%s>收到来自<%s.%s>的Intent<%d,%s,0x%x>",
            this->getName().c_str(),
            pPin->getName().c_str(),
            pFromEq->getName().c_str(),
@@ -876,11 +877,11 @@
        // 以下解释处理数据
        // 以下解释处理数据
        int code = pIntent->getCode();
        // 测试
        // 测试
        if (code == FLOW_TEST) {
            AfxMessageBox(pIntent->getMsg());
        }
@@ -895,7 +896,7 @@
            return -1;
        }
        // 找到指定的glass id,
        // 找到指定的glass id,
        Lock();
        CGlass* pContext = nullptr;
        for (int i = 0; i < SLOT_MAX; i++) {
@@ -946,7 +947,7 @@
        CGlass* pBuddy = pGlass->getBuddy();
        if (pBuddy != nullptr) pBuddy->addPath(m_nID, getSlotUnit(putSlot), putSlot);
        m_slot[putSlot - 1].setContext(pGlass);
        pGlass->release();                // tempFetchOut需要调用一次release
        pGlass->release();                // tempFetchOut需要调用一次release
        Unlock();
        /*
@@ -1174,17 +1175,17 @@
            return -1;
        }
        LOGI("<CEquipment-%s>准备设置DispatchingMode<%d>", m_strName.c_str(), (int)mode);
        LOGI("<CEquipment-%s>准备设置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("<CEquipment-%s>设置DispatchingMode成功.", m_strName.c_str());
                    LOGI("<CEquipment-%s>设置DispatchingMode成功.", m_strName.c_str());
                }
                else {
                    LOGE("<CEquipment-%s>设置DispatchingMode失败,code:%d", m_strName.c_str(), code);
                    LOGE("<CEquipment-%s>设置DispatchingMode失败,code:%d", m_strName.c_str(), code);
                }
                return 0;
@@ -1202,19 +1203,19 @@
        }
        unsigned short operationMode = (unsigned short)((unsigned short)mode + getIndexerOperationModeBaseValue());
        LOGI("<CEquipment-%s>准备设置indexerOperationMode<%d>", m_strName.c_str(), (int)mode);
        LOGI("<CEquipment-%s>准备设置indexerOperationMode<%d>", m_strName.c_str(), (int)mode);
        pStep->writeShort(operationMode, [&, pStep, mode, onWritedRetBlock](int code) -> int {
            int retCode = 0;
            if (code == WOK) {
                LOGI("<CEquipment-%s>设置indexerOperationMode成功.", m_strName.c_str());
                LOGI("<CEquipment-%s>设置indexerOperationMode成功.", m_strName.c_str());
                const char* pszRetData = nullptr;
                pStep->getReturnData(pszRetData);
                ASSERT(pszRetData);
                retCode = (unsigned int)CToolUnits::toInt16(pszRetData);
                LOGI("<CEquipment-%s>返回值: %d", m_strName.c_str(), retCode);
                LOGI("<CEquipment-%s>返回值: %d", m_strName.c_str(), retCode);
            }
            else {
                LOGE("<CEquipment-%s>设置indexerOperationMode失败,code:%d", m_strName.c_str(), code);
                LOGE("<CEquipment-%s>设置indexerOperationMode失败,code:%d", m_strName.c_str(), code);
            }
            if (onWritedRetBlock != nullptr) {
@@ -1234,18 +1235,18 @@
            return -1;
        }
        LOGI("<CEquipment-%s>正在请求单元<%d>主配方列表", m_strName.c_str(), unitNo);
        LOGI("<CEquipment-%s>正在请求单元<%d>主配方列表", m_strName.c_str(), unitNo);
        m_recipesManager.setOnSyncingStateChanged(block);
        if (m_recipesManager.syncing() != 0) {
            return -2;
        }
        pStep->writeShort(unitNo, [&, unitNo](int code) -> int {
            if (code == WOK) {
                LOGI("<CEquipment-%s>请求单元<%d>主配方列表成功,正在等待数据.", m_strName.c_str(), unitNo);
                LOGI("<CEquipment-%s>请求单元<%d>主配方列表成功,正在等待数据.", m_strName.c_str(), unitNo);
            }
            else {
                m_recipesManager.syncFailed();
                LOGE("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
                LOGE("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
            }
            return 0;
@@ -1255,7 +1256,7 @@
    int CEquipment::recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo, ONSYNCINGSTATECHANGED block)
    {
        LOGI("<CEquipment-%s>正在请求单元<%d>主配参数列表", m_strName.c_str(), unitNo);
        LOGI("<CEquipment-%s>正在请求单元<%d>主配参数列表", m_strName.c_str(), unitNo);
        m_recipesManager.setOnSyncingStateChanged(block);
        if (m_recipesManager.syncing() != 0) {
            return -2;
@@ -1276,11 +1277,11 @@
        pStep->writeDataEx(szBuffer, 14 * 2, [&, unitNo](int code) -> int {
            if (code == WOK) {
                LOGI("<CEquipment-%s>请求单元<%d>主配方参数列表成功,正在等待数据.", m_strName.c_str(), unitNo);
                LOGI("<CEquipment-%s>请求单元<%d>主配方参数列表成功,正在等待数据.", m_strName.c_str(), unitNo);
            }
            else {
                m_recipesManager.syncFailed();
                LOGE("<CEquipment-%s>请求单元<%d>主配方参数列表失败,code:%d", m_strName.c_str(), unitNo, code);
                LOGE("<CEquipment-%s>请求单元<%d>主配方参数列表失败,code:%d", m_strName.c_str(), unitNo, code);
            }
            return 0;
@@ -1584,7 +1585,7 @@
        int nRet = processData.unserialize(&pszData[0], (int)size);
        if (nRet < 0) return nRet;
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        CAttributeVector& attrubutes = pStep->attributeVector();
        processData.getAttributeVector(attrubutes, weight);
@@ -1592,11 +1593,11 @@
        // 找到玻璃,关联数据
        // 找到玻璃,关联数据
        CGlass* pGlass = this->getGlassWithCassette(processData.getCassetteSequenceNo(),
            processData.getJobSequenceNo());
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>找不到对应Glass, 关联工艺参数失败。CassetteSequenceNo:%d/%d",
            LOGE("<CEquipment-%s>找不到对应Glass, 关联工艺参数失败。CassetteSequenceNo:%d/%d",
                this->getName().c_str(),
                processData.getCassetteSequenceNo(),
                processData.getJobSequenceNo());
@@ -1610,7 +1611,7 @@
        std::vector<CParam> params(tempParams.begin(), tempParams.begin() + min(n, (int)tempParams.size()));
        pGlass->addParams(params);
        
        // 关联的Glass也要更新
        // 关联的Glass也要更新
        CGlass* pBuddy = pGlass->getBuddy();
        LOGI("<Equipment-%s>decodeProcessDataReport pBuddy=%x %s", getName().c_str(), pBuddy, pGlass->getID().c_str());
        if (pBuddy != nullptr) {
@@ -1627,7 +1628,7 @@
        int nRet = jobDataS.unserialize(&pszData[0], (int)size);
        if (nRet < 0) return nRet;
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        CAttributeVector& attrubutes = pStep->attributeVector();
        jobDataS.getAttributeVector(attrubutes, weight);
@@ -1641,10 +1642,10 @@
        LOGI("<CEquipment-%s>onReceivedJob.", m_strName.c_str());
        // 可以在此更新JobDataS数据了
        // 可以在此更新JobDataS数据了
        int nRet = ((CArm*)m_pArm)->glassUpdateJobDataS(pJobDataS);
        if (nRet < 0) {
            LOGE("<CEquipment-%s>onReceivedJob,更新JobDataS失败,glassUpdateJobDataS返回%d",
            LOGE("<CEquipment-%s>onReceivedJob,更新JobDataS失败,glassUpdateJobDataS返回%d",
                m_strName.c_str(), nRet);
        }
@@ -1657,7 +1658,7 @@
        int nRet = jobDataS.unserialize(&pszData[0], (int)size);
        if (nRet < 0) return nRet;
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        CAttributeVector& attrubutes = pStep->attributeVector();
        jobDataS.getAttributeVector(attrubutes, weight);
@@ -1692,7 +1693,7 @@
        index += sizeof(short);
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("UnitOrPort",
            std::to_string(unitOrPort).c_str(), "", weight++));
@@ -1736,7 +1737,7 @@
            return fetchedOutJob(port, pJobDataB);
        }
        // 数据异常,处理或显示
        // 数据异常,处理或显示
        LOGI("<CEquipment-%s>onFetchedOutJob Error.ort:%d|GlassId:%s",
            m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
        return -1;
@@ -1761,7 +1762,7 @@
        index += sizeof(short);
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("UnitOrPort",
            std::to_string(unitOrPort).c_str(), "", weight++));
@@ -1793,7 +1794,7 @@
            vcrEventReport.getGlassId().c_str());
        // 更新Glass的ID
        // 更新Glass的ID
        CGlass* pGlass = getGlassWithCassette(vcrEventReport.getCassetteSequenceNo(),
            vcrEventReport.getJobSequenceNo());
        if (pGlass != nullptr) {
@@ -1801,13 +1802,13 @@
        }
        
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        CAttributeVector& attrubutes = pStep->attributeVector();
        vcrEventReport.getAttributeVector(attrubutes, weight);
        // 0426, 先固定返回1(OK)
        // 0426, 先固定返回1(OK)
        ((CReadStep*)pStep)->setReturnCode((short)VCR_Reply_Code::OK);
@@ -1829,7 +1830,7 @@
        index += 256 * 2;
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("CassetteNo",
            std::to_string(cassetteNo).c_str(), "", weight++));
@@ -1841,10 +1842,10 @@
            strPanelGradeData.c_str(), "", weight++));
        // 更新检测结果
        // 更新检测结果
        CGlass* pGlass = getGlassWithCassette(cassetteNo, jobSequenceNo);
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>更新Panel Data失败,找不到对应的Glass.cassetteNo=%d, jobSequenceNo=%d",
            LOGE("<CEquipment-%s>更新Panel Data失败,找不到对应的Glass.cassetteNo=%d, jobSequenceNo=%d",
                getName().c_str(), cassetteNo, jobSequenceNo);
            return -1;
        }
@@ -1885,7 +1886,7 @@
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("CassetteSequenceNo",
            (std::to_string(cassetteSequenceNo)).c_str(), "", weight++));
@@ -1941,7 +1942,7 @@
        CGlass* pGlass = getGlassFromSlot(slotNo);
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>decodeJobProcessStartReport, 找不到对应glass", getName().c_str());
            LOGE("<CEquipment-%s>decodeJobProcessStartReport, 找不到对应glass", getName().c_str());
        }
        if (slotNo <= 0 || slotNo > 8) return -1;
@@ -1953,7 +1954,7 @@
        }
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("CassetteNo",
            std::to_string(cassetteNo).c_str(), "", weight++));
@@ -2023,7 +2024,7 @@
        }
    
        if (pGlass == nullptr) {
            LOGE("<CEquipment-%s>decodeJobProcessEndReport, 找不到对应glass", getName().c_str());
            LOGE("<CEquipment-%s>decodeJobProcessEndReport, 找不到对应glass", getName().c_str());
        }
        else {
            CJobDataS* pJs = pGlass->getJobDataS();
@@ -2032,7 +2033,7 @@
                pGlass->processEnd(m_nID, getSlotUnit(slotNo));
            }
            else {
                LOGE("<CEquipment-%s>decodeJobProcessEndReport, jobSequenceNo或jobSequenceNo不匹配",
                LOGE("<CEquipment-%s>decodeJobProcessEndReport, jobSequenceNo或jobSequenceNo不匹配",
                    getName().c_str());
            }
        }
@@ -2040,7 +2041,7 @@
        // 缓存Attribute,用于调试时显示信息
        // 缓存Attribute,用于调试时显示信息
        unsigned int weight = 201;
        pStep->addAttribute(new CAttribute("CassetteNo",
            std::to_string(cassetteNo).c_str(), "", weight++));
@@ -2064,10 +2065,10 @@
        LOGI("<CEquipment-%s>onPreStoredJob:port:%d|GlassId:%s",
            m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
        // 当前要存片,之前肯定有拔片,因此片子在Arm那里
        // 当前要存片,之前肯定有拔片,因此片子在Arm那里
        CGlass* pGlass = ((CArm*)m_pArm)->getGlassFromSlot(1);
        if (pGlass == nullptr) {
            LOGE("<CFliper-%s>onPreStoredJob,缓存中没有找到对应的Glass(CassetteSequenceNo:%d, JobSequenceNo:%d),请检查数据,注意风险。", m_strName.c_str(),
            LOGE("<CFliper-%s>onPreStoredJob,缓存中没有找到对应的Glass(CassetteSequenceNo:%d, JobSequenceNo:%d),请检查数据,注意风险。", m_strName.c_str(),
                pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo());
            return FALSE;
        }
@@ -2075,19 +2076,19 @@
        CJobDataS* pJobDataS = pGlass->getJobDataS();
        ASSERT(pJobDataS);
        if (!compareJobData(pJobDataB, pJobDataS)) {
            LOGE("<CEquipemnt-%s>onPreStoredJob,JobData数据不匹配(JobDataB(%d, %d),JobDataS(%d, %d)), 注意排查风险!", m_strName.c_str(),
            LOGE("<CEquipemnt-%s>onPreStoredJob,JobData数据不匹配(JobDataB(%d, %d),JobDataS(%d, %d)), 注意排查风险!", m_strName.c_str(),
                pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo(),
                pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo());
            return FALSE;
        }
        // 如果没有可用位置,报错
        // 如果没有可用位置,报错
        Lock();
        CSlot* pSlot = getSlot(putSlot - 1);
        ASSERT(pSlot);
        if (pSlot->getContext() != nullptr) {
            Unlock();
            LOGE("<CEquipemnt-%s>onPreStoredJob,指定slot(port:%d)有料,请注意风险!", m_strName.c_str(), port);
            LOGE("<CEquipemnt-%s>onPreStoredJob,指定slot(port:%d)有料,请注意风险!", m_strName.c_str(), port);
            return FALSE;
        }
        Unlock();
@@ -2117,7 +2118,7 @@
            return storedJob(port, pJobDataB, putSlot);
        }
        // 数据异常,处理或显示
        // 数据异常,处理或显示
        LOGI("<CEquipment-%s>onStoredJob Error.port:%d|GlassId:%s",
            m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
        return -1;
@@ -2131,8 +2132,8 @@
    }
    /*
     * 当从CC-Link检测到设备Send Able为On时调用此函数
     * 可能会多次重复调用(根据扫描频率), 注意防呆
     * 当从CC-Link检测到设备Send Able为On时调用此函数
     * 可能会多次重复调用(根据扫描频率), 注意防呆
     */
    int CEquipment::onSendAble(int port)
    {
@@ -2148,7 +2149,7 @@
        return 0;
    }
    int CEquipment::onProcessStateChanged(int nSlotNo, PROCESS_STATE state)
    int CEquipment::onProcessStateChanged(int nSlotNo, PROCESS_STATE prevState, PROCESS_STATE state)
    {
        return 0;
    }
@@ -2261,4 +2262,4 @@
    {
        return m_svDatas;
    }
}
}
SourceCode/Bond/Servo/CEquipment.h
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Log.h"
#include "ServoCommo.h"
#include "CCLinkIEControl.h"
@@ -55,7 +55,7 @@
    typedef std::function<void(void* pEiuipment, void* pReport)> ONVCREVENTREPORT;
    typedef std::function<BOOL(void* pEiuipment, int port, CJobDataB* pJobDataB)> ONPREFETCHEDOUTJOB;
    typedef std::function<BOOL(void* pEiuipment, int port, CJobDataB* pJobDataB, short& putSlot)> ONPRESTOREDJOB;
    typedef std::function<void(void* pEiuipment, int nSlotNo, PROCESS_STATE state)> ONPROCESSSTATE;
    typedef std::function<void(void* pEiuipment, int nSlotNo, PROCESS_STATE prevState, PROCESS_STATE state)> ONPROCESSSTATE;
    typedef std::function<void(void* pEiuipment, short scanMap, short downMap)> ONMAPMISMATCH;
    typedef std::function<void(void* pEiuipment, short status, __int64 data)> ONPORTSTATUSCHANGED;
    
@@ -140,7 +140,7 @@
        virtual int onProcessData(CProcessData* pProcessData);
        virtual int onSendAble(int port);
        virtual int onReceiveAble(int port);
        virtual int onProcessStateChanged(int nSlotNo, PROCESS_STATE state);
        virtual int onProcessStateChanged(int nSlotNo, PROCESS_STATE prevState, PROCESS_STATE state);
        virtual int getIndexerOperationModeBaseValue();
        virtual bool isSlotProcessed(int slot) { return true; };
        bool isAlarmStep(SERVO::CStep* pStep);
@@ -163,47 +163,47 @@
        void printDebugString001();
        std::vector<SERVO::CSVData>& getSVDatas();
        // 请求主配方列表
        // 请求主配方列表
        // unitNo: 0:local; Others:unit No
        int masterRecipeListRequest(short unitNo, ONSYNCINGSTATECHANGED block);
        // 请求配方参数
        // masterRecipeId: 主配方id
        // localRecipeId: 本地配方id
        // 请求配方参数
        // masterRecipeId: 主配方id
        // localRecipeId: 本地配方id
        // unitNo: 0:local; Others:unit No
        int recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo, ONSYNCINGSTATECHANGED block);
        // 解析配方参数列表
        // 解析配方参数列表
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& params) { return 0;  };
        virtual int parsingParams(const char* pszData, size_t size, std::string& strOut);
        virtual int parsingProcessData(const char* pszData, size_t size, std::vector<CParam>& params) { return 0; };
        virtual int parsingSVData(const char* pszData, size_t size, std::vector<CParam>& params) { return 0; };
        // 获取指定的Slot
        // 获取指定的Slot
        CSlot* getSlot(int index);
        CSlot* getSlotWithNo(int slotNo);
        // 获取一个可用的槽位
        // 获取一个可用的槽位
        CSlot* getAvailableSlot();
        // 获取一个指定物料类型(G1,G2,G1&G2)的空槽位
        // 获取一个指定物料类型(G1,G2,G1&G2)的空槽位
        CSlot* getAvailableSlotForGlass(MaterialsType type);
        CSlot* getAvailableSlotForGlassExcludeSignal(MaterialsType type);
        CSlot* isSlotAvailable(unsigned int slot);
        // 在指定的槽列表中,获取一个指定物料类型(G1,G2,G1&G2)的空槽位
        // 在指定的槽列表中,获取一个指定物料类型(G1,G2,G1&G2)的空槽位
        CSlot* getAvailableSlotForGlass2(MaterialsType type, const std::vector<int>& candidates);
        // 获取一个指定物料类型(G1,G2,G1&G2)的非空槽位
        // 获取一个指定物料类型(G1,G2,G1&G2)的非空槽位
        CSlot* getNonEmptySlot(MaterialsType type);
        // 获取一个指定物料类型(G1,G2,G1&G2)的且已经加工处理的槽位
        // 获取一个指定物料类型(G1,G2,G1&G2)的且已经加工处理的槽位
        CSlot* getProcessedSlot(MaterialsType putSlotType, BOOL bJobMode = FALSE);
        CSlot* getProcessedSlot2(MaterialsType putSlotType, const std::vector<int>& candidates);
        CSlot* getInspFailSlot();
        CSlot* getProcessedSlotCt(unsigned int slot);
        // 获取玻璃物料
        // 获取玻璃物料
        CGlass* getGlassFromSlot(int slotNo);
        CGlass* getGlassWithCassette(int cassetteSequenceNo, int jobSequenceNo);
        CGlass* getAnyGlass();
@@ -211,26 +211,27 @@
        int getAllGlass(std::vector<CGlass*>& glasses);
        CJobDataS* getJobDataSWithCassette(int cassetteSequenceNo, int jobSequenceNo);
        // 验证玻璃和槽是否匹配
        // 验证玻璃和槽是否匹配
        BOOL ValidateGlassSlotMatch();
        // 是否有玻璃
        // 是否有玻璃
        BOOL hasGlass();
        BOOL slotHasGlass(int slotIndex = 0);
        // 指定槽位是否可以放置玻璃
        // 指定槽位是否可以放置玻璃
        BOOL canPlaceGlassInSlot(const short slotIndex);
        // 手动移除物料
        // 手动移除物料
        int removeGlass(int slotNo);
        // 字符串检测结果转换
        // 字符串检测结果转换
        InspResult judgeStringToInspResult(std::string& strJudge);
        // for test
        void fireSetProcessState(int nSlotNo, PROCESS_STATE state) { return setProcessState(nSlotNo, state); }
    // 以下为从CC-Link读取到的Bit标志位检测函数
    // 以下为从CC-Link读取到的Bit标志位检测函数
    public:
        BOOL isAlive();
        BOOL isCimOn();
@@ -242,7 +243,7 @@
        BOOL isLinkSignalUpstreamOn(unsigned int path, unsigned int signal);
        BOOL isLinkSignalDownstreamOn(unsigned int path, unsigned int signal);
        // 只在模拟测试时使用的函数,用于模拟信号
        // 只在模拟测试时使用的函数,用于模拟信号
        void setLinkSignalUpstream(unsigned int path, unsigned int signal, BOOL bOn);
        void setLinkSignalUpstreamBlock(unsigned int path, BOOL* pSignal);
        void setLinkSignalDownstream(unsigned int path, unsigned int signal, BOOL bOn);
@@ -271,7 +272,7 @@
        float toFloat(const char* pszAddr);
    protected:
        // 部分优化/简化代码、暂实现部分,到时平铺开
        // 部分优化/简化代码、暂实现部分,到时平铺开
        void addFacDataReportStep(int dataDev, int writeSignalDev, int port);
@@ -289,7 +290,7 @@
        std::vector<CPin*> m_outputPins;
        // 以下为从CC-Link读取到的Bit标志位
        // 以下为从CC-Link读取到的Bit标志位
    protected:
        ALIVE m_alive;
        BOOL m_bCimState;            // ON/OFF
SourceCode/Bond/Servo/CMaster.cpp
@@ -1540,7 +1540,7 @@
                unlock();
            }
        };
        listener.onProcessStateChanged = [&](void* pEquipment, int slotNo, PROCESS_STATE state) -> void {
        listener.onProcessStateChanged = [&](void* pEquipment, int slotNo, PROCESS_STATE prevState, PROCESS_STATE state) -> void {
            ASSERT(1 <= slotNo && slotNo <= 8);
            int eqid = ((CEquipment*)pEquipment)->getID();
            CGlass* pGlass = ((CEquipment*)pEquipment)->getGlassFromSlot(slotNo);
@@ -1558,7 +1558,7 @@
            }
            if (m_listener.onProcessStateChanged != nullptr) {
                m_listener.onProcessStateChanged(this, (CEquipment*)pEquipment, slotNo, state);
                m_listener.onProcessStateChanged(this, (CEquipment*)pEquipment, slotNo, prevState, state);
            }
        };
        listener.onMapMismatch = [&](void* pEquipment, short scanMap, short downMap) {
@@ -2115,8 +2115,9 @@
                    }
                };
                auto fireProcessState = [&](SERVO::CEquipment* pEq, int slotNo, SERVO::PROCESS_STATE st) {
                    if (m_listener.onProcessStateChanged != nullptr && pEq != nullptr) {
                        m_listener.onProcessStateChanged(this, pEq, slotNo, st);
                    // Drive equipment state so listeners receive prev/current states consistently.
                    if (pEq != nullptr) {
                        pEq->fireSetProcessState(slotNo, st);
                    }
                };
SourceCode/Bond/Servo/CMaster.h
@@ -58,7 +58,7 @@
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int code)> ONEQDATACHANGED;
    typedef std::function<void(void* pMaster, CRobotTask* pTask, int code)> ONROBOTTASKEVENT;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, short status, __int64 data)> ONLOADPORTSTATUSCHANGED;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int slotNo, PROCESS_STATE state)> ONPROCESSSTATECHANGED;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int slotNo, PROCESS_STATE prevState, PROCESS_STATE state)> ONPROCESSSTATECHANGED;
    typedef std::function<void(void* pMaster, int round)> ONCTROUNDEND;
    typedef std::function<void(void* pMaster, void* pj)> ONPJSTART;
    typedef std::function<void(void* pMaster)> ONCONTROLJOBCHANGED;
SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -525,26 +525,37 @@
void CHsmsPassive::setVariableValue(const char* pszName, __int64 value)
{
    auto v = getVariable(pszName);
    if (v != nullptr) {
    // Protect variable list updates; multiple threads may set SVs.
    Lock();
    if (auto v = getVariable(pszName)) {
        v->setValue(value);
    }
    Unlock();
}
void CHsmsPassive::setVariableValue(const char* pszName, const char* value)
{
    auto v = getVariable(pszName);
    if (v != nullptr) {
    Lock();
    if (auto v = getVariable(pszName)) {
        v->setValue(value);
    }
    Unlock();
}
void CHsmsPassive::setVariableValue(const char* pszName, std::vector<SERVO::CVariable>& vars)
{
    auto v = getVariable(pszName);
    if (v != nullptr) {
    Lock();
    if (auto v = getVariable(pszName)) {
        v->setValue(vars);
    }
    Unlock();
}
void CHsmsPassive::withVariableLock(const std::function<void()>& fn)
{
    Lock();
    if (fn) fn();
    Unlock();
}
static bool isValidFormat(const std::string& fmt)
SourceCode/Bond/Servo/HsmsPassive.h
@@ -160,6 +160,8 @@
    void setVariableValue(const char* pszName, __int64 value);
    void setVariableValue(const char* pszName, const char* value);
    void setVariableValue(const char* pszName, std::vector<SERVO::CVariable>& vars);
    // 执行一段持锁的代码块,用于保证 set+send 的原子性
    void withVariableLock(const std::function<void()>& fn);
    // 从文件中加载CReport列表
    int loadReports(const char* pszFilepath);
SourceCode/Bond/Servo/Model.cpp
@@ -35,17 +35,17 @@
{
    const auto prev = m_currentControlState;
    if (newState != m_currentControlState) {
        m_hsmsPassive.setVariableValue("PreviousControlState", (__int64)static_cast<uint8_t>(prev));
        m_currentControlState = newState;
    }
    // Always keep SV in sync (even if state didn't change or variables were just loaded).
    m_hsmsPassive.setVariableValue("CurrentControlState", (__int64)static_cast<uint8_t>(m_currentControlState));
    if (newState != prev) {
        // S6F11 (CEID=600): ControlStateChanged
        m_hsmsPassive.requestEventReportSend("ControlStateChanged");
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PreviousControlState", (__int64)static_cast<uint8_t>(prev));
            m_hsmsPassive.setVariableValue("CurrentControlState", (__int64)static_cast<uint8_t>(m_currentControlState));
            m_hsmsPassive.requestEventReportSend("ControlStateChanged");
        });
        notifyInt(RX_CODE_CONTROL_STATE_CHANGED, static_cast<int>(m_currentControlState));
    } else {
        // Keep SV in sync even if unchanged/load-time refresh.
        m_hsmsPassive.setVariableValue("CurrentControlState", (__int64)static_cast<uint8_t>(m_currentControlState));
    }
}
@@ -241,9 +241,11 @@
                    return CAACK_5;
                }
                m_hsmsPassive.setVariableValue("SlotMapScan", pLoadPort->getScanCassetteMap());
                m_hsmsPassive.setVariableValue("SlotMapDownload", pLoadPort->getDownloadCassetteMap());
                m_hsmsPassive.requestEventReportSend_SlotMapVerificationOK();
                m_hsmsPassive.withVariableLock([&] {
                    m_hsmsPassive.setVariableValue("SlotMapScan", pLoadPort->getScanCassetteMap());
                    m_hsmsPassive.setVariableValue("SlotMapDownload", pLoadPort->getDownloadCassetteMap());
                    m_hsmsPassive.requestEventReportSend_SlotMapVerificationOK();
                });
                // Host 确认 SlotMap 后再开始加工/流程
                m_master.proceedWithCarrier(portIndex);
@@ -271,8 +273,10 @@
            vars.push_back(var);
        }
        m_hsmsPassive.setVariableValue("PJQueued", vars);
        m_hsmsPassive.requestEventReportSend_PJ_Queued();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJQueued", vars);
            m_hsmsPassive.requestEventReportSend_PJ_Queued();
        });
        return nRet;
    };
    listener.onControlJobCreate = [&](void* pFrom, SERVO::CControlJob& controlJob) -> int {
@@ -376,11 +380,13 @@
    masterListener.onEqVcrEventReport = [&](void* pMaster, SERVO::CEquipment* pEquipment, SERVO::CVcrEventReport* pReport) {
        LOGE("<CModel>onEqVcrEventReport.");
        if (pReport != nullptr) {
            m_hsmsPassive.setVariableValue("VCRPanelID", pReport->getGlassId().c_str());
            int nRet = m_hsmsPassive.requestEventReportSend_OCR_PanelID_Read_OK();
            if (nRet != ER_NOERROR) {
                LOGE("<CModel>requestEventReportSend_OCR_PanelID_Read_OK failed, ret=%d", nRet);
            }
            m_hsmsPassive.withVariableLock([&] {
                m_hsmsPassive.setVariableValue("VCRPanelID", pReport->getGlassId().c_str());
                int nRet = m_hsmsPassive.requestEventReportSend_OCR_PanelID_Read_OK();
                if (nRet != ER_NOERROR) {
                    LOGE("<CModel>requestEventReportSend_OCR_PanelID_Read_OK failed, ret=%d", nRet);
                }
            });
        }
    };
    masterListener.onEqDataChanged = [&](void* pMaster, SERVO::CEquipment* pEquipment, int code) {
@@ -486,97 +492,155 @@
        s_prevPortStatus[eqId] = status;
        if (status == PORT_INUSE) {
            SERVO::CLoadPort* pLoadPort = dynamic_cast<SERVO::CLoadPort*>(pEquipment);
            if (pLoadPort != nullptr) {
                m_hsmsPassive.setVariableValue("CarrierID", pLoadPort->getCassetteId().c_str());
                if (prevStatus != PORT_INUSE && pLoadPort->isCompareMapsBeforeProceeding()) {
                    // TODO(Host协商):
                    // 文档中标明:1-Empty,3-Exist,因此我们可能需要将uint的map转换为list上传
                    m_hsmsPassive.setVariableValue("SlotMap", pLoadPort->getScanCassetteMap());
                    m_hsmsPassive.requestEventReportSend_CheckSlotMap();
            m_hsmsPassive.withVariableLock([&] {
                if (pLoadPort != nullptr) {
                    m_hsmsPassive.setVariableValue("CarrierID", pLoadPort->getCassetteId().c_str());
                    if (prevStatus != PORT_INUSE && pLoadPort->isCompareMapsBeforeProceeding()) {
                        // TODO(Host协商):
                        // 文档中标明:1-Empty,3-Exist,因此我们可能需要将uint的map转换为list上传
                        m_hsmsPassive.setVariableValue("SlotMap", pLoadPort->getScanCassetteMap());
                        m_hsmsPassive.requestEventReportSend_CheckSlotMap();
                    }
                }
            }
            m_hsmsPassive.requestEventReportSend_CarrierID_Readed();
                m_hsmsPassive.requestEventReportSend_CarrierID_Readed();
            });
        }
        else if (status == PORT_BLOCKED) {
            SERVO::CLoadPort* pLoadPort = dynamic_cast<SERVO::CLoadPort*>(pEquipment);
            if (pLoadPort != nullptr) {
                m_hsmsPassive.setVariableValue("BlockedPortId", pLoadPort->getID());
            }
            m_hsmsPassive.requestEventReportSend_Port_Blocked();
            m_hsmsPassive.withVariableLock([&] {
                if (pLoadPort != nullptr) {
                    m_hsmsPassive.setVariableValue("BlockedPortId", pLoadPort->getID());
                }
                m_hsmsPassive.requestEventReportSend_Port_Blocked();
            });
        }
        else if (status == PORT_LOAD_READY) {
            SERVO::CLoadPort* pLoadPort = dynamic_cast<SERVO::CLoadPort*>(pEquipment);
            if (pLoadPort != nullptr) {
                m_hsmsPassive.setVariableValue("LoadReadyPortId", pLoadPort->getID());
            }
            m_hsmsPassive.requestEventReportSend_Port_Load_Ready();
            m_hsmsPassive.withVariableLock([&] {
                if (pLoadPort != nullptr) {
                    m_hsmsPassive.setVariableValue("LoadReadyPortId", pLoadPort->getID());
                }
                m_hsmsPassive.requestEventReportSend_Port_Load_Ready();
            });
        }
        else if (status == PORT_UNLOAD_READY) {
            SERVO::CLoadPort* pLoadPort = dynamic_cast<SERVO::CLoadPort*>(pEquipment);
            if (pLoadPort != nullptr) {
                m_hsmsPassive.setVariableValue("UnloadReadyPortId", pLoadPort->getID());
                if (prevStatus == PORT_INUSE) {
                    m_hsmsPassive.setVariableValue("ReadyToReleasePortId", pLoadPort->getID());
                    m_hsmsPassive.requestEventReportSend_Port_Ready_To_Release();
            m_hsmsPassive.withVariableLock([&] {
                if (pLoadPort != nullptr) {
                    m_hsmsPassive.setVariableValue("UnloadReadyPortId", pLoadPort->getID());
                    if (prevStatus == PORT_INUSE) {
                        m_hsmsPassive.setVariableValue("ReadyToReleasePortId", pLoadPort->getID());
                        m_hsmsPassive.requestEventReportSend_Port_Ready_To_Release();
                    }
                }
            }
            m_hsmsPassive.requestEventReportSend_Port_Unload_Ready();
                m_hsmsPassive.requestEventReportSend_Port_Unload_Ready();
            });
        }
        else if (status == PORT_EMPTY) {
            SERVO::CLoadPort* pLoadPort = dynamic_cast<SERVO::CLoadPort*>(pEquipment);
            if (pLoadPort != nullptr) {
                m_hsmsPassive.setVariableValue("LoadPortNotAssocPortId", pLoadPort->getID());
            }
            m_hsmsPassive.requestEventReportSend_LoadPortNotAssoc();
            m_hsmsPassive.withVariableLock([&] {
                if (pLoadPort != nullptr) {
                    m_hsmsPassive.setVariableValue("LoadPortNotAssocPortId", pLoadPort->getID());
                }
                m_hsmsPassive.requestEventReportSend_LoadPortNotAssoc();
            });
        }
        notifyPtr(RX_CODE_LOADPORT_STATUS_CHANGED, pEquipment);
    };
    masterListener.onProcessStateChanged = [&](void* pMaster, SERVO::CEquipment* pEquipment, int slotNo, SERVO::PROCESS_STATE state) {
        // SubEqpStart/SubEqpEnd: align to log's EV_SubEqpStart/EV_SubEqpEnd stage (no report payload required).
    masterListener.onProcessStateChanged = [&](void* pMaster, SERVO::CEquipment* pEquipment, int slotNo, SERVO::PROCESS_STATE prevState, SERVO::PROCESS_STATE state) {
        (void)pMaster;
        if (pEquipment != nullptr) {
            m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
        }
        m_hsmsPassive.setVariableValue("SubEqpSlot", slotNo);
        if (state == SERVO::PROCESS_STATE::Processing) {
            m_hsmsPassive.requestEventReportSend_SubEqpStart();
        }
        else if (state == SERVO::PROCESS_STATE::Complete) {
            m_hsmsPassive.requestEventReportSend_SubEqpEnd();
        }
        const int eqId = pEquipment ? pEquipment->getID() : 0;
        // 保持同一锁范围内:更新所需 SV 并依次上报,保证 set+send 原子性
        m_hsmsPassive.withVariableLock([&] {
            // Timestamp VID (Clock, VID=500) for all related reports.
            m_hsmsPassive.setVariableValue("Clock", CToolUnits::getCurrentTimeString().c_str());
            // Common payload VIDs for SubEqp/Unit
            if (pEquipment != nullptr) {
                m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
            }
            m_hsmsPassive.setVariableValue("SubEqpSlot", slotNo);
            // ProcessStateChanged (equipment-level): update SVs 700/701, then report CEID=700
            m_hsmsPassive.setVariableValue("PreviousProcessState", (__int64)prevState);
            m_hsmsPassive.setVariableValue("CurrentProcessState", (__int64)state);
            m_hsmsPassive.requestEventReportSend("ProcessStateChanged");
            // SubEqp events (per equipment, ignore slot distinction except payload)
            static std::map<int, SERVO::PROCESS_STATE> s_prevSubEqpState;
            const auto prevEqState = s_prevSubEqpState[eqId];
            if (prevEqState != state) {
                // state change
                m_hsmsPassive.requestEventReportSend("SubEqpStateChange");
            }
            if (state == SERVO::PROCESS_STATE::Processing) {
                m_hsmsPassive.requestEventReportSend_SubEqpStart();
            }
            else if (state == SERVO::PROCESS_STATE::Complete) {
                m_hsmsPassive.requestEventReportSend_SubEqpEnd();
            }
            s_prevSubEqpState[eqId] = state;
            // Unit events (per equipment slot)
            static std::map<int, std::map<int, SERVO::PROCESS_STATE>> s_prevUnitState;
            const auto prevUnitState = s_prevUnitState[eqId][slotNo];
            if (prevUnitState != state) {
                m_hsmsPassive.requestEventReportSend("UnitStateChange");
                if (state == SERVO::PROCESS_STATE::Processing) {
                    m_hsmsPassive.requestEventReportSend("UnitStart");
                }
                else if (state == SERVO::PROCESS_STATE::Complete) {
                    m_hsmsPassive.requestEventReportSend("UnitEnd");
                }
                s_prevUnitState[eqId][slotNo] = state;
            }
        });
    };
    masterListener.onCTRoundEnd = [&](void* pMaster, int round) {
        m_configuration.setContinuousTransferCount(round);
    };
    masterListener.onCjStart = [&](void* pMaster, void* pj) {
        m_hsmsPassive.setVariableValue("CJStartID", ((SERVO::CControlJob*)pj)->id().c_str());
        m_hsmsPassive.requestEventReportSend_CJ_Start();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("CJStartID", ((SERVO::CControlJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_CJ_Start();
        });
    };
    masterListener.onCjEnd = [&](void* pMaster, void* pj) {
        m_hsmsPassive.setVariableValue("CJEndID", ((SERVO::CControlJob*)pj)->id().c_str());
        m_hsmsPassive.requestEventReportSend_CJ_End();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("CJEndID", ((SERVO::CControlJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_CJ_End();
        });
        // 结批,保存ControlJob
        // 
    };
    masterListener.onPjStart = [&](void* pMaster, void* pj) {
        m_hsmsPassive.setVariableValue("PJStartID", ((SERVO::CProcessJob*)pj)->id().c_str());
        m_hsmsPassive.requestEventReportSend_PJ_Start();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJStartID", ((SERVO::CProcessJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_PJ_Start();
        });
    };
    masterListener.onPjEnd = [&](void* pMaster, void* pj) {
        m_hsmsPassive.setVariableValue("PJEndID", ((SERVO::CProcessJob*)pj)->id().c_str());
        m_hsmsPassive.requestEventReportSend_PJ_End();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PJEndID", ((SERVO::CProcessJob*)pj)->id().c_str());
            m_hsmsPassive.requestEventReportSend_PJ_End();
        });
    };
    masterListener.onPanelStart = [&](void* pMaster, void* pPanel) {
        m_hsmsPassive.setVariableValue("PanelStartID", ((SERVO::CGlass*)pPanel)->getID().c_str());
        m_hsmsPassive.requestEventReportSend_Panel_Start();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PanelStartID", ((SERVO::CGlass*)pPanel)->getID().c_str());
            m_hsmsPassive.requestEventReportSend_Panel_Start();
        });
    };
    masterListener.onPanelEnd = [&](void* pMaster, void* pPanel) {
        m_hsmsPassive.setVariableValue("PanelEndID", ((SERVO::CGlass*)pPanel)->getID().c_str());
        m_hsmsPassive.requestEventReportSend_Panel_End();
        // Placeholder payload to match log shape: EV_PROCESS_DATA_REPORT can carry a single A-string (may be empty).
        m_hsmsPassive.setVariableValue("ProcessDataReportText", "");
        m_hsmsPassive.requestEventReportSend_ProcessDataReport();
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("PanelEndID", ((SERVO::CGlass*)pPanel)->getID().c_str());
            m_hsmsPassive.requestEventReportSend_Panel_End();
            // Placeholder payload to match log shape: EV_PROCESS_DATA_REPORT can carry a single A-string (may be empty).
            m_hsmsPassive.setVariableValue("ProcessDataReportText", "");
            m_hsmsPassive.requestEventReportSend_ProcessDataReport();
        });
        auto& db = GlassLogDb::Instance();
        db.insertFromCGlass((*(SERVO::CGlass*)pPanel));
        SERVO::CGlass* pBuddy = ((SERVO::CGlass*)pPanel)->getBuddy();
SourceCode/Bond/x64/Debug/CollectionEventList.txt
@@ -6,6 +6,7 @@
10018,ProcessDataReport,,(33)
10015,SubEqpStart,,(10015)
10016,SubEqpEnd,,(10016)
10017,SubEqpStateChange,,(10017)
10000,RecipeChanged,,(10000)
10030,CarrierArrived,,(10300)
10031,CarrierRemoved,,(10300)
@@ -55,3 +56,6 @@
50010,Port_Blocked,,(50010)
50011,OCR_PanelID_Read_OK,扫码事件上报,(50012)
50012,Port_Ready_To_Release,,(50013)
12000,UnitStart,,(12000)
12001,UnitStateChange,,(12001)
12002,UnitEnd,,(12002)
SourceCode/Bond/x64/Debug/ReportList.txt
@@ -33,3 +33,7 @@
50014,(5016)
10015,(5018,5019)
10016,(5018,5019)
10017,(500,5018)
12000,(500,5018,5019)
12001,(500,5018,5019)
12002,(500,5018,5019)