1.配方列表和配方参数获取合并在线程中获取,并更新状态到对话框;
2.配方参数获取;
3.Bonder, AOI, 真空烘烤, 冷却烧烤配方参数解释。
已添加5个文件
已修改22个文件
817 ■■■■ 文件已修改
Document/EO2860AVA-101工艺参数.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.10.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
Document/配方参数.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBakeCooling.cpp 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBakeCooling.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBonder.cpp 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CBonder.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CJobDataS.cpp 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMeasurement.cpp 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMeasurement.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CParam.cpp 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CParam.h 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipeList.cpp 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipeList.h 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipesManager.cpp 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRecipesManager.h 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CRobotTask.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CVacuumBake.cpp 95 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CVacuumBake.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.cpp 125 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/RecipeManager.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Document/EO2860AVA-101¹¤ÒÕ²ÎÊý.xlsx
Binary files differ
Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.10.xlsx
Binary files differ
Document/Åä·½²ÎÊý.xlsx
Binary files differ
SourceCode/Bond/Servo/CBakeCooling.cpp
@@ -207,33 +207,33 @@
        {
            // è¯·æ±‚配方参数
            //CEqWriteStep* pStep = new CEqWriteStep();
            //pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            //pStep->setWriteSignalDev(0x967);
            //pStep->setDataDev(0x379b);
            //if (addStep(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pStep) != 0) {
            //    delete pStep;
            //}
            CEqWriteStep* pStep = new CEqWriteStep();
            pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            pStep->setWriteSignalDev(0x967);
            pStep->setDataDev(0x24fb);
            if (addStep(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pStep) != 0) {
                delete pStep;
            }
        }
        {
            // recipe parameter report
            //CEqReadStep* pStep = new CEqReadStep(0x1aa54, 257 * 2,
            //    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
            //        if (code == ROK && pszData != nullptr && size > 0) {
            //            // æ­¤å¤„解释配方数据
            //            short ret = decodeRecipeParameterReport(pszData, size);
            //            pStep->setReturnCode(ret);
            //        }
            //        pStep->setReturnCode(MRLRC_OK);
            //        return -1;
            //    });
            //pStep->setName(STEP_EQ_RECIPE_PARAMETER);
            //pStep->setWriteSignalDev(0x94c);
            //pStep->setReturnDev(m_nIndex == 0 ? 0x126c : 0x1bbc);
            //if (addStep(STEP_ID_RECIPE_PARAMETER_REPORT, pStep) != 0) {
            //    delete pStep;
            //}
            CEqReadStep* pStep = new CEqReadStep(0x12a54, 257 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        // æ­¤å¤„解释配方数据
                        short ret = decodeRecipeParameterReport(pszData, size);
                        pStep->setReturnCode(ret);
                    }
                    pStep->setReturnCode(MRLRC_OK);
                    return -1;
                });
            pStep->setName(STEP_EQ_RECIPE_PARAMETER);
            pStep->setWriteSignalDev(0x94c);
            pStep->setReturnDev(0x250c);
            if (addStep(STEP_ID_RECIPE_PARAMETER_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        // ä½¿ç”¨CEqReadStep替换CEqJobEventStep
@@ -422,4 +422,46 @@
        if (pGlass == nullptr) return false;
        return pGlass->isProcessed(m_nID, getSlotUnit(slot));
    }
    int CBakeCooling::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
    {
        ASSERT(pszData);
        if (size < 250) return 0;
        int i = 0, v;
        // 1.A_腔烘烤时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("A_腔烘烤时间", 0, "", v * 0.01f));
        i += 2;
        // 2.A_腔冷却时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("A_腔冷却时间", 0, "", v * 0.01f));
        i += 2;
        // 3.B_腔烘烤时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("B_腔烘烤时间", 0, "", v * 0.01f));
        i += 2;
        // 4.BB_腔冷却时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("B_腔冷却时间", 0, "", v * 0.01f));
        i += 2;
        // 5.A_烘烤温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("A_烘烤温度设定", 0, "", v * 0.1f));
        i += 2;
        // 6.B_烘烤温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("B_烘烤温度设定", 0, "", v * 0.1f));
        i += 2;
        return (int)parsms.size();
    }
}
SourceCode/Bond/Servo/CBakeCooling.h
@@ -24,6 +24,7 @@
        virtual int getIndexerOperationModeBaseValue();
        virtual short getSlotUnit(short slotNo) { return slotNo % 2 == 1 ? 0 : 1; };
        virtual bool isSlotProcessed(int slot);
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms);
    };
}
SourceCode/Bond/Servo/CBonder.cpp
@@ -351,10 +351,10 @@
        {
            // FAC Data Report
            CEqReadStep* pStep = new CEqReadStep(0xA60E, 108 * 2,
            CEqReadStep* pStep = new CEqReadStep(m_nIndex == 0 ? 0xA60E : 0xE60E, 108 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        decodePanelDataReport((CStep*)pFrom, pszData, size);
                        decodeFacDataReport((CStep*)pFrom, pszData, size);
                    }
                    return -1;
                });
