From 5cc675212e96d87ebbf00f4fd7a8106b06a490ff Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期三, 13 八月 2025 14:00:50 +0800
Subject: [PATCH] 1. 侧面检功能添加优化(主要是现场获取图像问题)

---
 EdgeInspector_App/Recipe/HardwareSettings.h   |    4 
 EdgeInspector_App/Grabber/RadientControl.cpp  |  678 ++++++++++++++++++++-------------
 EdgeInspector_App/View/ViewMain_HWSetting.cpp |   64 +-
 EdgeInspector_App/Grabber/SapLineGrab.cpp     |   11 
 EdgeInspector_App/Process/InspectCamera.cpp   |   73 +--
 EdgeInspector_App/Define/Global_Define.h      |    2 
 EdgeInspector_App/Define/StatusMonitor.cpp    |   58 +-
 EdgeInspector_App/Grabber/SapControl.cpp      |   11 
 EdgeInspector_App/Grabber/MulticamControl.cpp |    9 
 EdgeInspector_App/Grabber/MulticamControl.h   |    5 
 EdgeInspector_App/Grabber/SapLineGrab.h       |    5 
 EdgeInspector_App/Grabber/SoliosControl.cpp   |   17 
 EdgeInspector_App/InterfaceManager.cpp        |   54 +-
 EdgeInspector_App/Grabber/RadientControl.h    |    4 
 EdgeInspector_App/Grabber/SapControl.h        |    5 
 EdgeInspector_App/Define/StatusMonitor.h      |   10 
 EdgeInspector_App/Recipe/HardwareSettings.cpp |  127 +++--
 EdgeInspector_App/View/GlassMap.cpp           |    3 
 EdgeInspector_App/BICommon.h                  |    2 
 SDK/BlGrabber/include/GrabberControl.h        |    1 
 EdgeInspector_App/Grabber/SoliosControl.h     |    3 
 21 files changed, 651 insertions(+), 495 deletions(-)

diff --git a/EdgeInspector_App/BICommon.h b/EdgeInspector_App/BICommon.h
index 1688d1f..8cff88d 100644
--- a/EdgeInspector_App/BICommon.h
+++ b/EdgeInspector_App/BICommon.h
@@ -8,7 +8,7 @@
 #include <string>
 #include <time.h>
 
-#define OFFLINE_KEY           1   //OFFLINE_KEY:1鏄绾挎ā寮�;0鏄湪绾挎ā寮�
+#define OFFLINE_KEY           0   //OFFLINE_KEY:1鏄绾挎ā寮�;0鏄湪绾挎ā寮�
 #define MINI_LED              0   //Mini杞﹂棿
 #define MINI_NOTCH			  0   //Mini杞﹂棿, 鏄惁浣跨敤鍒绘Ы鍔熻兘
 #define HALCON_VISION_KEY     0   //鏄惁鍚敤HALCON
diff --git a/EdgeInspector_App/Define/Global_Define.h b/EdgeInspector_App/Define/Global_Define.h
index 4ce3921..4e8ffb0 100644
--- a/EdgeInspector_App/Define/Global_Define.h
+++ b/EdgeInspector_App/Define/Global_Define.h
@@ -80,7 +80,7 @@
 	enum	LIGHT_TYPE					{LIGHT_TYPE_TRANS=0,LIGHT_TYPE_REF,LIGHT_TYPE_NONE};
 	enum	LIGHT_MAKER					{MAKER_LCP=0,MAKER_AKP,MAKER_NONE};
 
-	enum	CAMERA_DIR					{CAMDIR_TOP=0,CAMDIR_BOTTOM,CAMDIR_NONE};	
+	enum	CAMERA_DIR					{CAMDIR_TOP=0,CAMDIR_BOTTOM,CAMDIR_SIDE,CAMDIR_NONE};
 	enum	CAMERA_INSPECTION_DIR		{INSPECTDIR_FORWARD=0,INSPECTDIR_BACKWARD,INSPECTDIR_NONE};
 	enum	CAMERA_SCANDIR				{SCANGLASS_X=0,SCANGLASS_Y,SCANGLASS_NONE};	
 	enum	BOARD_TYPE					{GRAB_LINK_BOARD=0,RADIENT_BOARD,SOLIOS_BOARD,SAP_BOARD,BOARDTYPE_NONE};
diff --git a/EdgeInspector_App/Define/StatusMonitor.cpp b/EdgeInspector_App/Define/StatusMonitor.cpp
index d3b61b9..92f9435 100644
--- a/EdgeInspector_App/Define/StatusMonitor.cpp
+++ b/EdgeInspector_App/Define/StatusMonitor.cpp
@@ -1,17 +1,19 @@
 锘�#include "StdAfx.h"
 #include "StatusMonitor.h"
 
+#define VALID_IDX(i, max)     ((unsigned)(i) < (unsigned)(max))
+#define VALID_CAM(c)          VALID_IDX((c), MAX_CAMERA_COUNT)
+#define VALID_SCAN(s)         VALID_IDX((s), MAX_SCAN_COUNT)
+#define VALID_CAM_SCAN(c, s)  (VALID_CAM(c) && VALID_SCAN(s))
 
 //////////////////////////////////////////////////////////////////////////
 
 CStatusMonitor::CStatusMonitor(void)
 {
 	m_iScanIdx = -1;
-
-	for(int iCam=0;iCam<MAX_CAMERA_COUNT;iCam++)
+	for (int iCam = 0; iCam < MAX_CAMERA_COUNT; iCam++) {
 		m_pFrameBuffer[iCam] = NULL;
-
-	InitGlassLoading();
+	}
 
 	m_pControlInterface		= NULL;
 	m_pLightManager			= NULL;
@@ -21,6 +23,8 @@
 	m_pHWSettings			= NULL;
 	m_pLanguageControl		= NULL;
 	m_pLicenseChecker		= NULL;
+
+	InitGlassLoading();
 }
 
 CStatusMonitor::~CStatusMonitor(void)
