From e8a27bb203fe2aff70390a5eca002d7438da9b0f Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期三, 22 十月 2025 14:24:34 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp |  789 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 625 insertions(+), 164 deletions(-)

diff --git a/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp b/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
index d6bc177..ae284a7 100644
--- a/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
+++ b/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
@@ -8,6 +8,7 @@
 #include "SGMeasurementDlg.h"
 #include "afxdialogex.h"
 #include "SGIF.h"
+#include "Logger.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -16,6 +17,7 @@
 #define DeviceID 0
 
 // 鎵樼洏鍥炬爣 ID 涓庢秷鎭畯
+#define ID_TRAY_OPEN_DIR	   2000				// 鎵撳紑鐩綍
 #define ID_TRAY_RESTORE		   2001				// 鎭㈠绐楀彛
 #define ID_TRAY_EXIT		   2002				// 閫�鍑虹▼搴�
 #define WM_TRAY_ICON_NOTIFY    (WM_USER + 1000) // 鎵樼洏鍥炬爣鍥炶皟娑堟伅 ID
@@ -33,6 +35,19 @@
 // 瀹氭椂鍣ㄧ浉鍏冲畯瀹氫箟
 #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
 {
@@ -71,7 +86,7 @@
 	, 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)
@@ -80,6 +95,7 @@
 	, m_nTrayIconID(0)
 	, m_bTrayIconCreated(FALSE)
 	, m_bExitingFromTray(FALSE)
+	, m_nAutoStart(TRUE)
 {
 	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 }
@@ -115,6 +131,11 @@
 		Shell_NotifyIcon(NIM_DELETE, &m_trayIconData);
 		m_bTrayIconCreated = FALSE;
 	}
+
+	m_plcListener.Stop();
+
+	// 淇濆瓨閰嶇疆鏂囦欢
+	SaveConfig(GetConfigPath());
 
 	DestroyWindow();
 	CDialogEx::OnClose();
@@ -175,7 +196,7 @@
 	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;
@@ -197,16 +218,41 @@
 	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("[鏈煡]");
+	}
+
 	// 鎻掑叆鏃ュ織姝f枃锛堜紶鍏ラ鑹诧級
 	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)*/)
@@ -262,6 +308,149 @@
 	}
 }
 