@@ -522,4 +522,123 @@
    {
        return m_nIndex == 0 ? 15000 : 20000;
    }
    int CBonder::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
    {
        ASSERT(pszData);
        if (size < 250) return 0;
        int i = 0, v;
        // 1.校正对位延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("校正对位延时", 0, "", v * 0.01f));
        i += 2;
        // 2.保压时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("保压时间", 0, "", v * 0.01f));
        i += 2;
        // 3.腔体破真空延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("腔体破真空延时", 0, "", v * 0.01f));
        i += 2;
        // 4.腔体分子泵启动延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("腔体分子泵启动延时", 0, "", v * 0.1f));
        i += 2;
        // 5.腔体贴附抽真空延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("腔体贴附抽真空延时", 0, "", v * 0.1f));
        i += 2;
        // 6.加热等待延时
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("加热等待延时", 0, "", v * 0.1f));
        i += 2;
        // 7.气囊压力设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("气囊压力设定", 0, "", v * 0.1f));
        i += 4;
        // 8.气囊加压速率
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("气囊加压速率", 0, "", v * 0.1f));
        i += 4;
        // 9.气囊泄压速率
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("气囊泄压速率", 0, "", v * 0.1f));
        i += 4;
        // 10.贴附压力上限
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("贴附压力上限", 0, "", v * 0.1f));
        i += 4;
        // 11.Z轴转矩速度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("上腔Z轴转矩速度设定", 0, "", v * 0.001f));
        i += 4;
        // 12.上腔温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("上腔温度设定", 0, "", v * 0.1f));
        i += 2;
        // 13.下腔温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("下腔温度设定", 0, "", v * 0.1f));
        i += 2;
        // 14.上腔Z轴预贴合位速度
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("上腔Z轴预贴合位速度", 0, "", v * 0.001f));
        i += 4;
        // 15.上腔Z轴贴附位速度
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("上腔Z轴贴附位速度", 0, "", v * 0.001f));
        i += 4;
        // 16.上腔Z上腔加热位间距
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("上腔Z上腔加热位间距", 0, "", v * 0.001f));
        i += 4;
        // 17.上腔贴附位压入量
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("上腔贴附位压入量", 0, "", v * 0.001f));
        i += 4;
        // 18.上腔Z轴破真空距离
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("上腔Z轴破真空距离", 0, "", v * 0.001f));
        i += 4;
        // 19.下顶Pin破真空距离
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("下顶Pin破真空距离", 0, "", v * 0.001f));
        i += 4;
        // 20.下顶Pin加热位间距
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("下顶Pin加热位间距", 0, "", v * 0.001f));
        i += 4;
        // 21.腔体真空泵真空规设定值
        parsms.push_back(CParam("腔体真空泵真空规设定值", 0, "", (double)toFloat(&pszData[i])));
        i += 4;
        // 22.腔体分子泵到达设定值
        parsms.push_back(CParam("腔体分子泵到达设定值", 0, "", (double)toFloat(&pszData[i])));
        i += 4;
        return (int)parsms.size();
    }
}
SourceCode/Bond/Servo/CBonder.h
@@ -24,6 +24,7 @@
        virtual int onProcessData(CProcessData* pProcessData);
        virtual int onProcessStateChanged(PROCESS_STATE state);
        virtual int getIndexerOperationModeBaseValue();
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms);
    public:
        void setIndex(unsigned int index);
SourceCode/Bond/Servo/CEquipment.cpp
@@ -1189,28 +1189,39 @@
        return 0;
    }
    int CEquipment::recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo)
    int CEquipment::recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo, ONSYNCINGSTATECHANGED block)
    {
        SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_MASTER_RECIPE_LIST_REQ);
        LOGI("<CEquipment-%s>正在请求单元<%d>主配参数列表", m_strName.c_str(), unitNo);
        m_recipesManager.setOnSyncingStateChanged(block);
        if (m_recipesManager.syncing() != 0) {
            return -2;
        }
        SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_RECIPE_PARAMETER_REQ);
        if (pStep == nullptr) {
            return -1;
        }
        LOGI("<CEquipment-%s>正在请求单元<%d>主配方列表", m_strName.c_str(), unitNo);
        if (m_recipesManager.syncing() != 0) {
            return -2;
        }
        pStep->writeShort(unitNo, [&, unitNo](int code) -> int {
        char szBuffer[14 * 2] = {0};
        int index = 0;
        memcpy(&szBuffer[index], &masterRecipeId, sizeof(short));
        index += sizeof(short);
        memcpy(&szBuffer[index], &localRecipeId, sizeof(short));
        index += sizeof(short);
        memcpy(&szBuffer[index], &unitNo, sizeof(short));
        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();
                LOGI("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
                LOGI("<CEquipment-%s>请求单元<%d>主配方参数列表失败,code:%d", m_strName.c_str(), unitNo, code);
            }
            return 0;
            });
        return 0;
    }
