// VPCmdIF.cpp : Defines the exported functions for the DLL application.
//

#include "VPCmdIF.h"
#include "VPcmdDefsi.h"
#include "VPContext.h"
#include "VPtracei.h"
#include "VPdevIO.h"
#include "stdformat.h"
#include <io.h>

const char * g_vp_build_date = __DATE__;
const char * g_vp_build_time = __TIME__;
const char * g_vp_build_dt = __DATE__ " " __TIME__;

std::wstring g_vp_wsversion;
std::wstring g_vp_wsbuild_date;
std::wstring g_vp_wsbuild_time;
std::wstring g_vp_wsbuild_dt;

void Init_wstrings()
{
	if (g_vp_wsversion.empty())
	{
		std::string stmp(VPCMDIF_VERSION_STR);
		g_vp_wsversion.clear();
		stdformat::converttows(g_vp_wsversion, stmp);
	}
	if (g_vp_wsbuild_date.empty())
	{
		std::string stmp(g_vp_build_date);
		g_vp_wsbuild_date.clear();
		stdformat::converttows(g_vp_wsbuild_date, stmp);
	}
	if (g_vp_wsbuild_time.empty())
	{
		std::string stmp(g_vp_build_time);
		g_vp_wsbuild_time.clear();
		stdformat::converttows(g_vp_wsbuild_time, stmp);
	}
	if (g_vp_wsbuild_dt.empty())
	{
		std::string stmp(g_vp_build_dt);
		g_vp_wsbuild_dt.clear();
		stdformat::converttows(g_vp_wsbuild_dt, stmp);
	}
}

// All api-level functions begin with vpcmdif_
/** @fn vpcmdif_init
* @details
* Initializes VPcmdIF API library and allocates a new context.
* @param[out] ctx Reference to @ref vpcmd_context where new handle will be placed.
* @returns @ref errorval
*/
int VPCMD_API vpcmdif_init(vpcmd_context & ctx)
{
	/** \snippet{lineno} VPcmdWinConsole.cpp Initializing
	* This is an example of how to use vpcmdif_init().
	* More details about this example.
	*/
	int ires = 0;
	//fprintf(stdout, __FUNCTION__ " : %d\r\n", __LINE__);

	Init_wstrings();

	CVPcontext *pctx = new CVPcontext();

	if (pctx == 0)
	{
		ires = E_VPERR_MEMORY_ALLOCATION;
	}
	else
	{
		pctx->pushPctx(pctx);
		ctx = (vpcmd_context)pctx;

		//check existence of $(CONOUT):

		HANDLE hndconout = CreateFileA("CONOUT$", 0, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,0);
		if (hndconout != INVALID_HANDLE_VALUE)
		{
			FILE *f = 0;
			f = freopen("CONOUT$", "w", stdout);

		}

		//fprintf(stdout, __FUNCTION__ " : %d : ctx %d 0x%x : sizeof(pctx)=%d, sizeof(ctx)=%d\r\n", 
		//	__LINE__, pctx, pctx, sizeof(pctx), sizeof(ctx));

		trTracefHP1("%s : VPcmdIF %s %s : ctx 0x%x : sizeof(ctx)=%d : %d active contexts\r\n", 
			__FUNCTION__, vpcmdif_version(), vpcmdif_datetime(), pctx, sizeof(ctx), pctx->g_vecActiveCtx.size());
		pctx->SetTraceLev(g_eVPTraceLev);
	}

	return ires;
}

#define PCTX(hnd)  	(CVPcontext*)hnd;

/** Releases previously allocated context.
* Disconnects and releases all @ref vpdev_hnd device handles in the context.
* @param[in] ctx  @ref vpcmd_context to release.
* @returns @ref errorval
*/int VPCMD_API vpcmdif_release(vpcmd_context ctx)
{
	CVPcontext * pctx = (CVPcontext*)ctx;

	if (!(CVPcontext::findPctx(pctx)))
		return E_VPERR_INVALID_CONTEXT;

	//Destroy Context: Disc(inc Hub objects), HubIO and Context object
	CVPcontext::destroyPctx(pctx);

	return E_VP_SUCCESS;
}