+CString CSGMeasurementDlg::GetAppDirectory()
+{
+	TCHAR szPath[MAX_PATH] = { 0 };
+	GetModuleFileName(NULL, szPath, MAX_PATH);
+
+	CString strPath = szPath;
+	int pos = strPath.ReverseFind('\\');
+	if (pos != -1) {
+		strPath = strPath.Left(pos + 1);
+	}
+
+	return strPath;
+}
+
+CString CSGMeasurementDlg::GetConfigPath()
+{
+	return GetAppDirectory() + _T("SGConfig.ini");
+}
+
+bool CSGMeasurementDlg::LoadConfig(const CString& strFile)
+{
+	CString strSection = _T("StorageConfig");
+	TCHAR buf[256];
+
+	GetPrivateProfileString(strSection, _T("UseTrigger"), _T("0"), buf, 256, strFile);
+	m_nUseTrigger = _ttoi(buf);
+
+	GetPrivateProfileString(strSection, _T("SavePointCount"), _T("100000"), buf, 256, strFile);
+	m_nSavePointCount = _ttoi(buf);
+
+	// 杈撳嚭绔彛
+	GetPrivateProfileString(strSection, _T("OutputPort"), _T("OUT1"), buf, 256, strFile);
+	{
+		int idx = m_comboOutputPort.FindStringExact(-1, buf);
+		if (idx != CB_ERR) {
+			m_comboOutputPort.SetCurSel(idx);
+		}
+		else {
+			m_comboOutputPort.SetCurSel(0);
+		}
+	}
+
+	// 璺冲彉妫�娴嬪弬鏁�
+	GetPrivateProfileString(strSection, _T("JumpThreshold"), _T("0.2"), buf, 256, strFile);
+	m_fJumpThreshold = static_cast<float>(_tstof(buf));
+
+	GetPrivateProfileString(strSection, _T("JumpWindow"), _T("3"), buf, 256, strFile);
+	m_nJumpWindow = _ttoi(buf);
+
+	GetPrivateProfileString(strSection, _T("ValleyMargin"), _T("0"), buf, 256, strFile);
+	m_nValleyMargin = _ttoi(buf);
+
+	GetPrivateProfileString(strSection, _T("MinGlass1Count"), _T("10"), buf, 256, strFile);
+	m_nMinGlass1Count = _ttoi(buf);
+
+	// 绋冲畾鍖哄煙鍙傛暟
+	GetPrivateProfileString(strSection, _T("FixedCount"), _T("5"), buf, 256, strFile);
+	m_nFixedCount = _ttoi(buf);
+
+	GetPrivateProfileString(strSection, _T("MaxDelta"), _T("0.05"), buf, 256, strFile);
+	m_fMaxDelta = static_cast<float>(_tstof(buf));
+
+	// 鑷惎鍔�
+	GetPrivateProfileString(strSection, _T("AutoStart"), _T("1"), buf, 256, strFile);
+	m_nAutoStart = _ttoi(buf);
+
+	return true;
+}
+
+bool CSGMeasurementDlg::SaveConfig(const CString& strFile)
+{
+	CString strSection = _T("StorageConfig");
+
+	WritePrivateProfileString(strSection, _T("UseTrigger"), std::to_wstring(m_nUseTrigger).c_str(), strFile);
+	WritePrivateProfileString(strSection, _T("SavePointCount"), std::to_wstring(m_nSavePointCount).c_str(), strFile);
+
+	// 杈撳嚭绔彛涓嬫媺妗�
+	CString strPort;
+	m_comboOutputPort.GetWindowText(strPort);
+	WritePrivateProfileString(strSection, _T("OutputPort"), strPort, strFile);
+
+	// 璺冲彉妫�娴�
+	WritePrivateProfileString(strSection, _T("JumpThreshold"), std::to_wstring(m_fJumpThreshold).c_str(), strFile);
+	WritePrivateProfileString(strSection, _T("JumpWindow"), std::to_wstring(m_nJumpWindow).c_str(), strFile);
+	WritePrivateProfileString(strSection, _T("ValleyMargin"), std::to_wstring(m_nValleyMargin).c_str(), strFile);
+	WritePrivateProfileString(strSection, _T("MinGlass1Count"), std::to_wstring(m_nMinGlass1Count).c_str(), strFile);
+
+	// 绋冲畾鍖�
+	WritePrivateProfileString(strSection, _T("FixedCount"), std::to_wstring(m_nFixedCount).c_str(), strFile);
+	WritePrivateProfileString(strSection, _T("MaxDelta"), std::to_wstring(m_fMaxDelta).c_str(), strFile);
+
+	// 鑷惎鍔�
+	WritePrivateProfileString(strSection, _T("AutoStart"), std::to_wstring(m_nAutoStart).c_str(), strFile);
+
+	return true;
+}
+
+bool CSGMeasurementDlg::SetAutoStart(bool bEnable)
+{
+	// 鑾峰彇褰撳墠绋嬪簭璺緞
+	TCHAR szPath[MAX_PATH] = { 0 };
+	GetModuleFileName(NULL, szPath, MAX_PATH);
+	CString strAppPath = szPath;
+
+	// 鑾峰彇搴旂敤绋嬪簭鍚嶇О
+	CString strAppName = ::PathFindFileName(strAppPath);
+	strAppName = strAppName.Left(strAppName.ReverseFind('.'));
+
+	HKEY hKey;
+	LONG lRet = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_READ | KEY_WRITE, &hKey);
+
+	if (lRet != ERROR_SUCCESS) { 
+		return false;
+	}
+
+	DWORD dwType = 0;
+	TCHAR szValue[MAX_PATH] = { 0 };
+	DWORD dwSize = sizeof(szValue);
+	lRet = RegQueryValueEx(hKey, strAppName, 0, &dwType, (LPBYTE)szValue, &dwSize);
+
+	if (bEnable) {
+		if (lRet != ERROR_SUCCESS || _tcsicmp(szValue, strAppPath) != 0) {
+			// 璁剧疆鑷惎
+			lRet = RegSetValueEx(hKey, strAppName, 0, REG_SZ, (BYTE*)(LPCTSTR)strAppPath, (strAppPath.GetLength() + 1) * sizeof(TCHAR));
+		}
+		else {
+			lRet = ERROR_SUCCESS;
+		}
+	}
+	else {
+		if (lRet == ERROR_SUCCESS) {
+			// 鍙栨秷鑷惎
+			lRet = RegDeleteValue(hKey, strAppName);
+		}
+		else {
+			lRet = ERROR_SUCCESS;
+		}
+	}
+
+	RegCloseKey(hKey);
+	return (lRet == ERROR_SUCCESS);
+}
+
 bool CSGMeasurementDlg::ConnectToDevice()
 {
 	if (m_bConnected) {
@@ -311,32 +500,38 @@
 		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);
 
+	// 鍏堝仠姝㈡暟鎹瓨鍌紙濡傛灉姝e湪杩涜锛�
+	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;
@@ -345,6 +540,8 @@
 
 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; });
 
