/********************************************************************************/
/* 
 * File name: CLProtocol.cpp 
 * Location:  ...\Matrox Imaging\MILxxx\Examples\BoardSpecific\radient\C++\clprotocol
 *             
 *
 * Synopsis:  This program demonstrates how to use GenICam� (through CLProtocol)
 *            on MIL Camera Link� systems.
 */
#include <mil.h>

#if M_MIL_UNICODE_API

#ifndef MosStrtok
#define MosStrtok wcstok_s
#endif

#else

#ifndef MosStrtok
#define MosStrtok strtok_s
#endif

#endif

typedef struct  
   {
   MIL_INT NbDevIDs;
   MIL_INT DevIdStrLen;
   MIL_TEXT_PTR* DevIDs;
   long UserSelection;
   }CLProtocolDataStruct;

/* Enumerates installed CLProtocol devices. */
void CLProtocolEnumDevices(MIL_ID MilDigitizer, CLProtocolDataStruct& CLProtocolData);
/* Prompts user to select a CLProtocol device matching his camera. */
void CLProtocolSelectDevice(MIL_ID MilDigitizer, CLProtocolDataStruct& CLProtocolData);

typedef enum { eDriverDirectory, eDriverFileName,  eManufacturer,
               eFamily,          eModel,           eVersion,      eSerialNumber} eCLProtocolDevIdFields;
/* Extract info from CLProtocol Device ID string. */
void CLProtocolExtractField(  const MIL_TEXT_PTR DeviceID, const eCLProtocolDevIdFields Field,
                              MIL_TEXT_PTR ExtractedData, MIL_INT DataSize);