@@ -29,35 +33,31 @@
 
 void CStatusMonitor::InitGlassLoading()
 {	
-	for(int i=0;i<MAX_SCAN_COUNT;i++)
-	{
-		m_nGrabFrame[i] = 0;
-		m_bGrabEnd[i] = FALSE;
+	ZeroMemory(m_nGrabFrame, sizeof(m_nGrabFrame));
+	ZeroMemory(m_bGrabEnd, sizeof(m_bGrabEnd));
+}
+
+int	CStatusMonitor::GetGrabFrameCount(int nCamera, int iScan)
+{
+	if (VALID_CAM_SCAN(nCamera, iScan)) {
+		return m_nGrabFrame[nCamera][iScan];
+	}
+
+	return 0;
+}
+
+void CStatusMonitor::SetGrabEnd(int nCamera, int iScan)
+{
+	if (VALID_CAM_SCAN(nCamera, iScan)) {
+		m_bGrabEnd[nCamera][iScan] = TRUE;
 	}
 }
 
-int	CStatusMonitor::GetGrabFrameCount(int iScan)
+void CStatusMonitor::SetGrabFrametoScan(int nCamera, int iScan,int nFrame)
 {
-	if(iScan < 0 || iScan >= MAX_SCAN_COUNT)
-		return 0;
-
-	return m_nGrabFrame[iScan];
-}
-
-void CStatusMonitor::SetGrabEnd(int iScan)
-{
-	if(iScan < 0 || iScan >= MAX_SCAN_COUNT)
-		return;
-
-	m_bGrabEnd[iScan] = TRUE;
-}
-
-void CStatusMonitor::SetGrabFrametoScan(int iScan,int nFrame)
-{
-	if(iScan < 0 || iScan >= MAX_SCAN_COUNT)
-		return;
-
-	m_nGrabFrame[iScan] = nFrame;
+	if (VALID_CAM_SCAN(nCamera, iScan)) {
+		m_nGrabFrame[nCamera][iScan] = nFrame;
+	}
 }
 
 BOOL CStatusMonitor::DeleteFolder(const CString &strFolder)
diff --git a/EdgeInspector_App/Define/StatusMonitor.h b/EdgeInspector_App/Define/StatusMonitor.h
index 7ad3b82..e9fb842 100644
--- a/EdgeInspector_App/Define/StatusMonitor.h
+++ b/EdgeInspector_App/Define/StatusMonitor.h
@@ -36,9 +36,9 @@
 	
 	void		InitGlassLoading();
 
-	void		SetGrabFrametoScan(int iScan,int nFrame);
-	int			GetGrabFrameCount(int iScan);
-	void		SetGrabEnd(int iScan);
+	void		SetGrabFrametoScan(int nCamera, int iScan, int nFrame);
+	int			GetGrabFrameCount(int nCamera, int iScan);
+	void		SetGrabEnd(int nCamera, int iScan);
 
 	BOOL		DeleteFolder(const CString &strFolder);
 	BOOL		CheckDirectory(const TCHAR szPathName[], BOOL bDelete = FALSE);
@@ -47,8 +47,8 @@
 	int			m_iScanIdx;
 	CFrameBufferController	*m_pFrameBuffer[MAX_CAMERA_COUNT];
 	
-	int			m_nGrabFrame[MAX_SCAN_COUNT];
-	BOOL		m_bGrabEnd[MAX_SCAN_COUNT];
+	int			m_nGrabFrame[MAX_CAMERA_COUNT][MAX_SCAN_COUNT];
+	BOOL		m_bGrabEnd[MAX_CAMERA_COUNT][MAX_SCAN_COUNT];
 
 	CControl_Interface*		m_pControlInterface;
 	CLightManager*			m_pLightManager;
diff --git a/EdgeInspector_App/Grabber/MulticamControl.cpp b/EdgeInspector_App/Grabber/MulticamControl.cpp
index c091380..14b0c93 100644
--- a/EdgeInspector_App/Grabber/MulticamControl.cpp
+++ b/EdgeInspector_App/Grabber/MulticamControl.cpp
@@ -374,18 +374,19 @@
 	m_nEndFrameIdx++;			//Count
 	m_nSetBufferIdx++;		//index
 	
-	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(m_nScanIndex))
+	int nCameraIdx = m_Param.nCameraIdx;
+	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex))
 	{
 		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_nBoardID, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(m_nScanIndex));
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_nBoardID, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex));
 		return TRUE;
 	}
 
 	if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount())
 	{
 		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
 		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_nBoardID, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
diff --git a/EdgeInspector_App/Grabber/MulticamControl.h b/EdgeInspector_App/Grabber/MulticamControl.h
index 489fb35..4de1b74 100644
--- a/EdgeInspector_App/Grabber/MulticamControl.h
+++ b/EdgeInspector_App/Grabber/MulticamControl.h
@@ -42,8 +42,9 @@
 	virtual void	ClearGrabIdx();
 	virtual stFrameIndex	GetGrabFrame();
 	virtual stFrameIndex	GetGrabFrameNoRemove();
-	virtual CFrameBufferController	*GetFrameBuffer(){return m_pFrameBuffer;}
-	virtual BOOL	SetTriggerMode( BOOL bExTrigger ){return TRUE;}
+	virtual CFrameBufferController	*GetFrameBuffer() { return m_pFrameBuffer; }
+	virtual BOOL	SetTriggerMode( BOOL bExTrigger ) { return TRUE; }
+	virtual BOOL	DumpBufferAsOneImage(int iScan, LPCTSTR pszPath) { return TRUE; }
 
 public:	
 #if OFFLINE_KEY == 0
diff --git a/EdgeInspector_App/Grabber/RadientControl.cpp b/EdgeInspector_App/Grabber/RadientControl.cpp
index 37ddb61..1496118 100644
--- a/EdgeInspector_App/Grabber/RadientControl.cpp
+++ b/EdgeInspector_App/Grabber/RadientControl.cpp
@@ -2,8 +2,12 @@
 #include "RadientControl.h"
 #include "FrameBufferController.h"
 
-MIL_ID		g_MilApplication_Radient	= M_NULL;	/* Application identifier.  */
-int			g_nGrabberCount_Radient		= 0;		// grabber count
+MIL_ID g_MilApplication_Radient	= M_NULL;	/* Application identifier.  */
+int	   g_nGrabberCount_Radient	= 0;		// grabber count
+
+// 璋冭瘯
+#define GRAB_DEBUG_ENABLE	0				// 缃� 0 鍏抽棴鎵�鏈夎皟璇曡緭鍑轰笌杞瓨
+#define GRAB_DUMP_DIR		_T("D:\\Dump")  // 杈撳嚭鐩綍
 
 //==========================================================================================================================================================================
 // Grabber Radient
@@ -23,152 +27,161 @@
 
 CGrabberRadient::~CGrabberRadient()
 {
-	if(m_pFrameBuffer != NULL)
+	if (m_pFrameBuffer != NULL) {
 		delete m_pFrameBuffer;
-	m_pFrameBuffer = NULL;
+		m_pFrameBuffer = NULL;
+	}
 }
 
 BOOL CGrabberRadient::Initialize(void *pParam, int *pErrorCode,int iBoard)
 {
 	_GRABBER_INIT_PARAM_ *pParameter = (_GRABBER_INIT_PARAM_ *)pParam;
-
-	if(NULL != pParameter)
-	{
-		m_Param = *pParameter;		
-		
-	//	return TRUE;
-
-		CString			strDCF;
-		strDCF = m_Param.cDCFPath;
-
-		CString strTmp;		
-
-		if(g_nGrabberCount_Radient == 0)
-		{
-			MappAlloc(M_NULL,M_DEFAULT, &g_MilApplication_Radient);
-		}		
-
-		g_nGrabberCount_Radient++;				
-
-		MsysAlloc(M_SYSTEM_RADIENTEVCL, m_Param.nBoardIdx, M_DEFAULT, &m_MilSystem);
-		//MsysAlloc(M_DEFAULT, MIL_TEXT("M_DEFAULT"), m_Param.nBoardIdx, M_DEFAULT, &m_MilSystem);
-		if(CheckLastError())
-			return FALSE;		
-		
-		MdigAlloc(m_MilSystem  , m_Param.nBoardCh , strDCF, M_DEFAULT, &m_MilDigitizer);
-		if(CheckLastError())
-			return FALSE;
-
-		for(int j = 0; j < BUFFERING_SIZE_MAX ;j++)
-		{
-			MbufAlloc2d(m_MilSystem, m_Param.nFrameWidth, m_Param.nFrameHeight, 8+M_UNSIGNED, M_IMAGE+M_GRAB, &m_Milbufgrab[j]);
-		}		
-		if(CheckLastError())
-			return FALSE;
-
-		/*
-		INT nExposureTimer = m_Param.nExposure*1000;
-		INT nExposureTimerDelay = m_Param.nExposureDelay*1000;
-
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1,  nExposureTimer);                        //10us
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);                 //10us
-
-		if(m_Param.nImgFlipX == 1)
-			SetImageFlipX(TRUE);
-		else
-			SetImageFlipX(FALSE);
-		*/
-
-		//MdigControl(m_MilDigitizer,M_GRAB_MODE   , M_ASYNCHRONOUS);
-		MdigControl(m_MilDigitizer,M_GRAB_TIMEOUT, M_INFINITE);
-		if(CheckLastError())
-			return FALSE;
-		
-		m_DigitizerStatus.status = M_STOP;	
-		
-	}
-	else
+	if(NULL == pParameter) {
 		return FALSE;
+	}
+	m_Param = *pParameter;
+
+	CString	strDCF;
+	strDCF = m_Param.cDCFPath;
+
+	if (g_nGrabberCount_Radient == 0) {
+		MappAlloc(M_NULL, M_DEFAULT, &g_MilApplication_Radient);
+	}
+	g_nGrabberCount_Radient++;
+
+	// 鍒嗛厤绯荤粺
+	MsysAlloc(M_SYSTEM_RADIENTEVCL, m_Param.nBoardIdx, M_DEFAULT, &m_MilSystem);
+	if (CheckLastError()) {
+		return FALSE;
+	}
+
+	// 鍒嗛厤 digitizer锛孧_DEV0/M_DEV1 鍖哄垎 CH0/CH1
+	MIL_INT nDev = m_Param.nBoardCh;
+	MdigAlloc(m_MilSystem, nDev, strDCF, M_DEFAULT, &m_MilDigitizer);
+	if (CheckLastError()) {
+		MIL_INT nErrorCode = 0;
+		MappGetError(M_GLOBAL, &nErrorCode);
+		g_pLog->DisplayMessage(_T("Digitizer Alloc Error | BoardIdx=%d, BoardCh=%d, DCF=\"%s\", MIL_Error=%ld"), m_Param.nBoardIdx, m_Param.nBoardCh, strDCF, nErrorCode);
+		return FALSE;
+	}
+	g_pLog->DisplayMessage(_T("Digitizer Alloc | BoardIdx=%d, BoardCh=%d, DCF=\"%s\""), m_Param.nBoardIdx, m_Param.nBoardCh, strDCF);
+
+	// 鏌ヨ鐪熷疄灏哄
+	MIL_INT nSizeX = 0, nSizeY = 0, nBands = 1, nType = 0;
+	MdigInquire(m_MilDigitizer, M_SIZE_X, &nSizeX);
+	MdigInquire(m_MilDigitizer, M_SIZE_Y, &nSizeY);
+	MdigInquire(m_MilDigitizer, M_SIZE_BAND, &nBands);
+	MdigInquire(m_MilDigitizer, M_TYPE, &nType);
+
+	// 鐢ㄧ‖浠跺疄闄呭�艰鐩栭厤缃�
+	if (m_Param.nFrameWidth != (int)nSizeX || m_Param.nFrameHeight != (int)nSizeY) {
+		g_pLog->DisplayMessage(_T("Digitizer Size sync: cfg %dx%d -> hw %dx%d"), m_Param.nFrameWidth, m_Param.nFrameHeight, (int)nSizeX, (int)nSizeY);
+		m_Param.nFrameWidth = (int)nSizeX;
+		m_Param.nFrameHeight = (int)nSizeY;
+	}
+
+	// 鍒嗛厤缂撳啿
+	for (int j = 0; j < BUFFERING_SIZE_MAX; j++) {
+		MbufAlloc2d(m_MilSystem, m_Param.nFrameWidth, m_Param.nFrameHeight, (/*nType ? nType : */8 + M_UNSIGNED), M_IMAGE + M_GRAB + M_PROC, &m_Milbufgrab[j]);
+	}
+
+	if (CheckLastError()) {
+		return FALSE;
+	}
+
+	/*
+	INT nExposureTimer = m_Param.nExposure*1000;
+	INT nExposureTimerDelay = m_Param.nExposureDelay*1000;
+
+	MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1,  nExposureTimer);                        //10us
+	MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);             //10us
+
+	if(m_Param.nImgFlipX == 1)
+		SetImageFlipX(TRUE);
+	else
+		SetImageFlipX(FALSE);
+	*/
+
+	// 鎶撳彇鎺у埗
+	MdigControl(m_MilDigitizer, M_GRAB_MODE, M_ASYNCHRONOUS);
+	MdigControl(m_MilDigitizer, M_GRAB_TIMEOUT, M_INFINITE);
+	if (CheckLastError()) {
+		return FALSE;
+	}
+
+	m_DigitizerStatus.status = M_STOP;
 
 	return TRUE;
 }
 
 BOOL CGrabberRadient::SetImageFlipX(BOOL bOn)
 {
-	if(bOn == TRUE)
+	if (bOn == TRUE) {
 		MdigControl(m_MilDigitizer, M_GRAB_DIRECTION_X, M_REVERSE);
-	else
+	}
+	else {
 		MdigControl(m_MilDigitizer, M_GRAB_DIRECTION_X, M_FORWARD);
+	}
 
 	return TRUE;
 }
 
 BOOL CGrabberRadient::CheckLastError()
 {
-	BOOL bReturn = FALSE;
-
 	MIL_INT nErrorCode; 
-	CString strMsg;
-
-	if(MappGetError(M_GLOBAL, &nErrorCode))
-	{
+	if(MappGetError(M_GLOBAL, &nErrorCode)) {
 		int	iCam = m_Param.nCameraIdx;	
 		int	iScan = m_Param.nCameraScan;
 		int	iBoard = m_Param.nBoardIdx;
 		int	iBoardCh = m_Param.nBoardCh;
 		
-		strMsg.Format(_T("[Board:%d,ch %d] [Camera:%d,Scan %d] MIL Error Code : %d"), iBoard,iBoardCh,iCam,iScan, nErrorCode);
+		CString strMsg;
+		strMsg.Format(_T("[Board=%d,ch=%d] [Camera=%d,Scan=%d] MIL Error Code : %d"), iBoard,iBoardCh,iCam,iScan, nErrorCode);
 		g_pLog->DisplayMessage(strMsg);	
 		
-		bReturn = TRUE;
+		return TRUE;
 	}	
-	else
-		bReturn = FALSE;
 
-	return bReturn;
+	return FALSE;
 }
 
 BOOL CGrabberRadient::InitializeBuffer(void *pParam)
 {
 	_GRABBER_INIT_PARAM_ *pParameter = (_GRABBER_INIT_PARAM_ *)pParam;
-
-	BOOL		bRet = TRUE;
-	if(NULL != pParameter)
-	{
-		m_Param = *pParameter;
-
-		bRet = CreateGrabBuffer(m_Param.nScanCount,m_Param.nGrabBufCount,m_Param.nFrameWidth,m_Param.nFrameHeight);
+	if (NULL == pParameter) {
+		g_pLog->DisplayMessage(_T("InitializeBuffer : pParameter is NULL"));
+		return FALSE;
 	}
 
-	return bRet;
+	m_Param = *pParameter;
+	return CreateGrabBuffer(m_Param.nScanCount, m_Param.nGrabBufCount, m_Param.nFrameWidth, m_Param.nFrameHeight);
 }
 
 BOOL CGrabberRadient::Deinitialize(void)
 {	
-	if (IsGrabbing())
+	if (IsGrabbing()) {
 		GrabScanStop();
+	}
 
 	g_nGrabberCount_Radient--;
 
-	for(int i = 0; i < BUFFERING_SIZE_MAX ;i++)
-	{
+	for(int i = 0; i < BUFFERING_SIZE_MAX ;i++) {
 		MbufFree(m_Milbufgrab[i]);
 	}		
 
-	MdigFree(m_MilDigitizer);	
-	
+	MdigFree(m_MilDigitizer);		
 	MsysFree(m_MilSystem);
 
-	if(g_nGrabberCount_Radient == 0)
+	if (g_nGrabberCount_Radient == 0) {
 		MappFree(g_MilApplication_Radient);
+	}
 
 	return TRUE;
 }
 
 BOOL CGrabberRadient::GrabLiveStart(int nExposure)
 {
-	if (IsGrabbing())
-	{
+	if (IsGrabbing()) {
 		g_pLog->DisplayMessage(_T("Start Live Acq : IsGrabbing -> Stop Acq %d"), m_nEndFrameIdx);
 		GrabScanStop();
 		Sleep(100);				
@@ -179,11 +192,10 @@
 	m_nSetBufferIdx = -1;
 	m_nScanIndex = 0;	
 
-	if(m_DigitizerStatus.status == M_STOP)
-	{				
-		m_DigitizerStatus.status			= M_FREE_START;
-		m_DigitizerStatus.nCount			= 0;
-		m_DigitizerStatus.nIndex			= m_Param.nCameraScan;					
+	if(m_DigitizerStatus.status == M_STOP) {				
+		m_DigitizerStatus.status = M_FREE_START;
+		m_DigitizerStatus.nCount = 0;
+		m_DigitizerStatus.nIndex = m_Param.nCameraScan;					
 
 		MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);				
 	}
@@ -197,9 +209,11 @@
 
 BOOL CGrabberRadient::GrabScanStart(int iScan, BOOL bFreeRun, int nPeriod, int nExposure, BOOL bAuto)
 {	
-	if (IsGrabbing())
-	{
-		g_pLog->DisplayMessage(_T("Start Acq : IsGrabbing -> Stop Acq %d"), m_nEndFrameIdx);
+	int nCameraIdx = m_Param.nCameraIdx;
+	g_pLog->DisplayMessage(_T("%d Start Acq : Camera=%d, Scan=%d, GrabFrameCount=%d, FrameHeight=%d"), m_Param.nBoardIdx, nCameraIdx, iScan, g_pStatus->GetGrabFrameCount(nCameraIdx, iScan), m_Param.nFrameHeight);
+
+	if (IsGrabbing()) {
+		g_pLog->DisplayMessage(_T("%d Start Acq : Camera=%d, Scan=%d, IsGrabbing -> Stop Acq %d"), m_Param.nBoardIdx, nCameraIdx, iScan, m_nEndFrameIdx);
 		GrabScanStop();
 		Sleep(100);
 	}
@@ -209,84 +223,73 @@
 	m_nSetBufferIdx = -1;
 	m_nScanIndex = iScan;
 
-	if(bAuto == TRUE)
-	{
+	if (bAuto == TRUE) {
 		int nDigitizer = 0;
 
-		if(bFreeRun == FALSE)
-		{
+		if (bFreeRun == FALSE) {
 			SetTriggerMode(TRUE);
 
 			/* Start the processing. The processing function is called for every frame grabbed. */
-			if(m_DigitizerStatus.status == M_STOP)
-			{				
-				m_DigitizerStatus.status			= M_START;
-				m_DigitizerStatus.nCount			= 0;
-				m_DigitizerStatus.nIndex			= iScan;				
-				
-				MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);				
+			if (m_DigitizerStatus.status == M_STOP) {
+				m_DigitizerStatus.status = M_START;
+				m_DigitizerStatus.nCount = 0;
+				m_DigitizerStatus.nIndex = iScan;
+
+				MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);
 			}
 		}
-		else
-		{
-			if(m_DigitizerStatus.status == M_STOP)
-			{				
-				m_DigitizerStatus.status			= M_FREE_START;
-				m_DigitizerStatus.nCount			= 0;
-				m_DigitizerStatus.nIndex			= iScan;				
+		else {
+			if (m_DigitizerStatus.status == M_STOP) {
+				m_DigitizerStatus.status = M_FREE_START;
+				m_DigitizerStatus.nCount = 0;
+				m_DigitizerStatus.nIndex = iScan;
 
-				MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);				
+				MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);
 			}
 		}
 
 		m_isGrabbing = TRUE;
 		m_isLiveGrab = FALSE;
 	}
-	else
-	{
+	else {
 		SimulationGrab(iScan);
-	}	
-
-	g_pLog->DisplayMessage(_T("Start Acq : %d"), iScan);
+	}
 
 	return TRUE;
 }
 
 void CGrabberRadient::SimulationGrab(int iScan)
 {
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return;
-		
-	int			nFrameCnt = m_pFrameBuffer->GetFrameCount();
+	}
+	
+	int	nFrameCnt = m_pFrameBuffer->GetFrameCount();
 
 	m_nEndFrameIdx = nFrameCnt;
-	m_nSetBufferIdx = nFrameCnt -1;
+	m_nSetBufferIdx = nFrameCnt - 1;
 	
-	for(int i=0;i<nFrameCnt;i++)
-	{
-		SetInsertFrame(iScan,i);
+	for (int i = 0; i < nFrameCnt; i++) {
+		SetInsertFrame(iScan, i);
 	}
 }
 
 BOOL CGrabberRadient::GrabScanStop(void)
 {
-	g_pLog->DisplayMessage(_T("%d StopAcq : Scan %d, Grab %d, End %d"), m_Param.nBoardIdx,m_nScanIndex,m_nSetBufferIdx, m_nEndFrameIdx);
-	
+	g_pLog->DisplayMessage(_T("%d StopAcq : Camera %d, Scan %d, Grab %d, End %d"), m_Param.nBoardIdx, m_Param.nCameraIdx, m_nScanIndex, m_nSetBufferIdx, m_nEndFrameIdx);
+
 	CString strMsg;
-	
-	if( m_DigitizerStatus.status == M_START)
-	{
-		MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);
-		m_DigitizerStatus.nIndex	= m_nScanIndex;
-		m_DigitizerStatus.status	= M_STOP;				
-	}	
-	else if(m_DigitizerStatus.status == M_FREE_START)
-	{
-		MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);
-		m_DigitizerStatus.nIndex	= m_nScanIndex;
-		m_DigitizerStatus.status	= M_STOP;		
+	if (m_DigitizerStatus.status == M_START) {
+		MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);
+		m_DigitizerStatus.nIndex = m_nScanIndex;
+		m_DigitizerStatus.status = M_STOP;
 	}
-	
+	else if (m_DigitizerStatus.status == M_FREE_START) {
+		MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);
+		m_DigitizerStatus.nIndex = m_nScanIndex;
+		m_DigitizerStatus.status = M_STOP;
+	}
+
 	m_isGrabbing = FALSE;
 	m_isLiveGrab = FALSE;
 
@@ -303,57 +306,62 @@
 	return m_nSetBufferIdx - nFrameNo;		
 }
 
-LPBYTE	CGrabberRadient::GetFrameHeaderLine(int iScan,int nLine, BOOL* bSuccess)
+LPBYTE CGrabberRadient::GetFrameHeaderLine(int iScan,int nLine, BOOL* bSuccess)
 {	
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return NULL;
-
+	}
 	return m_pFrameBuffer->GetFrameHeaderLine(iScan,nLine);
 }
 
 LPBYTE CGrabberRadient::GetFrameHeader(int iScan,int nFrameNo, BOOL* bRet)
 {		
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return NULL;
-
-	return m_pFrameBuffer->GetFrameBuferHeader(iScan,nFrameNo);
+	}
+	return m_pFrameBuffer->GetFrameBuferHeader(iScan, nFrameNo);
 }
 
-BOOL CGrabberRadient::GetSmallImage(int iScan,LPBYTE lpIn, int nXStart, int nYStart, int nXSize, int nYSize, BOOL bMustMapping) 
+BOOL CGrabberRadient::GetSmallImage(int iScan, LPBYTE lpIn, int nXStart, int nYStart, int nXSize, int nYSize, BOOL bMustMapping)
 {
 	int nBufSizeX = m_Param.nFrameWidth;
 	int nBufSizeY = m_Param.nFrameHeight;
 
-	if (nXStart < 0 || nYStart < 0)
+	if (nXStart < 0 || nYStart < 0) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : Invalid Start Position X=%d, Y=%d"), nXStart, nYStart);
 		return FALSE;
-	if (nXStart + nXSize > nBufSizeX)
+	}
+
+	if (nXStart + nXSize > nBufSizeX) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : Invalid X Size Start=%d, Size=%d, BufferSizeX=%d"), nXStart, nXSize, nBufSizeX);
 		return FALSE;
-	if (nYStart + nYSize > nBufSizeY* GetEndFrameIdx())
+	}
+
+	if (nYStart + nYSize > nBufSizeY * GetEndFrameIdx()) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : Invalid Y Size Start=%d, Size=%d, BufferSizeY=%d"), nYStart, nYSize, nBufSizeY);
 		return FALSE;
+	}
 	
-	// 鐭疮 姗囬キ鐑� 閿呴緥瀹� 鍦� 姗囬キ鐑� 閿呴緥.
 	int nStartFrameNo = nYStart / nBufSizeY;
 	int nEndFrameNo = (nYStart + nYSize) / nBufSizeY;
-	LPBYTE	lpHeadAddr = GetFrameHeader(iScan,nStartFrameNo);
-	if (!lpHeadAddr)
-	{
+	LPBYTE lpHeadAddr = GetFrameHeader(iScan, nStartFrameNo);
+	if (!lpHeadAddr) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : GetFrameHeader Failed for Scan %d, Frame %d"), iScan, nStartFrameNo);
 		return FALSE;
 	}
 	LPBYTE lpStart = lpHeadAddr + (nYStart % nBufSizeY) * nBufSizeX + nXStart;
 	
 	int nLine = 0;
-	for (int i = 0; i < nYSize; i++)
-	{
+	for (int i = 0; i < nYSize; i++) {
 		memcpy(lpIn + i * nXSize, lpStart + nLine * nBufSizeX, nXSize);
-		if (nStartFrameNo <= nEndFrameNo && (nYStart + i + 1) % nBufSizeY  == 0)
-		{
-			// 鎹炲浐鐦ょ敨 铦堕兇鍏风獚缁� 搴峰紑鎹� MemFrameNo 鐗堟媽淇� 鍚у獨涔愮话 鐗堝揩 璐稿簻.
-			lpHeadAddr = GetFrameHeader(iScan,++nStartFrameNo);
+		if (nStartFrameNo <= nEndFrameNo && (nYStart + i + 1) % nBufSizeY == 0) {
+			lpHeadAddr = GetFrameHeader(iScan, ++nStartFrameNo);
 			lpStart = lpHeadAddr + nXStart;
 			nLine = 0;
 		}
-		else
+		else {
 			nLine++;
+		}
 	}
 	
 	return TRUE;
@@ -361,107 +369,201 @@
 
 void CGrabberRadient::SetSimulFrame(int nFrame)
 {
-// 	if(nFrame == 0)
-// 	{
-// 		for(int i = 0; i < g_pBase->m_nProcessMargin; i++)
-// 			SetSimulBuffer(i, m_nScanIndex % 2 == 1);
-// 	}
-// 
-// 	m_nEndFrameIdx = CHKMIN(GetGrabFrameNo(m_nScanIndex), nFrame + g_pBase->m_nProcessMargin + 1);
-// 	SetSimulBuffer(m_nEndFrameIdx - 1, m_nScanIndex % 2 == 1);
-// 
-// 	if(GetParents() != NULL)
-// 		GetParents()->PostMessage(UM_IMAGE_GRAB, m_nEndFrameIdx - 1,NULL);
+	return;
 }
 
 BOOL CGrabberRadient::Processing(long HookType, MIL_ID HookId)
 {
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return FALSE;
-	
+	}
+
+	m_nEndFrameIdx++;	//Count
+	m_nSetBufferIdx++;	//index
+
+	int nCameraIdx = m_Param.nCameraIdx;
+	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex)) {
+		GrabScanStop();
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab [Cam:%d][Scan:%d] - EndFrameIdx=%d  FrameCount=%d"), m_Param.nBoardIdx, nCameraIdx, m_nScanIndex, m_nEndFrameIdx, g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex));
+		return TRUE;
+	}
+
+	if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount()) {
+		GrabScanStop();
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d BufferIndex Overflow : Stop Grab [Cam:%d][Scan:%d] - FrameIdx=%d  BufferCount=%d"), m_Param.nBoardIdx, nCameraIdx, m_nScanIndex, m_nEndFrameIdx, m_pFrameBuffer->GetFrameCount());
+		return TRUE;
+	}
+
 	MIL_ID ModifiedImage = 0;
-
-	m_nEndFrameIdx++;			//Count
-	m_nSetBufferIdx++;		//index
-
-	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(m_nScanIndex))
-	{
-		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(m_nScanIndex));
+	LPBYTE pBuffer = m_pFrameBuffer->GetFrameBuferHeader(m_nScanIndex, m_nSetBufferIdx);
+	if (pBuffer == NULL) {
+		GrabScanStop();
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d BufferPointer NULL : Stop Grab [Cam:%d][Scan:%d] - FrameIdx=%d  BufferCount=%d"), m_Param.nBoardIdx, nCameraIdx, m_nScanIndex, m_nEndFrameIdx, m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
 
-	if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount())
-	{
-		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
-		return TRUE;
+	MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedImage);
+	MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);
+	MbufGet2d(ModifiedImage, 0, 0, m_Param.nFrameWidth, m_Param.nFrameHeight, pBuffer);
+	MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);
+
+	SetInsertFrame(m_nScanIndex, m_nSetBufferIdx);
+
+#if GRAB_DEBUG_ENABLE
+	// 璋冭瘯鐢ㄧ殑璇︾粏鏃ュ織
+	g_pLog->DisplayMessage(
+		_T("[Grab-Processing] FrameAcquired | Board=%d Cam=%d Scan=%d FrameIdx=%d BufIdx=%d Size=%dx%d BufCount=%d"),
+		m_Param.nBoardIdx,
+		m_Param.nCameraIdx,
+		m_nScanIndex,
+		m_nEndFrameIdx,
+		m_nSetBufferIdx,
+		m_Param.nFrameWidth,
+		m_Param.nFrameHeight,
+		m_pFrameBuffer->GetFrameCount()
+	);
+#endif // GRAB_DEBUG_ENABLE
+
+	return TRUE;
+}
+
+BOOL CGrabberRadient::DumpCurrentBuffer(LPBYTE pBuffer, LPCTSTR pszDir)
+{
+	if (!pszDir || !*pszDir) {
+		g_pLog->DisplayMessage(_T("Dump invalid dir"));
+		return FALSE;
 	}
 
-	LPBYTE		pBuffer = m_pFrameBuffer->GetFrameBuferHeader(m_nScanIndex,m_nSetBufferIdx);
-	if(pBuffer == NULL)
-	{
-		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
-		return TRUE;
+	const MIL_INT W = m_Param.nFrameWidth;
+	const MIL_INT H = m_Param.nFrameHeight;
+
+	MIL_INT bits = 8;
+	if (m_MilDigitizer) { 
+		MdigInquire(m_MilDigitizer, M_SIZE_BIT, &bits);
+	}
+	const MIL_INT milType = (bits > 8) ? (16 + M_UNSIGNED) : (8 + M_UNSIGNED);
+
+	if (CreateDirectory(pszDir, nullptr) == 0) {
+		DWORD e = GetLastError();
+		if (e != ERROR_ALREADY_EXISTS) {
+			g_pLog->DisplayMessage(_T("DumpFB CreateDirectory failed (%lu): %s"), e, pszDir);
+			return FALSE;
+		}
 	}
 
-	MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedImage);
-	MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);	
-	MbufGet2d(ModifiedImage,0,0,m_Param.nFrameWidth,m_Param.nFrameHeight,pBuffer);
-	MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);	
-			
+	MIL_ID img = M_NULL;
+	MbufAlloc2d(m_MilSystem, W, H, milType, M_IMAGE + M_PROC, &img);
+	if (img == M_NULL) {
+		g_pLog->DisplayMessage(_T("DumpFB MbufAlloc2d failed: %dx%dx%dbit"), (int)W, (int)H, (int)bits);
+		return FALSE;
+	}
 