@@ -1733,7 +1744,7 @@
        std::string strSvTimeRecord, strSvData;
        CToolUnits::convertString(&pszData[index], 8 * 2, strSvTimeRecord);
        index += 128 * 2;
        CToolUnits::convertString(&pszData[index], 640 * 2, strSvData);
        CToolUnits::convertString(&pszData[index], 100 * 2, strSvData);
        index += 256 * 2;
@@ -2075,4 +2086,17 @@
        return InspResult::NotInspected;
    }
    float CEquipment::toFloat(const char* pszAddr)
    {
        BYTE szBuffer[4];
        szBuffer[0] = pszAddr[0];
        szBuffer[1] = pszAddr[1];
        szBuffer[2] = pszAddr[2];
        szBuffer[3] = pszAddr[3];
        float f = 0.0;
        memcpy(&f, szBuffer, 4);
        return f;
    }
}
SourceCode/Bond/Servo/CEquipment.h
@@ -35,6 +35,7 @@
#include "CProcessData.h"
#include "CPortStatusReport.h"
#include "CSlot.h"
#include "CParam.h"
namespace SERVO {
@@ -165,7 +166,10 @@
        // masterRecipeId: ä¸»é…æ–¹id
        // localRecipeId: æœ¬åœ°é…æ–¹id
        // unitNo: 0:local; Others:unit No
        int recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo);
        int recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo, ONSYNCINGSTATECHANGED block);
        // è§£æžé…æ–¹å‚数列表
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms) { return 0;  };
        // èŽ·å–æŒ‡å®šçš„Slot
        CSlot* getSlot(int index);
@@ -254,6 +258,7 @@
        int decodeJobProcessEndReport(CStep* pStep, const char* pszData, size_t size);
        BOOL compareJobData(CJobDataB* pJobDataB, CJobDataS* pJobDataS);
        void setProcessState(PROCESS_STATE state);
        float toFloat(const char* pszAddr);
    protected:
        BOOL m_bEnable;
SourceCode/Bond/Servo/CJobDataS.cpp
@@ -457,7 +457,7 @@
    int CJobDataS::serialize(char* pszBuffer, int nBufferSize)
    {
        if (nBufferSize < 256 * 2) return -1;
        if (nBufferSize < JOBDATAS_SIZE) return -1;
        int index = 0;
        memcpy(&pszBuffer[index], &m_nCassetteSequenceNo, sizeof(short));
@@ -558,7 +558,7 @@
        memcpy(&pszBuffer[index], &m_nProductJudge, sizeof(short));
        index += sizeof(short);
        return 256 * 2;
        return JOBDATAS_SIZE;
    }
    int CJobDataS::unserialize(const char* pszBuffer, int nBufferSize)
SourceCode/Bond/Servo/CMaster.cpp
@@ -2499,7 +2499,9 @@
            m_pControlJob = new CControlJob();
            if (!CControlJob::deserialize(ifs, *m_pControlJob)) return false;
        }
        else {
            return false;
        }
        // è¯»å– ProcessJob åˆ—表
        uint32_t count = 0;