@@ -380,62 +577,87 @@
 	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);
 	}
 
@@ -445,11 +667,61 @@
 	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;
+	}
+
+	// 鍒嗙粍锛歮ap<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);
+	}
+
+	// 鎵惧嚭鏁伴噺鏈�澶氱殑閭g粍
+	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;
@@ -494,11 +766,15 @@
 	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;
@@ -511,13 +787,171 @@
 
 	fAvg1 = CalcAverage(vecGlass1);
 	fAvg2 = CalcAverage(vecGlass2);
-	fOffset = std::fabs(fAvg2 - fAvg1);  // 绗簩鐗� - 绗竴鐗�
+	fOffset = fAvg2 - fAvg1;				// 绗簩鐗� - 绗竴鐗�
+	//fOffset = std::fabs(fAvg2 - fAvg1);	// 绗簩鐗� - 绗竴鐗�
 
 	CString strLog;
 	strLog.Format(_T("绗竴鐗囩幓鐠冨钩鍧囧��: %.3f锛岀浜岀墖鐜荤拑骞冲潎鍊�: %.3f锛屽亸绉婚噺: %.3f"), fAvg1, fAvg2, fOffset);
 	AppendLogLineRichStyled(strLog, LOG_COLOR_SUCCESS);
 
+	MEASURE_FUNC_END();
+
 	return true;