-	SetInsertFrame(m_nScanIndex,m_nSetBufferIdx);
+	static LONG sSeq = 0;
+	LONG seq = InterlockedIncrement(&sSeq);
 
+	MbufPut2d(img, 0, 0, W, H, pBuffer);
+
+	CString path;
+	path.Format(_T("%s\\Cam%d_Scan%d_seq%06ld.tif"), pszDir, m_Param.nCameraIdx, m_nScanIndex, (long)seq);
+
+	MIL_INT dummy = 0;
+	MappGetError(M_GLOBAL, &dummy);
+
+	MbufExport((MIL_CONST_TEXT_PTR)(LPCTSTR)path, M_TIFF, img);
+
+	MIL_INT err = 0;
+	if (MappGetError(M_GLOBAL, &err)) {
+		g_pLog->DisplayMessage(_T("DumpFB export failed (MIL_ERR=%lld): %s"), err, path);
+	}
+
+	MbufFree(img);
 	return TRUE;
 }
 
 long MFTYPE CGrabberRadient::CallbackHookFunction(long HookType, MIL_ID HookId, void MPTYPE *HookDataPtr)
 {
-	if(GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST)
+	if (GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST) {
 		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+		g_pLog->DisplayMessage(_T("[Grab] CallbackHookFunction : thread priority set to HIGHEST"));
+	}
 
+	MIL_ID nEventDig = M_NULL;
 	CGrabberRadient	*pRadient = (CGrabberRadient*)HookDataPtr;
+	if (nullptr == pRadient){
+		return 0;
+	}
 
-	pRadient->Processing(HookType,HookId);	
+	MdigGetHookInfo(HookId, M_DIGITIZER_ID, &nEventDig);
+	if (nEventDig != pRadient->m_MilDigitizer) {
+		g_pLog->DisplayMessage(_T("CallbackHookFunction : HookId %lld does not match Digitizer %lld"), HookId, pRadient->m_MilDigitizer);
+		return 0;
+	}
 
-	return 0;
+	return pRadient->Processing(HookType, HookId) ? 0 : 1;
 }
 
 long MFTYPE CGrabberRadient::CallbackFreeRunFunction(long HookType, MIL_ID HookId, void MPTYPE *HookDataPtr)
 {
-	if(GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST)
+	if (GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST) {
 		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+		g_pLog->DisplayMessage(_T("CallbackFreeRunFunction : thread priority set to HIGHEST"));
+	}
 
+	MIL_ID nEventDig = M_NULL;
 	CGrabberRadient	*pRadient = (CGrabberRadient*)HookDataPtr;
+	if (nullptr == pRadient) {
+		return 0;
+	}
 
-	if(pRadient->m_isLiveGrab == TRUE)		// Live Grab 鐭�.
-	{
+	MdigGetHookInfo(HookId, M_DIGITIZER_ID, &nEventDig);
+	if (nEventDig != pRadient->m_MilDigitizer) {
+		g_pLog->DisplayMessage(_T("CallbackFreeRunFunction : HookId %lld does not match Digitizer %lld"), HookId, pRadient->m_MilDigitizer);
+		return 0;
+	}
+
+	if(pRadient->m_isLiveGrab == TRUE) {
 		pRadient->m_nSetBufferIdx = 0;
+		int nCameraIdx = pRadient->m_Param.nCameraIdx;
 
-		LPBYTE		pBuffer = pRadient->m_pFrameBuffer->GetFrameBuferHeader(pRadient->m_nScanIndex,pRadient->m_nSetBufferIdx);
-		if(pBuffer == NULL)
-		{
+		LPBYTE pBuffer = pRadient->m_pFrameBuffer->GetFrameBuferHeader(pRadient->m_nScanIndex, pRadient->m_nSetBufferIdx);
+		if(pBuffer == NULL) {
 			pRadient->GrabScanStop();		
-			g_pStatus->SetGrabEnd(pRadient->m_nScanIndex);
+			g_pStatus->SetGrabEnd(nCameraIdx, pRadient->m_nScanIndex);
 			g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), pRadient->m_Param.nBoardIdx, pRadient->m_nScanIndex, pRadient->m_nEndFrameIdx,pRadient->m_pFrameBuffer->GetFrameCount());
 			return TRUE;
 		}
 
 		MIL_ID ModifiedImage = 0;
-		MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedImage);
-		MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);	
-		MbufGet2d(ModifiedImage,0,0,pRadient->m_Param.nFrameWidth,pRadient->m_Param.nFrameHeight,pBuffer);
-		MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);	
+		MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedImage);
+		MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);
+		MbufGet2d(ModifiedImage, 0, 0, pRadient->m_Param.nFrameWidth, pRadient->m_Param.nFrameHeight, pBuffer);
+		MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);
 		
 		/*
-		int			iGrab = pRadient->m_nSetBufferIdx%pRadient->m_Param.nGrabBufCount;
+		int iGrab = pRadient->m_nSetBufferIdx%pRadient->m_Param.nGrabBufCount;
 		MbufGet(pRadient->m_MilImageChild[iGrab],pBuffer);
 		*/
