| | |
| | | #include "SGMeasurementDlg.h" |
| | | #include "afxdialogex.h" |
| | | #include "SGIF.h" |
| | | #include "Logger.h" |
| | | |
| | | #ifdef _DEBUG |
| | | #define new DEBUG_NEW |
| | |
| | | // 定时器相关宏定义 |
| | | #define TIMER_INTERVAL_MS 500 |
| | | #define TIMER_ID_OUTPUT_UPDATE 1 |
| | | |
| | | // 计时宏定义 |
| | | #define MEASURE_FUNC_START() \ |
| | | clock_t __startClock = clock(); |
| | | |
| | | #define MEASURE_FUNC_END() \ |
| | | do { \ |
| | | clock_t __endClock = clock(); \ |
| | | double __elapsedMs = 1000.0 * (__endClock - __startClock) / CLOCKS_PER_SEC; \ |
| | | CString __strElapsed; \ |
| | | __strElapsed.Format(_T("%s 执行耗时:%.1f ms"), _T(__FUNCTION__), __elapsedMs); \ |
| | | AppendLogLineRichStyled(__strElapsed, LOG_COLOR_SUCCESS); \ |
| | | } while (0) |
| | | |
| | | class CAboutDlg : public CDialogEx |
| | | { |
| | |
| | | , m_dOutValues{ 0.0, 0.0, 0.0, 0.0 } |
| | | , m_nUseTrigger(0) |
| | | , m_nSavePointCount(100000) |
| | | , m_fJumpThreshold(1.0f) |
| | | , m_fJumpThreshold(0.2f) |
| | | , m_nJumpWindow(3) |
| | | , m_nValleyMargin(0) |
| | | , m_nMinGlass1Count(10) |
| | |
| | | Shell_NotifyIcon(NIM_DELETE, &m_trayIconData); |
| | | m_bTrayIconCreated = FALSE; |
| | | } |
| | | |
| | | m_plcListener.Stop(); |
| | | |
| | | DestroyWindow(); |
| | | CDialogEx::OnClose(); |
| | |
| | | m_editLog.ReplaceSel(_T("")); // 删除 |
| | | } |
| | | |
| | | void CSGMeasurementDlg::AppendLogLineRichStyled(const CString& content, COLORREF color /*= RGB(0, 0, 0)*/) |
| | | void CSGMeasurementDlg::AppendLogLineRichStyled(const CString& strContent, COLORREF color /*= RGB(0, 0, 0)*/) |
| | | { |
| | | if (!::IsWindow(GetSafeHwnd()) || !::IsWindow(m_editLog.GetSafeHwnd())) { |
| | | return; |
| | |
| | | m_editLog.SetSelectionCharFormat(cfTime); |
| | | m_editLog.ReplaceSel(strTimestamp); |
| | | |
| | | // 生成日志级别标签 |
| | | CString strLevel; |
| | | if (color == LOG_COLOR_WARNING) { |
| | | strLevel = _T("[警告]"); |
| | | } |
| | | else if (color == LOG_COLOR_ERROR) { |
| | | strLevel = _T("[错误]"); |
| | | } |
| | | else if (color == LOG_COLOR_NORMAL) { |
| | | strLevel = _T("[信息]"); |
| | | } |
| | | else if (color == LOG_COLOR_SUCCESS) { |
| | | strLevel = _T("[成功]"); |
| | | } |
| | | else { |
| | | strLevel = _T("[未知]"); |
| | | } |
| | | |
| | | // 插入日志正文(传入颜色) |
| | | CHARFORMAT2 cfMsg = {}; |
| | | cfMsg.cbSize = sizeof(cfMsg); |
| | | cfMsg.dwMask = CFM_COLOR; |
| | | cfMsg.crTextColor = color; |
| | | m_editLog.SetSelectionCharFormat(cfMsg); |
| | | m_editLog.ReplaceSel(content + _T("\r\n")); |
| | | m_editLog.ReplaceSel(strLevel + strContent + _T("\r\n")); |
| | | |
| | | // 限制最大行数 |
| | | TrimRichEditLineLimit(100); |
| | | |
| | | // 拼接完整日志行 |
| | | CString strFullLogLine; |
| | | strFullLogLine.Format(_T("%s %s"), strLevel, strContent); |
| | | |
| | | // 写入日志文件 |
| | | // LOG_LINE(strFullLogLine); |
| | | } |
| | | |
| | | void CSGMeasurementDlg::HighlightAllMatches(const CString& strSearch, COLORREF clrHighlight/* = RGB(255, 165, 0)*/) |
| | |
| | | return false; |
| | | } |
| | | |
| | | RC nRet = SGIF_CloseDevice(DeviceID); |
| | | if (nRet == RC_OK) { |
| | | if (m_bSaving) { |
| | | m_bSaving = FALSE; |
| | | nRet = SGIF_DataStorageStop(DeviceID); |
| | | if (nRet == RC_OK) { |
| | | AppendLogLineRichStyled(_T("数据存储已停止。"), LOG_COLOR_SUCCESS); |
| | | } |
| | | else { |
| | | CString strError; |
| | | strError.Format(_T("停止数据存储失败,错误码:%#X"), nRet); |
| | | AppendLogLineRichStyled(strError, LOG_COLOR_ERROR); |
| | | } |
| | | } |
| | | // 停止定时器,避免在断开后仍尝试更新输出数据 |
| | | KillTimer(TIMER_ID_OUTPUT_UPDATE); |
| | | |
| | | // 先停止数据存储(如果正在进行) |
| | | RC nRet; |
| | | if (m_bConnected && m_bSaving) { |
| | | nRet = SGIF_DataStorageStop(DeviceID); |
| | | if (nRet == RC_OK) { |
| | | m_bSaving = FALSE; |
| | | AppendLogLineRichStyled(_T("数据存储已停止。"), LOG_COLOR_SUCCESS); |
| | | } |
| | | else { |
| | | CString strError; |
| | | strError.Format(_T("停止数据存储失败,错误码:%#X"), nRet); |
| | | AppendLogLineRichStyled(strError, LOG_COLOR_ERROR); |
| | | } |
| | | } |
| | | |
| | | // 断开设备连接 |
| | | nRet = SGIF_CloseDevice(DeviceID); |
| | | if (nRet == RC_OK) { |
| | | AppendLogLineRichStyled(_T("断开连接成功!"), LOG_COLOR_SUCCESS); |
| | | |
| | | m_bConnected = FALSE; |
| | | UpdateControlStatus(FALSE, FALSE); |
| | | KillTimer(TIMER_ID_OUTPUT_UPDATE); |
| | | return true; |
| | | } |
| | | else { |
| | | CString strError; |
| | | strError.Format(_T("断开连接失败,错误码:%#X"), nRet); |
| | | AppendLogLineRichStyled(strError, LOG_COLOR_ERROR); |
| | | AppendLogLineRichStyled(_T("保持当前状态,断开失败。"), LOG_COLOR_ERROR); |
| | | |
| | | UpdateControlStatus(m_bConnected, m_bSaving); |
| | | return false; |
| | |
| | | |
| | | void CSGMeasurementDlg::CleanInvalidValuesInPlace(int nOutNo, std::vector<float>& vecData, float fInvalid/* = -999.0f*/) |
| | | { |
| | | MEASURE_FUNC_START(); |
| | | |
| | | // 找到第一个有效值 |
| | | auto itStart = std::find_if(vecData.begin(), vecData.end(), [=](float v) { return v > fInvalid; }); |
| | | |
| | |
| | | else { |
| | | vecData.clear(); |
| | | } |
| | | |
| | | MEASURE_FUNC_END(); |
| | | } |
| | | |
| | | bool CSGMeasurementDlg::SplitGlassSegments(int nOutNo, const std::vector<float>& vecData, std::vector<float>& vecGlass1, std::vector<float>& vecGlass2, float fJumpThreshold /*= 0.2f*/, int nWindow /*= 3*/, int nValleyMargin /*= 0*/, int nMinGlass1Count /*= 10*/) |
| | | bool CSGMeasurementDlg::SplitGlassSegments(int nOutNo, const std::vector<float>& vecData, std::vector<float>& vecGlass1, std::vector<float>& vecGlass2, float fJumpThreshold /*= 0.2f*/, int nWindow /*= 3*/, int nValleyMargin /*= 0*/, int nMinGlassCount /*= 10*/) |
| | | { |
| | | const int n = static_cast<int>(vecData.size()); |
| | | if (n < 2 * nWindow + 1 + nMinGlass1Count) { |
| | | CString strError; |
| | | strError.Format(_T("OUT%d: 数据量不足,至少需要 %d 个点才能进行切割。"), nOutNo, 2 * nWindow + 1 + nMinGlass1Count); |
| | | AppendLogLineRichStyled(strError, LOG_COLOR_WARNING); |
| | | MEASURE_FUNC_START(); |
| | | |
| | | CString strLog; |
| | | const int nTotal = static_cast<int>(vecData.size()); |
| | | |
| | | if (nTotal < 2 * nWindow + 1 + nMinGlassCount) { |
| | | strLog.Format(_T("OUT%d: 数据量不足,至少需要 %d 个点才能切割。"), nOutNo, 2 * nWindow + 1 + nMinGlassCount); |
| | | AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING); |
| | | return false; |
| | | } |
| | | |
| | | int nValleyIdx = -1; |
| | | for (int i = nWindow; i < n - nWindow - nMinGlass1Count; ++i) { |
| | | float fDelta = std::fabs(vecData[i + nWindow] - vecData[i - nWindow]); |
| | | if (fDelta > fJumpThreshold) { |
| | | // 找 valley 点(稍微往后跳几步以避开边缘抖动) |
| | | int nSearchStart = i + nWindow + 2; |
| | | int nSearchEnd = min(nSearchStart + 10, n); |
| | | // 从中间向两边查找 valley 候选点 |
| | | int nMid = nTotal / 2; |
| | | int nValleyLeft = -1, nValleyRight = -1; |
| | | |
| | | auto itValley = std::min_element(vecData.begin() + nSearchStart, vecData.begin() + nSearchEnd, |
| | | [](float a, float b) { |
| | | return (a > -900.0f && b > -900.0f) ? a < b : false; |
| | | }); |
| | | |
| | | if (itValley != vecData.begin() + nSearchEnd) { |
| | | nValleyIdx = static_cast<int>(std::distance(vecData.begin(), itValley)); |
| | | break; |
| | | } |
| | | // 向左查找 valley |
| | | for (int i = nMid; i >= nWindow; --i) { |
| | | float fDelta = std::fabs(vecData[i] - vecData[i - nWindow]); |
| | | if (fDelta > fJumpThreshold && |
| | | vecData[i] < vecData[i - 1] && |
| | | vecData[i] < vecData[i + 1]) { |
| | | nValleyLeft = i; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (nValleyIdx < 0 || nValleyIdx < nMinGlass1Count) { |
| | | AppendLogLineRichStyled(_T("未找到合适 valley 点,或 valley 太靠前。"), LOG_COLOR_WARNING); |
| | | return false; |
| | | // 向右查找 valley |
| | | for (int i = nMid; i <= nTotal - nWindow - 2; ++i) { |
| | | float fDelta = std::fabs(vecData[i + nWindow] - vecData[i]); |
| | | if (fDelta > fJumpThreshold && |
| | | vecData[i] < vecData[i - 1] && |
| | | vecData[i] < vecData[i + 1]) { |
| | | nValleyRight = i; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // 从 valley 处开始切割,或者往后偏移 |
| | | int nCutStart = min(nValleyIdx + nValleyMargin, n); |
| | | vecGlass1.assign(vecData.begin(), vecData.begin() + nCutStart); |
| | | vecGlass2.assign(vecData.begin() + nCutStart, vecData.end()); |
| | | // 选定 valley 点 |
| | | int nValleyIdx = -1; |
| | | if (nValleyLeft > 0 && nValleyRight > 0) { |
| | | nValleyIdx = (vecData[nValleyLeft] < vecData[nValleyRight]) ? nValleyLeft : nValleyRight; |
| | | } |
| | | else if (nValleyLeft > 0) { |
| | | nValleyIdx = nValleyLeft; |
| | | } |
| | | else if (nValleyRight > 0) { |
| | | nValleyIdx = nValleyRight; |
| | | } |
| | | |
| | | // fallback: valley 未找到,使用中间切割法 |
| | | if (nValleyIdx < 0) { |
| | | AppendLogLineRichStyled(_T("未找到 valley 跳变点,使用中间位置切割。"), LOG_COLOR_WARNING); |
| | | nValleyIdx = nMid; |
| | | } |
| | | |
| | | // 应用切割位置,限制边界 |
| | | int nCutPos = max(1, min(nTotal - 1, nValleyIdx + nValleyMargin)); |
| | | |
| | | vecGlass1.assign(vecData.begin(), vecData.begin() + nCutPos); |
| | | vecGlass2.assign(vecData.begin() + nCutPos, vecData.end()); |
| | | |
| | | int nGlass1Count = static_cast<int>(vecGlass1.size()); |
| | | int nGlass2Count = static_cast<int>(vecGlass2.size()); |
| | | |
| | | // 日志输出 |
| | | CString strLog; |
| | | strLog.Format(_T("OUT%d: 切割成功,第一片玻璃数据量 %d,第二片玻璃数据量 %d。"), nOutNo, nGlass1Count, nGlass2Count); |
| | | strLog.Format(_T("OUT%d: 切割成功,第一片玻璃 %d 点,第二片玻璃 %d 点。"), nOutNo, nGlass1Count, nGlass2Count); |
| | | AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS); |
| | | |
| | | if (nGlass1Count < nMinGlass1Count) { |
| | | strLog.Format(_T("OUT%d: 第一片玻璃数据量过少,可能影响后续处理。"), nOutNo); |
| | | if (nGlass1Count < nMinGlassCount) { |
| | | strLog.Format(_T("OUT%d: 第一片玻璃数据量少于 %d 点,可能影响计算。"), nOutNo, nMinGlassCount); |
| | | AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING); |
| | | } |
| | | if (nGlass2Count < nMinGlass1Count) { |
| | | strLog.Format(_T("OUT%d: 第二片玻璃数据量过少,可能影响后续处理。"), nOutNo); |
| | | |
| | | if (nGlass2Count < nMinGlassCount) { |
| | | strLog.Format(_T("OUT%d: 第二片玻璃数据量少于 %d 点,可能影响计算。"), nOutNo, nMinGlassCount); |
| | | AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING); |
| | | } |
| | | |
| | |
| | | AppendLogLineRichStyled(_T("第二片玻璃数据:"), LOG_COLOR_NORMAL); |
| | | PrintSampleData(nOutNo, vecGlass2); |
| | | |
| | | return !vecGlass1.empty() && !vecGlass2.empty(); |
| | | MEASURE_FUNC_END(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CSGMeasurementDlg::FilterDominantGroup(int nOutNo, const std::vector<float>& vecInput, std::vector<float>& vecOutput) |
| | | { |
| | | MEASURE_FUNC_START(); |
| | | |
| | | if (vecInput.empty()) { |
| | | AppendLogLineRichStyled(_T("输入数据为空,无法进行分组筛选。"), LOG_COLOR_WARNING); |
| | | return false; |
| | | } |
| | | |
| | | // 分组:map<int整数部分, vector<float>> |
| | | std::map<int, std::vector<float>> mapGroup; |
| | | for (float fVal : vecInput) { |
| | | int nKey = static_cast<int>(fVal); |
| | | mapGroup[nKey].push_back(fVal); |
| | | } |
| | | |
| | | // 找出数量最多的那组 |
| | | size_t nMaxCount = 0; |
| | | auto itMaxGroup = mapGroup.begin(); |
| | | for (auto it = mapGroup.begin(); it != mapGroup.end(); ++it) { |
| | | if (it->second.size() > nMaxCount) { |
| | | nMaxCount = it->second.size(); |
| | | itMaxGroup = it; |
| | | } |
| | | } |
| | | |
| | | if (nMaxCount == 0) { |
| | | AppendLogLineRichStyled(_T("所有数据都被过滤或为空,无法筛选出主要分组。"), LOG_COLOR_WARNING); |
| | | return false; |
| | | } |
| | | |
| | | vecOutput = itMaxGroup->second; |
| | | |
| | | CString strLog; |
| | | strLog.Format(_T("成功从 %d 个组中筛选出主要分组:值约为 %d,共 %zu 个点。"), static_cast<int>(mapGroup.size()), itMaxGroup->first, nMaxCount); |
| | | AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS); |
| | | |
| | | // 打印筛选后的数据 |
| | | AppendLogLineRichStyled(_T("筛选后的主要分组数据:"), LOG_COLOR_NORMAL); |
| | | PrintSampleData(nOutNo, vecOutput); |
| | | |
| | | MEASURE_FUNC_END(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CSGMeasurementDlg::ExtractStableRegionFixed(int nOutNo, const std::vector<float>& vecIn, std::vector<float>& vecOut, int nFixedCount/* = 5*/, float fMaxDelta/* = 0.04f*/) |
| | | { |
| | | MEASURE_FUNC_START(); |
| | | |
| | | const int n = static_cast<int>(vecIn.size()); |
| | | if (n < nFixedCount) { |
| | | CString strError; |
| | |
| | | AppendLogLineRichStyled(_T("提取的稳定区数据:"), LOG_COLOR_NORMAL); |
| | | PrintSampleData(nOutNo, vecOut); |
| | | |
| | | MEASURE_FUNC_END(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool CSGMeasurementDlg::CalcGlassOffset(const std::vector<float>& vecGlass1, const std::vector<float>& vecGlass2, float& fAvg1, float& fAvg2, float& fOffset) |
| | | { |
| | | MEASURE_FUNC_START(); |
| | | |
| | | if (vecGlass1.empty() || vecGlass2.empty()) { |
| | | AppendLogLineRichStyled(_T("稳定区数据为空,无法计算平均值和偏移。"), LOG_COLOR_WARNING); |
| | | return false; |
| | |
| | | CString strLog; |
| | | strLog.Format(_T("第一片玻璃平均值: %.3f,第二片玻璃平均值: %.3f,偏移量: %.3f"), fAvg1, fAvg2, fOffset); |
| | | AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS); |
| | | |
| | | MEASURE_FUNC_END(); |
| | | |
| | | return true; |
| | | } |
| | |
| | | |
| | | float CSGMeasurementDlg::AnalyzeStoredData(int nOutNo) |
| | | { |
| | | MEASURE_FUNC_START(); |
| | | |
| | | UpdateData(TRUE); |
| | | |
| | | if (m_nUseTrigger) { |
| | |
| | | return -1.0f; |
| | | } |
| | | |
| | | std::vector<float> vecGlass1Filtered, vecGlass2Filtered; |
| | | bool bGlass1Filtered = FilterDominantGroup(nOutNo, vecGlass1, vecGlass1Filtered); |
| | | bool bGlass2Filtered = FilterDominantGroup(nOutNo, vecGlass2, vecGlass2Filtered); |
| | | |
| | | if (!bGlass1Filtered) { |
| | | AppendLogLineRichStyled(_T("Glass1 分段中未能识别出主数据组,使用原始数据。"), LOG_COLOR_WARNING); |
| | | vecGlass1Filtered = vecGlass1; |
| | | } |
| | | else { |
| | | AppendLogLineRichStyled(_T("Glass1 主数据组已提取。"), LOG_COLOR_SUCCESS); |
| | | } |
| | | |
| | | if (!bGlass2Filtered) { |
| | | AppendLogLineRichStyled(_T("Glass2 分段中未能识别出主数据组,使用原始数据。"), LOG_COLOR_WARNING); |
| | | vecGlass2Filtered = vecGlass2; |
| | | } |
| | | else { |
| | | AppendLogLineRichStyled(_T("Glass2 主数据组已提取。"), LOG_COLOR_SUCCESS); |
| | | } |
| | | |
| | | std::vector<float> vecStable1, vecStable2; |
| | | bool bStable1 = ExtractStableRegionFixed(nOutNo, vecGlass1, vecStable1, m_nFixedCount, m_fMaxDelta); |
| | | bool bStable2 = ExtractStableRegionFixed(nOutNo, vecGlass2, vecStable2, m_nFixedCount, m_fMaxDelta); |
| | | bool bStable1 = ExtractStableRegionFixed(nOutNo, vecGlass1Filtered, vecStable1, m_nFixedCount, m_fMaxDelta); |
| | | bool bStable2 = ExtractStableRegionFixed(nOutNo, vecGlass2Filtered, vecStable2, m_nFixedCount, m_fMaxDelta); |
| | | |
| | | float fAvg1 = 0.0f, fAvg2 = 0.0f, fOffset = 0.0f; |
| | | if (bStable1 && bStable2) { |
| | |
| | | AppendLogLineRichStyled(_T("未能提取到稳定区数据,尝试使用原始分段数据计算偏移。"), LOG_COLOR_WARNING); |
| | | CalcGlassOffset(vecGlass1, vecGlass2, fAvg1, fAvg2, fOffset); |
| | | } |
| | | |
| | | MEASURE_FUNC_END(); |
| | | |
| | | return fOffset; |
| | | } |
| | |
| | | // 初始化IP地址控件,设置为默认IP地址 |
| | | ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->SetAddress(192, 168, 0, 10); |
| | | |
| | | // 设置 PLC 监听器的日志回调函数 |
| | | m_plcListener.SetLogCallback([this](const CString& msg, int type) { |
| | | if (type == -1) { |
| | | AppendLogLineRichStyled(msg, LOG_COLOR_ERROR); |
| | | } |
| | | else if (type == 0) { |
| | | AppendLogLineRichStyled(msg, LOG_COLOR_SUCCESS); |
| | | } |
| | | else if (type == 1) { |
| | | AppendLogLineRichStyled(msg, LOG_COLOR_WARNING); |
| | | } |
| | | else if (type == 2) { |
| | | AppendLogLineRichStyled(msg, LOG_COLOR_NORMAL); |
| | | } |
| | | }); |
| | | |
| | | // 初始化 PLC 监听器 |
| | | m_plcListener.Initialize(StationIdentifier(0, 255), 200); |
| | | |
| | | // 设置 PLC 监听器的开始采集回调函数 |
| | | m_plcListener.SetStartCallback([this]() { |
| | | if (!m_bConnected) { |
| | | ConnectToDevice(); |
| | | } |
| | | |
| | | if (InitDataStorage()) { |
| | | StartDataStorage(); |
| | | UpdateControlStatus(m_bConnected, m_bSaving); |
| | | } |
| | | }); |
| | | |
| | | // 设置 PLC 监听器的停止采集回调函数 |
| | | m_plcListener.SetStopCallback([this]() { |
| | | StopDataStorage(); |
| | | UpdateControlStatus(m_bConnected, m_bSaving); |
| | | }); |
| | | |
| | | // 设置 PLC 监听器的分析回调函数 |
| | | m_plcListener.SetAnalyzeCallback([this]() { |
| | | if (!m_bConnected) { |
| | | AppendLogLineRichStyled(_T("设备未连接,请先连接设备。"), LOG_COLOR_WARNING); |
| | | return std::array<double, 4>{ -1.0, -1.0, -1.0, -1.0 }; |
| | | } |
| | | |
| | | std::array<double, 4> result; |
| | | for (int i = 0; i < 4; ++i) { |
| | | result[i] = AnalyzeStoredData(i + 1); // OUT1 ~ OUT4 |
| | | } |
| | | |
| | | if (std::any_of(result.begin(), result.end(), [](double v) { return v < 0; })) { |
| | | AppendLogLineRichStyled(_T("分析失败,某些输出端口数据无效。"), LOG_COLOR_ERROR); |
| | | return std::array<double, 4>{ -1.0, -1.0, -1.0, -1.0 }; |
| | | } |
| | | |
| | | CString strLog; |
| | | strLog.Format(_T("分析结果:OUT1: %.3f, OUT2: %.3f, OUT3: %.3f, OUT4: %.3f"), result[0], result[1], result[2], result[3]); |
| | | return result; |
| | | }); |
| | | m_plcListener.Start(); |
| | | |
| | | // 初始化日志框 |
| | | AppendLogLineRichStyled(_T("准备就绪..."), LOG_COLOR_SUCCESS); |
| | | |
| | |
| | | CString strError; |
| | | strError.Format(_T("获取测量值失败,错误码:%#X"), nRet); |
| | | AppendLogLineRichStyled(strError, LOG_COLOR_ERROR); |
| | | |
| | | // 断开连接 |
| | | if (m_bConnected) { |
| | | DisconnectFromDevice(); |
| | | } |
| | | } |
| | | } |
| | | |