///@file VPCmdIF.h
/// Header file for using the C++ VPcmdIF SDK with the Viper tracker.
#pragma once
#include "VPcmdDefs.h"
#include "VPcmdErr.h"
#include "VPif.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef void* vpcmd_context;	//!< API context handle. Usually create one context to contain multiple devices.
typedef void* vpdev_hnd;		//!< device handle. Once handle per device connection
#define VIPER_USB_PID 0xBF01	//!< Viper USB device PID
#define DEF_SERPORT_ANY -1		//!< Serial Port ANY
#define VP_ID_ALL -1			//!< ID wildcard value. Supported by sensor_level functions only
typedef void (CALLBACK *VP_PNOREADY_CALLBACK)(void* pInfo, uint8_t *pdata, uint32_t nbytes);
int VPCMD_API vpdev_SetPnoCallback(vpcmd_context, vpdev_hnd, VP_PNOREADY_CALLBACK cb, PVOID pInfo);

////////////////////////////////////////
///@defgroup api_level VPcmdIF API global functions
/// API-centric functions begin with vpcmdif_
///@{

int VPCMD_API vpcmdif_init(vpcmd_context & );///<Initialize VPcmdIF and allocate a @ref vpcmd_context handle
int VPCMD_API vpcmdif_release(vpcmd_context);///<Dispose of previously allocated @ref vpcmd_context handle

// set trace level before init to propogate to all future contexts. Does not affect existing contexts.
void VPCMD_API vpcmdif_trace(int32_t iLev);///<Set trace output level.  Default @ref VPCMD_NOTRACE 

VPCMD_API const char *	  vpcmdif_errorStr	(int err);	///<Convert returned error code to ASCII string
VPCMD_API const char *    vpcmdif_version   ();			///<Return ASCII version string of VPcmdIF
VPCMD_API const char *    vpcmdif_date      ();			///<Return ASCII build date of VPcmdIF
VPCMD_API const char *    vpcmdif_time      ();			///<Return ASCII build time of VPcmdIF
VPCMD_API const char *    vpcmdif_datetime  ();			///<Return ASCII build time of VPcmdIF

VPCMD_API const wchar_t* vpcmdif_errorStrW  (int err);	///<Convert returned error code to UNICODE string
VPCMD_API const wchar_t* vpcmdif_versionW   ();			///<Return UNICODE version string of VPcmdIF
VPCMD_API const wchar_t* vpcmdif_dateW      ();			///<Return UNICODE build date of VPcmdIF
VPCMD_API const wchar_t* vpcmdif_timeW      ();			///<Return UNICODE build time of VPcmdIF
VPCMD_API const wchar_t* vpcmdif_datetimeW  ();			///<Return UNICODE build time of VPcmdIF
														///@} //end api_level

////////////////////////////////////////
///@defgroup context_level Context-centric functions
/// Context-level functions begin with vpctx_
///  All context-level functions take a @ref vpcmd_context parameter
///@{
/// Create a new device connection via USB.  Allocate a @ref vpdev_hnd device handle.
int VPCMD_API vpctx_connectusb	(vpcmd_context, vpdev_hnd &, uint16_t pid=VIPER_USB_PID );
/// Create a new device connection via Serial port.  Allocate a @ref vpdev_hnd device handle.
int VPCMD_API vpctx_connectser  (vpcmd_context, vpdev_hnd &, int32_t port=DEF_SERPORT_ANY, uint32_t sercfg=0);
/// Disconnect and release connected device.
int VPCMD_API vpctx_dev_release(vpcmd_context, vpdev_hnd);
/// Generate a text report of all connected devices in context.
int VPCMD_API vpctx_dev_report	(vpcmd_context, const char * &);
/// Generate a text report of all connected devices in context.
int VPCMD_API vpctx_dev_reportW(vpcmd_context, const wchar_t*&);
/// Set trace output level for context and all devices in context
int VPCMD_API vpctx_trace		(vpcmd_context, int32_t iTraceLev = 0);
///@} //end context_level

