/***************************************************************************/
/*
 * File name: FdkAddConstantPrimitive.cpp
 * Location:  ...\Matrox Imaging\MILxxx\Examples\BoardSpecific\solios\C++\SoliosFDK
 *             \AddConstantPrimitive
 *
 * Synopsis:  This example shows how to create an FPGA accelerated processing  
 *            function using the Mfpga API. It also includes MIL Master 
 *            and Slave functions that will be used to call the processing 
 *            primitive.
 *
 *            These Master and Slave functions allow the primitive to 
 *            become a true MIL function that does minimal parameter checking, 
 *            can log MIL errors and will make the custom FPGA function 
 *            visible to the MIL trace mechanism.
 */

/* Headers. */
#include <mil.h>
#include <milfpga.h>
#include <fpga_addconst.h>

#define FUNCTION_NB_PARAM                  4
#define FUNCTION_OPCODE_FPGA_ADD_CONSTANT  1 

/* Error codes */
#define FUNCTION_PARAMETER_ERROR_CODE   1
#define FUNCTION_WRONG_FPGA_ERROR_CODE  2

/* Master, Slave and Primitive MIL functions declarations. */
void FpgaAddConstant(MIL_ID SrcImageId, MIL_ID DstImageId, MIL_INT ConstantToAdd, 
                     MIL_INT ControlFlag);
void MFTYPE FPGAAddConstantSlave(MIL_ID Func);
void FPGAAddConstantPrimitive(MIL_ID Func, MIL_ID MilSourceImage, 
         MIL_ID MilDestinationImage, MIL_INT ConstantValue, MIL_INT ControlFlag);

/******************************************************************************
**                _______
**               | add   |
** SrcImage ---->| const |----> DestImage
**               |_______|
**
** DestImage = SrcImage + ConstantValue
**
*******************************************************************************/

/* MIL Primitive function definition. */
/* ---------------------------------- */

void FPGAAddConstantPrimitive(MIL_ID Func,MIL_ID MilSourceImage,
     MIL_ID MilDestinationImage, MIL_INT ConstantValue, MIL_INT ControlFlag)
   {
   MIL_BUFFER_INFO Src, Dest;
   MIL_FPGA_CONTEXT AddConstantContext;
   FPGA_ADDCONST_USER_ST ShadowRegisters;
   memset(&ShadowRegisters, 0, sizeof(ShadowRegisters));

   /* Inquire the buffer info object for the source and destination buffers. */
   MfuncInquire(MilSourceImage, M_BUFFER_INFO, &Src);
   MfuncInquire(MilDestinationImage, M_BUFFER_INFO, &Dest);

   /* Verify if source and destination buffers are 8 bit monochrome. */
   if(((MfuncBufSizeBit(Src) != 8) && (MfuncBufSizeBand(Src) != 1)) ||
      ((MfuncBufSizeBit(Dest) != 8) && (MfuncBufSizeBand(Dest)!= 1))
      )
      {
      MfuncErrorReport(Func, M_FUNC_ERROR+FUNCTION_PARAMETER_ERROR_CODE,
           MIL_TEXT("Only 8 bit, monochrome buffers are supported for Add Constant."),
           M_NULL, M_NULL, M_NULL );
      return;
      }

   /* Allocate an asynchronous command context for the AddConstant processing unit
      and check for valid source and destination buffers.
   */
   if(MfpgaCommandAlloc(MfuncBufOwnerSystemId(Src), M_DEV0, FPGA_ADDCONST_FID,
            M_DEFAULT, M_DEV0, M_ASYNCHRONOUS, M_DEFAULT, &AddConstantContext)
      )
      {
      /* Input0 of AddConstant processing unit is connected to the Src buffer. */
      MfpgaSetSource(AddConstantContext, Src, M_INPUT0, M_DEFAULT);

      /* Output0 of AddConstant processing unit is connected to the Dest buffer. */
      MfpgaSetDestination(AddConstantContext, Dest, M_OUTPUT0, M_DEFAULT);

      /* Program the Constant value to add to each pixel in the shadow registers. */
      ShadowRegisters.val.f.val = ConstantValue;

      /* Program the operation Sign in the shadow registers. */
      if(MfuncBufType(Src) == 8+M_SIGNED) 
         ShadowRegisters.ctrl.f.optype = 0; /* Signed operation. */
      else  
         ShadowRegisters.ctrl.f.optype = 1; /* Unsigned operation. */

      /* Program Saturation in the shadow registers (Saturate to 0xff or not). */
      if(ControlFlag & M_SATURATION)
         ShadowRegisters.ctrl.f.sat = 1;
      else
         ShadowRegisters.ctrl.f.sat = 0;

      /* Pass the initialized shadow register structure. It will be programmed
         only when the processing operation is dispatched (before processing
         starts). 
      */
      MfpgaSetRegister(AddConstantContext, M_USER, 0, sizeof(ShadowRegisters),
                       (void*)(&ShadowRegisters), M_WHEN_DISPATCHED);

      /* Queue the processing operation. Because this context is asynchronous,
         MfpgaCommandQueue will return before the operation is completed.
      */
      MfpgaCommandQueue(AddConstantContext, M_DEFAULT, M_DEFAULT);

      /* Free the allocated context. */
      MfpgaCommandFree(AddConstantContext, M_DEFAULT);
      }
   else
      {
      /* Report a MIL error. */
      MfuncErrorReport( 
          Func, M_FUNC_ERROR+FUNCTION_WRONG_FPGA_ERROR_CODE,
          MIL_TEXT("No AddConstant acceleration supported by this FPGA configuration."),
          MIL_TEXT("Please select the proper FPGA configuration file."),
          MIL_TEXT("See the processing FPGA section of the milconfig utility."),
          M_NULL
          );
      }
   }

