
/*
-----------------------------------------------------------------------------
This source file is part of OpenSpace3D
For the latest info, see http://www.openspace3d.com

Copyright (c) 2010 I-maginer

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

You may alternatively use this source under the terms of a specific version of
the OpenSpace3D Unrestricted License provided you have obtained such a license from
I-maginer.
-----------------------------------------------------------------------------
*/

/*
 SMI RED eye tracking system library based on iView X SDK
 First version : june 2011
 Author : Aymeric Suteau
*/

/*! @defgroup grpsmi Scol functions definition
 *  Scol functions definition
 *  @{
 */
/** @} */

/**
* @file Plugin.cpp
*
* @brief The file contains the sources for SMI RED Scol plugin
* and the definition of each function of the DLL
**/


// Include Header File
#include "Plugin.h"

//!Scol machine declaration for MM macros
cbmachine ww;
HWND HScol = NULL;	

//!Scol object declaration 
int OBJSMISCOL;

//!Scol CallBacks declaration 
//===== CB Connected ===
int SCOL_SMI_CONNECTED_CB          = 0;
int SMI_CONNECTED_CB;

//===== CB Disconnected ===
int SCOL_SMI_DISCONNECTED_CB       = 1;
int SMI_DISCONNECTED_CB;

//===== CB Calibration done ===
int SCOL_SMI_CALIBRATION_DONE_CB   = 2;
int SMI_CALIBRATION_DONE_CB;

//===== CB New fixation data ===
int SCOL_SMI_NEW_FIXATION_CB       = 3;
int SMI_NEW_FIXATION_CB;

//===== CB New sample data ===
int SCOL_SMI_NEW_SAMPLE_CB         = 4;
int SMI_NEW_SAMPLE_CB;


/*! \mainpage SMI RED Scol Plugin
 *
 * \section intro_sec Introduction
 * This plugin allows Scol Virtual Machine to manage SMI RED eye tracking system.
 * The SMI RED is a remote eye tracking system which allows binocular gaze and pupil data retrieving. 60Hz and 120Hz sampling rates are both supported.
 * <br/>This plugin is based on iView X SDK provided by SMI company : 
 * <br/>http://update.smivision.com/Setup_iViewX_SDK_32bit.msi for 32bit version
 * <br/>http://update.smivision.com/Setup_iViewX_SDK_64bit.msi for 64bit version
 * <br/>The latest available version is 3.0.6, released on June 30th, 2011
 * 
*/


//!Scol CallBack for ObjSmi destruction
int destroySmiObj(mmachine m, int handsys, int eyeTrackingTab) 
{
	// Read the first element of a TAB element (table of objects)
	EyeTracking* EyeTrackingObj = (EyeTracking*) MMfetch(m, MTOP(eyeTrackingTab), 0);

	// Safely dispose of "EyeTrackingObj" pointer
	SAFE_DELETE(EyeTrackingObj);

	// Write the first element of a TAB element
	MMstore(m, MTOP(eyeTrackingTab), 0, 0);

	// Display debug message
	MMechostr(0, "EyeTrackingObj destroyed.\n");
	return 0;
}