////////////////////////////////////////
/// @defgroup device_level Device-centric functions
///  Device-level functions commands begin with vpdev_
///  All device-level functions take @ref vpcmd_context and @ref vpdev_hnd parameters
//@{

	/// Set trace level for single device (SEU)
	int VPCMD_API vpdev_trace(vpcmd_context, vpdev_hnd, int iTraceLev = 0);
	/// Set command response timeout (ms) for a single device (SEU)  SET, RESET only
	int VPCMD_API vpdev_timeoutms(vpcmd_context, vpdev_hnd, eCmdActions, int iTimeoutMS);
	/// Retrieve printable ASCII device report 
	int VPCMD_API vpdev_info(vpcmd_context, vpdev_hnd, const WHOAMI_STRUCT *&,  VIPER_SEUID &);
	/// Retrieve printable ASCII device report 
	int VPCMD_API vpdev_report(vpcmd_context, vpdev_hnd, const char * &);
	/// Retrieve printable UNICODE device report 
	int VPCMD_API vpdev_reportW(vpcmd_context, vpdev_hnd, const wchar_t*&);
	/// Enable std::chrono::steady_clock Timestamp capture in @ref vpFrameInfo.  This is typically the ms since PC boot.
	int VPCMD_API vpdev_tsenable(vpcmd_context, vpdev_hnd, bool bEn);
	///@todo allow selection of which clock to use for timestamp

	////////////////////////////////////////
	// configuration cmds
	/// @defgroup config_cmds  Configuration command functions
	/// Device configuration commands universally take a @ref vpcmd_context, @ref vpdev_hnd,
	/// an @ref eCmdActions and optionally a data struct for @ref CMD_ACTION_GET and @ref CMD_ACTION_SET actions.
	///@{

		///SEU P&O update rate (GET/SET/RESET)
		int VPCMD_API vpcmd_dev_framerate		(vpcmd_context, vpdev_hnd, eCmdActions, FRAMERATE_CONFIG *); 
		///SEU device id (GET/SET/RESET)
		int VPCMD_API vpcmd_dev_id				(vpcmd_context, vpdev_hnd, eCmdActions, SEUID_CONFIG*);
		///SEU serial port settings (GET/SET/RESET)
		int VPCMD_API vpcmd_dev_serialif		(vpcmd_context, vpdev_hnd, eCmdActions, SERIAL_CONFIG*);
		///SEU source rotation (GET/SET/RESET)
		int VPCMD_API vpcmd_dev_sourcerot		(vpcmd_context, vpdev_hnd, int src, eCmdActions, SRCROT_CONFIG*);
		///SEU source configuration (GET/SET/RESET)
		int VPCMD_API vpcmd_dev_sourcecfg(vpcmd_context, vpdev_hnd, int src, eCmdActions, SRC_CONFIG*);
		///SEU Stylus mode configuration (GET/SET/RESET) Control what happens when Stylus button is pressed.
		int VPCMD_API vpcmd_dev_stylusmode(vpcmd_context, vpdev_hnd, eCmdActions, STYLUS_CONFIG*);
		///@todo SEU sync mode (BINARY, GET/SET/RESET)
		int VPCMD_API vpcmd_dev_syncmode	(vpcmd_context, vpdev_hnd, eCmdActions, BINARY_CONFIG*);
		///SEU P&O output units (GET/SET/RESET)
		int VPCMD_API vpcmd_dev_units			(vpcmd_context, vpdev_hnd, eCmdActions, UNITS_CONFIG *);
		///SEU dual output mode (BINARY, GET/SET/RESET)
		int VPCMD_API vpcmd_dev_dualoutput(vpcmd_context, vpdev_hnd, eCmdActions, BINARY_CONFIG*);
		///Configure Self-Cal Compensation
		int VPCMD_API vpcmd_dev_selfcalstate(vpcmd_context, vpdev_hnd, eCmdActions, SELFCAL_CONFIG*);
		///Collect InstaMap Data
		int VPCMD_API vpcmd_dev_selfcalsave(vpcmd_context, vpdev_hnd, eCmdActions, BINARY_CONFIG*);
		// generic device command performs no command verification
		///SEU generic command function
		int VPCMD_API vpcmd_dev_generic(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, uint32_t cmd, void * pay_buf = 0, uint32_t size = 0, uint32_t arg1 = 0, uint32_t arg2 = 0);
	///@} // end config_cmds

	////////////////////////////////////////
	///executive cmds
	/// @defgroup exec_cmds Executive command functions
	///@{

		///@todo Reset SEU P&O frame number
		int VPCMD_API vpcmd_dev_reset_framecount	(vpcmd_context, vpdev_hnd);
		/// Make current configuration persistent
		int VPCMD_API vpcmd_dev_persist			(vpcmd_context, vpdev_hnd);
		///Configuration Block (RESET ONLY)
		int VPCMD_API vpcmd_dev_resetblockcfg(vpcmd_context, vpdev_hnd);
		///@} // end exec cmds

	////////////////////////////////////////
	///@defgroup readonly Read-only commands
	/// Read-only commands retrieve information from the tracker.
	/// No @ref eCmdActions parameter is required because the action defaults to @ref CMD_ACTION_GET.
	///@{

		/// Retrieve tracker SEU WhoAmI information
		int VPCMD_API vpcmd_dev_whoami			(vpcmd_context, vpdev_hnd,				WHOAMI_STRUCT *);
		/// Retrieve tracker SEU WhoAmI information formatted into a printable ASCII string
		int VPCMD_API vpcmd_dev_whoami_report	(vpcmd_context, vpdev_hnd,				const char * &);
		/// Retrieve tracker SEU WhoAmI information formatted into a printable UNICODE string
		int VPCMD_API vpcmd_dev_whoami_reportW  (vpcmd_context, vpdev_hnd,              const wchar_t * &);
		/// Retrieve tracker Source WhoAmI information
		int VPCMD_API vpcmd_dev_sourcewhoami    (vpcmd_context, vpdev_hnd, int src, WHOAMI_STRUCT *);
		/// Retrieve tracker Source WhoAmI information formatted into a printable ASCII string
		int VPCMD_API vpcmd_dev_sourcewhoami_report (vpcmd_context, vpdev_hnd, int src, const char * &);
		/// Retrieve tracker Source WhoAmI information formatted into a printable UNICODE string
		int VPCMD_API vpcmd_dev_sourcewhoami_reportW(vpcmd_context, vpdev_hnd, int src, const wchar_t * &);
		///Retrieve tracker SEU BIT result information
		int VPCMD_API vpcmd_dev_bit				(vpcmd_context, vpdev_hnd,				BIT_STRUCT *);
		///Retrieve tracker SEU BIT result information formatted into a printable ASCII string
		int VPCMD_API vpcmd_dev_bit_report		(vpcmd_context, vpdev_hnd,				const char * &);
		///Retrieve tracker SEU BIT result information formatted into a printable UNICODE string
		int VPCMD_API vpcmd_dev_bit_reportW     (vpcmd_context, vpdev_hnd,              const wchar_t * &);
		///Retrieve SEU detected sensors and sources station map (GET)
		int VPCMD_API vpcmd_dev_stationmap		(vpcmd_context, vpdev_hnd,				STATION_MAP *);
		///@} //end read only commands

