mrDarker
2025-08-13 5cc675212e96d87ebbf00f4fd7a8106b06a490ff
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,M_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;
}