+}
+
+bool CSGMeasurementDlg::InitDataStorage()
+{
+	if (!m_bConnected) {
+		AppendLogLineRichStyled(_T("璁惧鏈繛鎺ワ紝璇峰厛杩炴帴璁惧銆�"), LOG_COLOR_WARNING);
+		return false;
+	}
+
+	if (m_bSaving) {
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍姝e湪杩涜涓紝璇峰厛鍋滄瀛樺偍銆�"), LOG_COLOR_WARNING);
+		return false;
+	}
+
+	RC nRet = SGIF_DataStorageInit(DeviceID);
+	if (nRet == RC_OK) {
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸叉竻闄ゃ��"), LOG_COLOR_SUCCESS);
+		return true;
+	}
+
+	CString strError;
+	strError.Format(_T("娓呴櫎鏁版嵁瀛樺偍澶辫触锛岄敊璇爜锛�%#X"), nRet);
+	AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
+	return false;
+}
+
+bool CSGMeasurementDlg::StartDataStorage()
+{
+	if (m_bSaving) {
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸插湪杩涜涓紝璇峰厛鍋滄瀛樺偍銆�"), LOG_COLOR_WARNING);
+		return false;
+	}
+
+	RC nRet = SGIF_DataStorageStart(DeviceID);
+	if (nRet == RC_OK) {
+		m_bSaving = TRUE;
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸插紑濮嬨��"), LOG_COLOR_SUCCESS);
+		return true;
+	}
+
+	CString strError;
+	strError.Format(_T("寮�濮嬫暟鎹瓨鍌ㄥけ璐ワ紝閿欒鐮侊細%#X"), nRet);
+	AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
+	return false;
+}
+
+bool CSGMeasurementDlg::StopDataStorage()
+{
+	if (!m_bSaving) {
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍鏈湪杩涜涓紝璇峰厛寮�濮嬪瓨鍌ㄣ��"), LOG_COLOR_WARNING);
+		return false;
+	}
+
+	RC nRet = SGIF_DataStorageStop(DeviceID);
+	if (nRet == RC_OK) {
+		m_bSaving = FALSE;
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸插仠姝€��"), LOG_COLOR_SUCCESS);
+		return true;
+	}
+
+	CString strError;
+	strError.Format(_T("鍋滄鏁版嵁瀛樺偍澶辫触锛岄敊璇爜锛�%#X"), nRet);
+	AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
+	return false;
+}
+
+double CSGMeasurementDlg::AnalyzeStoredData(int nOutNo)
+{
+	MEASURE_FUNC_START();
+
+	UpdateData(TRUE);
+
+	if (m_nUseTrigger) {
+		UpdateControlStatus(m_bConnected, m_bSaving);
+		AfxMessageBox(_T("褰撳墠鏄‖瑙﹀彂妯″紡锛岃妫�鏌ヨЕ鍙戝櫒鐘舵�併��"), MB_ICONINFORMATION);
+		return DBL_MAX;
+	}
+
+	if (!m_bConnected) {
+		AppendLogLineRichStyled(_T("璁惧鏈繛鎺ワ紝璇峰厛杩炴帴璁惧銆�"), LOG_COLOR_WARNING);
+		return DBL_MAX;
+	}
+
+	if (m_bSaving) {
+		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍姝e湪杩涜涓紝璇峰厛鍋滄瀛樺偍銆�"), LOG_COLOR_WARNING);
+		return DBL_MAX;
+	}
+
+	if (nOutNo < 1 || nOutNo > 4) {
+		AppendLogLineRichStyled(_T("杈撳嚭绔彛缂栧彿鏃犳晥锛屽繀椤诲湪 1 鍒� 4 涔嬮棿銆�"), LOG_COLOR_ERROR);
+		return DBL_MAX;
+	}
+
+	if (m_nSavePointCount < 0) {
+		AppendLogLineRichStyled(_T("鏁版嵁鐐规暟蹇呴』澶т簬 0銆�"), LOG_COLOR_ERROR);
+		return DBL_MAX;
+	}
+
+	std::vector<float> vecBuffer(m_nSavePointCount, 0.0f);
+	int nReceived = 0;
+
+	RC nRet = SGIF_DataStorageGetData(DeviceID, nOutNo, m_nSavePointCount, vecBuffer.data(), &nReceived);
+	if (nRet != RC_OK) {
+		CString strError;
+		strError.Format(_T("璇诲彇 OUT%d 鏁版嵁澶辫触锛岄敊璇爜锛�%#X"), nOutNo, nRet);
+		AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
+		return DBL_MAX;
+	}
+
+	vecBuffer.resize(nReceived);
+	CleanInvalidValuesInPlace(nOutNo, vecBuffer);
+
+	std::vector<float> vecGlass1, vecGlass2;
+	if (!SplitGlassSegments(nOutNo, vecBuffer, vecGlass1, vecGlass2, m_fJumpThreshold, m_nJumpWindow, m_nValleyMargin, m_nMinGlass1Count)) {
+		AppendLogLineRichStyled(_T("鏈兘璇嗗埆鍑轰袱鐗囩幓鐠冪殑鏁版嵁銆�"), LOG_COLOR_WARNING);
+		return DBL_MAX;
+	}
+
+	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, 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_SUCCESS);
+		CalcGlassOffset(vecStable1, vecStable2, fAvg1, fAvg2, fOffset);
+	}
+	else {
+		AppendLogLineRichStyled(_T("鏈兘鎻愬彇鍒扮ǔ瀹氬尯鏁版嵁锛屽皾璇曚娇鐢ㄥ師濮嬪垎娈垫暟鎹绠楀亸绉汇��"), LOG_COLOR_WARNING);
+		CalcGlassOffset(vecGlass1, vecGlass2, fAvg1, fAvg2, fOffset);
+	}
+
+	MEASURE_FUNC_END();
+
+	return fOffset;
 }
 
 BEGIN_MESSAGE_MAP(CSGMeasurementDlg, CDialogEx)