SourceCode/Bond/Servo/CMeasurement.cpp
@@ -207,33 +207,33 @@
        {
            // è¯·æ±‚配方参数
            //CEqWriteStep* pStep = new CEqWriteStep();
            //pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            //pStep->setWriteSignalDev(0xf67);
            //pStep->setDataDev(0x379b);
            //if (addStep(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pStep) != 0) {
            //    delete pStep;
            //}
            CEqWriteStep* pStep = new CEqWriteStep();
            pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            pStep->setWriteSignalDev(0xf67);
            pStep->setDataDev(0x379b);
            if (addStep(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pStep) != 0) {
                delete pStep;
            }
        }
        {
            // recipe parameter report
            //CEqReadStep* pStep = new CEqReadStep(0x1aa54, 257 * 2,
            //    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
            //        if (code == ROK && pszData != nullptr && size > 0) {
            //            // æ­¤å¤„解释配方数据
            //            short ret = decodeRecipeParameterReport(pszData, size);
            //            pStep->setReturnCode(ret);
            //        }
            //        pStep->setReturnCode(MRLRC_OK);
            //        return -1;
            //    });
            //pStep->setName(STEP_EQ_RECIPE_PARAMETER);
            //pStep->setWriteSignalDev(0xf4c);
            //pStep->setReturnDev(m_nIndex == 0 ? 0x126c : 0x1bbc);
            //if (addStep(STEP_ID_RECIPE_PARAMETER_REPORT, pStep) != 0) {
            //    delete pStep;
            //}
            CEqReadStep* pStep = new CEqReadStep(0x1aa54, 257 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        // æ­¤å¤„解释配方数据
                        short ret = decodeRecipeParameterReport(pszData, size);
                        pStep->setReturnCode(ret);
                    }
                    pStep->setReturnCode(MRLRC_OK);
                    return -1;
                });
            pStep->setName(STEP_EQ_RECIPE_PARAMETER);
            pStep->setWriteSignalDev(0xf4c);
            pStep->setReturnDev(0x37ac);
            if (addStep(STEP_ID_RECIPE_PARAMETER_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        // ä½¿ç”¨CEqReadStep替换CEqJobEventStep
@@ -416,4 +416,20 @@
    {
        return 35000;
    }
    int CMeasurement::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
    {
        ASSERT(pszData);
        if (size < 250) return 0;
        int i = 0, v;
        // 1.检测功能启用/禁用
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("检测功能启用/禁用", 0, "", v));
        i += 2;
        return (int)parsms.size();
    }
}
SourceCode/Bond/Servo/CMeasurement.h
@@ -22,6 +22,7 @@
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
        virtual int getIndexerOperationModeBaseValue();
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms);
    };
}
SourceCode/Bond/Servo/CParam.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
#include "stdafx.h"
#include "CParam.h"
CParam::CParam()
{
    m_nValueType = PVT_INT;
    m_nValue = 0;
    m_fValue = 0.0;
}
CParam::CParam(const char* pszName, const char* pszId, const char* pszUnit, int value)
{
    m_nValueType = PVT_INT;
    m_nValue = value;
    m_fValue = 0.0;
    m_strId = pszId;
    m_strName = pszName;
    m_strUnit = pszUnit;
}
CParam::CParam(const char* pszName, const char* pszId, const char* pszUnit, double value)
{
    m_nValueType = PVT_DOUBLE;
    m_nValue = 0;
    m_fValue = value;
    m_strId = pszId;
    m_strName = pszName;
    m_strUnit = pszUnit;
}
CParam::~CParam()
{
}
std::string& CParam::getName()
{
    return m_strName;
}
std::string& CParam::getId()
{
    return m_strId;
}
std::string& CParam::getUnit()
{
    return m_strUnit;
}
int CParam::getValueType()
{
    return m_nValueType;
}
int CParam::getIntValue()
{
    return m_nValue;
}
void CParam::setIntValue(int value)
{
    m_nValue = value;
}
double CParam::getDoubleValue()
{
    return m_fValue;
}
void CParam::setDoubleValue(double value)
{
    m_fValue = value;
}
void CParam::Serialize(CArchive& ar)
{
    if (ar.IsStoring())
    {
        WriteString(ar, m_strName);
        WriteString(ar, m_strUnit);
        ar << m_nValueType;
        ar << m_nValue;
        ar << m_fValue;
    }
    else
    {
        ReadString(ar, m_strName);
        ReadString(ar, m_strUnit);
        ar >> m_nValueType;
        ar >> m_nValue;
        ar >> m_fValue;
    }
}
void CParam::ReadString(CArchive& ar, std::string& string)
{
    CString strTemp;
    ar >> strTemp;
    string = (LPTSTR)(LPCTSTR)strTemp;
}
void CParam::WriteString(CArchive& ar, std::string& string)
{
    CString strTemp = string.c_str();
    ar << strTemp;
}
SourceCode/Bond/Servo/CParam.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
#pragma once
#include <string>
#define PVT_INT        0
#define PVT_DOUBLE    1
class CParam
{
public:
    CParam();
    CParam(const char* pszName, const char* pszId, const char* pszUnit, int value);
    CParam(const char* pszName, const char* pszId, const char* pszUnit, double value);
    ~CParam();
public:
    std::string& getId();
    std::string& getName();
    std::string& getUnit();
    int getValueType();
    int getIntValue();
    void setIntValue(int value);
    double getDoubleValue();
    void setDoubleValue(double value);
    void Serialize(CArchive& ar);
private:
    void ReadString(CArchive& ar, std::string& string);
    void WriteString(CArchive& ar, std::string& string);
private:
    int m_nValueType;
    std::string m_strId;
    std::string m_strName;
    std::string m_strUnit;
    int m_nValue;
    double m_fValue;
};
SourceCode/Bond/Servo/CRecipeList.cpp
@@ -77,10 +77,47 @@
        return m_ids;
    }
    std::unordered_map<short, std::vector<uint8_t>>& CRecipeList::getParamsRawData()
    {
        return m_paramsRawData;
    }
    void CRecipeList::reset()
    {
        m_nToatlGroupCount = 0;
        m_nCurrentGroupCount = 0;
        m_ids.clear();
        m_paramsRawData.clear();
    }
    int CRecipeList::addParamsPacket(int totalCount, int totalGroup, int currentGroup,
        short unitId, short recipeId,
        const char* pszData, size_t size)
    {
        if (m_nToatlGroupCount == 0) m_nToatlGroupCount = totalGroup;
        if (m_nToatlGroupCount != totalGroup) {
            reset();
            return MRLRC_GROUP_COUNT_NG;
        }
        if (currentGroup == 0) {
            reset();
        }
        if (m_nCurrentGroupCount + 1 > currentGroup) {
            return MRLRC_DUPLICATION_GROUP_COUNT_NG;
        }
        if (m_nCurrentGroupCount + 1 < currentGroup) {
            return ORDER_BY_GROUP_COUNT_NG;
        }
        m_nCurrentGroupCount++;
        m_paramsRawData[recipeId].insert(m_paramsRawData[recipeId].end(), (uint8_t*)(pszData), (uint8_t*)(pszData) + size);
        if (m_nCurrentGroupCount == m_nToatlGroupCount) {
            // è§£é‡Šæ•°æ®å°±äº¤ç»™åº”用层吧
            return MRLRC_CURRENT_RECIPE_COMPLETE;
        }
        return MRLRC_CONTINUE;
    }
}
SourceCode/Bond/Servo/CRecipeList.h
@@ -15,13 +15,20 @@
        int addRecipePacket(int totalCount,int totalGroup, int currentGroup, const char* pszData, size_t size);
        int addRecipe(int index, short id);
        std::map<int, short>& getIds();
        std::unordered_map<short, std::vector<uint8_t>>& getParamsRawData();
        void reset();
        // æ·»åŠ å‚æ•°åŒ…
        int addParamsPacket(int totalCount, int totalGroup, int currentGroup,
            short unitId, short recipeId,
            const char* pszData, size_t size);
    private:
        int m_nUnitNo;
        int m_nToatlGroupCount;
        int m_nCurrentGroupCount;
        std::map<int, short> m_ids;
        std::unordered_map<short, std::vector<uint8_t>> m_paramsRawData;
    };
}
SourceCode/Bond/Servo/CRecipesManager.cpp
@@ -169,7 +169,7 @@
                }
                m_mapRecipes = m_mapRecipesTemp;
                m_mapRecipesTemp.clear();
                m_nSyncStatus = SS_COMPLETE;
                m_nSyncStatus = SS_LIST_COMPLETE;
                unlock();
                if (m_onSyncingStateChanged != nullptr) {
@@ -230,17 +230,14 @@
        // æ‰¾åˆ°å¯¹åº”CRecipeList, æ‰¾ä¸åˆ°åˆ™æ–°å»º
        /*
        // æ‰¾åˆ°å¯¹åº”CRecipeList, æ‰¾ä¸åˆ°åˆ™è¿”回NG
        lock();
        CRecipeList* pRecipeList = getRecipeListFromTemp(unitNo);
        if (pRecipeList == nullptr) {
            pRecipeList = new CRecipeList(unitNo);
            m_mapRecipesTemp[unitNo] = pRecipeList;
            unlock();
            return MRLRC_NG;
        }
        unlock();
        ASSERT(pRecipeList);
        */
        /*
         1: Create
@@ -248,7 +245,6 @@
         3: Delete
         4: Request from EAS
         */
        /*
        if (reportType == RT_CREATE) {
        }
@@ -259,26 +255,19 @@
        }
        else if (reportType == RT_REQUEST_FROM_EAS) {
            int nRet = pRecipeList->addRecipePacket(toatlGroupCount, currentGroupCount, pszIdsData, 250 * 2);
            int nRet = pRecipeList->addParamsPacket(totalParameterCount, toatlGroupCount, currentGroupCount,
                unitNo, localRecipeId,
                pszParameterData, 250 * 2);
            if (MRLRC_CURRENT_RECIPE_COMPLETE == nRet) {
                lock();
                if (m_nTotalMasterRecipeCount == m_mapRecipesTemp.size()) {
                    for (auto item : m_mapRecipes) {
                        delete item.second;
                    }
                    m_mapRecipes = m_mapRecipesTemp;
                    m_mapRecipesTemp.clear();
                    m_nSyncStatus = SS_COMPLETE;
                m_nSyncStatus = SS_PARAMS_COMPLETE;
                    unlock();
                    return MRLRC_OK;
                }
                unlock();
            return nRet;
            }
            else if (MRLRC_CONTINUE == nRet) {
                return MRLRC_CONTINUE;
            }
        }
        */
        return MRLRC_OK;
    }
