/********************************************************************************/
/* 
* File name: Mdigitizer.cpp
* Location:  ...\Matrox Imaging\MILxxx\Examples\BoardSpecific\OrionHD\C++\MdigCrossBar
 *             
*
* Synopsis:  This class manages a digitizer.
*            
*            It manages:
*             - The allocations of the grab buffers.
*             - The drawing of the moving line.
*             - The starting and stopping of a grab stream.
*             - The statistics.
*/
#include <windows.h> 
#include <mil.h>
#include <queue>
#include <list>
#include "mdigitizer.h"


// Private.
// Initialisation.
void CDigitizer::Init(bool iAll)
   {
   m_IsAllocated = false;
   m_IsDeviceUsed = false;
   m_CameraPresent = false;
   
   m_MilDigitizer = M_NULL;
   memset(m_DetectDCFName, 0, sizeof(m_DetectDCFName));
   memset(m_MilImageWork, 0, sizeof(m_MilImageWork));
   memset(m_MilBuffers, 0, sizeof(m_MilBuffers));
   m_GrabCount = 0;
   m_Index = 0;
   m_SizeX = 0;
   m_SizeY = 0;
   m_EnableMovingLine = true;
   m_GraLinePos = 0;
   m_GraLineDir = 0;
   m_LatencyFromDispIndex = -1;
   m_GrabHalfFrameRate = false;
   m_Decimation = 1;
   m_SourceId = 0;

   if(iAll)
      {
      m_MilSystem  = M_NULL;
      m_MilDitizerMinimal = M_NULL;
      m_DigDeviceNumber = M_INVALID;
      m_Channel = M_INVALID;
      memset(m_DCFName, 0, sizeof(m_DCFName));
      m_ProcessingFunctionPtr = M_NULL;
      m_PrivateData = NULL;
      }

   }


// Private.
// Allocates the digitizer.
bool CDigitizer::AllocateDigitizer(MIL_ID iMilSystem, MIL_INT DevNum, MIL_TEXT_CHAR *pDCFName)
   {
   MIL_ID MilDigitizer;
   MdigAlloc(iMilSystem, DevNum, pDCFName, M_DEFAULT, &MilDigitizer);
   if(MilDigitizer)
      {
      if(m_Channel != M_CH0)
         Sleep(250);

      MdigInquire(MilDigitizer, M_CAMERA_PRESENT, &m_CameraPresent);
      if(m_CameraPresent)
         {
         m_MilDigitizer = MilDigitizer;
         MdigInquire(m_MilDigitizer, M_SIZE_X, &m_SizeX);
         MdigInquire(m_MilDigitizer, M_SIZE_Y, &m_SizeY);
         }
      else
         MdigFree(MilDigitizer);
      }
   return m_MilDigitizer? true:false;
   }

// Private.
// Allocates the grab buffers.
bool CDigitizer::AllocateBuffers(MIL_INT iIndex)
   {
   MIL_INT ReturnValue = 0;
   m_Index = iIndex;
   m_IsAllocated = false;

   if(m_MilDigitizer)
      {
      MdigControl(m_MilDigitizer, M_GRAB_TIMEOUT, 5000);

      for(MIL_INT Buf = 0; Buf < MAX_BUFFERING; Buf++)
         {
         MbufAllocColor(m_MilSystem,
            3,
            m_SizeX,
            m_SizeY,
            8 + M_UNSIGNED,
            M_IMAGE + M_PROC + M_GRAB + M_PACKED + M_BGR32,
            &m_MilBuffers[Buf]);

         MbufAllocColor(m_MilSystem,
            3,
            m_SizeX,
            m_SizeY,
            8 + M_UNSIGNED,
            M_IMAGE + M_YUV16 + M_PACKED + M_HOST_MEMORY,
            &m_MilImageWork[Buf]);
         }

      m_IsAllocated = true;
      }

   return m_IsAllocated;
   }