#define VALIDATE_CONTEXT(pctx, ctx) {pctx=(CVPcontext*)ctx;if (!(CVPcontext::findPctx(pctx))) return E_VPERR_INVALID_CONTEXT; }

/** Parses simple and compound @ref errorval returned by VPcmdIF function 
* into an ASCII string.
* @param[in] err  @ref errorval to parse.
* @returns null-terminated ASCII string.
*/
const char * vpcmdif_errorStr(int err)
{
	return trErrStr(err);
}
/** Parses simple and compound @ref errorval returned by VPcmdIF function
* into a UNICODE string.
* @param[in] err  @ref errorval to parse.
* @returns null-terminated UNICODE string.
*/
const wchar_t* vpcmdif_errorStrW(int err)
{
	return trErrStrW(err);
}
/** 
* @returns const char * null-terminated ASCII version string.
*/
const char * vpcmdif_version()
{
	return VPCMDIF_VERSION_STR;
}
/**
* @returns const char * null-terminated UNICODE version string.
*/
const wchar_t* vpcmdif_versionW()
{
	Init_wstrings();
	return g_vp_wsversion.c_str();
}
/**
* @returns const char * null-terminated ASCII date string of the form <EM>Mmm dd yyyy.</EM>
*/
const char * vpcmdif_date()
{
	return g_vp_build_date;// __DATE__;
}
/**
* @returns const char * null-terminated UNICODE date string of the form <EM>Mmm dd yyyy.</EM>
*/
const wchar_t* vpcmdif_dateW()
{
	Init_wstrings();
	return g_vp_wsbuild_date.c_str();;// __DATE__;
}
/**
* @returns const char * null-terminated ASCII time string of the form <EM>hh:mm:ss.</EM>
*/
const char * vpcmdif_time()
{
	return g_vp_build_time; // __TIME__;
}
/**
* @returns const char * null-terminated UNICODE time string of the form <EM>hh:mm:ss.</EM>
*/
const wchar_t* vpcmdif_timeW()
{
	Init_wstrings();
	return g_vp_wsbuild_time.c_str();; // __TIME__;
}
/**
* @returns const char * null-terminated ASCII time string of the form <EM>hh:mm:ss.</EM>
*/
const char * vpcmdif_datetime()
{
	return g_vp_build_dt; // __TIME__;
}
/**
* @returns const char * null-terminated ASCII time string of the form <EM>hh:mm:ss.</EM>
*/
const wchar_t* vpcmdif_datetimeW()
{
	Init_wstrings();
	return g_vp_wsbuild_dt.c_str(); // __TIME__;
}
/** Set trace level before init to propogate to all future contexts. 
 *  Does not affect existing contexts.
 * @param iLev 32-bit integer expression of enum @ref eVPcmdTraceLevel
 */
void vpcmdif_trace(int32_t iLev)
{
	if ((iLev >= VPCMD_NOTRACE) && (iLev <= VPCMD_TRACE_7_VERBOSE))
		trTraceEnable((iLev>0), iLev);
}
// All context-centric operations begin with vpctx_
/** Attempts to create a new USB connection to device with the supplied PID.
*   USB Vendor ID (VID) is assumed to be Polhemus' USB Vendor ID
*   If successful, allocates a new @ref vpdev_hnd device handle.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[out] dev Reference to @ref vpdev_hnd where new device handle will be placed.
* @param[in]  pid USB Product ID (PID) for device. Default @ref VIPER_USB_PID
* @returns @ref errorval
*/
int VPCMD_API vpctx_connectusb(vpcmd_context ctx, vpdev_hnd & dev, uint16_t pid)
{
	int iRet = 0;

	CVPcontext * pctx=0;

	VALIDATE_CONTEXT(pctx,ctx);
	//CVPcontext * pctx = (CVPcontext*)ctx;

	//if (!(CVPcontext::findPctx(pctx)))
	//	return E_VPERR_INVALID_CONTEXT;

	return pctx->connectNewUSB(dev, POLHEMUS_VID, pid);


}