SourceCode/Bond/Servo/CRecipesManager.h
@@ -6,9 +6,10 @@
#define SS_NONE                    0
#define SS_SYNCING                1
#define SS_COMPLETE                2
#define SS_TIMEOUT                3
#define SS_FAILED                4
#define SS_LIST_COMPLETE        2
#define SS_PARAMS_COMPLETE        3
#define SS_TIMEOUT                4
#define SS_FAILED                5
namespace SERVO {
    typedef std::function<void(int state)> ONSYNCINGSTATECHANGED;
SourceCode/Bond/Servo/CRobotTask.cpp
@@ -220,7 +220,7 @@
                    LOGI(_T("RobotTask已下发到EFEM"));
                }
                else {
                    LOGI(_T("RobotTask已下发失败"));
                    LOGI(_T("RobotTask下发失败"));
                }
                return 0;
SourceCode/Bond/Servo/CVacuumBake.cpp
@@ -207,33 +207,33 @@
        {
            // è¯·æ±‚配方参数
            //CEqWriteStep* pStep = new CEqWriteStep();
            //pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            //pStep->setWriteSignalDev(0xc67);
            //pStep->setDataDev(0x379b);
            //if (addStep(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pStep) != 0) {
            //    delete pStep;
            //}
            CEqWriteStep* pStep = new CEqWriteStep();
            pStep->setName(STEP_EQ_RECIPE_PARAMETER_REQ);
            pStep->setWriteSignalDev(0xc67);
            pStep->setDataDev(0x2e4b);
            if (addStep(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pStep) != 0) {
                delete pStep;
            }
        }
        {
            // recipe parameter report
            //CEqReadStep* pStep = new CEqReadStep(0x1aa54, 257 * 2,
            //    [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
            //        if (code == ROK && pszData != nullptr && size > 0) {
            //            // æ­¤å¤„解释配方数据
            //            short ret = decodeRecipeParameterReport(pszData, size);
            //            pStep->setReturnCode(ret);
            //        }
            //        pStep->setReturnCode(MRLRC_OK);
            //        return -1;
            //    });
            //pStep->setName(STEP_EQ_RECIPE_PARAMETER);
            //pStep->setWriteSignalDev(0xc4c);
            //pStep->setReturnDev(m_nIndex == 0 ? 0x126c : 0x1bbc);
            //if (addStep(STEP_ID_RECIPE_PARAMETER_REPORT, pStep) != 0) {
            //    delete pStep;
            //}
            CEqReadStep* pStep = new CEqReadStep(0x16a54, 257 * 2,
                [&](void* pFrom, int code, const char* pszData, size_t size) -> int {
                    if (code == ROK && pszData != nullptr && size > 0) {
                        // æ­¤å¤„解释配方数据
                        short ret = decodeRecipeParameterReport(pszData, size);
                        pStep->setReturnCode(ret);
                    }
                    pStep->setReturnCode(MRLRC_OK);
                    return -1;
                });
            pStep->setName(STEP_EQ_RECIPE_PARAMETER);
            pStep->setWriteSignalDev(0xc4c);
            pStep->setReturnDev(0x2ec);
            if (addStep(STEP_ID_RECIPE_PARAMETER_REPORT, pStep) != 0) {
                delete pStep;
            }
        }
        // ä½¿ç”¨CEqReadStep替换CEqJobEventStep