+
+#if GRAB_DEBUG_ENABLE
+		// 鎵撳嵃閲囬泦璇︾粏淇℃伅
+		g_pLog->DisplayMessage(
+			_T("[Grab-FreeRun] FrameAcquired | Board=%d Cam=%d Scan=%d FrameIdx=%d BufIdx=%d Size=%dx%d BufCount=%d"),
+			pRadient->m_Param.nBoardIdx,
+			pRadient->m_Param.nCameraIdx,
+			pRadient->m_nScanIndex,
+			pRadient->m_nEndFrameIdx,
+			pRadient->m_nSetBufferIdx,
+			pRadient->m_Param.nFrameWidth,
+			pRadient->m_Param.nFrameHeight,
+			pRadient->m_pFrameBuffer->GetFrameCount()
+		);
+
+		// 璋冭瘯鐢ㄧ殑鍥惧儚杞瓨
+		 pRadient->DumpCurrentBuffer(pBuffer, GRAB_DUMP_DIR);
+#endif  // GRAB_DEBUG_ENABLE
 
 		return TRUE;
 	}	
@@ -471,24 +573,22 @@
 
 BOOL CGrabberRadient::CreateGrabBuffer(int nScanCount,int nBufSize, int nBufSizeX, int nBufSizeY)
 {
-	SIZE_T tempBufferSize= nBufSize;
-	SIZE_T tempFrmCX = nBufSizeX;
-	SIZE_T tempFrmCY = nBufSizeY;
-	SIZE_T TotalBufferSize= tempBufferSize*tempFrmCX*tempFrmCY;	
+	SIZE_T nTempBufferSize= nBufSize;
+	SIZE_T nTempFrmCX = nBufSizeX;
+	SIZE_T nTempFrmCY = nBufSizeY;
+	SIZE_T nTotalBufferSize= nTempBufferSize * nTempFrmCX * nTempFrmCY;
 	m_nAllocatedGrabBufSize = nBufSize;	
 
-	if(m_pFrameBuffer != NULL)
+	if (m_pFrameBuffer != NULL) {
 		delete m_pFrameBuffer;
-	m_pFrameBuffer = NULL;
+		m_pFrameBuffer = NULL;
+	}
 
 	m_pFrameBuffer = new CFrameBufferController;
-
-	if(TRUE == m_pFrameBuffer->CreateBuffer(m_Param.nCameraIdx,nBufSizeX ,nBufSizeY,nBufSize, nScanCount))
-	{		
+	if (TRUE == m_pFrameBuffer->CreateBuffer(m_Param.nCameraIdx, nBufSizeX, nBufSizeY, nBufSize, nScanCount)) {		
 		g_pLog->DisplayMessage(_T("Create Buffer success!:Id[%d],Frame[%d,%d],Cnt[%d]"),m_Param.nCameraIdx,nBufSizeX,nBufSizeY,nBufSize);		
 	}
-	else
-	{
+	else {
 		g_pLog->DisplayMessage(_T("Create Buffer Fail!:Id[%d],Frame[%d,%d],Cnt[%d]"),m_Param.nCameraIdx,nBufSizeX,nBufSizeY,nBufSize);
 		return FALSE;
 	}
@@ -498,8 +598,9 @@
 
 void CGrabberRadient::ClearBuffer()
 {
-	if(m_pFrameBuffer != NULL)
+	if (m_pFrameBuffer != NULL) {
 		m_pFrameBuffer->ClearBuffer();
+	}
 }
 
 void CGrabberRadient::ClearGrabIdx()
@@ -525,21 +626,19 @@
 	return TRUE;
 }
 
-BOOL CGrabberRadient::FindGrabIdx(int iScan,int iFrame)
+BOOL CGrabberRadient::FindGrabIdx(int iScan, int iFrame)
 {
 	CSingleLock MyLock(&m_csIdxLock);
 	MyLock.Lock();
 
-	BOOL				bRet = FALSE;
-	stFrameIndex		stFrame;
-	for(dqGrabIdxIt it=m_dqCallbackFrame.begin();it!=m_dqCallbackFrame.end();it++)
-	{
+	BOOL bRet = FALSE;
+	stFrameIndex stFrame;
+	for (dqGrabIdxIt it = m_dqCallbackFrame.begin(); it != m_dqCallbackFrame.end(); it++) {
 		stFrame = *it;
-
-		if(stFrame.nScanIdx == iScan)
-		{
-			if(stFrame.nFrameIdx < iFrame)
+		if (stFrame.nScanIdx == iScan) {
+			if (stFrame.nFrameIdx < iFrame) {
 				bRet = TRUE;
+			}
 		}
 	}
 	MyLock.Unlock();
@@ -558,8 +657,7 @@
 
 	CSingleLock MyLock(&m_csIdxLock);
 	MyLock.Lock();
-	if(IsHasGrabFrame() == FALSE)
-	{
+	if(IsHasGrabFrame() == FALSE) {
 		MyLock.Unlock();
 		return stPop;
 	}
@@ -574,11 +672,9 @@
 stFrameIndex CGrabberRadient::GetGrabFrame()
 {
 	stFrameIndex stPop(-1, -1);	
-
 	CSingleLock MyLock(&m_csIdxLock);
 	MyLock.Lock();
-	if(IsHasGrabFrame() == FALSE)
-	{
+	if(IsHasGrabFrame() == FALSE) {
 		MyLock.Unlock();
 		return stPop;
 	}
@@ -598,29 +694,73 @@
 
 BOOL CGrabberRadient::SetTriggerMode( BOOL bExTrigger )
 {	
-	INT nExposureTimer = m_Param.nExposure*1000;
-	INT nExposureTimerDelay = m_Param.nExposureDelay*1000;
-
-	if(bExTrigger == TRUE)	// Trigger
-	{
-		/*
-		MdigControl(m_MilDigitizer, M_CAMERALINK_CC1_SOURCE, M_GRAB_EXPOSURE+M_TIMER1);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE+M_TIMER1, M_ENABLE);
-		//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_SOURCE+M_TIMER1, nHWPort);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1,  nExposureTimer);                        //10us
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);                 //10us
-		*/
-	}
-	else		// Live
-	{
-		/*
-		MdigControl(m_MilDigitizer, M_CAMERALINK_CC1_SOURCE, M_GRAB_EXPOSURE+M_TIMER1);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE+M_TIMER1, M_ENABLE);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_SOURCE+M_TIMER1, M_CONTINUOUS);                      // Periodic 鑴氶緥 鐗㈠晩
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1, nExposureTimer);                        //10000ns
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);                 //10000ns
-		*/
+	if (m_MilDigitizer == M_NULL) {
+		g_pLog->DisplayMessage(_T("SetTriggerMode failed: digitizer is NULL"));
+		return FALSE;
 	}
 
+	INT nExposureTimer = m_Param.nExposure * 1000;
+	INT nExposureTimerDelay = m_Param.nExposureDelay * 1000;
+	//MdigControl(m_MilDigitizer, M_CAMERALINK_CC1_SOURCE, M_GRAB_EXPOSURE + M_TIMER1);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE + M_TIMER1, M_ENABLE);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_SOURCE + M_TIMER1, bExTrigger ? M_HARDWARE : M_CONTINUOUS);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME + M_TIMER1, nExposureTimer);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY + M_TIMER1, nExposureTimerDelay);
+	g_pLog->DisplayMessage(_T("TriggerMode=%s, Exp(ns)=%d, Delay(ns)=%d"), bExTrigger ? _T("External") : _T("Live"), nExposureTimer, nExposureTimerDelay);
+
+	return TRUE;
+}
+
+BOOL CGrabberRadient::DumpBufferAsOneImage(int iScan, LPCTSTR pszPath)
+{
+	if (!m_pFrameBuffer) {
+		g_pLog->DisplayMessage(_T("Dump m_pFrameBuffer is NULL"));
+		return FALSE;
+	}
+
+	const int nFramesAlloc = m_pFrameBuffer->GetFrameCount();
+	const int nFramesGrab = GetEndFrameIdx();
+	const int nFrames = (nFramesGrab > 0 && nFramesGrab <= nFramesAlloc) ? nFramesGrab : nFramesAlloc;
+	if (nFrames <= 0) {
+		return FALSE;
+	}
+
+	const MIL_INT W = m_Param.nFrameWidth;
+	const MIL_INT H = m_Param.nFrameHeight;
+
+	// 淇濇寔鐪熷疄浣嶆繁锛�8/10/12/16bit -> 8/16bit缂撳啿锛�
+	MIL_INT bits = 8;
+	if (m_MilDigitizer) { 
+		MdigInquire(m_MilDigitizer, M_SIZE_BIT, &bits);
+	}
+
+	const int bpp = (int)((bits + 7) / 8);
+	const MIL_INT type = (bpp >= 2) ? (16 + M_UNSIGNED) : (8 + M_UNSIGNED);
+
+	// 鎷兼帴鎴愪竴寮犻暱鍥�
+	MIL_ID img = M_NULL;
+	MbufAlloc2d(m_MilSystem, W, H * nFrames, type, M_IMAGE + M_PROC, &img);
+	if (img == M_NULL) { 
+		return FALSE;
+	}
+
+	for (int f = 0; f < nFrames; ++f) {
+		LPBYTE src = m_pFrameBuffer->GetFrameBuferHeader(iScan, f);
+		if (!src) { 
+			break;
+		}
+
+		MbufPut2d(img, 0, (MIL_INT)f * H, W, H, src);
+	}
+
+	MbufExport((MIL_CONST_TEXT_PTR)(LPCTSTR)pszPath, M_TIFF, img);
+
+	MIL_INT err = 0;
+	if (MappGetError(M_GLOBAL, &err)) {
+		g_pLog->DisplayMessage(_T("DumpBufferAsOneImage Error : %d"), err);
+		return FALSE;
+	}
+
+	MbufFree(img);
 	return TRUE;
 }
\ No newline at end of file
diff --git a/EdgeInspector_App/Grabber/RadientControl.h b/EdgeInspector_App/Grabber/RadientControl.h
index 3eb84d7..993b039 100644
--- a/EdgeInspector_App/Grabber/RadientControl.h
+++ b/EdgeInspector_App/Grabber/RadientControl.h
@@ -46,15 +46,17 @@
 	virtual stFrameIndex	GetGrabFrameNoRemove();
 	virtual CFrameBufferController	*GetFrameBuffer(){return m_pFrameBuffer;}
 	virtual BOOL	SetTriggerMode( BOOL bExTrigger );
+	virtual BOOL	DumpBufferAsOneImage(int iScan, LPCTSTR pszPath);
 
 	dqGrabIdx		*GetGrabIdx(){return &m_dqCallbackFrame;}	
 	BOOL			FindGrabIdx(int iScan,int iFrame);	
 	BOOL			SetInsertFrame(int iScan,int iFrame);
 		
-	BOOL			IsHasGrabFrame();	
+	BOOL			IsHasGrabFrame();
 
 protected:	
 	BOOL			Processing(long HookType, MIL_ID HookId);
+	BOOL			DumpCurrentBuffer(LPBYTE pBuffer, LPCTSTR pszDir);
 //////////////////////////////////////////////////////////////////////////
 // Buffer
 public:	
diff --git a/EdgeInspector_App/Grabber/SapControl.cpp b/EdgeInspector_App/Grabber/SapControl.cpp
index 28c2ec7..bb613e8 100644
--- a/EdgeInspector_App/Grabber/SapControl.cpp
+++ b/EdgeInspector_App/Grabber/SapControl.cpp
@@ -761,18 +761,19 @@
 	pX64->m_nEndFrameIdx++;			//Count
 	pX64->m_nSetBufferIdx++;		//index	
 
-	if (pX64->m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(pX64->m_nScanIndex))
+	int nCameraIdx = pX64->m_Param.nCameraIdx;
+	if (pX64->m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(nCameraIdx, pX64->m_nScanIndex))
 	{
 		pX64->GrabScanStop();		
-		g_pStatus->SetGrabEnd(pX64->m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), pX64->m_Param.nBoardIdx, pX64->m_nScanIndex, pX64->m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(pX64->m_nScanIndex));
+		g_pStatus->SetGrabEnd(nCameraIdx, pX64->m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), pX64->m_Param.nBoardIdx, pX64->m_nScanIndex, pX64->m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(nCameraIdx, pX64->m_nScanIndex));
 		return TRUE;
 	}
 
 	if (pX64->m_nSetBufferIdx > pX64->m_pFrameBuffer->GetFrameCount())
 	{
 		pX64->GrabScanStop();		
-		g_pStatus->SetGrabEnd(pX64->m_nScanIndex);
+		g_pStatus->SetGrabEnd(nCameraIdx, pX64->m_nScanIndex);
 		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), pX64->m_Param.nBoardIdx, pX64->m_nScanIndex, pX64->m_nEndFrameIdx,pX64->m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
@@ -781,7 +782,7 @@
 	if(pBuffer == NULL)
 	{
 		pX64->GrabScanStop();		
-		g_pStatus->SetGrabEnd(pX64->m_nScanIndex);
+		g_pStatus->SetGrabEnd(nCameraIdx, pX64->m_nScanIndex);
 		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), pX64->m_Param.nBoardIdx, pX64->m_nScanIndex, pX64->m_nEndFrameIdx,pX64->m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
diff --git a/EdgeInspector_App/Grabber/SapControl.h b/EdgeInspector_App/Grabber/SapControl.h
index 61e3a60..be09225 100644
--- a/EdgeInspector_App/Grabber/SapControl.h
+++ b/EdgeInspector_App/Grabber/SapControl.h
@@ -34,8 +34,9 @@
 	virtual void	ClearGrabIdx();
 	virtual stFrameIndex	GetGrabFrame();
 	virtual stFrameIndex	GetGrabFrameNoRemove();
-	virtual CFrameBufferController	*GetFrameBuffer(){return m_pFrameBuffer;}
-	virtual BOOL	SetTriggerMode( BOOL bExTrigger ){return TRUE;}
+	virtual CFrameBufferController	*GetFrameBuffer() { return m_pFrameBuffer; }
+	virtual BOOL	SetTriggerMode( BOOL bExTrigger ) { return TRUE; }
+	virtual BOOL	DumpBufferAsOneImage(int iScan, LPCTSTR pszPath) { return TRUE; }
 	BOOL			FindGrabIdx(int iScan,int iFrame);
 
 protected:
diff --git a/EdgeInspector_App/Grabber/SapLineGrab.cpp b/EdgeInspector_App/Grabber/SapLineGrab.cpp
index 1b3a541..c47bbdb 100644
--- a/EdgeInspector_App/Grabber/SapLineGrab.cpp
+++ b/EdgeInspector_App/Grabber/SapLineGrab.cpp
@@ -231,18 +231,19 @@
 		if(m_bGrabLive == TRUE)
 			m_nSetBufferIdx = 0;
 		
-		if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(m_nScanIndex))
+		int nCameraIdx = m_Param.nCameraIdx;
+		if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex))
 		{
 			GrabScanStop();		
-			g_pStatus->SetGrabEnd(m_nScanIndex);
-			g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(m_nScanIndex));
+			g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+			g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex));
 			return;
 		}
 
 		if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount())
 		{
 			GrabScanStop();		
-			g_pStatus->SetGrabEnd(m_nScanIndex);
+			g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
 			g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
 			return;
 		}