@@ -529,6 +963,7 @@
 	ON_WM_DRAWITEM()
 	ON_WM_CLOSE()
 	ON_MESSAGE(WM_TRAY_ICON_NOTIFY, &CSGMeasurementDlg::OnTrayIconClick)
+	ON_COMMAND(ID_TRAY_OPEN_DIR, &CSGMeasurementDlg::OnTrayOpenDir)
 	ON_COMMAND(ID_TRAY_RESTORE, &CSGMeasurementDlg::OnTrayRestore)
 	ON_COMMAND(ID_TRAY_EXIT, &CSGMeasurementDlg::OnTrayExit)
 	ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CSGMeasurementDlg::OnBnClickedButtonConnect)
@@ -597,6 +1032,86 @@
 	// 鍒濆鍖朓P鍦板潃鎺т欢锛岃缃负榛樿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>{ DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX };
+		}
+
+		std::array<double, 4> result;
+		for (int i = 0; i < 4; ++i) {
+			result[i] = AnalyzeStoredData(i + 1); // OUT1 ~ OUT4
+		}
+
+		std::string strProductID;
+		m_plcListener.ReadProductID(strProductID);
+		m_resultStorage.SaveAnalyzeResult(CString(strProductID.c_str()), result);
+
+		CString strLog;
+		strLog.Format(_T("鍒嗘瀽缁撴灉锛歄UT1: %.3f, OUT2: %.3f, OUT3: %.3f, OUT4: %.3f"), result[0], result[1], result[2], result[3]);
+		return result;
+	});
+	m_plcListener.Start();
+
+	// 鍔犺浇閰嶇疆鏂囦欢
+	if (LoadConfig(GetConfigPath())) {
+		AppendLogLineRichStyled(_T("閰嶇疆宸蹭粠 SGConfig.ini 鍔犺浇鎴愬姛"), LOG_COLOR_SUCCESS);
+	}
+	else {
+		AppendLogLineRichStyled(_T("閰嶇疆鍔犺浇澶辫触锛屼娇鐢ㄩ粯璁ゅ弬鏁�"), LOG_COLOR_WARNING);
+	}
+
+	// 璁剧疆鑷姩鍚姩
+	if (SetAutoStart(m_nAutoStart)) {
+		if (m_nAutoStart) {
+			AppendLogLineRichStyled(_T("宸插惎鐢ㄥ紑鏈鸿嚜鍚姩"), LOG_COLOR_SUCCESS);
+		}
+		else {
+			AppendLogLineRichStyled(_T("宸插彇娑堝紑鏈鸿嚜鍚姩"), LOG_COLOR_WARNING);
+		}
+	}
+	else {
+		AppendLogLineRichStyled(_T("璁剧疆寮�鏈鸿嚜鍚姩澶辫触锛岃妫�鏌ユ潈闄�"), LOG_COLOR_ERROR);
+	}
+
 	// 鍒濆鍖栨棩蹇楁
 	AppendLogLineRichStyled(_T("鍑嗗灏辩华..."), LOG_COLOR_SUCCESS);
 
