已修改9个文件
399 ■■■■■ 文件已修改
SourceCode/Bond/Servo/CGlass.cpp 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CLoadPort.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageGlassList.cpp 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ProcessJob.cpp 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ProcessJob.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CGlass.cpp
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "CGlass.h"
#include "Log.h"
@@ -384,7 +384,7 @@
        if (s.size() > maxLen) s.resize(maxLen);
    }
    // —— 时间戳 & 工具 ——
    // 状态时间戳:排队/开始/结束
    void CGlass::markQueued() 
    {
        m_state = GlsState::Queued;
@@ -432,29 +432,44 @@
        return strOut;
    }
    // ========== SV数据管理接口实现 ==========
    // ========== SV数据口袋 ==========
    static constexpr size_t MAX_SV_DATA_KEEP = 4800;
    void CGlass::addSVData(int machineId, const std::string& dataType, const SVDataItem& dataItem) {
        m_svDatas[machineId][dataType].push_back(dataItem);
        auto& vec = m_svDatas[machineId][dataType];
        vec.push_back(dataItem);
        if (vec.size() > MAX_SV_DATA_KEEP) {
            vec.erase(vec.begin(), vec.begin() + (vec.size() - MAX_SV_DATA_KEEP));
        }
    }
    void CGlass::addSVData(int machineId, const std::string& dataType, double value) {
        auto now = std::chrono::system_clock::now();
        m_svDatas[machineId][dataType].emplace_back(now, value);
        auto& vec = m_svDatas[machineId][dataType];
        vec.emplace_back(now, value);
        if (vec.size() > MAX_SV_DATA_KEEP) {
            vec.erase(vec.begin(), vec.begin() + (vec.size() - MAX_SV_DATA_KEEP));
        }
    }
    void CGlass::addSVData(int machineId, const std::string& dataType, int64_t timestamp, double value) {
        // 将int64_t时间戳转换为system_clock::time_point
        // int64_t时间转成system_clock::time_point
        std::chrono::system_clock::time_point timePoint{
            std::chrono::milliseconds(timestamp)  // 假设timestamp是毫秒
            // 如果是秒,使用:std::chrono::seconds(timestamp)
            std::chrono::milliseconds(timestamp)  // timestamp精度:毫秒
            // 如果需要精度更高,可能要使用其他时间单位,如std::chrono::seconds(timestamp)
        };
        m_svDatas[machineId][dataType].emplace_back(timePoint, value);
        auto& vec = m_svDatas[machineId][dataType];
        vec.emplace_back(timePoint, value);
        if (vec.size() > MAX_SV_DATA_KEEP) {
            vec.erase(vec.begin(), vec.begin() + (vec.size() - MAX_SV_DATA_KEEP));
        }
    }
    void CGlass::addSVData(int machineId, const std::string& dataType, const std::vector<SVDataItem>& dataItems) {
        auto& dataList = m_svDatas[machineId][dataType];
        dataList.insert(dataList.end(), dataItems.begin(), dataItems.end());
        if (dataList.size() > MAX_SV_DATA_KEEP) {
            dataList.erase(dataList.begin(), dataList.begin() + (dataList.size() - MAX_SV_DATA_KEEP));
        }
    }
    std::vector<SVDataItem> CGlass::getSVData(int machineId, const std::string& dataType) const {
@@ -515,7 +530,6 @@
        auto machineIt = m_svDatas.find(machineId);
        if (machineIt != m_svDatas.end()) {
            machineIt->second.erase(dataType);
            // 如果该机器没有其他数据了,也清除机器条目
            if (machineIt->second.empty()) {
                m_svDatas.erase(machineIt);
            }
SourceCode/Bond/Servo/CLoadPort.cpp
@@ -364,6 +364,7 @@
        // 模拟测试
        /*
        if (m_nIndex == 0) {
            static int ii = 0;
            ii++;
@@ -394,6 +395,7 @@
                LOGI("<CLoadPort>Port2载入模拟数据, id:CID1004 map: 0xff");
            }
        }
        */
    }
    void CLoadPort::serialize(CArchive& ar)
SourceCode/Bond/Servo/CMaster.cpp
@@ -138,128 +138,147 @@
    int CMaster::init()
    {
        const ULONGLONG boot_master_begin = GetTickCount64();
        LOGI("<Master>正在初始化...");
        LOGI("[BOOT][MASTER] init begin");
        //     cclink
        if (m_cclink.Connect(CC_LINK_IE_CONTROL_CHANNEL(1)) != 0) {
        const ULONGLONG boot_cclink_begin = GetTickCount64();
        const int cc_ret = m_cclink.Connect(CC_LINK_IE_CONTROL_CHANNEL(1));
        LOGI("[BOOT][MASTER] CC-Link connect ret=%d, cost=%llu ms",
            cc_ret,
            (unsigned long long)(GetTickCount64() - boot_cclink_begin));
        if (cc_ret != 0) {
            LOGE("连接CC-Link失败.");
        }
        else {
            LOGI("连接CC-Link成功.");
            BoardVersion version{};
            int nRet = m_cclink.GetBoardVersion(version);
            if (nRet == 0) {
                LOGD("版本信息:%s.", version.toString().c_str());
            }
            else {
                LOGE("获取CC-Link版本信息失败.");
                LOGI("连接CC-Link成功.");
                BoardVersion version{};
                int nRet = m_cclink.GetBoardVersion(version);
                if (nRet == 0) {
                    LOGD("版本信息:%s.", version.toString().c_str());
                }
                else {
                    LOGE("获取CC-Link版本信息失败.");
                }
                BoardStatus status;
                nRet = m_cclink.GetBoardStatus(status);
                if (nRet == 0) {
                    LOGD("状态:%s.", status.toString().c_str());
                }
                else {
                    LOGE("获取CC-Link状态失败.");
                }
            }
            BoardStatus status;
            nRet = m_cclink.GetBoardStatus(status);
            if (nRet == 0) {
                LOGD("状态:%s.", status.toString().c_str());
            // 初始化添加各子设备
            CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
            CBonder* pBonder1, * pBonder2;
            CEFEM* pEfem;
            CArm* pArm;
            CArmTray* pArmTray1, * pArmTray2;
            CFliper* pFliper;
            CVacuumBake* pVacuumBake;
            CAligner* pAligner;
            CBakeCooling* pBakeCooling;
            CMeasurement* pMeasurement;
            pPort1 = addLoadPort(0);
            pPort2 = addLoadPort(1);
            pPort3 = addLoadPort(2);
            pPort4 = addLoadPort(3);
            pEfem = addEFEM();
            pArm = addArm();
            pArmTray1 = addArmTray(0);
            pArmTray2 = addArmTray(1);
            pFliper = addFliper();
            pVacuumBake = addVacuumBake();
            pAligner = addAligner();
            pBonder1 = addBonder(0);
            pBonder2 = addBonder(1);
            pBakeCooling = addBakeCooling();
            pMeasurement = addMeasurement();
            ASSERT(pEfem);
            ASSERT(pFliper);
            ASSERT(pVacuumBake);
            ASSERT(pAligner);
            ASSERT(pBonder1);
            ASSERT(pBonder2);
            ASSERT(pBakeCooling);
            ASSERT(pMeasurement);
            pEfem->setPort(0, pPort1);
            pEfem->setPort(1, pPort2);
            pEfem->setPort(2, pPort3);
            pEfem->setPort(3, pPort4);
            pEfem->setFliper(pFliper);
            pEfem->setAligner(pAligner);
            pEfem->setArmTray(0, pArmTray1);
            pEfem->setArmTray(1, pArmTray2);
            pPort1->setArm(pArm);
            pPort2->setArm(pArm);
            pPort3->setArm(pArm);
            pPort4->setArm(pArm);
            pArmTray1->setArm(pArm);
            pArmTray2->setArm(pArm);
            pFliper->setArm(pArm);
            pVacuumBake->setArm(pArm);
            pAligner->setArm(pArm);
            pBonder1->setArm(pArm);
            pBonder2->setArm(pArm);
            pBakeCooling->setArm(pArm);
            pMeasurement->setArm(pArm);
            connectEquipments();
            // 读缓存数据
            const ULONGLONG boot_cache_begin = GetTickCount64();
            const ULONGLONG boot_read_begin = GetTickCount64();
            readCache();
            LOGI("[BOOT][MASTER] readCache finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_read_begin));
            const ULONGLONG boot_state_begin = GetTickCount64();
            loadState();
            LOGI("[BOOT][MASTER] loadState finished, cost=%llu ms", (unsigned long long)(GetTickCount64() - boot_state_begin));
            if (m_listener.onControlJobChanged) {
                notifyControlJobChanged();
            }
            else {
                LOGE("获取CC-Link状态失败.");
            }
            LOGI("[BOOT][MASTER] cache/state loaded, cost=%llu ms (since init %llu ms)",
                (unsigned long long)(GetTickCount64() - boot_cache_begin),
                (unsigned long long)(GetTickCount64() - boot_master_begin));
            // 定时器
            g_pMaster = this;
            SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
            // 调度线程
            m_hDispatchThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::DispatchThreadFunction, this,
                0, &m_nDispatchThreadAddr);
            // 监控bit线程
            m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
                0, &m_nReadBitsThreadAddr);
            // 曲线服务
            CreateDAQBridgeServer();
            LOGI("<Master>初始化完成.");
            LOGI("[BOOT][MASTER] init finished, total cost=%llu ms",
                (unsigned long long)(GetTickCount64() - boot_master_begin));
            return 0;
        }
        // 初始化添加各子设备
        CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
        CBonder* pBonder1, * pBonder2;
        CEFEM* pEfem;
        CArm* pArm;
        CArmTray* pArmTray1, * pArmTray2;
        CFliper* pFliper;
        CVacuumBake* pVacuumBake;
        CAligner* pAligner;
        CBakeCooling* pBakeCooling;
        CMeasurement* pMeasurement;
        pPort1 = addLoadPort(0);
        pPort2 = addLoadPort(1);
        pPort3 = addLoadPort(2);
        pPort4 = addLoadPort(3);
        pEfem = addEFEM();
        pArm = addArm();
        pArmTray1 = addArmTray(0);
        pArmTray2 = addArmTray(1);
        pFliper = addFliper();
        pVacuumBake = addVacuumBake();
        pAligner = addAligner();
        pBonder1 = addBonder(0);
        pBonder2 = addBonder(1);
        pBakeCooling = addBakeCooling();
        pMeasurement = addMeasurement();
        ASSERT(pEfem);
        ASSERT(pFliper);
        ASSERT(pVacuumBake);
        ASSERT(pAligner);
        ASSERT(pBonder1);
        ASSERT(pBonder2);
        ASSERT(pBakeCooling);
        ASSERT(pMeasurement);
        pEfem->setPort(0, pPort1);
        pEfem->setPort(1, pPort2);
        pEfem->setPort(2, pPort3);
        pEfem->setPort(3, pPort4);
        pEfem->setFliper(pFliper);
        pEfem->setAligner(pAligner);
        pEfem->setArmTray(0, pArmTray1);
        pEfem->setArmTray(1, pArmTray2);
        pPort1->setArm(pArm);
        pPort2->setArm(pArm);
        pPort3->setArm(pArm);
        pPort4->setArm(pArm);
        pArmTray1->setArm(pArm);
        pArmTray2->setArm(pArm);
        pFliper->setArm(pArm);
        pVacuumBake->setArm(pArm);
        pAligner->setArm(pArm);
        pBonder1->setArm(pArm);
        pBonder2->setArm(pArm);
        pBakeCooling->setArm(pArm);
        pMeasurement->setArm(pArm);
        connectEquipments();
        // 读缓存数据
        readCache();
        loadState();
        if (m_listener.onControlJobChanged) {
            m_listener.onControlJobChanged(this);
        }
        // 定时器
        g_pMaster = this;
        SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
        // 调度线程
        m_hDispatchThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::DispatchThreadFunction, this,
            0, &m_nDispatchThreadAddr);
        // 监控bit线程
        m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
            0, &m_nReadBitsThreadAddr);
        // 曲线服务
        CreateDAQBridgeServer();
        LOGI("<Master>初始化完成.");
        return 0;
    }
    int CMaster::term()
    {
@@ -1675,6 +1694,14 @@
            }
        };
        listener.onSVDataReport = [&](void* pEquipment, void* pData) {
            const bool allowSvLog =
                (m_state == MASTERSTATE::RUNNING ||
                    m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER ||
                    m_state == MASTERSTATE::RUNNING_BATCH ||
                    m_state == MASTERSTATE::STARTING);
            if (!allowSvLog) {
                return;
            }
            CSVData* pSVData = (CSVData*)pData;
            auto rawData = pSVData->getSVRawData();
            std::vector<CParam> params;
@@ -2896,7 +2923,7 @@
        this->saveState();
        if (m_listener.onControlJobChanged) {
            m_listener.onControlJobChanged(this);
            notifyControlJobChanged();
        }
        return (int)m_processJobs.size();
@@ -2956,7 +2983,7 @@
        m_pControlJob->setPJs(temps);
        this->saveState();
        if (m_listener.onControlJobChanged) {
            m_listener.onControlJobChanged(this);
            notifyControlJobChanged();
        }
@@ -3077,7 +3104,7 @@
        }
        if (pausedAny && m_listener.onControlJobChanged) {
            // 通知应用层刷新 UI/按钮状态
            m_listener.onControlJobChanged(this);
            notifyControlJobChanged();
        }
        if (pausedAny && !m_bPauseAlarmRaised) {
            std::string desc = CToolUnits::formatString("<PauseEvent CEID=%u>", ceid);
@@ -3392,7 +3419,7 @@
        saveState();
        if (m_listener.onControlJobChanged) {
            m_listener.onControlJobChanged(this);
            notifyControlJobChanged();
        }
        return true;
@@ -3429,7 +3456,7 @@
        saveState();
        if (m_listener.onControlJobChanged) {
            m_listener.onControlJobChanged(this);
            notifyControlJobChanged();
        }
        return true;
SourceCode/Bond/Servo/CMaster.h
@@ -296,5 +296,10 @@
    private:
        Collector* m_pCollector = nullptr;
        void CreateDAQBridgeServer();
        inline void notifyControlJobChanged() {
            if (m_listener.onControlJobChanged) {
                m_listener.onControlJobChanged(this);
            }
        }
    };
}
SourceCode/Bond/Servo/CPageGlassList.cpp
@@ -1088,9 +1088,10 @@
{
    CDialogEx::OnInitDialog();
    // 定时器:1=初始化订阅,2=周期刷新(只增量)
    // 定时器:1=初始化订阅,2=周期刷新(只增量),3=延迟加载首屏数据
    SetTimer(1, 3000, nullptr);
    SetTimer(2, 2000, nullptr);
    SetTimer(3, 10, nullptr);
    // 下拉框控件
    InitStatusCombo();
@@ -1140,7 +1141,6 @@
    m_listCtrl.SetPopupFullTextColumns({ 11, 12 });
    Resize();
    OnBnClickedButtonSearch(); // 触发一次查询与首屏填充
    return TRUE;  // return TRUE unless you set the focus to a control
}
@@ -1200,6 +1200,10 @@
    else if (nIDEvent == 2) {
        UpdateWipData();  // 只做增量,不重建
    }
    else if (nIDEvent == 3) {
        KillTimer(3);
        OnBnClickedButtonSearch(); // 延迟首屏查询,避免卡住 OnInitDialog
    }
    CDialogEx::OnTimer(nIDEvent);
}
@@ -1229,6 +1233,8 @@
void CPageGlassList::OnBnClickedButtonSearch()
{
    CWaitCursor wait; // 显示等待光标,提示正在加载
    // 获取关键字输入框内容
    CString strKeyword;
    GetDlgItemText(IDC_EDIT_KEYWORD, strKeyword);
@@ -2059,4 +2065,4 @@
    double randomNoise = (rand() % 100 - 50) / 100.0 * variation * 0.3;  // 随机噪声
    
    return baseValue + timeTrend + randomNoise;
}
}
SourceCode/Bond/Servo/Model.cpp
@@ -184,6 +184,7 @@
int CModel::init()
{
    const ULONGLONG boot_model_begin = GetTickCount64();
    CString strIniFile;
    CString strUnitId;
    strIniFile.Format(_T("%s\\ServoConfiguration.ini"), (LPTSTR)(LPCTSTR)m_strWorkDir);
@@ -214,6 +215,7 @@
    CLog::GetLog()->SetLogsDir(strLogDir);
    CLog::GetLog()->SetEquipmentId((LPTSTR)(LPCTSTR)strUnitId);
    LOGI("\r\n\r\n~~~ Prog Start! ~~~");
    LOGI("[BOOT][MODEL] init begin");
    SECSListener listener;
@@ -354,6 +356,23 @@
        for (auto p : pjs) {
            LOGI("<Model>onPRJobMultiCreate %s %s", p->id().c_str(), p->recipeSpec().c_str());
        }
        auto rejectAll = [&](uint32_t code, const std::string& msg) -> int {
            LOGW("<Model>onPRJobMultiCreate rejected: %s", msg.c_str());
            for (auto p : pjs) {
                if (p != nullptr) p->addIssue(code, msg);
            }
            return -1;
        };
        // 单 PJ 模式:只接受 1 条且当前无在制 PJ
        if (pjs.size() != 1) {
            return rejectAll(1200, "Only 1 ProcessJob supported (single-PJ mode)");
        }
        if (!m_master.isProcessJobsEmpty()) {
            return rejectAll(1201, "ProcessJob exists, cannot create new in single-PJ mode");
        }
        int nRet = m_master.setProcessJobs(pjs);
        auto processJobs = m_master.getProcessJobs();
        std::vector<SERVO::CVariable> vars;
@@ -402,6 +421,8 @@
    }
    strVarialbleFile.Format(_T("%s\\HsmsPassive.cache"), (LPTSTR)(LPCTSTR)m_strWorkDir);
    m_hsmsPassive.loadCacheFromFile(strVarialbleFile);
    LOGI("[BOOT][MODEL] HSMS config loaded, cost=%llu ms",
        (unsigned long long)(GetTickCount64() - boot_model_begin));
    SERVO::MasterListener masterListener;