@@ -251,7 +252,7 @@
 		if(pBuffer == NULL)
 		{
 			GrabScanStop();		
-			g_pStatus->SetGrabEnd(m_nScanIndex);
+			g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
 			g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
 			return;
 		}
diff --git a/EdgeInspector_App/Grabber/SapLineGrab.h b/EdgeInspector_App/Grabber/SapLineGrab.h
index d78f311..ede147e 100644
--- a/EdgeInspector_App/Grabber/SapLineGrab.h
+++ b/EdgeInspector_App/Grabber/SapLineGrab.h
@@ -35,8 +35,9 @@
 	virtual void	ClearGrabIdx();
 	virtual stFrameIndex	GetGrabFrame();
 	virtual stFrameIndex	GetGrabFrameNoRemove();
-	virtual CFrameBufferController	*GetFrameBuffer(){return m_pFrameBuffer;}
-	virtual BOOL	SetTriggerMode( BOOL bExTrigger ){return TRUE;}
+	virtual CFrameBufferController	*GetFrameBuffer() { return m_pFrameBuffer; }
+	virtual BOOL	SetTriggerMode( BOOL bExTrigger ) { return TRUE; }
+	virtual BOOL	DumpBufferAsOneImage(int iScan, LPCTSTR pszPath) { return TRUE; }
 
 	BOOL			CreateGrabBuffer(int nScanCount,int nBufSize, int nBufSizeX, int nBufSizeY);
 	void			SimulationGrab(int iScan);