/*! @ingroup grpsmi
* \brief _OpenSmiDevice : This function opens a remote connection to SMI RED system
*
* <b>Prototype:</b> fun [Chn S I S I] ObjSmi
* \param Chn : the current channel
* \param S : IP address for iViewX workstation to enable UDP communication
* \param I : port for iViewX workstation to enable UDP communication
* \param S : IP address for stimulus PC to enable UDP communication
* \param I : port for stimulus PC to enable UDP communication
*
* \return ObjSmi : The EyeTracking object or NIL if creation fails
*/
int _OpenSmiDevice(mmachine m)
{
	#ifdef	_SCOL_DEBUG_
		MMechostr(0,"_OpenSmiDevice\n");
	#endif

	// Declare local variables
	int k = 0;

  // Retrieve stack parameters : [S I S I]
  // NOTE: The first parameter to pull from the stack is the last one to have been pushed
  int iReceiverPort = MMpull(m);
  int iReceiverIp = MMpull(m);
  int iSenderPort = MMpull(m);
  int iSenderIp = MMpull(m);
 
  // Convert sender IP from magma to char*
  char* senderIp = (char*) MMstartstr(m, MTOP(iSenderIp));

  // Convert sender port from Magma to Integer
  int senderPort = 4444;
	if (iSenderPort != NIL)
		senderPort = MTOI(iSenderPort);

  // Convert receiver IP from magma to char*
  char* receiverIp = (char*) MMstartstr(m, MTOP(iReceiverIp));

  // Convert receiver port from Magma to Integer
  int receiverPort = 5555;
  if (iReceiverPort != NIL)
		receiverPort = MTOI(iReceiverPort);

	// Create EyeTracking instance
	EyeTracking* eyeTracking = new EyeTracking();
  MMechostr(0, "_OpenSmiDevice ...new SMI RED EyeTracking instance created !\n");

	// TODO: Open remote EyeTracking system
  if (!eyeTracking->Connect(senderIp, senderPort, receiverIp, receiverPort))
  {
		MMechostr(0, "_OpenSmiDevice ...initialization failed\n");
		SAFE_DELETE(eyeTracking);
		MMset(m, 0, NIL);
		return 0;
	}
 
	// Allocate a block in the stack for a table of EyeTracking objects
	int eyeTrackingTab = MMmalloc(m, 1, TYPETAB);
	if (eyeTrackingTab == NIL)
  {
		MMechostr(0, "_OpenSmiDevice ...MMmalloc failed\n");
		SAFE_DELETE(eyeTracking); 
		MMset(m, 0, NIL);
    return MERRMEM;
	}
	MMechostr(0, "_OpenSmiDevice ...MMmalloc successful\n");

	// Push the TAB EyeTracking object into the stack
	MMstore(m, eyeTrackingTab, 0, (int)eyeTracking);
	MMpush(m, PTOM(eyeTrackingTab));

	// Create a new SMI RED EyeTracking object
	k = OBJcreate(m, OBJSMISCOL, (int)eyeTracking, NULL, NULL);
	MMechostr(0, "_OpenSmiDevice ...object creation successful\n");

	#ifdef	_SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

	// Return EyeTracking object
	return k;
}


/*! @ingroup grpsmi
* \brief _CloseSmiDevice : This function closes a remote connection to SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi] I
* \param ObjSmi : the current ObjSmi
*
* \return I : 0 if success, NIL otherwise
*/
int _CloseSmiDevice(mmachine m)
{
	#ifdef	_SCOL_DEBUG_
		MMechostr(0,"_CloseSmiDevice\n");
  #endif

	// Get the table of EyeTracking objects into the stack (without pulling it)
	int eyeTrackingTab = MMget(m, 0);
  MMechostr(0, "_CloseSmiDevice\n");
	if (eyeTrackingTab == NIL)
  {
		MMechostr(0, "_CloseSmiDevice ...ObjSmi NIL\n");
		MMset(m, 0, NIL);
		return 0;
	}

	// Destroy EyeTracking object according to its type and magma object
  OBJdelTM(m, OBJSMISCOL, eyeTrackingTab);

	// Reinitialize the stack
	MMset(m, 0, ITOM(0));

	#ifdef	_SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

	return 0;
}


/*! @ingroup grpsmi
* \brief _CBSmiConnected : This function sets the Callback for a connected event from SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi fun [ObjSmi u0] u1 u0] ObjSmi
* \param ObjSmi : the current ObjSmi
* \param fun [ObjSmi u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjSmi if success
*/
int _CBSmiConnected(mmachine m)
{
  MMechostr(0, "_CBSmiConnected ...adding reflex\n");
	return OBJaddreflex(m, OBJSMISCOL, SCOL_SMI_CONNECTED_CB);
}

int getSmiConnectedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	EyeTracking* EyeTrackingObj = (EyeTracking*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJSMISCOL, (int)EyeTrackingObj, SCOL_SMI_CONNECTED_CB))
  {
    MMechostr(0, "getSmiConnectedCb -> OBJbeginreflex failed.\n");
		return 0;
  }
	return (OBJcallreflex(m, 0));
}