/* Main function. */
int MosMain(void)
   { 
   MIL_ID MilApplication,  /* Application identifier.  */
          MilSystem,       /* System identifier.       */
          MilDisplay,      /* Display identifier.      */
          MilDigitizer,    /* Digitizer identifier.    */ 
          MilImage;        /* Image buffer identifier. */
   MIL_INT BoardType = 0, SystemNum = 0, DigitizerNum = 0, Size = 0;
   MIL_TEXT_PTR SystemDescriptor = M_NULL;
   CLProtocolDataStruct CLProtocolData;
   MIL_TEXT_CHAR VendorName[256] = {'\0'}, ModelName[256] = {'\0'};

   /* Allocate defaults. */
   MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem,
                             &MilDisplay, &MilDigitizer, &MilImage);

   /* Make sure we are running on a Radient Camera Link.. */
   MsysInquire(MilSystem, M_BOARD_TYPE, &BoardType);
   if(!(((BoardType & M_BOARD_TYPE_MASK) == M_RADIENT) && (BoardType & M_CL)))
      {
      MosPrintf(MIL_TEXT("This example program can only be used with a Camera Link system type\n"));
      MosPrintf(MIL_TEXT("such as Matrox Solios or Matrox Radient Camera Link boards.\n"));
      MosPrintf(MIL_TEXT("Please ensure that the default system type is set accordingly in ")
                MIL_TEXT("MIL Config.\n"));
      MosPrintf(MIL_TEXT("-------------------------------------------------------------\n\n"));
      MosPrintf(MIL_TEXT("Press <enter> to quit.\n"));
      MosGetch();

      MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImage);
      return 1;
      }

   /* Print a message. */
   MosPrintf(MIL_TEXT("This example shows how to use GenICam with Camera Link devices.\n\n"));
   MosPrintf(MIL_TEXT("GenICam is supported with Camera Link devices as long as your camera\n"));
   MosPrintf(MIL_TEXT("vendor supplies a standard compliant CLProtocol dll.\n\n"));
   MosPrintf(MIL_TEXT("Press <Enter> to enumerate the list of installed CLProtocol devices.\n\n"));
   MosGetch();

   /* Enumerates installed CLProtocol devices. */
   CLProtocolEnumDevices(MilDigitizer, CLProtocolData);

   if(CLProtocolData.NbDevIDs == 0)
      {
      MosPrintf(MIL_TEXT("\nNo CLProtocol devices have been found.\n"));
      MosPrintf(MIL_TEXT("Make sure the CLProtocol library supplied by your camera vendor is\n"));
      MosPrintf(MIL_TEXT("properly installed.\n\n"));

      MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImage);
      return 1;
      }

   /* Inquire system and digitizer numbers. */
   MsysInquire(MilSystem, M_NUMBER, &SystemNum);
   MdigInquire(MilDigitizer, M_NUMBER, &DigitizerNum);

   /* Inquire the system descriptor for printf below. */
   MsysInquire(MilSystem, M_SYSTEM_DESCRIPTOR_SIZE, &Size);
   SystemDescriptor = new MIL_TEXT_CHAR[Size];
   MsysInquire(MilSystem, M_SYSTEM_DESCRIPTOR, SystemDescriptor);

   /* Ask the user to select the correct device matching his camera. */
   MosPrintf(MIL_TEXT("\nPlease select the CLProtocol device connected to:\n"));
   MosPrintf(MIL_TEXT("%s M_DEV%d digitizer M_DEV%d (0-%d)\n"), SystemDescriptor, SystemNum, DigitizerNum, CLProtocolData.NbDevIDs);

   /* Prompt user to select a CLProtocol device matching his camera. */
   CLProtocolSelectDevice(MilDigitizer, CLProtocolData);

   /* Print a message. */
   MosPrintf(MIL_TEXT("\nNow showing the camera's features through the feature browser window.\n"));
   MosPrintf(MIL_TEXT("You can use the feature browser to change camera parameters.\n\n"));
   
   /* At this point the CLProtocol (and GenICam�) should be properly initialized. */
   /* Pop up the camera's feature browser.                                        */
   MdigControl(MilDigitizer, M_GC_FEATURE_BROWSER, M_OPEN+M_ASYNCHRONOUS);

   /* Grab continuously. */
   MdigGrabContinuous(MilDigitizer, MilImage);

   /* Print a message. */
   MosPrintf(MIL_TEXT("Press <Enter> to use MdigInquireFeature to read \"DeviceVendorName\" and\n"));
   MosPrintf(MIL_TEXT("\"DeviceModelName\" features from the camera.\n\n"));
   MosPrintf(MIL_TEXT("Note: an error will be generated if the features do not exist in your camera\n\n"));
   MosGetch();

   /* Use MdigInquireFeature to read data from the camera.              */
   /* Note: MdigControlFeature can be used to write data to the camera. */
   MdigInquireFeature(MilDigitizer, M_FEATURE_VALUE, MIL_TEXT("DeviceVendorName"), M_TYPE_STRING, VendorName);
   MdigInquireFeature(MilDigitizer, M_FEATURE_VALUE, MIL_TEXT("DeviceModelName"), M_TYPE_STRING, ModelName);

   /* Print a message. */
   MosPrintf(MIL_TEXT("Vendor:\t%s\nModel:\t%s\n\n"), VendorName, ModelName);

   /* When a key is pressed, halt. */
   MosPrintf(MIL_TEXT("Press <Enter> to stop.\n\n"));
   MosGetch();

   /* Stop continuous grab. */
   MdigHalt(MilDigitizer);

   /* Free defaults. */
   MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImage);

   /* Free allocated memory. */
   for(MIL_INT i=0; i<CLProtocolData.NbDevIDs; i++)
      delete [] CLProtocolData.DevIDs[i];

   delete [] CLProtocolData.DevIDs;
   delete [] SystemDescriptor;

   return 0;
   }