@@ -905,6 +926,8 @@
    char szBuffer[MAX_PATH];
    sprintf_s(szBuffer, MAX_PATH, "%s\\AlarmList.csv", (LPTSTR)(LPCTSTR)m_strWorkDir);
    alarmManager.readAlarmFile(szBuffer);
    LOGI("[BOOT][MODEL] Alarm list loaded, cost=%llu ms",
        (unsigned long long)(GetTickCount64() - boot_model_begin));
    // Glass数据库
@@ -913,6 +936,8 @@
    GlassLogDb::Init(path);
    LOGI("[BOOT][MODEL] init finished, total cost=%llu ms",
        (unsigned long long)(GetTickCount64() - boot_model_begin));
    return 0;
}
SourceCode/Bond/Servo/ProcessJob.cpp
@@ -75,6 +75,11 @@
        return m_issues;
    }
    void CProcessJob::addIssue(uint32_t code, const std::string& msg)
    {
        m_issues.push_back({ code, msg });
    }
    bool CProcessJob::validate(const IResourceView& rv)
    {
        m_issues.clear();
@@ -83,10 +88,6 @@
        auto add = [&](uint32_t code, std::string msg) {
            m_issues.push_back({ code, std::move(msg) });
        };
        if (!rv.isProcessJobsEmpty()) {
            add(1000, "ProcessJobs Conflict!");
        }
        // —— 基本 / 标识 ——
        if (m_pjId.empty())            add(1001, "PJID empty");
SourceCode/Bond/Servo/ProcessJob.h
@@ -133,6 +133,7 @@
        // 返回问题清单(空=通过)
        bool validate(const IResourceView& rv);
        const std::vector<ValidationIssue>& issues() const;
        void addIssue(uint32_t code, const std::string& msg);
        // —— 状态机(带守卫)——
        bool queue();           // NoState -> Queued
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -363,6 +363,8 @@
BOOL CServoDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    const ULONGLONG boot_ui_begin = GetTickCount64();
    CWaitCursor wait; // 整个初始化期显示等待光标,避免用户误以为卡死
    // 将“关于...”菜单项添加到系统菜单中。
@@ -398,13 +400,19 @@
    // model init
    const ULONGLONG boot_model_begin = GetTickCount64();
    theApp.m_model.init();
    LOGI("[BOOT][UI] m_model.init finished, cost=%llu ms (since OnInit start %llu ms)",
        (unsigned long long)(GetTickCount64() - boot_model_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    SetTimer(TIMER_ID_LOGIN, 1500, nullptr);
    LOGI("[BOOT][UI] after model.init, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // 菜单
    CMenu menu;
    menu.LoadMenu(IDR_MENU_APP);
    SetMenu(&menu);
    LOGI("[BOOT][UI] menu loaded, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // toolbar
@@ -417,23 +425,46 @@
    ASSERT(hMenu);
    ::EnableMenuItem(hMenu, ID_OPEATOR_SWITCH, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
    m_pTopToolbar->GetBtn(IDC_BUTTON_JOBS)->EnableWindow(TRUE);
    LOGI("[BOOT][UI] toolbar created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // Tab
    const ULONGLONG boot_pages_begin = GetTickCount64();
    m_pPageGraph1 = new CPageGraph1();
    m_pPageGraph1->Create(IDD_PAGE_GRAPH1, this);
    LOGI("[BOOT][UI] page Graph1 created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    m_pPageGraph2 = new CPageGraph2();
    m_pPageGraph2->Create(IDD_PAGE_GRAPH2, this);
    LOGI("[BOOT][UI] page Graph2 created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    m_pPageGlassList = new CPageGlassList();
    m_pPageGlassList->Create(IDD_PAGE_GLASS_LIST, this);
    LOGI("[BOOT][UI] page GlassList created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    m_pPageRecipe = new CPageRecipe();
    m_pPageRecipe->Create(IDD_PAGE_RECIPE, this);
    LOGI("[BOOT][UI] page Recipe created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    m_pPageAlarm = new CPageAlarm();
    m_pPageAlarm->Create(IDD_DIALOG_ALARM, this);
    LOGI("[BOOT][UI] page Alarm created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    m_pPageLog = new CPageLog();
    m_pPageLog->Create(IDD_DIALOG_LOG, this);
    LOGI("[BOOT][UI] page Log created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    m_pPageTransferLog = new CPageTransferLog();
    m_pPageTransferLog->Create(IDD_PAGE_TRANSFER_LOG, this);
    LOGI("[BOOT][UI] page TransferLog created, cost=%llu ms (elapsed=%llu ms)",
        (unsigned long long)(GetTickCount64() - boot_pages_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    CHmTab* m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd);
    m_pTab->SetPaddingLeft(20);
@@ -448,6 +479,7 @@
    m_pTab->SetCurSel(0);
    m_pTab->SetBkgndColor(RGB(222, 222, 222));
    ShowChildPage(0);
    LOGI("[BOOT][UI] pages/tabs created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // 读取面板宽
    CString strIniFile;
@@ -467,11 +499,13 @@
    m_pPanelAttributes = new CPanelAttributes();
    m_pPanelAttributes->Create(IDD_PANEL_ATTRIBUTES, this);
    
    LOGI("[BOOT][UI] panels created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // statusbar
    m_pMyStatusbar = new CMyStatusbar();
    m_pMyStatusbar->Create(IDD_STATUSBAR, this);
    m_pMyStatusbar->ShowWindow(SW_SHOW);
    LOGI("[BOOT][UI] statusbar created, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
@@ -488,10 +522,23 @@
    InitRxWindows();
    Resize();
    // 加载历史缓存提示
    {
        CWaitCursor wait;
        if (m_pMyStatusbar != nullptr) {
            m_pMyStatusbar->setRunTimeText(_T("正在加载历史缓存..."));
            m_pMyStatusbar->UpdateWindow();
        }
        LOGI("[BOOT][UI] before master.init, elapsed=%llu ms", (unsigned long long)(GetTickCount64() - boot_ui_begin));
    // 相当于延时调用master的初始化
    const ULONGLONG boot_master_begin = GetTickCount64();
    theApp.m_model.m_master.init();
    LOGI("[BOOT][UI] m_master.init finished, cost=%llu ms (since OnInit start %llu ms)",
        (unsigned long long)(GetTickCount64() - boot_master_begin),
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    theApp.m_model.loadPortParams();
    }
    // 初始化master以后需要控件绑定数据
@@ -504,6 +551,9 @@
    //SystemLogManager::getInstance.
    LOGI("[BOOT][UI] OnInitDialog finished, total cost=%llu ms",
        (unsigned long long)(GetTickCount64() - boot_ui_begin));
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}