/*! @ingroup grpsmi
* \brief _CBSmiDisconnected : This function sets the Callback for a disconnected event from SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi fun [ObjSmi u0] u1 u0] ObjSmi
* \param ObjSmi : the current ObjSmi
* \param fun [ObjSmi u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjSmi if success
*/
int _CBSmiDisconnected(mmachine m)
{
  MMechostr(0, "_CBSmiDisconnected ...adding reflex\n");
	return OBJaddreflex(m, OBJSMISCOL, SCOL_SMI_DISCONNECTED_CB);
}

int getSmiDisconnectedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	EyeTracking* EyeTrackingObj = (EyeTracking*) id;

	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJSMISCOL, (int)EyeTrackingObj, SCOL_SMI_DISCONNECTED_CB))
  {
    MMechostr(0, "getSmiDisconnectedCb -> OBJbeginreflex failed.\n");
		return 0;
  }
	return (OBJcallreflex(m, 0));
}


/*! @ingroup grpsmi
* \brief _CBSmiCalibrationDone : This function sets the Callback for a calibration done event from SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi fun [ObjSmi u0] u1 u0] ObjSmi
* \param ObjSmi : the current ObjSmi
* \param fun [ObjSmi u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjSmi if success
*/
int _CBSmiCalibrationDone(mmachine m)
{
  MMechostr(0, "_CBSmiCalibrationDone ...adding reflex\n");
	return OBJaddreflex(m, OBJSMISCOL, SCOL_SMI_CALIBRATION_DONE_CB);
}

int getSmiCalibrationDoneCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	EyeTracking* EyeTrackingObj = (EyeTracking*) id;

	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJSMISCOL, (int)EyeTrackingObj, SCOL_SMI_CALIBRATION_DONE_CB))
  {
    MMechostr(0, "getSmiCalibrationDoneCb -> OBJbeginreflex failed.\n");
		return 0;
  }
	return (OBJcallreflex(m, 0));
}


/*! @ingroup grpsmi
* \brief _CBSmiNewFixation : This function sets the Callback for new fixation data available from SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi fun [ObjSmi u0 F I I] u1 u0] ObjSmi
* \param ObjSmi : the current ObjSmi
* \param fun [ObjSmi u0 F I I] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjSmi if success
*/
int _CBSmiNewFixation(mmachine m)
{
  MMechostr(0, "_CBSmiNewFixation ...adding reflex\n");
	return OBJaddreflex(m, OBJSMISCOL, SCOL_SMI_NEW_FIXATION_CB);
}

int getSmiNewFixationCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
  FixationData* FixationDataObj = (FixationData*) param;
	EyeTracking* EyeTrackingObj = (EyeTracking*) id;
  float fDuration = FixationDataObj->duration;
  int iPosX = FixationDataObj->posX;
  int iPosY = FixationDataObj->posY;

	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJSMISCOL, (int)EyeTrackingObj, SCOL_SMI_NEW_FIXATION_CB))
  {
    MMechostr(0, "getSmiNewFixationCb -> OBJbeginreflex failed.\n");
		return 0;
  }

  // Push fixation data into the stack
	MMpush(m, FTOM(fDuration));
  MMpush(m, ITOM(iPosX));
  MMpush(m, ITOM(iPosY));
	return (OBJcallreflex(m, 3));
}


/*! @ingroup grpsmi
* \brief _CBSmiNewSample : This function sets the Callback for new sample data available from SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi fun [ObjSmi u0 [F I I] [F I I]] u1 u0] ObjSmi
* \param ObjSmi : the current ObjSmi
* \param fun [ObjSmi u0 [F I I] [F I I]] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjSmi if success
*/
int _CBSmiNewSample(mmachine m)
{
  MMechostr(0, "_CBSmiNewSample ...adding reflex\n");
	return OBJaddreflex(m, OBJSMISCOL, SCOL_SMI_NEW_SAMPLE_CB);
}

int getSmiNewSampleCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
  SampleData* SampleDataObj = (SampleData*) param;
	EyeTracking* EyeTrackingObj = (EyeTracking*) id;
  float fLeftDiam = SampleDataObj->leftPupilDiameter;
  float fRightDiam = SampleDataObj->rightPupilDiameter;
  int iLeftGazeX = SampleDataObj->leftGazeX;
  int iRightGazeX = SampleDataObj->rightGazeX;
  int iLeftGazeY = SampleDataObj->leftGazeY;
  int iRightGazeY = SampleDataObj->rightGazeY;

	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJSMISCOL, (int)EyeTrackingObj, SCOL_SMI_NEW_FIXATION_CB))
  {
    MMechostr(0, "getSmiNewFixationCb -> OBJbeginreflex failed.\n");
		return 0;
  }

  // Push sample data into the stack
  int tupleLeftEye = MMmalloc(m, 3, TYPETAB);
	if (tupleLeftEye == NIL) 
  {	
    MMset(m, 0, NIL);		
    return MERRMEM;	
  }
  MMstore(m, tupleLeftEye, 0, FTOM(fLeftDiam));
	MMstore(m, tupleLeftEye, 1, ITOM(iLeftGazeX));
  MMstore(m, tupleLeftEye, 2, ITOM(iLeftGazeY));
  MMpush(m, PTOM(tupleLeftEye));

  int tupleRightEye = MMmalloc(m, 3, TYPETAB);
	if (tupleRightEye == NIL) 
  {	
    MMset(m, 0, NIL);		
    return MERRMEM;	
  }
  MMstore(m, tupleRightEye, 0, FTOM(fRightDiam));
	MMstore(m, tupleRightEye, 1, ITOM(iRightGazeX));
  MMstore(m, tupleRightEye, 2, ITOM(iRightGazeY));
  MMpush(m, PTOM(tupleRightEye));

	return (OBJcallreflex(m, 2));
}