/** Attempts to create a new serial connection to device with the supplied com port num and SERIAL_CONFIG.sercfg bitfield.
*   if sercfg is zero, default baud/parity of 1152.K/None is used.
*   If successful, allocates a new @ref vpdev_hnd device handle.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[out] dev Reference to @ref vpdev_hnd where new device handle will be placed.
* @param[in]  serport COM port
* @param[in]  srcfg baud+parity bitfield, format as in @ref SERIAL_CONFIG
* @returns @ref errorval
*/
int VPCMD_API vpctx_connectser(vpcmd_context ctx, vpdev_hnd & dev, int32_t serport, uint32_t sercfg)
{
	int iRet = 0;

	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->connectNewSer(dev, serport, sercfg);

}
#define G4P_PID 0xCF11  
int VPCMD_API vpctx_connectusb_g4p(vpcmd_context ctx, vpdev_hnd & dev, uint16_t pid)
{
	int r = 0;

	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);
	//CVPcontext * pctx = (CVPcontext*)ctx;

	//if (!(CVPcontext::findPctx(pctx)))
	//	return E_VPERR_INVALID_CONTEXT;
	dev = 0;

	if (r = pctx->connectNewUSB(dev, POLHEMUS_VID, G4P_PID, G4P_PID))
	{
	}
	else
	{
		//((CVPdevIO*)dev)->CmdPreamble() = G4PLUS_CMD_PREAMBLE;
		//((CVPdevIO*)dev)->PnoPreamble() = G4PLUS_PNO_PREAMBLE;
	}

	return r;
}

int VPCMD_API vpctx_dev_release(vpcmd_context ctx , vpdev_hnd hnd)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_release(hnd);
}
/** Retrieves identifying information saved with all connected @ref vpdev_hnd device handles associated
* with the referenced @ref vpcmd_context and formats into a printable ASCII string.
* ASCII report includes SEU ID, serial number and @ref WHOAMI_STRUCT.device_name.
* Note: The report string is returned as a pointer to a VPcmdIF heap buffer.  Contents of the buffer
* are not guaranteed after subsequent calls into VPcmdIF.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[out] szrpt Reference to const char *. If successful this will point to the resulting formatted string.
* @returns @ref errorval
* @sa vpdev_report() 
*/
int VPCMD_API vpctx_dev_report(vpcmd_context ctx, const char *& szrpt)
{
	int r = 0;

	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	pctx->reportsClear();
	pctx->reportAlldevs();

	szrpt = pctx->reportBuf();

	return r;
}
/** Retrieves identifying information saved with all connected @ref vpdev_hnd device handles associated
* with the referenced @ref vpcmd_context and formats into a printable UNICODE string.
* UNICODE report includes SEU ID, serial number and @ref WHOAMI_STRUCT.device_name.
* Note: The report string is returned as a pointer to a VPcmdIF heap buffer.  Contents of the buffer
* are not guaranteed after subsequent calls into VPcmdIF.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[out] szrpt Reference to const wchar_t *. If successful this will point to the resulting formatted string.
* @returns @ref errorval
* @sa vpdev_report()
*/
int VPCMD_API vpctx_dev_reportW(vpcmd_context ctx, const wchar_t*& wszrpt)
{
	int r = 0;

	CVPcontext* pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	pctx->reportsClear();
	pctx->reportAlldevs();

	wszrpt = pctx->reportBufW();

	return r;
}

int VPCMD_API vpctx_trace(vpcmd_context ctx, int32_t iTraceLev/* = 0*/)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	pctx->SetTraceLev(iTraceLev);

	return 0;
}
int VPCMD_API vpdev_SetPnoCallback(vpcmd_context ctx, vpdev_hnd hnd, VP_PNOREADY_CALLBACK cb, PVOID pInfo)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_SetPnoCB(hnd, cb, pInfo);

}
// device-centric commands begin with vpdev_
int VPCMD_API vpdev_trace(vpcmd_context ctx, vpdev_hnd hnd, int iTraceLev/* = 0*/)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_tracelev(hnd, iTraceLev);
}

/// Set command response timeout (ms) for a single device (SEU)  SET, RESET only
int VPCMD_API vpdev_timeoutms(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eAct, int iTimeoutMS)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_timeoutms(hnd, eAct, iTimeoutMS);

}