///@} end dev cmds

////////////////////////////////////////
///@defgroup sensor_level Sensor-centric functions
/// Sensor-level commands begin with vpsns_
///  All sensor-level functions take @ref vpcmd_context, @ref vpdev_hnd and an @code int @endcode
///   sensor number parameters
///  Sensor number parameter can be wildcarded with @ref VP_ID_ALL
///@{

	////////////////////////////////////////
	// sensor configuration commands
	///@defgroup sensor_cfg Sensor Configuration functions
	///@{

		///Sensor Boresight (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_boresight		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, BORESIGHT_CONFIG *, uint32_t ResetOrigin=0);
		///Sensor Filter settings (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_filter			(vpcmd_context, vpdev_hnd, int sns, eCmdActions, FILTER_CONFIG *, eViperFilterTargets);
		///Sensor Hemisphere configuration (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_hemisphere		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, HEMISPHERE_CONFIG*);
		///Sensor Increment (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_increment		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, INCREMENT_CONFIG*);
		///@todo Sensor Tip Offset (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_tipoffset		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, TIP_OFFSET_CONFIG *);
		///Sensor FTT Mode (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_fttmode			(vpcmd_context, vpdev_hnd, int sns, eCmdActions, ENUM_CONFIG *);
		///Sensor Source Select (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_srcselect		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, SRC_SEL_CONFIG *);
		///Sensor Origin (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_origin			(vpcmd_context, vpdev_hnd, int sns, eCmdActions, ENUM_CONFIG *);
		///Virtual Sensor (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_virtual			(vpcmd_context, vpdev_hnd, int sns, eCmdActions, VIRTUAL_SNS_CONFIG *);
		//Sensor Configuration Block (RESET) (not implemented)
		//int VPCMD_API vpcmd_sns_blockcfg		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, SENSOR_CONFIG*);
		///Sensor prediction filter (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_predfilter		(vpcmd_context, vpdev_hnd, int sns, eCmdActions, PF_CONFIG*);
		///Extended Sensor prediction filter (GET/SET/RESET)
		int VPCMD_API vpcmd_sns_predfilterext	(vpcmd_context, vpdev_hnd, int sns, eCmdActions, PF_CONFIG_EXT*);
		// generic sensor command performs no command verification
		///Sensor generic command function
		int VPCMD_API vpcmd_sns_generic			(vpcmd_context, vpdev_hnd, int sns, eCmdActions eact, uint32_t cmd, void * pay_buf = 0, uint32_t size = 0, uint32_t arg2 = 0);
	///@} end sensor_cfg

	// read-only sensor commands
	///@addtogroup readonly
	///@{

		///@todo Retrieve Sensor WhoAmI information
		int VPCMD_API vpcmd_sns_whoami			(vpcmd_context, vpdev_hnd, int sns,				 WHOAMI_STRUCT *);
		///@todo Retrieve Sensor WhoAmI information formatted into a printable ASCII string
		int VPCMD_API vpcmd_sns_whoami_report	(vpcmd_context, vpdev_hnd, int sns,				 const char * &);
		///@Retrieve Sensor WhoAmI information formatted into a printable ASCII string
		int VPCMD_API vpcmd_sns_whoami_reportW  (vpcmd_context, vpdev_hnd, int sns,              const wchar_t*&);
		///@} //end readonly