diff --git a/EdgeInspector_App/Grabber/SoliosControl.cpp b/EdgeInspector_App/Grabber/SoliosControl.cpp
index 0f2e984..5a4f9dc 100644
--- a/EdgeInspector_App/Grabber/SoliosControl.cpp
+++ b/EdgeInspector_App/Grabber/SoliosControl.cpp
@@ -383,18 +383,19 @@
 	m_nEndFrameIdx++;			//Count
 	m_nSetBufferIdx++;		//index
 
-	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(m_nScanIndex))
+	int nCameraIdx = m_Param.nCameraIdx;
+	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex))
 	{
 		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(m_nScanIndex));
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex));
 		return TRUE;
 	}
 
 	if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount())
 	{
 		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
 		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
@@ -403,7 +404,7 @@
 	if(pBuffer == NULL)
 	{
 		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
 		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
@@ -438,15 +439,17 @@
 
 	CGrabberSolios	*pRadient = (CGrabberSolios*)HookDataPtr;
 
+
 	if(pRadient->m_isLiveGrab == TRUE)		// Live Grab 鐭�.
 	{
 		pRadient->m_nSetBufferIdx = 0;
+		int nCameraIdx = pRadient->m_Param.nCameraIdx;
 
-		LPBYTE		pBuffer = pRadient->m_pFrameBuffer->GetFrameBuferHeader(pRadient->m_nScanIndex,pRadient->m_nSetBufferIdx);
+		LPBYTE pBuffer = pRadient->m_pFrameBuffer->GetFrameBuferHeader(pRadient->m_nScanIndex,pRadient->m_nSetBufferIdx);
 		if(pBuffer == NULL)
 		{
 			pRadient->GrabScanStop();		
-			g_pStatus->SetGrabEnd(pRadient->m_nScanIndex);
+			g_pStatus->SetGrabEnd(nCameraIdx, pRadient->m_nScanIndex);
 			g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), pRadient->m_Param.nBoardIdx, pRadient->m_nScanIndex, pRadient->m_nEndFrameIdx,pRadient->m_pFrameBuffer->GetFrameCount());
 			return TRUE;
 		}
diff --git a/EdgeInspector_App/Grabber/SoliosControl.h b/EdgeInspector_App/Grabber/SoliosControl.h
index 7655c32..a469d0d 100644
--- a/EdgeInspector_App/Grabber/SoliosControl.h
+++ b/EdgeInspector_App/Grabber/SoliosControl.h
@@ -44,8 +44,9 @@
 	virtual void	ClearGrabIdx();
 	virtual stFrameIndex	GetGrabFrame();
 	virtual stFrameIndex	GetGrabFrameNoRemove();
-	virtual CFrameBufferController	*GetFrameBuffer(){return m_pFrameBuffer;}
+	virtual CFrameBufferController	*GetFrameBuffer() { return m_pFrameBuffer; }
 	virtual BOOL	SetTriggerMode( BOOL bExTrigger );
+	virtual BOOL	DumpBufferAsOneImage(int iScan, LPCTSTR pszPath) { return TRUE; }
 
 	dqGrabIdx		*GetGrabIdx(){return &m_dqCallbackFrame;}	
 	BOOL			FindGrabIdx(int iScan,int iFrame);	
diff --git a/EdgeInspector_App/InterfaceManager.cpp b/EdgeInspector_App/InterfaceManager.cpp
index 7eb3223..a6e32cf 100644
--- a/EdgeInspector_App/InterfaceManager.cpp
+++ b/EdgeInspector_App/InterfaceManager.cpp
@@ -581,13 +581,13 @@
 	DWORD dwTick = GetTickCount();
 	g_pLog->DisplayMessage(_T("Full Image Save Start"));
 
-	int					iCam,iScan;
-	CHardwareSettings	*pHard = &m_HardwareRecipe;
-	CCameraSettings		*pCamera;	
-	CGlassRecipe		*pGlsRcp = &m_GlassRecipe;
-	CString				strFolder,strFileJpg,strPanelID;
-	pINSPECTFULLIMAGE_BUFFER pBuffer;	
-	int					nQuality = pHard->m_nSaveImageQuality;
+	int	iCam, iScan;
+	CHardwareSettings* pHard = &m_HardwareRecipe;
+	CCameraSettings* pCamera;
+	CGlassRecipe* pGlsRcp = &m_GlassRecipe;
+	CString	strFolder, strFileJpg, strPanelID;
+	pINSPECTFULLIMAGE_BUFFER pBuffer;
+	int	nQuality = pHard->m_nSaveImageQuality;
 
 	if (nQuality < 0 || nQuality > 100) {
 		nQuality = 30;
@@ -601,24 +601,24 @@
 		strPanelID = _T("TestGlass");
 	}
 
-	for(iCam=0;iCam<pHard->GetCameraCount();iCam++) {		
-		for(iScan=0;iScan<MAX_SCAN_COUNT;iScan++) {
-			pCamera = pHard->GetCameraSettings(iCam,iScan);
+	for (iCam = 0; iCam < pHard->GetCameraCount(); iCam++) {
+		for (iScan = 0; iScan < MAX_SCAN_COUNT; iScan++) {
+			pCamera = pHard->GetCameraSettings(iCam, iScan);
 			if (pCamera == NULL) {
 				continue;
 			}
 
-			pBuffer = m_pInspect[iCam]->GetFullImgBuffer(iScan);		
+			pBuffer = m_pInspect[iCam]->GetFullImgBuffer(iScan);
 			if (pBuffer == NULL) {
 				continue;
 			}
 
 			g_pLog->DisplayMessage(_T("Sava %s iCam=%d, iScan=%d, szImage.cx=%ld, pBuffer->szImage.cy=%ld"), PANEL_SIDE[pCamera->m_eDimension], iCam, iScan, pBuffer->szImage.cx, pBuffer->szImage.cy);
 
-			if(pBuffer->pImage != NULL && pBuffer->szImage.cx > 100 && pBuffer->szImage.cy > 100) {
-				strFileJpg.Format(_T("%s\\%s_%s_%s.jpg"),strFolder, strPanelID, PANEL_SIDE[pCamera->m_eDimension],g_pBase->m_strLoadingTime);
+			if (pBuffer->pImage != NULL && pBuffer->szImage.cx > 100 && pBuffer->szImage.cy > 100) {
+				strFileJpg.Format(_T("%s\\%s_%s_%s.jpg"), strFolder, strPanelID, PANEL_SIDE[pCamera->m_eDimension], g_pBase->m_strLoadingTime);
 				SaveFullImageModern(strFileJpg, pBuffer->pImage, pBuffer->szImage.cx, pBuffer->szImage.cy, (int)pCamera->m_eDimension, 0, nQuality);
-			}		
+			}
 		}
 	}
 	g_pLog->DisplayMessage(_T("Full Image Save Completed : Time[%d]"),GetTickCount()-dwTick);
@@ -954,21 +954,19 @@
 	int nPeriod = m_HardwareRecipe.m_nFreerunPeriod;
 	int nExposureTime = m_HardwareRecipe.m_nFreerunExposureTime;
 
-	CCameraSettings *pCamSettings = m_HardwareRecipe.GetCameraSettings(iCam,g_pStatus->m_iScanIdx);
-
-	g_pStatus->SetGrabFrametoScan(g_pStatus->m_iScanIdx,pCamSettings->m_nGrabFrameCount);
-	if(m_pGrabber[iCam] != NULL)
-	{
-		m_pGrabber[iCam]->GrabScanStart(g_pStatus->m_iScanIdx,bFreerun,nPeriod,nExposureTime);
+	CCameraSettings* pCamSettings = m_HardwareRecipe.GetCameraSettings(iCam, g_pStatus->m_iScanIdx);
+	g_pStatus->SetGrabFrametoScan(iCam, g_pStatus->m_iScanIdx, pCamSettings->m_nGrabFrameCount);
+	if(m_pGrabber[iCam] != NULL) {
+		m_pGrabber[iCam]->GrabScanStart(g_pStatus->m_iScanIdx, bFreerun, nPeriod, nExposureTime);
+		g_pLog->DisplayMessage(_T("Cam %d Scan %d Grab Start : GrabFrameCount %d"), iCam, g_pStatus->m_iScanIdx, pCamSettings->m_nGrabFrameCount);
+		g_pLog->DisplayMessage(_T("Cam %d Scan %d Grab Start : bFreerun %d, nPeriod %d, nExposureTime %d"),iCam, g_pStatus->m_iScanIdx, bFreerun, nPeriod, nExposureTime);
 	}
 
-	if(m_pInspect[iCam] != NULL)
-	{
+	if(m_pInspect[iCam] != NULL) {
 		m_pInspect[iCam]->SetSimulation(FALSE);
 		m_pInspect[iCam]->SetViewScanHWnd(m_pView->GetViewScanHWnd());
 
-		if(m_pInspect[iCam]->ScanStart(g_pStatus->m_iScanIdx) == FALSE)
-		{
+		if(m_pInspect[iCam]->ScanStart(g_pStatus->m_iScanIdx) == FALSE) {
 			g_pLog->DisplayMessage(_T("Cam %d Scan %d Start Fail"),iCam,g_pStatus->m_iScanIdx);
 		}
 	}
@@ -1502,8 +1500,7 @@
 		Param.nScanCount = g_pBase->m_nScanCount;
 		Param.nBoardIdx = g_pBase->m_nBoardID[iCam];
 		Param.nBoardCh = g_pBase->m_nBoardCh[iCam];
-		Param.nImgFlipX = 0;		
-		Param.nBoardCh = 0;
+		Param.nImgFlipX = 0;
 		Param.nCameraIdx = iCam;
 		Param.nCameraScan = 0;
 
@@ -1582,8 +1579,9 @@
 			Param.nBoardIdx = nBoardId;
 		}
 
-		if(Param.nBoardIdx < 0)
+		if (Param.nBoardIdx < 0) {
 			Param.nBoardIdx = nBoardId;
+		}
 
 		g_pLog->DisplayMessage( _T("Grabber Board ID[%d-%d]-Init"), Param.nBoardIdx, iCam);	
 
@@ -1899,6 +1897,8 @@
 	double dRatio = 1. - tmp;
 	dRatio = dRatio - 0.01 < 0.0 ? 1.0 : dRatio;
 
+	g_pLog->DisplayMessage(_T("Save Full Image Start(%s, %s, %d, %d, %d)"), strPath, PANEL_SIDE[iSide], nStartY, nImgHeight, nQuality);
+
 #if 0
 	IplImage* pImg = cvCreateImageHeader(cvSize(nImgWidth, nImgHeight), 8, 1);
 	IplImage* pImgNew = cvCreateImage(cvSize((int)(nImgWidth * dRatio), (int)(nImgHeight * dRatio)), 8, 1);
diff --git a/EdgeInspector_App/Process/InspectCamera.cpp b/EdgeInspector_App/Process/InspectCamera.cpp
index 885b18b..0ccd88e 100644
--- a/EdgeInspector_App/Process/InspectCamera.cpp
+++ b/EdgeInspector_App/Process/InspectCamera.cpp
@@ -182,38 +182,24 @@
 	iScan = m_iScan;
 
 	stFrameIndex stFrame;
-
 	stFrame.nScanIdx = m_iScan;
 
-	if (m_bFindGlassStart[stFrame.nScanIdx] == TRUE)
+	if (m_bFindGlassStart[stFrame.nScanIdx] == TRUE) {
 		return ERR_FINDGLASSSTART_SUCCESS;
+	}
 
-	// 鞛愲彊鞚茧晫 頂勲爤鞛� 靾橂ゼ 於╇秳頌� 鞛§溂氅� 氍胳牅臧� 鞎堧悩電旉卑 臧欕嫟毵�... 頂勲爤鞛� 靾橁皜 攵�臁表晿氅� 鞐赴靹� 氍错暅鞙茧 瓯鸽.. 攴鸽Μ瓿� 鞁滌瀾靹� 彀眷晿鞙茧┐ 攴鸽儱 雱橃柎臧�氅� 霅橃 鞎婋倶?
-	if (m_pGrabber->GetGrabFrameCount() < 1)
-	{
+	if (m_pGrabber->GetGrabFrameCount() < 1 || iThread != 0) {
 		Sleep(0);
 		return ERR_FINDGLASSSTART_FAIL;
 	}
 
-	/*
-	stFrameIndex stFrame;
-
-	stFrame.nScanIdx = m_iScan;
-
-	if(m_bFindGlassStart[stFrame.nScanIdx] == TRUE)
-		return ERR_FINDGLASSSTART_SUCCESS;
-	*/
-
-	if (iThread != 0)
-		return ERR_FINDGLASSSTART_FAIL;
-
 	DimensionDir emDim = GetDimension(stFrame.nScanIdx);
-
 	iScan = stFrame.nScanIdx;
 
-	if (FindGlassStartLine(emDim, stFrame) == TRUE)
-	{
-		g_pLog->DisplayMessage(_T("Find Start Line Success!"));
+	g_pLog->DisplayMessage(_T("%s Is Glass Start Line!"), PANEL_SIDE[emDim]);
+
+	if (FindGlassStartLine(emDim, stFrame) == TRUE) {
+		g_pLog->DisplayMessage(_T("%s Find Start Line Success!"), PANEL_SIDE[emDim]);
 
 		ScanRegionSet(stFrame);
 		m_bFindGlassStart[stFrame.nScanIdx] = TRUE;
@@ -222,15 +208,15 @@
 		m_MsgJob.nDispLine = 0;
 		m_MsgJob.nSide = (int)emDim;
 		CSide_Data* pSideData = m_pGlassData->GetSideData(emDim);
-		if (pSideData != NULL)
+		if (pSideData != NULL) {
 			m_MsgJob.nDispLine = pSideData->m_nGlassStartLine;
+		}
 
 		::SendMessage(m_hWndViewScan, WM_POCESS_STATUS, (WPARAM)&m_MsgJob, (int)emDim);
 
 		return ERR_FINDGLASSSTART_SUCCESS;
 	}
-	else
-	{
+	else {
 		return ERR_FINDGLASSSTART_FIND_FAIL;
 	}
 
@@ -883,7 +869,7 @@
 	CSingleLock myLoc(&m_csThreadEnd);
 	myLoc.Lock();
 
-	int        iScan = stFrame.nScanIdx;
+	int iScan = stFrame.nScanIdx;
 	if (m_iThreadEnd[iScan][iThread] == 1) {
 		myLoc.Unlock();
 		return FALSE;
@@ -913,6 +899,11 @@
 			if (m_pII2S != NULL) {
 				m_pII2S->II2S_InspectionEnd(m_iCamera, iScan);
 			}
+
+			// Save the image as one image
+			//CString strFileName;
+			//strFileName.Format(_T("D:\\Dump\\%s.tif"), PANEL_SIDE[emDim]);
+			//m_pGrabber->DumpBufferAsOneImage(iScan, strFileName);
 		}
 	}
 
@@ -1292,7 +1283,7 @@
 	if (pSideData == NULL)
 		return FALSE;
 
-	if (g_pStatus->GetGrabFrameCount(stFrame.nScanIdx) - 1 <= stFrame.nFrameIdx)
+	if (g_pStatus->GetGrabFrameCount(m_iCamera, stFrame.nScanIdx) - 1 <= stFrame.nFrameIdx)
 		return TRUE;
 
 	if (pSideData->m_nPreGlassEndFrame + MAX_THREAD <= stFrame.nFrameIdx)
@@ -1307,8 +1298,6 @@
 
 void CInspectCamera::ScanRegionSet(stFrameIndex stFrame)
 {
-	g_pLog->DisplayMessage(_T("Scan Region Set"));
-
 	SetGrabEnd(stFrame.nScanIdx);
 }
 
@@ -6446,14 +6435,11 @@
 	m_pRecipe = pRecipe;
 	m_pHardparm = pHW;
 
-	if (m_pGrabber != NULL)
-	{
+	if (m_pGrabber != NULL) {
 		m_pGrabber->ClearGrabIdx();
-		//m_pGrabber->ClearBuffer();
 	}
 
-	if (m_pDefectControl != NULL)
-	{
+	if (m_pDefectControl != NULL) {
 		m_pDefectControl->SetHWRecipe(pHW);
 		m_pDefectControl->ResetDefectControl();
 	}
@@ -6496,33 +6482,30 @@
 
 void CInspectCamera::SetGrabEnd(int iScan)
 {
-	g_pLog->DisplayMessage(_T("Set Grab End"));
-
 	CCameraSettings* pCamera = m_pHardparm->GetCameraSettings(m_iCamera, iScan);
-
-	if (pCamera == NULL)
-	{
+	if (pCamera == NULL) {
 		g_pLog->DisplayMessage(_T("Camera Setting NULL"));
 		return;
 	}
 
-	DimensionDir		emDim = pCamera->m_eDimension;
+	DimensionDir emDim = pCamera->m_eDimension;
 	CSide_Data* pSideData = m_pGlassData->GetSideData(emDim);
-	if (pSideData == NULL)
+	if (pSideData == NULL) {
 		return;
+	}
 
-	int		nStageNo = g_pBase->m_nStageNo;
+	g_pLog->DisplayMessage(_T("%s Set Grab End"), PANEL_SIDE[emDim]);
 
-	if (nStageNo < 0 || nStageNo > 1)
+	int nStageNo = g_pBase->m_nStageNo;
+	if (nStageNo < 0 || nStageNo > 1) {
 		nStageNo = 0;
+	}
 
 	int	nGlassSize = (int)(((double)m_pRecipe->m_SideParam[(int)emDim].m_nSidePanelSize_um) / pCamera->m_dScanResolution[nStageNo]);
-
 	pSideData->m_nPreGlassEndLine = pSideData->m_nGlassStartLine + nGlassSize;
 	pSideData->m_nPreGlassEndFrame = pSideData->m_nPreGlassEndLine / pCamera->m_FrameSize.cy;
 
-	g_pStatus->SetGrabFrametoScan(iScan, pSideData->m_nPreGlassEndFrame + 5);
-
+	g_pStatus->SetGrabFrametoScan(m_iCamera, iScan, pSideData->m_nPreGlassEndFrame + 5);
 	g_pLog->DisplayMessage(_T("%s Scan %d : Set Grab EndFrame - GlassEnd %d, Frame %d, GrabBuf %d"), PANEL_SIDE[emDim], iScan, pSideData->m_nPreGlassEndLine, pSideData->m_nPreGlassEndFrame, pSideData->m_nPreGlassEndFrame + 5);
 }
 
diff --git a/EdgeInspector_App/Recipe/HardwareSettings.cpp b/EdgeInspector_App/Recipe/HardwareSettings.cpp
index 4cfde21..d3bcaf1 100644
--- a/EdgeInspector_App/Recipe/HardwareSettings.cpp
+++ b/EdgeInspector_App/Recipe/HardwareSettings.cpp
@@ -1826,33 +1826,39 @@
 
 BOOL CHardwareSettings::WriteHardwareSettingsFile(CString strFilePath)
 {
-	CConfig		BasicInfoFile;
-	CString				str;
-	int					iCam,iScan,iLight,iLoop;	
+	g_pLog->DisplayMessage(_T("HWSettings Start writing hardware settings to file: %s"), strFilePath);
 
-	if(BasicInfoFile.SetRegiConfig(NULL, NULL, (TCHAR*)(LPCTSTR)strFilePath, FileMap_Mode) == FALSE)
-	{
+	int	iCam, iScan, iLight, iLoop;
+
+	CConfig	BasicInfoFile;
+	if(BasicInfoFile.SetRegiConfig(NULL, NULL, (TCHAR*)(LPCTSTR)strFilePath, FileMap_Mode) == FALSE) {
 		CFile File;
-		if (!File.Open((TCHAR*)(LPCTSTR)strFilePath, CFile::modeCreate))
-		{			
+		if (!File.Open((TCHAR*)(LPCTSTR)strFilePath, CFile::modeCreate)) {
+			DWORD dwErr = GetLastError();
+			g_pLog->DisplayMessage(_T("HWSettings failed | Path=%s | Error=%lu"), strFilePath, dwErr);
 			return FALSE;
 		}
 		File.Close();
 	}
 
+	CString	str;
 	str = GetFileString((void *)&m_nCameraCount);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
+
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nCameraCount);
 
 	str = GetFileString((void *)&m_nScanCount);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nScanCount);	
 
 	str = GetFileString((void *)&m_nBoardType);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nBoardType);	
 	
 	// 	str = GetFileString((void *)&m_dOneScanTime);
@@ -1861,140 +1867,163 @@
 	// 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_dOneScanTime);	
 
 	str = GetFileString((void *)&m_strMachineName);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
-	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,(TCHAR*)(LPCTSTR)m_strMachineName);	
+	}
+	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,(TCHAR*)(LPCTSTR)m_strMachineName);
 
 	str = GetFileString((void *)&m_strLineID);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
+
 		return FALSE;
-	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,(TCHAR*)(LPCTSTR)m_strLineID);	
+	}
+	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,(TCHAR*)(LPCTSTR)m_strLineID);
 
 	str = GetFileString((void *)&m_nPLCSignalRetry);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nPLCSignalRetry);	
 
 	str = GetFileString((void *)&m_bInsDirReverse);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_bInsDirReverse);
 
 	str = GetFileString((void *)&m_bUseColorVisual);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_bUseColorVisual);
 
 	str = GetFileString((void *)&m_nSaveImageQuality);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nSaveImageQuality);	
 