/** Retrieves identifying information saved with the referenced @ref vpdev_hnd device handle and
* formats it into a printable ASCII string.
* ASCII report includes SEU ID, serial number and @ref WHOAMI_STRUCT.device_name.
* Note: The report string is returned as a pointer to a VPcmdIF heap buffer.  Contents of the buffer 
* are not guaranteed after subsequent calls into VPcmdIF.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[in]  hnd Active device handle created with @ref vpctx_connectusb() or @ref vpctx_connectser()
* @param[out] szrpt Reference to const char *. If successful this will point to the resulting formatted string.
* @returns @ref errorval
* @sa vpctx_dev_report()
*/
int VPCMD_API vpdev_report(vpcmd_context ctx, vpdev_hnd hnd, const char *& szrpt)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	pctx->reportsClear();
	pctx->dev_report( hnd );

	szrpt = pctx->reportBuf();
	return 0;
}
/** Retrieves identifying information saved with the referenced @ref vpdev_hnd device handle and
* formats it into a printable UNICODE string.
* ASCII report includes SEU ID, serial number and @ref WHOAMI_STRUCT.device_name.
* Note: The report string is returned as a pointer to a VPcmdIF heap buffer.  Contents of the buffer
* are not guaranteed after subsequent calls into VPcmdIF.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[in]  hnd Active device handle created with @ref vpctx_connectusb() or @ref vpctx_connectser()
* @param[out] szrpt Reference to const char *. If successful this will point to the resulting formatted string.
* @returns @ref errorval
* @sa vpctx_dev_report()
*/
int VPCMD_API vpdev_reportW(vpcmd_context ctx, vpdev_hnd hnd, const wchar_t*& wszrpt)
{
	CVPcontext* pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	pctx->reportsClear();
	pctx->dev_report(hnd);

	wszrpt = pctx->reportBufW();
	return 0;
}