@@ -653,16 +1168,31 @@
 		RC nRet = SGIF_GetCalcDataALL(DeviceID, value);
 		if (nRet == RC_OK) {
 			for (int i = 0; i < 4; ++i) {
-				m_dOutValues[i] = value[i].Value;
-			}
+				double dNew = value[i].Value;
+				if (fabs(m_dOutValues[i] - dNew) > 1e-6) {
+					m_dOutValues[i] = dNew;
 
-			// 鏇存柊缁戝畾鎺т欢
-			UpdateData(FALSE);
+					CString str;
+					str.Format(_T("%.3f"), dNew);
+
+					switch (i) {
+					case 0: GetDlgItem(IDC_EDIT_OUT1)->SetWindowText(str); break;
+					case 1: GetDlgItem(IDC_EDIT_OUT2)->SetWindowText(str); break;
+					case 2: GetDlgItem(IDC_EDIT_OUT3)->SetWindowText(str); break;
+					case 3: GetDlgItem(IDC_EDIT_OUT4)->SetWindowText(str); break;
+					}
+				}
+			}
 		}
 		else {
 			CString strError;
 			strError.Format(_T("鑾峰彇娴嬮噺鍊煎け璐ワ紝閿欒鐮侊細%#X"), nRet);
 			AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
+
+			// 鏂紑杩炴帴
+			if (m_bConnected) {
+				DisconnectFromDevice();
+			}
 		}
 	}
 
@@ -693,6 +1223,10 @@
 
 	// 鍥炬爣
 	HICON hIcon = nullptr;
+	if (id == ID_TRAY_OPEN_DIR) {
+		hIcon = AfxGetApp()->LoadIcon(IDI_ICON_OPEN_DIR);
+	}
+
 	if (id == ID_TRAY_RESTORE) {
 		hIcon = AfxGetApp()->LoadIcon(IDI_ICON_RESTORE);
 	}
@@ -707,6 +1241,10 @@
 
 	// 鏂囨湰
 	CString str;
+	if (id == ID_TRAY_OPEN_DIR) {
+		str = _T("鎵撳紑鐩綍");
+	}
+
 	if (id == ID_TRAY_RESTORE) { 
 		str = _T("鎭㈠鐣岄潰");
 	}
@@ -750,22 +1288,23 @@
 			// 鍙抽敭鐐瑰嚮寮瑰嚭鑿滃崟
 			CMenu menu;
 			menu.CreatePopupMenu();
+			menu.AppendMenu(MF_OWNERDRAW, ID_TRAY_OPEN_DIR, (LPCTSTR)ID_TRAY_OPEN_DIR);
 			menu.AppendMenu(MF_OWNERDRAW, ID_TRAY_RESTORE, (LPCTSTR)ID_TRAY_RESTORE);
 			menu.AppendMenu(MF_OWNERDRAW, ID_TRAY_EXIT, (LPCTSTR)ID_TRAY_EXIT);
-
-			// 鍔犺浇鍥炬爣
-			HICON hIconRestore = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON_RESTORE), IMAGE_ICON, 16, 16, LR_SHARED);
-			HICON hIconExit = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON_EXIT), IMAGE_ICON, 16, 16, LR_SHARED);
 
 			// 璁剧疆鍥炬爣鍒拌彍鍗曢」
 			MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
 			mii.fMask = MIIM_BITMAP;
 
-			// 鎭㈠鑿滃崟椤瑰浘鏍�
+			// 鎵撳紑鐩綍鑿滃崟椤瑰浘鏍�
+			mii.hbmpItem = HBMMENU_CALLBACK;
+			menu.SetMenuItemInfo(ID_TRAY_OPEN_DIR, &mii);
+
+			// 鎭㈠绐楀彛鑿滃崟椤瑰浘鏍�
 			mii.hbmpItem = HBMMENU_CALLBACK;
 			menu.SetMenuItemInfo(ID_TRAY_RESTORE, &mii);
 