-	if(m_pCameraSettings != NULL)
-	{
+	if (m_pCameraSettings != NULL) {
 		iLoop = 0;
-		for(iCam=0;iCam<m_nCameraCount;iCam++)
-		{
-			for(iScan=0;iScan<m_nScanCount;iScan++)
-			{
-				m_pCameraSettings[iLoop].WriteHardwareSettingsFile(&BasicInfoFile);	
+		for (iCam = 0; iCam < m_nCameraCount; iCam++) {
+			for (iScan = 0; iScan < m_nScanCount; iScan++) {
+				m_pCameraSettings[iLoop].WriteHardwareSettingsFile(&BasicInfoFile);
 				iLoop++;
 			}
 		}
 	}
 
 	str = GetFileString((void *)&m_nLightCount_Trans);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nLightCount_Trans);	
 
 	str = GetFileString((void *)&m_nLightCount_Reflect);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nLightCount_Reflect);
 
 	str = GetFileString((void *)&m_nFolderRemoveDay);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nFolderRemoveDay);
 
-	if(m_pLightSettings != NULL)
-	{		
-		for(iLight=0;iLight<m_nLightCount_Trans+m_nLightCount_Reflect;iLight++)
-		{
+	if (m_pLightSettings != NULL) {
+		for (iLight = 0; iLight < m_nLightCount_Trans + m_nLightCount_Reflect; iLight++) {
 			m_pLightSettings[iLight].WriteHardwareSettingsFile(&BasicInfoFile);
-		}		
+		}
 	}
 
 	m_PLCSettings.WriteHardwareSettingsFile(&BasicInfoFile);
-
 	m_SoftWareSettings.WriteHardwareSettingsFile(&BasicInfoFile);
 
-
 	str = GetFileString((void *)&m_bUseFreerun);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,(int) m_bUseFreerun);
 
 	str = GetFileString((void *)&m_nFreerunPeriod);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nFreerunPeriod);
 
 	str = GetFileString((void *)&m_nFreerunExposureTime);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nFreerunExposureTime);
 
 	str = GetFileString((void *)&m_bUse_MvsolTriggerControl);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_bUse_MvsolTriggerControl);
 
 	str = GetFileString((void *)&m_nPort_MvsolTriggerControl);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_nPort_MvsolTriggerControl);
 
 	str = GetFileString((void *)&m_bUse_SaveDebugImage);