///@} //end sensor_level

// pno-related commands & operations for specific device for now.  Next: for whole context when >1 device

///@defgroup pno_centric P&O functions
/// Functions for managing P&O status and retrieving P&O data
///@{

	///@defgroup pno_cmd P&O commands
	/// Commands for controlling tracker P&O output
	///@{

		/// Start/Stop SEU Continuous P&O  (SET/RESET)
		int VPCMD_API vpcmd_dev_contpno(vpcmd_context, vpdev_hnd, eCmdActions, CONT_FC_CONFIG * fc=0, ePnoMode eMode=E_PNOMODE_STD);

		/// Get Single SEU P&O frame (GET)
		/// Frame info points to SEUPNO, not entire raw buf with preamble 
		/// @sa vpctx_dev_fifopnof
		int VPCMD_API vpcmd_dev_singlepno(vpcmd_context, vpdev_hnd, vpFrameInfo &, ePnoMode eMode = E_PNOMODE_STD);
	///@} //end pno_cmd

	///@defgroup pno_collect P&O collection functions
	/// Functions for collecting streaming P&O data
	///@{

		///@defgroup fifo FIFO 
		/// (First-in-First-out) P&O data collection
		/// Used when all data must be collected, e.g. for recording and/or movement analysis
		///@{

			///@defgroup fbyf Frame-By-Frame
			/// Collect one frame at a time.
			///@{

				/// Get @ref vpFrameInfo for next avail P&O data block received from device.
				/// Frame info points to SEUPNO struct, not entire raw buf with preamble. 
				/// FIFO. Pops (removes) the frame from the received queue. Queue holds up to 2 seconds of frames
				int VPCMD_API vpctx_dev_fifopnof(vpcmd_context, vpdev_hnd, vpFrameInfo &);

				/// Get @ref vpFrameInfo for next avail Raw P&O frame received from device.
				/// Frame info points to complete raw frame w/ preamble and CRC. 
				/// FIFO. Pops the frame from the queue. Queue holds up to 2 seconds of frames.
				int VPCMD_API vpctx_dev_fifopnofraw(vpcmd_context, vpdev_hnd, vpFrameInfo &);
			///@} // end fbyf

			///@defgroup blockpno Block by Block
			/// Collect P&O data in raw data blocks for batch processing or archiving.
			///@{

				/// Get number of unread frames in device FIFO queue and how many bytes total in those frames
				/// Used in conjunction with vpctx_dev_fifo_readrawbuf().
				int VPCMD_API vpctx_dev_fifo_unread_count(vpcmd_context, vpdev_hnd, uint32_t & fc, uint32_t & bc);

				/// Read @code fc @endcode number of unread FIFO raw frames into buffer of given size. 
				/// Returns number of frames, bytes written in fc, size params. 
				/// Pop retrieved frames from the queue.  Queue holds up to 2 seconds of frames.
				int VPCMD_API vpctx_dev_fifo_readrawbuf(vpcmd_context, vpdev_hnd, uint32_t & fc, uint8_t * & pbuf, uint32_t & size);
			///@} //end blockpno
		///@} //end fifo

		///@defgroup lifo LIFO (Last-In-First-Out) 
		/// Collect only the most recent frame received from the device.  Discard uncollected frames.
		/// Use for real-time animation, gaming, simulation and/or other VR applications.
		///@{

			/// Get @ref vpFrameInfo for latest P&O frame received from device.
			/// Frame info points to PNO hdr, not entire raw buf with preamble. 
			/// Pops all older frames from the queue. 
			/// @ingroup fbf
			int VPCMD_API vpctx_dev_lastpnof(vpcmd_context, vpdev_hnd, vpFrameInfo &);

			/// Get @ref vpFrameInfo for last Raw P&O frame received from device.
			/// Frame info points to complete raw frame w/ preamble and CRC. 
			/// Pops all older frames from the queue. 
			/// @ingroup fbf
			int VPCMD_API vpctx_dev_lastpnofraw(vpcmd_context, vpdev_hnd, vpFrameInfo &);
		///@} //end lifo

		/// Purge unread P&O data, Reset host frame counters for specified device.
		int VPCMD_API vpctx_dev_resetpnocounters(vpcmd_context, vpdev_hnd);

	///@} //end pno_collect
///@todo Implement context_level P&O collection functions
///@} //end pno_centric

/// Trace output verbosity levels
typedef enum
{
	VPCMD_NOTRACE					//!< No Trace output
	, VPCMD_TRACE_1_MIN				//!< Minimal trace + errors
	, VPCMD_TRACE_2_COMPACT
	, VPCMD_TRACE_3_NORMALIO		//!< Normal I/O trace + errors, no P&O 
	, VPCMD_TRACE_4_ALLIO		    //!< All Normal I/O trace + errors, includes P&O
	, VPCMD_TRACE_5_CODETRACE = 5	//!< Code trace + I/O + errors
	, VPCMD_TRACE_7_VERBOSE = 7		//!< Verbose trace output, from VPcmdIF and underlying USB & serial IO packakges.
}eVPcmdTraceLevel;



#ifdef __cplusplus
}
#endif /* __cplusplus */