/* MIL Master function definition. */
/* ------------------------------- */

void FpgaAddConstant(MIL_ID SrcImageId, MIL_ID DstImageId, MIL_INT ConstantToAdd, MIL_INT ControlFlag)
   {
   MIL_ID   Func;

   /* Allocate a MIL function context that will be used to call a target 
      Slave function locally on the Host to do the processing.
   */
   MfuncAlloc(MIL_TEXT("FPGAAddConstant"), 
              FUNCTION_NB_PARAM,
              FPGAAddConstantSlave, M_NULL, M_NULL, 
              M_USER_MODULE_1+FUNCTION_OPCODE_FPGA_ADD_CONSTANT, 
              M_DEFAULT, 
              &Func
             );

   /* Register the parameters. */
   MfuncParamMilId (Func, 1, SrcImageId, M_IMAGE, M_IN);
   MfuncParamMilId (Func, 2, DstImageId, M_IMAGE, M_OUT);
   MfuncParamMilInt(Func, 3, ConstantToAdd);
   MfuncParamMilInt(Func, 4, ControlFlag);

   /* Call the target Slave function. */
   MfuncCall(Func);

   /* Free the MIL function context. */
   MfuncFree(Func);
   }

/* MIL Slave function definition. */
/* ------------------------------ */

void MFTYPE FPGAAddConstantSlave(MIL_ID Func)
   {
   MIL_ID    SrcImageId, DstImageId;
   MIL_INT   ConstantToAdd, ControlFlag;

   /* Read the parameters. */
   MfuncParamValue(Func, 1, &SrcImageId);
   MfuncParamValue(Func, 2, &DstImageId);
   MfuncParamValue(Func, 3, &ConstantToAdd); 
   MfuncParamValue(Func, 4, &ControlFlag);
    
   /* Call the primitive controling the processing FPGA using the Mfpga API. */
   FPGAAddConstantPrimitive(Func, SrcImageId, DstImageId, ConstantToAdd, ControlFlag);
   }