/*! @ingroup grpsmi
* \brief _StartCalibration : This function starts the calibration process for SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi I I I I I I I I] I
* \param ObjSmi : the current ObjSmi
* \param I : number of calibration points (2, 5, 9 or 13)
* \param I : validation for calibration process (1 if required, 0 otherwise)
* \param I : device to display calibration process (0 for Primary device, 1 for Secondary device)
* \param I : speed for calibration process (0 for Slow, 1 for Fast)
* \param I : brightness of foreground displayed during calibration (from 0 to 255)
* \param I : brightness of background displayed during calibration (from 0 to 255)
* \param I : shape displayed during calibration (0 for Circle1, 1 for Circle2, 2 for Cross)
* \param I : shape size (from 1 to 50)

*
* \return I : 0 if success, NIL otherwise
*/
int _StartCalibration(mmachine m)
{
	#ifdef _SCOL_DEBUG_
		MMechostr(0,"_StartCalibration\n");
	#endif

  // Retrieve stack parameters : [I I I I I I I I]
  // NOTE: The first parameter to pull from the stack is the last one to have been pushed
  int iTargetSize = MMpull(m);
  int iTargetShape = MMpull(m);
  int iBackgroundBrightness = MMpull(m);
  int iForegroundBrightness = MMpull(m);
  int iSpeed = MMpull(m);
  int iDisplayDevice = MMpull(m);
  int iValidation = MMpull(m);
  int iNbPoints = MMpull(m);

  // Convert all stack parameters from Magma to Integer
  int nbPoints = 5;
	if (iNbPoints != NIL)
		nbPoints = MTOI(iNbPoints);

  int validation = 1;
  if (iValidation != NIL)
		validation = MTOI(iValidation);

  int displayDevice = 0;
  if (iDisplayDevice != NIL)
		displayDevice = MTOI(iDisplayDevice);

  int speed = 0;
  if (iSpeed != NIL)
		speed = MTOI(iSpeed);

  int foregroundBrightness = 20;
  if (iForegroundBrightness != NIL)
		foregroundBrightness = MTOI(iForegroundBrightness);

  int backgroundBrightness = 239;
  if (iBackgroundBrightness != NIL)
		backgroundBrightness = MTOI(iBackgroundBrightness);

  int targetShape = 1;
  if (iTargetShape != NIL)
		targetShape = MTOI(iTargetShape) + 1;
  
  int targetSize = 10;
  if (iTargetSize != NIL)
		targetSize = MTOI(iTargetSize);

  // Get the table of glove objects into the stack (without pulling it)
	int smiTab = MMget(m, 0);
  MMechostr(0, "_StartCalibration\n");
	if (smiTab == NIL) 
  {
		MMechostr(0, "_StartCalibration ...ObjSmi NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

  // Read the first element of a TAB element (table of objects)
	EyeTracking* SmiObj = (EyeTracking*) MMfetch(m, MTOP(smiTab), 0);
	if (SmiObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

  // Set up the calibration for SMI RED system
  SmiObj->SetCalibration(nbPoints,                    // 5-point calibration method
                         1,                           // Visualization by SDK
                         displayDevice,               // Primary device for display
                         speed,                       // Low validation speed
                         1,                           // Point auto-acceptance
                         foregroundBrightness,        // Target brightness
                         backgroundBrightness,        // Background brightness
                         targetShape,                 // Calibration target shape = CIRCLE1
                         targetSize,                  // Default target size is 10 pixels
                         "../resource/cursor1.bmp");  // Target shape filename

  // Start the calibration process
  SmiObj->Calibrate(validation);
  
  MMset(m, 0, ITOM(0));
  
  #ifdef _SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

  return 0;
}


/*! @ingroup grpsmi
* \brief _ShowEyes : This function displays/hides eye tracking window for SMI RED system
*
* <b>Prototype:</b> fun [ObjSmi I] I
* \param ObjSmi : the current ObjSmi
* \param I : 1 to display eye tracking window, 0 to hide it
*
* \return I : 0 if success, NIL otherwise
*/
int _ShowEyes(mmachine m)
{
	#ifdef _SCOL_DEBUG_
		MMechostr(0,"_ShowEyes\n");
	#endif

  // Retrieve stack parameter
  int iShowEyes = MMpull(m);

  // Convert stack parameter from Magma to Integer
  int showEyes = 1;
	if (iShowEyes != NIL)
		showEyes = MTOI(iShowEyes);

  // Get the table of glove objects into the stack (without pulling it)
	int smiTab = MMget(m, 0);
  MMechostr(0, "_ShowEyes\n");
	if (smiTab == NIL) 
  {
		MMechostr(0, "_ShowEyes ...ObjSmi NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

	EyeTracking* SmiObj = (EyeTracking*) MMfetch(m, MTOP(smiTab), 0);
	if (SmiObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

  // Check if eye tracking window must be displayed
  if (showEyes == 1)
    SmiObj->ShowTrackingWindow();
  
  MMset(m, 0, ITOM(0));
  
  #ifdef _SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

  return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											                                                         ////
///										                  DECLARATION OF FUNCTIONS (FOR SCOL)											                    ///
////																											                                                         ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//! Nb of Scol functions or types
#define NbTplPKG 10


/*!
*	Scol function names
*/
char *TplName[NbTplPKG] =
{
	"ObjSmi",
  "_OpenSmiDevice",
	"_CloseSmiDevice",
  "_CBSmiConnected",
  "_CBSmiDisconnected",
  "_CBSmiCalibrationDone",
  "_CBSmiNewFixation",
  "_CBSmiNewSample",
  "_StartCalibration",
  "_ShowEyes"
};


/*!
*	Pointers to C functions that manipulate the VM for each scol function previously defined
*/
int (*TplFunc[NbTplPKG])(mmachine m)=
{
	NULL,																		// ObjSmi
  _OpenSmiDevice,													// _OpenSmiDevice
	_CloseSmiDevice,												// _CloseSmiDevice
  _CBSmiConnected,                        // _CBSmiConnected
  _CBSmiDisconnected,                     // _CBSmiDisconnected
  _CBSmiCalibrationDone,                  // _CBSmiCalibrationDone
  _CBSmiNewFixation,                      // _CBSmiNewFixation
  _CBSmiNewSample,                        // _CBSmiNewSample
  _StartCalibration,                      // _StartCalibration
  _ShowEyes                               // _ShowEyes
};


/*!
*	Nb of arguments of each scol function
*/
int TplNArg[NbTplPKG]=
{
	TYPTYPE,																		// ObjSmi
  5,																					// _OpenSmiDevice
	1,																					// _CloseSmiDevice
  3,                                          // _CBSmiConnected
  3,                                          // _CBSmiDisconnected
  3,                                          // _CBSmiCalibrationDone
  3,                                          // _CBSmiNewFixation
  3,                                          // _CBSmiNewSample
  9,                                          // _StartCalibration
  2                                           // _ShowEyes
};


/*!
*	Prototypes of the scol functions
*/
char* TplType[NbTplPKG]=
{
	NULL,																				                              // ObjSmi
  "fun [Chn S I S I] ObjSmi",										                            // _OpenSmiDevice
	"fun [ObjSmi] I",											                                    // _CloseSmiDevice
  "fun [ObjSmi fun [ObjSmi u0] u1 u0] ObjSmi",   	                          // _CBSmiConnected
  "fun [ObjSmi fun [ObjSmi u0] u1 u0] ObjSmi",   	                          // _CBSmiDisconnected
  "fun [ObjSmi fun [ObjSmi u0] u1 u0] ObjSmi",                              // _CBSmiCalibrationDone
  "fun [ObjSmi fun [ObjSmi u0 F I I] u1 u0] ObjSmi",                        // _CBSmiNewFixation
  "fun [ObjSmi fun [ObjSmi u0 [F I I] [F I I]] u1 u0] ObjSmi",              // _CBSmiNewSample
  "fun [ObjSmi I I I I I I I I] I",                                         // _StartCalibration
  "fun [ObjSmi I] I"                                                        // _ShowEyes
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											                                                         ////
///												                        DLL CALL FUNCTIONS													                      ///
////																											                                                         ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Everything inside _cond and _endcond is ignored by doxygen
//! \cond

/*!
* \brief Load the packages in Scol virtual machine
* \param mmachine : the scol machine
*/
int LoadSmi(mmachine m) 
{
  // Return variable for PKhardpak function
	int k;

	// Declare a new type of object ("OBJSMISCOL")
	OBJSMISCOL = OBJregister(5, 1, destroySmiObj, "OBJSMISCOL");

  // Get new user events and associate these events with a callback
  SMI_CONNECTED_CB = OBJgetUserEvent();
  OBJdefEvent(SMI_CONNECTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getSmiConnectedCb);

  SMI_CALIBRATION_DONE_CB = OBJgetUserEvent();
  OBJdefEvent(SMI_CALIBRATION_DONE_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getSmiCalibrationDoneCb);

  SMI_DISCONNECTED_CB = OBJgetUserEvent();
  OBJdefEvent(SMI_DISCONNECTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getSmiDisconnectedCb);

  SMI_NEW_FIXATION_CB = OBJgetUserEvent();
  OBJdefEvent(SMI_NEW_FIXATION_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getSmiNewFixationCb);

  SMI_NEW_SAMPLE_CB = OBJgetUserEvent();
  OBJdefEvent(SMI_NEW_SAMPLE_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getSmiNewSampleCb);

	// Load package
	k = PKhardpak(m, "FusionEngine", NbTplPKG, TplName, TplFunc, TplNArg, TplType);
	return k;
}
//! \endcond


/*! 
* \brief Starting point of the DLL
*/
extern "C" __declspec (dllexport) int ScolLoadPlugin(mmachine m, cbmachine w) 
{
	SCOLinitplugin(w);

	// Get Scol window handle (for message callback)
	HScol = (HWND)SCgetExtra("hscol");	
	LoadSmi(m);
	return 0;
}


/*! 
* \brief Ending point of the DLL
*/
extern "C" __declspec (dllexport) int ScolUnloadPlugin() 
{
	return 0;
}