-			// 閫�鍑鸿彍鍗曢」鍥炬爣
+			// 閫�鍑虹▼搴忚彍鍗曢」鍥炬爣
 			mii.hbmpItem = HBMMENU_CALLBACK;
 			menu.SetMenuItemInfo(ID_TRAY_EXIT, &mii);
 
@@ -777,6 +1316,18 @@
 		}
 	}
 	return 0;
+}
+
+void CSGMeasurementDlg::OnTrayOpenDir()
+{
+	CString strDir = GetAppDirectory();
+	if (PathFileExists(strDir)) {
+		ShellExecute(NULL, _T("open"), strDir, NULL, NULL, SW_SHOWDEFAULT);
+		AppendLogLineRichStyled(_T("宸叉墦寮�绋嬪簭鐩綍"), LOG_COLOR_SUCCESS);
+	}
+	else {
+		AppendLogLineRichStyled(_T("鐩綍涓嶅瓨鍦紝鏃犳硶鎵撳紑"), LOG_COLOR_ERROR);
+	}
 }
 
 void CSGMeasurementDlg::OnTrayRestore()
@@ -827,120 +1378,30 @@
 void CSGMeasurementDlg::OnBnClickedButtonClearStore()
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	if (!m_bConnected) {
-		AppendLogLineRichStyled(_T("璁惧鏈繛鎺ワ紝璇峰厛杩炴帴璁惧銆�"), LOG_COLOR_WARNING);
-		return;
-	}
-
-	if (m_bSaving) {
-		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍姝e湪杩涜涓紝璇峰厛鍋滄瀛樺偍銆�"), LOG_COLOR_WARNING);
-		return;
-	}
-
-	RC nRet = SGIF_DataStorageInit(DeviceID);
-	if (nRet == RC_OK) {
-		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸叉竻闄ゃ��"), LOG_COLOR_SUCCESS);
-	}
-	else {
-		CString strError;
-		strError.Format(_T("娓呴櫎鏁版嵁瀛樺偍澶辫触锛岄敊璇爜锛�%#X"), nRet);
-		AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
-	}
+	InitDataStorage();
 }
 
 void CSGMeasurementDlg::OnBnClickedButtonStartStore()
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	if (m_bSaving) {
-		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸插湪杩涜涓紝璇峰厛鍋滄瀛樺偍銆�"), LOG_COLOR_WARNING);
-		return;
-	}
-
-	RC nRet = SGIF_DataStorageStart(DeviceID);
-	if (nRet == RC_OK) {
-		m_bSaving = TRUE;
-		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸插紑濮嬨��"), LOG_COLOR_SUCCESS);
-	}
-	else {
-		CString strError;
-		strError.Format(_T("寮�濮嬫暟鎹瓨鍌ㄥけ璐ワ紝閿欒鐮侊細%#X"), nRet);
-		AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
-	}
-
+	StartDataStorage();
 	UpdateControlStatus(m_bConnected, m_bSaving);
 }
 
 void CSGMeasurementDlg::OnBnClickedButtonStopStore()
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	UpdateData(TRUE);
+	StopDataStorage();
+	UpdateControlStatus(m_bConnected, m_bSaving);
 