int VPCMD_API vpdev_tsenable(vpcmd_context ctx, vpdev_hnd hnd, bool bTSen)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_tsenable(hnd, bTSen);
}
//allow pno frames with errors through. Put tag in pno hpinfo reserved field if frame err occurs.
//allows caller to examine all frames for troubleshooting.  
//Hidden, To use, manually declare extern as follows:
//int VPCMD_API vpdev_pnofrmerr_allow(vpcmd_context ctx, vpdev_hnd hnd, bool ballow);
int VPCMD_API vpdev_pnofrmerr_allow(vpcmd_context ctx, vpdev_hnd hnd, bool ballow)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_pnofrmerr_allow(hnd, ballow);
}
//Enable Viper USB buffering in continuous mode.
//When the user sends the continuous command, if he/she wants the data buffered they supply 
//the number of frames to buffer in the arg1 field.  The I/O proc then waits till that many 
//frames have been read then sends them all at once.  The max buffer size is 1024*32 (4)bytes = 4096 bytes, 
//so depending on the number of sensors, the user can buffer between 7 (16 sensors), 14 (8 sensors) and 73 (1 sensor) frames.
//Hidden, To use, manually declare extern as follows:
//int VPCMD_API vpdev_pnousb_buffer(vpcmd_context ctx, vpdev_hnd hnd, uint32_t buffer_count);
//Note this command currently applies to the entire context, which builds the cont pno command for all devhnds.
//(currently only one devhnd supported.)
int VPCMD_API vpdev_pnousb_buffer(vpcmd_context ctx, vpdev_hnd hnd, uint32_t count)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_pnousb_buffer(hnd, count);

}
/** Retrieves reference to identifying information saved with the referenced @ref vpdev_hnd device handle.
* This is the WhoAmI and SEU ID information acquired when vpdev_hnd was created at connection.
* @param[in]  ctx Active context created with @ref vpcmdif_init()
* @param[in]  hnd Active device handle created with @ref vpctx_connectusb() or @ref vpctx_connectser()
* @param[out] wai Reference to @ref WHOAMI_STRUCT pointer. If successful this will point to the WHOAMI_STRUCT saved by the context.
* @param[out] seuid Reference to @ref VIPER_SEUID where saved SEU ID will be placed.
* @returns @ref errorval
*/
int VPCMD_API vpdev_info(vpcmd_context ctx, vpdev_hnd hnd, const WHOAMI_STRUCT *& wai,  VIPER_SEUID & seuid)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_info(hnd, wai, seuid);

	//return 0;
}
// config commands
int VPCMD_API vpcmd_dev_resetblockcfg(vpcmd_context ctx, vpdev_hnd hnd)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_resetblockcfg(hnd);
}
int VPCMD_API vpcmd_dev_framerate(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, FRAMERATE_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_framerate(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_id(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, SEUID_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_seuid(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_serialif(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, SERIAL_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_serialif(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_sourcerot(vpcmd_context ctx, vpdev_hnd hnd, int src, eCmdActions eact, SRCROT_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_sourcerot(hnd, src, eact, wai);
}
int VPCMD_API vpcmd_dev_sourcecfg(vpcmd_context ctx, vpdev_hnd hnd, int src, eCmdActions eact, SRC_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_sourcecfg(hnd, src, eact, wai);
}
int VPCMD_API vpcmd_dev_stylusmode(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, STYLUS_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_stylusmode(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_syncmode(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, BINARY_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_syncmode(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_units(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, UNITS_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_units(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_dualoutput(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, BINARY_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_dualoutput(hnd, eact, wai);
}
int VPCMD_API vpcmd_dev_selfcalstate(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, SELFCAL_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_selfcalstate(hnd, eact, wai); 
}
int VPCMD_API vpcmd_dev_selfcalsave(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, BINARY_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_selfcalsave(hnd, eact, wai); 
}
// read-only commands
int VPCMD_API vpcmd_dev_whoami(vpcmd_context ctx, vpdev_hnd hnd, WHOAMI_STRUCT * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);
	
	return pctx->cmd_dev_whoami(hnd, wai);
}
int VPCMD_API vpcmd_dev_whoami_report(vpcmd_context ctx, vpdev_hnd hnd, const char * & szrpt)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_dev_whoami_report(hnd))
	{}
	else
		szrpt = pctx->reportBuf();

	return r;
}
int VPCMD_API vpcmd_dev_whoami_reportW(vpcmd_context ctx, vpdev_hnd hnd, const wchar_t*& wszrpt)
{
	CVPcontext* pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_dev_whoami_report(hnd))
	{
	}
	else
		wszrpt = pctx->reportBufW();

	return r;
}
int VPCMD_API vpcmd_dev_sourcewhoami(vpcmd_context ctx, vpdev_hnd hnd, int src, WHOAMI_STRUCT *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_sourcewhoami(hnd, src, wai);
}
int VPCMD_API vpcmd_dev_sourcewhoami_report(vpcmd_context ctx, vpdev_hnd hnd, int src, const char * & szrpt)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_dev_sourcewhoami_report(hnd, src))
	{
	}
	else
		szrpt = pctx->reportBuf();

	return r;
}
int VPCMD_API vpcmd_dev_sourcewhoami_reportW(vpcmd_context ctx, vpdev_hnd hnd, int src, const wchar_t*& wszrpt)
{
	CVPcontext* pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_dev_sourcewhoami_report(hnd, src))
	{
	}
	else
		wszrpt = pctx->reportBufW();

	return r;
}
int VPCMD_API vpcmd_dev_stationmap(vpcmd_context ctx, vpdev_hnd hnd, STATION_MAP * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_stationmap(hnd, CMD_ACTION_GET, wai);
}

int VPCMD_API vpcmd_dev_bit(vpcmd_context ctx, vpdev_hnd hnd, BIT_STRUCT * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_bit(hnd, wai);
}
int VPCMD_API vpcmd_dev_bit_report(vpcmd_context ctx, vpdev_hnd hnd, const char * & szrpt)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_dev_bit_report(hnd))
	{
	}
	else
		szrpt = pctx->reportBuf();

	return r;
}
int VPCMD_API vpcmd_dev_bit_reportW(vpcmd_context ctx, vpdev_hnd hnd, const wchar_t*& wszrpt)
{
	CVPcontext* pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_dev_bit_report(hnd))
	{
	}
	else
		wszrpt = pctx->reportBufW();

	return r;
}
// executive commands
int VPCMD_API vpcmd_dev_reset_framecount(vpcmd_context ctx, vpdev_hnd hnd)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_resetfc(hnd);
}
int VPCMD_API vpcmd_dev_persist(vpcmd_context ctx, vpdev_hnd hnd)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_persist(hnd);
}


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*/)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_gen(hnd, cmd, eact, (uint8_t*)pay_buf, size, arg1, arg2);

}
//int cmd_dev_gen(vpdev_hnd, uint32_t cmd, eCmdActions, uint8_t* pbuf = 0, uint32_t bufsize = 0, uint32_t a1 = 0, uint32_t a2 = 0);
//int cmd_sns_gen(vpdev_hnd, int sns, uint32_t cmd, eCmdActions, uint8_t* pbuf = 0, uint32_t bufsize = 0, uint32_t a2 = 0);
int VPCMD_API vpcmd_sns_generic(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, uint32_t cmd, void * pay_buf/* = 0*/, uint32_t size/* = 0*/, uint32_t arg2/* = 0*/)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_gen(hnd, sns, cmd, eact, (uint8_t*)pay_buf, size, arg2 );
}