// Private.
// Frees everything.
void CDigitizer::Free(bool iAll)
   {
   if(m_MilDigitizer)
      {
      MdigFree(m_MilDigitizer);
      for(MIL_INT Buf = 0; Buf < MAX_BUFFERING; Buf++)
         {
         if(m_MilBuffers[Buf])
            {
            MbufFree(m_MilBuffers[Buf]);
            m_MilBuffers[Buf] = M_NULL;
            }

         if(m_MilImageWork[Buf])
            {
            MbufFree(m_MilImageWork[Buf]);
            m_MilImageWork[Buf];
            }
         }
      }

   if(iAll)
      {
      if(m_MilDitizerMinimal)
         MdigFree(m_MilDitizerMinimal);
      }

   Init(iAll);
   }

// Public.
// Prints to the console the details of the detected input.
void CDigitizer::PrintDigitizerInfo()
   {
   MIL_TEXT_CHAR  DCFFormat[255];
   MIL_INT        ColorMode;
   MIL_INT        InputMode;
   MIL_INT        ScanMode;
   MIL_INT        SizeX, SizeY, SizeBand;
   MIL_DOUBLE     FrameRate;
   MIL_INT        DigitizerNumber;

   MdigInquire(m_MilDigitizer, M_NUMBER, &DigitizerNumber);
   MdigInquire(m_MilDigitizer, M_SIZE_X, &SizeX);
   MdigInquire(m_MilDigitizer, M_SIZE_Y, &SizeY);
   MdigInquire(m_MilDigitizer, M_SIZE_BAND, &SizeBand);
   MdigInquire(m_MilDigitizer, M_INPUT_MODE, &InputMode);
   MdigInquire(m_MilDigitizer, M_COLOR_MODE, &ColorMode);
   MdigInquire(m_MilDigitizer, M_SCAN_MODE, &ScanMode);
   MdigInquire(m_MilDigitizer, M_SELECTED_FRAME_RATE, &FrameRate);
   MdigInquire(m_MilDigitizer, M_FORMAT_DETECTED, DCFFormat);

   MosPrintf(MIL_TEXT("\t%d x %d, %d band(s). "), SizeX, SizeY, SizeBand);

   switch(ColorMode)
      {
      case M_DVI: MosPrintf(MIL_TEXT("DVI "));break;
      case M_SDI: MosPrintf(MIL_TEXT("SDI "));break;
      case M_COMPOSITE: MosPrintf(MIL_TEXT("Composite "));break;
      case M_RGB: MosPrintf(MIL_TEXT("RGB "));break;
      case M_EXTERNAL_CHROMINANCE: MosPrintf(MIL_TEXT("Y\\C "));break;
      case M_MONOCHROME: MosPrintf(MIL_TEXT("Monochrome "));break;
      default: MosPrintf(MIL_TEXT(" "));
      }
   switch(InputMode)
      {
      case M_ANALOG: MosPrintf(MIL_TEXT("analog "));break;
      case M_DIGITAL: MosPrintf(MIL_TEXT("digital "));break;
      default: MosPrintf(MIL_TEXT(" "));
      }
   switch(ScanMode)
      {
      case M_PROGRESSIVE: MosPrintf(MIL_TEXT("progressive "));break;
      case M_INTERLACE: MosPrintf(MIL_TEXT("interlaced "));break;
      default: MosPrintf(MIL_TEXT(" "));
      }

   MosStrcpy(m_DetectDCFName, MAX_PATH, DCFFormat);
   MosPrintf(MIL_TEXT("@ %0.2f fps.\n"), FrameRate);
   MosPrintf(MIL_TEXT("\tDCF: %s.\n\n"), DCFFormat);
   }

// Public.
// Start the grab stream.
void CDigitizer::Start(MIL_BUF_HOOK_FUNCTION_PTR UserProcessingFunctionPtr)
   {
   m_ProcessingFunctionPtr = UserProcessingFunctionPtr;

   if(m_MilDigitizer)
      if(!IsAllocated())
      AllocateBuffers(m_Index);

   if(IsAllocated())
      {
      MdigProcess(m_MilDigitizer, m_MilBuffers, MAX_BUFFERING,
         M_START, M_DEFAULT, DigProcessingFunction, this);

      m_IsDeviceUsed = true;
      }
   }