-	if (!m_bSaving) {
-		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍鏈湪杩涜涓紝璇峰厛寮�濮嬪瓨鍌ㄣ��"), LOG_COLOR_WARNING);
+	int nSel = m_comboOutputPort.GetCurSel();
+	if (CB_ERR == nSel) {
+		AppendLogLineRichStyled(_T("璇烽�夋嫨涓�涓湁鏁堢殑杈撳嚭绔彛銆�"), LOG_COLOR_WARNING);
 		return;
 	}
 
-	RC nRet = SGIF_DataStorageStop(DeviceID);
-	if (nRet == RC_OK) {
-		m_bSaving = FALSE;
-		AppendLogLineRichStyled(_T("鏁版嵁瀛樺偍宸插仠姝€��"), LOG_COLOR_SUCCESS);
-
-		if (m_nUseTrigger) {
-			UpdateControlStatus(m_bConnected, m_bSaving);
-			AfxMessageBox(_T("褰撳墠鏄‖瑙﹀彂妯″紡锛岃妫�鏌ヨЕ鍙戝櫒鐘舵�併��"), MB_ICONINFORMATION);
-			return;
-		}
-
-		int nReceived = 0;
-		std::vector<float> vecBuffer(m_nSavePointCount, 0.0f);
-
-		int nSel = m_comboOutputPort.GetCurSel();
-		if (CB_ERR == nSel) {
-			AppendLogLineRichStyled(_T("璇烽�夋嫨涓�涓湁鏁堢殑杈撳嚭绔彛銆�"), LOG_COLOR_WARNING);
-			return;
-		}
-
-		int nOutNo = nSel + 1;
-		nRet = SGIF_DataStorageGetData(DeviceID, nOutNo, m_nSavePointCount, vecBuffer.data(), &nReceived);
-
-		CString strLog;
-		if (nRet == RC_OK) {
-			vecBuffer.resize(nReceived);
-			CleanInvalidValuesInPlace(nOutNo, vecBuffer);
-
-			std::vector<float> vecGlass1, vecGlass2;
-			if (SplitGlassSegments(nOutNo, vecBuffer, vecGlass1, vecGlass2, m_fJumpThreshold, m_nJumpWindow, m_nValleyMargin, m_nMinGlass1Count)) {
-
-				std::vector<float> vecStableGlass1, vecStableGlass2;
-				bool bStable1 = ExtractStableRegionFixed(nOutNo, vecGlass1, vecStableGlass1, m_nFixedCount, m_fMaxDelta);
-				bool bStable2 = ExtractStableRegionFixed(nOutNo, vecGlass2, vecStableGlass2, m_nFixedCount, m_fMaxDelta);
-
-				float fAvg1 = 0.0f, fAvg2 = 0.0f, fOffset = 0.0f;
-				if (bStable1 && bStable2) {
-					AppendLogLineRichStyled(_T("鎴愬姛鎻愬彇鍒颁袱鐗囩幓鐠冪殑绋冲畾鍖烘暟鎹��"), LOG_COLOR_SUCCESS);
-					CalcGlassOffset(vecStableGlass1, vecStableGlass2, fAvg1, fAvg2, fOffset);
-				}
-				else {
-					AppendLogLineRichStyled(_T("鏈兘鎻愬彇鍒扮ǔ瀹氬尯鏁版嵁锛屾棤娉曟甯歌绠楀亸绉汇��"), LOG_COLOR_WARNING);
-					CalcGlassOffset(vecGlass1, vecGlass2, fAvg1, fAvg2, fOffset);
-				}
-			}
-			else {
-				AppendLogLineRichStyled(_T("鏈兘璇嗗埆鍑轰袱鐗囩幓鐠冪殑鏁版嵁銆�"), LOG_COLOR_WARNING);
-			}
-		}
-		else {
-			strLog.Format(_T("璇诲彇 OUT%d 鏁版嵁澶辫触锛岄敊璇爜锛�%#X"), nOutNo, nRet);
-			AppendLogLineRichStyled(strLog, LOG_COLOR_ERROR);
-		}
-	}
-	else {
-		CString strError;
-		strError.Format(_T("鍋滄鏁版嵁瀛樺偍澶辫触锛岄敊璇爜锛�%#X"), nRet);
-		AppendLogLineRichStyled(strError, LOG_COLOR_ERROR);
-	}
-
-	UpdateControlStatus(m_bConnected, m_bSaving);
+	int nOutNo = nSel + 1;
+	AnalyzeStoredData(nOutNo);
 }
 
 void CSGMeasurementDlg::OnBnClickedButtonClearLog()

--
Gitblit v1.9.3