@@ -409,4 +409,53 @@
    {
        return 30000;
    }
    int CVacuumBake::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
    {
        ASSERT(pszData);
        if (size < 250) return 0;
        int i = 0, v;
        // 1.A_腔加热时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("A_腔加热时间", 0, "", v * 0.1f));
        i += 2;
        // 2.B_腔加热时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("B_腔加热时间", 0, "", v * 0.1f));
        i += 2;
        // 3.A_腔破真空时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("A_腔破真空时间", 0, "", v * 0.01f));
        i += 2;
        // 4.B_腔破真空时间
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
        parsms.push_back(CParam("B_腔破真空时间", 0, "", v * 0.01f));
        i += 2;
        // 5.A_腔真空到达值
        parsms.push_back(CParam("A_腔真空到达值", 0, "", (double)toFloat(&pszData[i])));
        i += 4;
        // 6.B_腔真空到达值
        parsms.push_back(CParam("B_腔真空到达值", 0, "", (double)toFloat(&pszData[i])));
        i += 4;
        // 7.A_腔温控表主控温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("A_腔温控表主控温度设定", 0, "", v * 0.1f));
        i += 4;
        // 8.B_腔温控表主控温度设定
        v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
        parsms.push_back(CParam("B_腔温控表主控温度设定", 0, "", v * 0.1f));
        i += 4;
        return (int)parsms.size();
    }
}
SourceCode/Bond/Servo/CVacuumBake.h
@@ -22,7 +22,7 @@
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
        virtual int getIndexerOperationModeBaseValue();
        virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms);
    };
}
SourceCode/Bond/Servo/PageRecipe.cpp
@@ -5,8 +5,8 @@
#include "Servo.h"
#include "afxdialogex.h"
#include "PageRecipe.h"
#include "MsgDlg.h"
#include "RecipeDeviceBindDlg.h"
// CPageRecipe å¯¹è¯æ¡†
@@ -486,32 +486,11 @@
        FillDataToListCtrl(vecData);
    }
    else {
        // enable port
        CMsgDlg msgDlg("请等待", "正在获取配方...");
        pEq->masterRecipeListRequest(0, [&, pEq](int status) -> void {
            if (status == SS_FAILED || status == SS_TIMEOUT) {
                CString strMsg;
                strMsg.Format(status == SS_FAILED ? _T("获取配方失败!") : _T("获取配方超时!"));
                msgDlg.DelayClose(3000);
                msgDlg.SetIcon(MSG_BOX_ERROR);
                msgDlg.SetTitle(_T("操作失败"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(-1);
            }
            else if (status == SS_COMPLETE) {
                CString strMsg;
                strMsg.Format(_T("获取配方完成!"));
                msgDlg.DelayClose(3000);
                msgDlg.SetIcon(MSG_BOX_SUCCEED);
                msgDlg.SetTitle(_T("操作成功"));
                msgDlg.SetMessage((LPTSTR)(LPCTSTR)strMsg);
                msgDlg.SetMarquee(FALSE, 0);
                msgDlg.SetCompleteCode(0);
                SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
                FillRecipeListToListCtrl(pRecipeList);
            }
        });
        // èŽ·å–é…æ–¹åˆ—è¡¨
        CMsgDlg msgDlg("请等待", "正在获取配方列表...");
        msgDlg.SetData((DWORD_PTR)this);
        msgDlg.SetDataEx((DWORD_PTR)pEq);
        msgDlg.BeginThread(SyncThreadFunction);
        msgDlg.DoModal();
    }
}
@@ -556,3 +535,95 @@
        FillRecipeListToListCtrl(pRecipeList);
    }
}
UINT CPageRecipe::SyncThreadFunction(LPVOID lpvData)
{
    CMsgDlg* pMsgDlg = (CMsgDlg*)lpvData;
    CPageRecipe* pPageRecipe = (CPageRecipe*)pMsgDlg->GetData();
    return pPageRecipe->SyncThreadFunctionInner(pMsgDlg);
}
UINT CPageRecipe::SyncThreadFunctionInner(CMsgDlg* pMsgDlg)
{
    SERVO::CEquipment* pEq = (SERVO::CEquipment*)pMsgDlg->GetDataEx();
    HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    int nStep = 0;
    pEq->masterRecipeListRequest(0, [&, pEq, pMsgDlg, hEvent](int status) -> void {
        Sleep(300);
        if (status == SS_FAILED || status == SS_TIMEOUT) {
            CString strMsg;
            strMsg.Format(status == SS_FAILED ? _T("获取配方列表失败!") : _T("获取配方列表超时!"));
            pMsgDlg->SetIcon(MSG_BOX_ERROR);
            pMsgDlg->SetTitle(_T("操作失败"));
            pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
            SetEvent(hEvent);
        }
        else if (status == SS_LIST_COMPLETE) {
            CString strMsg;
            strMsg.Format(_T("获取配方列表完成!"));
            pMsgDlg->SetTitle(_T("操作成功"));
            pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
            SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
            if (pRecipeList != nullptr && !pRecipeList->getIds().empty()) {
                nStep = 1;
            }
            SetEvent(hEvent);
        }
    });
    ::WaitForSingleObject(hEvent, INFINITE);
    if (nStep != 1) {
        pMsgDlg->SetIcon(MSG_BOX_SUCCEED);
        pMsgDlg->SetMarquee(FALSE, 0);
        pMsgDlg->SetCompleteCode(-1);
        pMsgDlg->DelayClose(3000);
    }
    ResetEvent(hEvent);
    // å‚数列表
    if (nStep == 1) {
        SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
        ASSERT(pRecipeList);
        auto& ids = pRecipeList->getIds();
        pMsgDlg->SetTitle(_T("正在获取参数"));
        for (auto item : ids) {
            CString strMsg;
            strMsg.Format(_T("正在获取配方 %d å‚æ•°..."), item.second);
            pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
            pEq->recipeParameterRequest(0, item.second, 0, [&, pEq, pMsgDlg](int status) -> void {
                Sleep(500);
                if (status == SS_FAILED || status == SS_TIMEOUT) {
                    CString strMsg;
                    strMsg.Format(status == SS_FAILED ? _T("获取配方 %d å‚数失败!") : _T("获取配方 %d å‚数超时!"), item.second);
                    pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
                    Sleep(300);
                    SetEvent(hEvent);
                }
                else if (status == SS_PARAMS_COMPLETE) {
                    CString strMsg;
                    strMsg.Format(_T("获取配方 %d å‚数完成!"), item.second);
                    pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
                    Sleep(300);
                    SetEvent(hEvent);
                }
                });
            ::WaitForSingleObject(hEvent, INFINITE);
            ResetEvent(hEvent);
        }
        pMsgDlg->SetIcon(MSG_BOX_SUCCEED);
        pMsgDlg->SetTitle(_T("操作完成"));
        pMsgDlg->SetCompleteCode(0);
        pMsgDlg->SetMarquee(FALSE, 0);
        pMsgDlg->DelayClose(3000);
    };
    SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
    FillRecipeListToListCtrl(pRecipeList);
    CloseHandle(hEvent);
    return 0;
}
SourceCode/Bond/Servo/PageRecipe.h
@@ -2,6 +2,8 @@
#include "afxdialogex.h"
#include "RecipeManager.h"
#include "ListCtrlEx.h"
#include "MsgDlg.h"
// CPageRecipe å¯¹è¯æ¡†
@@ -13,6 +15,10 @@
    CPageRecipe(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CPageRecipe();
public:
    static UINT SyncThreadFunction(LPVOID lpvData);
    UINT SyncThreadFunctionInner(CMsgDlg* pMsgDlg);
private:
    void InitListCtrlHeaderForMaster();
    void InitListCtrlHeaderForDevice();
SourceCode/Bond/Servo/RecipeManager.h
@@ -6,6 +6,8 @@
#include <mutex>
#include <unordered_map>
#include "Database.h"
#include "CParam.h"
// å•个设备配方映射信息
struct DeviceRecipe {
@@ -21,6 +23,23 @@
    std::string strDescription;  // é…æ–¹æè¿°
    std::string strCreateTime;   // åˆ›å»ºæ—¶é—´
    std::vector<DeviceRecipe> vecDeviceList;  // å…³è”的设备信息列表
    std::vector<CParam*> m_params;            // å‡ºç«™æ—¶è®°å½•参数
    void RecipeInfo::addIntParam(const char* pszName, const char* pszId, const char* pszUnit, int value)
    {
        CParam* pParam = new CParam(pszName, pszId, pszUnit, value);
        m_params.push_back(pParam);
    }
    void RecipeInfo::addDoubleParam(const char* pszName, const char* pszId, const char* pszUnit, double value)
    {
        CParam* pParam = new CParam(pszName, pszId, pszUnit, value);
        m_params.push_back(pParam);
    }
    std::vector<CParam*>& RecipeInfo::getParams()
    {
        return m_params;
    }
};
using RecipeMap = std::unordered_map<std::string, RecipeInfo>; // æŒ‰ PPID æ˜ å°„的配方表
SourceCode/Bond/Servo/Servo.vcxproj
@@ -214,6 +214,7 @@
    <ClInclude Include="CPageLinkSignal.h" />
    <ClInclude Include="CPageReport.h" />
    <ClInclude Include="CPageVarialbles.h" />
    <ClInclude Include="CParam.h" />
    <ClInclude Include="CReport.h" />
    <ClInclude Include="CRobotCmdContainerDlg.h" />
    <ClInclude Include="CRobotCmdTestDlg.h" />
@@ -368,6 +369,7 @@
    <ClCompile Include="CPageLinkSignal.cpp" />
    <ClCompile Include="CPageReport.cpp" />
    <ClCompile Include="CPageVarialbles.cpp" />
    <ClCompile Include="CParam.cpp" />
    <ClCompile Include="CReport.cpp" />
    <ClCompile Include="CRobotCmdContainerDlg.cpp" />
    <ClCompile Include="CRobotCmdTestDlg.cpp" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -180,6 +180,7 @@
    <ClCompile Include="CControlJob.cpp" />
    <ClCompile Include="CExpandableListCtrl.cpp" />
    <ClCompile Include="CControlJobDlg.cpp" />
    <ClCompile Include="CParam.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
@@ -366,6 +367,7 @@
    <ClInclude Include="SerializeUtil.h" />
    <ClInclude Include="CExpandableListCtrl.h" />
    <ClInclude Include="CControlJobDlg.h" />
    <ClInclude Include="CParam.h" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc" />