// sensor-centric commands begin with vpsns_
int VPCMD_API vpcmd_sns_boresight(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, BORESIGHT_CONFIG *wai, uint32_t arg2 /*=0*/)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_boresight(hnd, sns, eact, wai, arg2);
}
int VPCMD_API vpcmd_sns_filter(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, FILTER_CONFIG *wai, eViperFilterTargets etar)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_filter(hnd, sns, eact, wai, etar);
}
int VPCMD_API vpcmd_sns_hemisphere(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, HEMISPHERE_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_hemisphere(hnd, sns, eact, wai);
}
int VPCMD_API vpcmd_sns_increment(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, INCREMENT_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_increment(hnd, sns, eact, wai);
}
int VPCMD_API vpcmd_sns_tipoffset(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, TIP_OFFSET_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_tipoffset(hnd, sns, eact, wai);
}

int VPCMD_API vpcmd_sns_fttmode(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, ENUM_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_ftt(hnd, sns, eAct, wai);
}
// not exposed.  To use, declare as below:
//  /Sensor FTT Home (SET/RESET)
// extern int VPCMD_API vpcmd_sns_ftthome(vpcmd_context, vpdev_hnd, int sns, eCmdActions, PNODATA *, eFTTHomeMethod);
int VPCMD_API vpcmd_sns_ftthome(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, PNODATA * wai, eFTTHomeMethod eMethod)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_ftthome(hnd, sns, eAct, wai, eMethod);
}

int VPCMD_API vpcmd_sns_srcselect(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, SRC_SEL_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_srcselect(hnd, sns, eAct, wai);
}

int VPCMD_API vpcmd_sns_origin(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, ENUM_CONFIG * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_origin(hnd, sns, eAct, wai);
}

int VPCMD_API vpcmd_sns_virtual(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, VIRTUAL_SNS_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_virtual(hnd, sns, eAct, wai);
}

//int VPCMD_API vpcmd_sns_blockcfg(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, SENSOR_CONFIG * wai)
//{
//	CVPcontext * pctx = 0;
//	VALIDATE_CONTEXT(pctx, ctx);
//
//	return pctx->cmd_sns_blockcfg(hnd, sns, eAct, wai);
//}
int VPCMD_API vpcmd_sns_predfilter(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, PF_CONFIG *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_predfilter(hnd, sns, eact, wai);
}
int VPCMD_API vpcmd_sns_predfilterext(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eact, PF_CONFIG_EXT *wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_predfilterext(hnd, sns, eact, wai);
}

//Sensor led control.  Hidden, To use, manually declare extern as follows:
//int VPCMD_API vpcmd_sns_led(vpcmd_context, vpdev_hnd, int sns, eCmdActions, BIT_STRUCT *);
int VPCMD_API vpcmd_sns_led(vpcmd_context ctx, vpdev_hnd hnd, int sns, eCmdActions eAct, BIT_STRUCT * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_gen(hnd, sns, CMD_BIT, eAct, (uint8_t*)wai, sizeof(BIT_STRUCT));
}