-	if(str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_bUse_SaveDebugImage);
 
 	// ly,2025.07.10
 	str = GetFileString((void*)&m_bSaveResultByHour);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, (int)m_bSaveResultByHour);
 
 	// ly,2025.07.07
 	str = GetFileString((void*)&m_bEnableAutoCopy);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, (int)m_bEnableAutoCopy);
+
 	str = GetFileString((void*)&m_strCopyToolExePath);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, m_strCopyToolExePath);
+
 	str = GetFileString((void*)&m_strCopyToolConfigPath);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, m_strCopyToolConfigPath);
+
 	str = GetFileString((void*)&m_bEnableAutoDelete);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, (int)m_bEnableAutoDelete);
+
 	str = GetFileString((void*)&m_strDeleteToolExePath);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
+	}
+
 	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, m_strDeleteToolExePath);
 	str = GetFileString((void*)&m_strDeleteToolConfigPath);
-	if (str.IsEmpty() == TRUE)
+	if (str.IsEmpty() == TRUE) {
 		return FALSE;
-	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, m_strDeleteToolConfigPath);
+	}
 
+	BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, m_strDeleteToolConfigPath);
 	BasicInfoFile.WriteToFile();
 
+	g_pLog->DisplayMessage(_T("HWSettings Finished writing hardware settings file: %s"), strFilePath);
+
 	return TRUE;
 }
 
diff --git a/EdgeInspector_App/Recipe/HardwareSettings.h b/EdgeInspector_App/Recipe/HardwareSettings.h
index 051ad0f..114a279 100644
--- a/EdgeInspector_App/Recipe/HardwareSettings.h
+++ b/EdgeInspector_App/Recipe/HardwareSettings.h
@@ -3,8 +3,8 @@
 #include "Config.h"
 #include "Global_Define.h"
 
-#define	HARDWARE_SETTING_PATH				_T("c:\\EdgeInspector_App\\Config\\HardwareSetting.cfg")		// cfg 绔嬭緹 鐗堣偤姹叉播
-#define HARDWARE_SETTING_BACKUP_DIR_PATH	_T("c:\\EdgeInspector_App\\Config\\Backup")
+#define	HARDWARE_SETTING_PATH				_T("C:\\EdgeInspector_App\\Config\\HardwareSetting.cfg")		// cfg 绔嬭緹 鐗堣偤姹叉播
+#define HARDWARE_SETTING_BACKUP_DIR_PATH	_T("C:\\EdgeInspector_App\\Config\\Backup")
 #define	KEY_BASIC							_T("Software\\EdgeInspector_App\\BASIC\\")						// 楗槫鑳堕搴� 绔嬭緹 鐗堣偤姹叉播
 #define MAX_CNC_COUNT						6
 #define MAX_NCUT_STAGE_COUNT				12
diff --git a/EdgeInspector_App/View/GlassMap.cpp b/EdgeInspector_App/View/GlassMap.cpp
index 61e481f..87602a7 100644
--- a/EdgeInspector_App/View/GlassMap.cpp
+++ b/EdgeInspector_App/View/GlassMap.cpp
@@ -2174,6 +2174,9 @@
 		{
 			if((CAMERA_DIR)pDefect->m_nDir == CAMDIR_BOTTOM)
 				continue;
+
+			if ((CAMERA_DIR)pDefect->m_nDir == CAMDIR_SIDE)
+				continue;
 		}
 
  		if(m_pSelDefect == pDefect)
diff --git a/EdgeInspector_App/View/ViewMain_HWSetting.cpp b/EdgeInspector_App/View/ViewMain_HWSetting.cpp
index f289452..6b944ba 100644
--- a/EdgeInspector_App/View/ViewMain_HWSetting.cpp
+++ b/EdgeInspector_App/View/ViewMain_HWSetting.cpp
@@ -373,7 +373,7 @@
 	int			iCam,iScan,i;
 	int			iRow,iCol;
 	CString		str;		
-	const   TCHAR* SET_CAMERA_DIR[] = {_T("Top"),_T("Bottom")};
+	const   TCHAR* SET_CAMERA_DIR[] = {_T("Top"),_T("Bottom"),_T("Side") };
 	const   TCHAR* SET_INS_DIR[] = {_T("Long"),_T("Short")};	
 	const TCHAR* SET_INS_DIMENSION[] = {
 		_T("A Top"), _T("B Top"), _T("C Top"), _T("D Top"),
@@ -384,15 +384,16 @@
 	CStringArray	arrDir,arrInsDir,arrDimension;
 	CGridCellCombo *pCell;		
 	
-	for(i=0;i<2;i++)
-	{
-		arrDir.Add(SET_CAMERA_DIR[i]);		
-		arrInsDir.Add(SET_INS_DIR[i]);		
-	}	
-	for(i=0;i<12;i++)
-	{
-		arrDimension.Add(SET_INS_DIMENSION[i]);				
-	}	
+	for (i = 0; i < 3; i++) {
+		arrDir.Add(SET_CAMERA_DIR[i]);
+	}
+
+	for (i = 0; i < 2; i++) {
+		arrInsDir.Add(SET_INS_DIR[i]);
+	}
+	for (i = 0; i < 12; i++) {
+		arrDimension.Add(SET_INS_DIMENSION[i]);
+	}
 	
 	if(bWrite == TRUE)
 	{
@@ -422,7 +423,8 @@
 				switch(pCamera->m_enCamDir)
 				{
 				case CAMDIR_TOP: str.Format(_T("%s"),SET_CAMERA_DIR[0]); break;
-				case CAMDIR_BOTTOM: str.Format(_T("%s"),SET_CAMERA_DIR[1]); break;				
+				case CAMDIR_BOTTOM: str.Format(_T("%s"),SET_CAMERA_DIR[1]); break;
+				case CAMDIR_SIDE: str.Format(_T("%s"), SET_CAMERA_DIR[2]); break;
 				default: str.Format(_T("%s"),_T("No")); break;
 				}			
 				m_CameraGrid.SetItemText(iRow,iCol,str);	
@@ -669,23 +671,19 @@
 
 void CViewMain_HWSetting::UpdateControlValue(BOOL bWrite)
 {
-	if(bWrite == TRUE)
-	{
+	if(bWrite == TRUE) {
 		UpdateData(FALSE);
 		FillLightGrid(TRUE);
 		FillCameraGrid(TRUE);
 
 		((CComboBox*)(GetDlgItem(IDC_COMBO_BORAD_TYPE)))->SetCurSel((int)m_pDlgHDSettingParm->m_nBoardType);		
 	}
-	else
-	{
+	else {
 		UpdateData(TRUE);
 		FillLightGrid(FALSE);
 		FillCameraGrid(FALSE);
-		if(m_pHDSetting != NULL)
-		{
+		if(m_pHDSetting != NULL) {
 			m_pDlgHDSettingParm->m_nBoardType = (BOARD_TYPE)((CComboBox*)(GetDlgItem(IDC_COMBO_BORAD_TYPE)))->GetCurSel();
-
 			*m_pHDSetting = *m_pDlgHDSettingParm;
 		}
 	}
@@ -721,40 +719,30 @@
 	CreateDirectory(_T("C:\\EdgeInspector_App\\Config"),NULL);
 	CreateDirectory(_T("C:\\EdgeInspector_App\\Config\\Backup"),NULL);
 
-	CTime currentTime = CTime::GetCurrentTime();
-	
 	CString	str;
-
-	str.Format(_T("%s\\HardwareSetting_%02d%02d%02d_%02d%02d%02d.cfg"), HARDWARE_SETTING_BACKUP_DIR_PATH
-																		, currentTime.GetYear()
-																		, currentTime.GetMonth()
-																		, currentTime.GetDay()
-																		, currentTime.GetHour()
-																		, currentTime.GetMinute()
-																		, currentTime.GetSecond());
+	CTime time = CTime::GetCurrentTime();
+	str.Format(_T("%s\\HardwareSetting_%02d%02d%02d_%02d%02d%02d.cfg"), HARDWARE_SETTING_BACKUP_DIR_PATH, time.GetYear(), time.GetMonth(), time.GetDay(), time.GetHour(), time.GetMinute(), time.GetSecond());
 
 	UpdateControlValue(FALSE);	
-	if(m_pHDSetting->WriteHardwareSettingsFile(str) == FALSE)
-	{
+	if(m_pHDSetting->WriteHardwareSettingsFile(str) == FALSE) {
 		AfxMessageBox(_T("Save Fail!"));
 	}
 }
 
 void CViewMain_HWSetting::ClickHWSaveButton()
 {
-	if(m_pHDSetting == NULL)
+	if (m_pHDSetting == NULL) {
 		return;
+	}
 
-	if (IDYES == AfxMessageBox(_T("Do you want to save? \n Restarting is required to change settings."), MB_YESNO | MB_ICONQUESTION))
-	{
+	if (IDYES == AfxMessageBox(_T("Do you want to save? \n Restarting is required to change settings."), MB_YESNO | MB_ICONQUESTION)) {
 		UpdateControlValue(FALSE);
-		
-		if(m_pHDSetting->WriteHardwareSettingsFile(HARDWARE_SETTING_PATH) == FALSE)// if(m_pHDSetting->WriteHardwareSettingsRegistry() == FALSE)
-		{
-			AfxMessageBox(_T("Save Fail!"));
+		g_pLog->DisplayMessage(_T("Saving HW settings file[%s]..."), HARDWARE_SETTING_PATH);
+		if (m_pHDSetting->WriteHardwareSettingsFile(HARDWARE_SETTING_PATH) == FALSE) {
+			g_pLog->DisplayMessage(_T("Failed to save hardware settings file!"));
 			return;
 		}
-		SaveHardwareFileBackup();		
+		SaveHardwareFileBackup();
 	}
 }
 
diff --git a/SDK/BlGrabber/include/GrabberControl.h b/SDK/BlGrabber/include/GrabberControl.h
index 5c7a10a..9028745 100644
--- a/SDK/BlGrabber/include/GrabberControl.h
+++ b/SDK/BlGrabber/include/GrabberControl.h
@@ -75,5 +75,6 @@
 	virtual stFrameIndex	GetGrabFrameNoRemove() = 0;
 	virtual CFrameBufferController	*GetFrameBuffer() = 0;
 	virtual BOOL	SetTriggerMode(BOOL bExTrigger) = 0;
+	virtual BOOL	DumpBufferAsOneImage(int iScan, LPCTSTR pszPath) = 0;
 };
 

--
Gitblit v1.9.3