MIL_INT CDigitizer::PrepareForGrabbing()
   {
   MIL_INT lRetVal = 0;

   if(AllocateDigitizer(m_MilSystem, DeviceNumber(), GetDcfName()))
      MdigInquire(m_MilDigitizer, M_FORMAT_DETECTED, m_DetectDCFName);
   else
      lRetVal = M_INVALID;

   return lRetVal;
   }

// Public.
// Stops the grab stream.
void CDigitizer::Stop()
   {
   if(IsDeviceUsed())
      MdigProcess(m_MilDigitizer, m_MilBuffers, MAX_BUFFERING,
         M_STOP, M_DEFAULT, DigProcessingFunction, this);
   }

MIL_INT CDigitizer::StopGrabbing()
   {
   MIL_INT lRetVal = 0;

   Stop();
   Free(false);
   m_IsDeviceUsed = false;
   m_CameraPresent = false;
   memset(m_DetectDCFName, 0, sizeof(m_DetectDCFName));

   return lRetVal;
   }

// Public.
// Returns grab statistics.
void CDigitizer::GetStatistics(MIL_INT *FrameCount, MIL_DOUBLE *FrameRate, MIL_INT *FramesMissed)
   {
   if(FrameCount)
      MdigInquire(m_MilDigitizer, M_PROCESS_FRAME_COUNT,  FrameCount);
   if(FrameRate)
      MdigInquire(m_MilDigitizer, M_PROCESS_FRAME_RATE,   FrameRate);
   if(FramesMissed)
      MdigInquire(m_MilDigitizer, M_PROCESS_FRAME_MISSED,  FramesMissed);
   }

// Public.
void CDigitizer::FreeDigitizer()
   {
   if(m_MilDigitizer)
      {
      MdigFree(m_MilDigitizer);
      m_MilDigitizer = M_NULL;
      }
   }
   // Public.
void CDigitizer::UpdateDetectedDcfName()
{ 
   if(m_MilDitizerMinimal)
      {
      MdigInquire(m_MilDitizerMinimal, M_CAMERA_PRESENT, &m_CameraPresent);
      if(m_CameraPresent)
         MdigInquire(m_MilDitizerMinimal, M_FORMAT_DETECTED, m_DetectDCFName);
      }
}
bool CDigitizer::AllocateDigitizerMinimal(MIL_ID iMilSystem, MIL_INT DevNum, MIL_TEXT_CHAR *pDCFName)
   {
   MdigAlloc(iMilSystem, DevNum, pDCFName, M_MINIMAL, &m_MilDitizerMinimal);

   if(m_MilDitizerMinimal)
      {
      MdigHookFunction(m_MilDitizerMinimal, M_CAMERA_PRESENT, CDigitizer::DigHookCameraPresent, this);
      UpdateDetectedDcfName();
      }

   return m_MilDitizerMinimal? true:false;
   }
// Private
// Hook on Camera present.
MIL_INT MFTYPE CDigitizer::DigHookCameraPresent(MIL_INT hookType, MIL_ID eventId, void *userData)
   {
   CDigitizer *pDig = (CDigitizer * )userData;
   MIL_INT CameraPresent;

   MdigInquire(pDig->MinimalDigitizer(), M_CAMERA_PRESENT, &CameraPresent);

   #ifdef SHOW_CAMERA_PRESENT_STATUS
   if(!CameraPresent)
      MosPrintf(MIL_TEXT("Camera disconnected from dev:%d \n"),pDig->DeviceNumber());
   else
      MosPrintf(MIL_TEXT("Camera connected from dev:%d \n"),pDig->DeviceNumber());
   #endif

   MthrControl(pDig->GetEvent(), M_EVENT_SET, M_SIGNALED);

   return 0;
   }