int VPCMD_API vpcmd_sns_whoami(vpcmd_context ctx, vpdev_hnd hnd, int sns, WHOAMI_STRUCT * wai)
{
	CVPcontext * pctx = 0;
	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_sns_whoami(hnd, sns, wai);
}
int VPCMD_API vpcmd_sns_whoami_report(vpcmd_context ctx, vpdev_hnd hnd, int sns, const char * & szrpt)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_sns_whoami_report(hnd, sns))
	{
	}
	else
		szrpt = pctx->reportBuf();

	return r;
}

int VPCMD_API vpcmd_sns_whoami_reportW(vpcmd_context ctx, vpdev_hnd hnd, int sns, const wchar_t*& wszrpt)
{
	CVPcontext* pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	pctx->reportsClear();
	if (r = pctx->cmd_sns_whoami_report(hnd, sns))
	{
	}
	else
		wszrpt = pctx->reportBufW();

	return r;
}


int VPCMD_API vpcmd_dev_contpno(vpcmd_context ctx, vpdev_hnd hnd, eCmdActions eact, CONT_FC_CONFIG *fc/* = 0*/, ePnoMode eMode /*= E_PNOMODE_STD*/)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);
	CONT_FC_CONFIG lfc = (fc) ? *fc : 0;

	return pctx->cmd_dev_contpno(hnd, eact, &lfc, eMode);

}
int VPCMD_API vpcmd_dev_singlepno(vpcmd_context ctx, vpdev_hnd hnd, vpFrameInfo & f, ePnoMode eMode /*= E_PNOMODE_STD*/)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->cmd_dev_singlepno(hnd, f, eMode);

}

int VPCMD_API vpcmd_dev_singlepno_g4p(vpcmd_context ctx, vpdev_hnd hnd, vpFrameInfo & f)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	int r = 0;
	CFrameInfo Fin;

	if (r = vpcmd_dev_singlepno(ctx, hnd, f))
	{
		int i = 0;
	}
	else
	{
		Fin = f;
		if (!Fin.IsPno())
			r = pctx->dev_nextpnof(hnd, Fin);

		(CFrameInfo&)f = Fin;
	}

	return r;	
}

int VPCMD_API vpctx_dev_fifopnof(vpcmd_context ctx, vpdev_hnd hnd, vpFrameInfo & f)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	CFrameInfo Fin;

	int r = pctx->dev_fifopnof(hnd, Fin);

	(CFrameInfo&)f = Fin;

	return r;
}

int VPCMD_API vpctx_dev_fifopnofraw(vpcmd_context ctx, vpdev_hnd hnd, vpFrameInfo & f)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	CFrameInfo Fin;

	int r = pctx->dev_fifopnofraw(hnd, Fin);

	(CFrameInfo&)f = Fin;

	return r;
}
int VPCMD_API vpctx_dev_fifo_unread_count(vpcmd_context ctx, vpdev_hnd hnd, uint32_t & fc, uint32_t & bc)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_fifo_count(hnd, fc, bc);
}

int VPCMD_API vpctx_dev_fifo_readrawbuf(vpcmd_context ctx, vpdev_hnd hnd, uint32_t & fc, uint8_t *& pbuf, uint32_t & size)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	return pctx->dev_fifo_readrawbuf(hnd, fc, pbuf, size);

	return 0;
}

int VPCMD_API vpctx_dev_lastpnof(vpcmd_context ctx, vpdev_hnd hnd, vpFrameInfo & f)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	CFrameInfo Fin;

	int r = pctx->dev_lastpnof(hnd, Fin);

	(CFrameInfo&)f = Fin;

	return r;
}

int VPCMD_API vpctx_dev_lastpnofraw(vpcmd_context ctx, vpdev_hnd hnd, vpFrameInfo & f)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	CFrameInfo Fin;

	int r = pctx->dev_lastpnofraw(hnd, Fin);

	(CFrameInfo&)f = Fin;

	return r;
}

int VPCMD_API vpctx_dev_resetpnocounters(vpcmd_context ctx, vpdev_hnd hnd)
{
	CVPcontext * pctx = 0;

	VALIDATE_CONTEXT(pctx, ctx);

	int r = pctx->dev_resetpno(hnd);

	return r;

}