/* Enumerates installed CLProtocol devices. */
void CLProtocolEnumDevices(MIL_ID MilDigitizer, CLProtocolDataStruct& CLProtocolData)
   {
   MIL_TEXT_PTR NextToken = M_NULL;
   MIL_TEXT_CHAR Field[7][256];

   /* Inquire the number of registered CLProtocol devices. */
   MdigInquire(MilDigitizer, M_GC_CLPROTOCOL_DEVICE_ID_NUM, &CLProtocolData.NbDevIDs);
   /* Inquire the maximum string length we will need to store the device IDs. */
   MdigInquire(MilDigitizer, M_GC_CLPROTOCOL_DEVICE_ID_SIZE_MAX, &CLProtocolData.DevIdStrLen);

   MosPrintf(MIL_TEXT("Installed CLProtocol devices found:\n\n"));

   if(CLProtocolData.NbDevIDs)
      {
      /* Allocate memory for Device ID storage. */
      CLProtocolData.DevIDs = new MIL_TEXT_PTR[CLProtocolData.NbDevIDs];

      MosPrintf(MIL_TEXT("%2s|%22.21s|%10.9s|%20.19s|%20.19s\n"), MIL_TEXT("Nb"), MIL_TEXT("CLProtocol File Name"), MIL_TEXT("Vendor"), MIL_TEXT("Family"), MIL_TEXT("Model"));
      MosPrintf(MIL_TEXT("--+----------------------+----------+--------------------+--------------------\n\n"));
      /* For each device, inquire it's DeviceID. */
      for(MIL_INT i=0; i<CLProtocolData.NbDevIDs; i++)
         {
         /* Allocate memory for Device ID storage. */
         CLProtocolData.DevIDs[i] = new MIL_TEXT_CHAR[CLProtocolData.DevIdStrLen];
         MdigInquire(MilDigitizer, M_GC_CLPROTOCOL_DEVICE_ID+i, CLProtocolData.DevIDs[i]);

         /* Tokenize the string to make printing more readable. */
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eDriverDirectory, Field[0], 256);
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eDriverFileName,  Field[1], 256);
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eManufacturer,    Field[2], 256);
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eFamily,          Field[3], 256);
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eModel,           Field[4], 256);
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eVersion,         Field[5], 256);
         CLProtocolExtractField(CLProtocolData.DevIDs[i], eSerialNumber,    Field[6], 256);

         MosPrintf(MIL_TEXT("%.2d %22.21s %10.9s %20.19s %20.19s\n"), i, Field[1], Field[2], Field[3], Field[4]);
         }

      MosPrintf(MIL_TEXT("\n%.2d Use Default from MilConfig.\n"), CLProtocolData.NbDevIDs);
      }
   }

/* Prompts user to select a CLProtocol device matching his camera. */
void CLProtocolSelectDevice(MIL_ID MilDigitizer, CLProtocolDataStruct& CLProtocolData)
   {
   bool Done = false;
   do
      {
      scanf_s("%d", &CLProtocolData.UserSelection);
      if(CLProtocolData.UserSelection >= 0 && CLProtocolData.UserSelection <= CLProtocolData.NbDevIDs)
         Done = true;
      else
         MosPrintf(MIL_TEXT("Invalid selection, please try again.\n"));
      }
      while(!Done);

      /* Apply the selected device. */
      if(CLProtocolData.UserSelection == CLProtocolData.NbDevIDs)
         MdigControl(MilDigitizer, M_GC_CLPROTOCOL_DEVICE_ID, M_PTR_TO_DOUBLE(MIL_TEXT("M_DEFAULT")));
      else
         MdigControl(MilDigitizer, M_GC_CLPROTOCOL_DEVICE_ID, M_PTR_TO_DOUBLE(CLProtocolData.DevIDs[CLProtocolData.UserSelection]));
      /* Initialize the CLProtocol driver and GenICam�. */
      /* If an error occurs, it is most likely that the wrong CLProtocol device has been selected. */
      MdigControl(MilDigitizer, M_GC_CLPROTOCOL, M_ENABLE);
   }

/* Extract field from CLProtocol DeviceID string. */
void CLProtocolExtractField(const MIL_TEXT_PTR DeviceID, const eCLProtocolDevIdFields Field, MIL_TEXT_PTR ExtractedData, MIL_INT DataSize)
   {
   MIL_INT Cnt = 0;
   MIL_TEXT_PTR TempString = new MIL_TEXT_CHAR [MosStrlen(DeviceID)+1];
   MIL_TEXT_PTR Token = NULL, NextToken = NULL;
   MIL_TEXT_CHAR FieldDelimitor[] = {MIL_TEXT("#")};

   MosStrcpy(TempString, MosStrlen(DeviceID)+1, DeviceID);
   
   switch(Field)
      {
      case eDriverDirectory:
         Cnt = 0; break;
      case eDriverFileName:
         Cnt = 1; break;
      case eManufacturer:
         Cnt = 2; break;
      case eFamily:
         Cnt = 3; break;
      case eModel:
         Cnt = 4; break;
      case eVersion:
         Cnt = 5; break;
      case eSerialNumber:
         Cnt = 6; break;
      }

   Token = MosStrtok(TempString, FieldDelimitor, &NextToken);
   for(MIL_INT i=0; i<Cnt && Token!=NULL; i++)
      {
      Token = MosStrtok(NULL, FieldDelimitor, &NextToken);
      }

   if(Token)
      MosStrcpy(ExtractedData, DataSize, Token);
   else
      ExtractedData[0] = '\0';

   delete [] TempString;
   }