/******************************************************************************
 *                                                                         
 *               (C) COPYRIGHT Pacific MindWorks, Inc. 2001-2005
 *                          All rights reserved.
 *
 *****************************************************************************/

#ifndef __NTLIOPROVIDERVISACOM_INCLUDED
#define __NTLIOPROVIDERVISACOM_INCLUDED

#include <stdarg.h>
#include <atlrx.h>
#include "ntlutil.h"

#import "GlobMgr.dll" no_namespace, raw_interfaces_only

//uuid(36F6E303-A9CE-11D4-98E5-00108301CB39)
static const GUID CLSID_AgilentSRM =
	 { 0x36F6E303, 0xA9CE, 0x11D4, { 0x98, 0xE5, 0x00, 0x10, 0x83, 0x01, 0xCB, 0x39 } };

///////////////////////////////////////////////////////////////////////////////
//	CVisaComIOProvider

class CVisaComIOProvider :
	public CDriverIOProvider
{
public:
	CVisaComIOProvider();
	virtual ~CVisaComIOProvider();

	// Initialization
	virtual HRESULT ioprvInitializeIOProvider(CObjectModelNodeBase* pObjectModelNode, CErrorManagerBase* pErrorManager, CPerfMonManager* pPerfMonManager, BSTR bstrResourceDescriptor);
	virtual HRESULT ioprvInitializeIOProvider(CObjectModelNodeBase* pObjectModelNode, CErrorManagerBase* pErrorManager, CPerfMonManager* pPerfMonManager, IVisaSession* pVisaSession, IMessage* pMessage, IFormattedIO488* pFormatted);
	virtual HRESULT ioprvCloseIOProvider();
	virtual IOProviderType ioprvGetIOProviderType();

	// Helpers for direct I/O
	virtual HRESULT ioprvGetIVisaSessionPointer(IVisaSession** ppVisaSession);
	virtual HRESULT ioprvGetIMessagePointer(IMessage** ppMessage);
	virtual HRESULT ioprvGetIRegisterPointer(IRegister** ppRegister);
	virtual HRESULT ioprvGetIFormattedIO488Pointer(IFormattedIO488** ppFormattedIO);

	// IRegister-style functions
	virtual HRESULT ioprvRegisterIn8(UINT16 space, UINT32 offset, UINT8* val);
	virtual HRESULT ioprvRegisterOut8(UINT16 space, UINT32 offset, UINT8 val);
	virtual HRESULT ioprvRegisterIn16(UINT16 space, UINT32 offset, UINT16* val);
	virtual HRESULT ioprvRegisterOut16(UINT16 space, UINT32 offset, UINT16 val);
	virtual HRESULT ioprvRegisterIn32(UINT16 space, UINT32 offset, UINT32* val);
	virtual HRESULT ioprvRegisterOut32(UINT16 space, UINT32 offset, UINT32 val);
	virtual HRESULT ioprvRegisterMoveIn8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[]);
	virtual HRESULT ioprvRegisterMoveOut8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[]);
	virtual HRESULT ioprvRegisterMoveIn16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[]);
	virtual HRESULT ioprvRegisterMoveOut16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[]);
	virtual HRESULT ioprvRegisterMoveIn32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[]);
	virtual HRESULT ioprvRegisterMoveOut32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[]);

protected:
	// IMessage-style functions.
	virtual HRESULT ioprvMessageIORead(BYTE* pBuf, long cbDesired, long* plActualLength);
	virtual HRESULT ioprvMessageIORead(long cbDesired, SAFEARRAY** ppsa);
	virtual HRESULT ioprvMessageIOReadString(long cchDesired, BSTR* pbstrBuf);
	virtual HRESULT ioprvMessageIOWrite(BYTE* pBuf, long cbDesired, long* pcbActual);
	virtual HRESULT ioprvMessageIOWrite(SAFEARRAY* psa, long cbDesired, long* pcbActual);
	virtual HRESULT ioprvMessageIOWriteString(BSTR bstrBuf, long* pcchActual);
	virtual HRESULT ioprvMessageIOClear();
	virtual HRESULT ioprvMessageIOReadSTB(long* plStatus);
	virtual HRESULT ioprvMessageIOSetSendEndEnabled(bool bEnable);
	virtual HRESULT ioprvMessageIOGetSendEndEnabled(bool* pbEnable);
	virtual HRESULT ioprvMessageIOSetTerminationCharacter(BYTE val);
	virtual HRESULT ioprvMessageIOGetTerminationCharacter(BYTE* pVal);
	virtual HRESULT ioprvMessageIOSetTerminationCharacterEnabled(bool bEnable);
	virtual HRESULT ioprvMessageIOGetTerminationCharacterEnabled(bool* pbEnable);
	virtual HRESULT ioprvMessageIOSetTimeout(long lTimeout);
	virtual HRESULT ioprvMessageIOGetTimeout(long* plTimeout);

	// Formatted I/O functions.
	virtual HRESULT ioprvFormattedIOSetInstrumentBigEndian(bool bBigEndian);
	virtual HRESULT ioprvFormattedIOGetInstrumentBigEndian(bool* pbBigEndian);
	virtual HRESULT ioprvFormattedIOWriteString(const CString& strData, bool bFlushAndEnd);
	virtual HRESULT ioprvFormattedIOWriteNumber(VARIANT data, NtlAsciiType type, bool bFlushAndEnd);
	virtual HRESULT ioprvFormattedIOWriteList(VARIANT data, NtlAsciiType type, const CString& strListSeparator, bool bFlushAndEnd);
	virtual HRESULT ioprvFormattedIOWriteIEEEBlock(const CString& strCommand, VARIANT data, bool bFlushAndEnd);
	virtual HRESULT ioprvFormattedIOReadString(CString& strData);
	virtual HRESULT ioprvFormattedIOReadNumber(NtlAsciiType type, VARIANT* pData, bool bFlushToEnd);
	virtual HRESULT ioprvFormattedIOReadList(NtlAsciiType type, const CString& strListSeparator, VARIANT* pData);
	virtual HRESULT ioprvFormattedIOReadIEEEBlock(NtlBinaryType type, VARIANT* pData, bool bSeekToBlock, bool bFlushToEnd);
	virtual HRESULT ioprvFormattedIOFlushWrite(bool bSendEND);
	virtual HRESULT ioprvFormattedIOFlushRead();
	virtual HRESULT ioprvFormattedIOSetBufferSize(NtlBufferMask mask, long lSize);

protected:
	BufferMask TranslateBufferMask(NtlBufferMask mask);
	IEEEASCIIType TranslateAsciiType(NtlAsciiType type);
	IEEEBinaryType TranslateBinaryType(NtlBinaryType type);
	HRESULT TranslateErrorCode(HRESULT hr);

protected:
	IVisaSession* m_pSession;							// pointer to VISA-COM I/O resource
	IMessage* m_pMessage;								// pointer to VISA-COM messaging interface
	IRegister* m_pRegister;								// pointer to VISA-COM register interface
	IFormattedIO488* m_pFormatted;						// pointer to VISA-COM formatted IO interface
};


inline CVisaComIOProvider::CVisaComIOProvider() 
	: m_pSession(NULL), m_pMessage(NULL), m_pFormatted(NULL), m_pRegister(NULL)
{
}

inline CVisaComIOProvider::~CVisaComIOProvider()
{
}

inline HRESULT CVisaComIOProvider::ioprvInitializeIOProvider(CObjectModelNodeBase* pObjectModelNode, CErrorManagerBase* pErrorManager, CPerfMonManager* pPerfMonManager, BSTR bstrResourceDescriptor)
{
	if (pErrorManager == NULL)
		return E_INVALIDARG;

	if (pPerfMonManager == NULL)
		return E_INVALIDARG;

	if (bstrResourceDescriptor == NULL)
		return E_INVALIDARG;

	HRESULT hr = S_OK;

	// If it already has been initialized, then it will get closed
	ioprvCloseIOProvider();

	// Initialize base class
	hr = __super::ioprvInitializeIOProvider(pObjectModelNode, pErrorManager, pPerfMonManager, bstrResourceDescriptor);
	if (SUCCEEDED(hr))
	{
		IResourceManager* pResourceManager;
		hr = ::CoCreateInstance(__uuidof(ResourceManager), NULL, CLSCTX_ALL, __uuidof(IResourceManager), (void**)&pResourceManager);
		if (FAILED(hr))
		{
			// An incomplete installation of VISA-COM supplied by Agilent may not have the global resource manager
			// in this case try with the Agilent resource manager
			hr = ::CoCreateInstance(CLSID_AgilentSRM, NULL, CLSCTX_ALL, __uuidof(IResourceManager), (void**)&pResourceManager);
		}

		if (SUCCEEDED(hr))
		{
			CComBSTR bstrOptionString("");
			hr = pResourceManager->Open(bstrResourceDescriptor, NO_LOCK, DEFAULT_TIMEOUT, bstrOptionString, &m_pSession);

			if (SUCCEEDED(hr))
			{
				hr = m_pSession->QueryInterface(__uuidof(IMessage), (void**)&m_pMessage);
				if (SUCCEEDED(hr))
				{
					// IRegister not being present is not a fatal error, since the driver
					// developer may not need the wrappers we expose for these functions
					HRESULT hr2 = m_pSession->QueryInterface(__uuidof(IRegister), (void**)&m_pRegister);
					if (FAILED(hr2))
					{
						m_pRegister = NULL;
					}

					hr = ::CoCreateInstance(__uuidof(FormattedIO488), NULL, CLSCTX_ALL, __uuidof(IFormattedIO488), (void**)&m_pFormatted);
					if (SUCCEEDED(hr))
					{
						hr = m_pFormatted->putref_IO(m_pMessage);
					}
					else
					{
						hr = AtlReportError(__uuidof(FormattedIO488), _T("Could not create instance of VISA-COM FormattedIO488 Component. Make sure it is installed properly."), __uuidof(IFormattedIO488), hr);
					}
				}
			}
			else
			{
				hr = E_IVI_RESOURCE_UNKNOWN;
			}

			pResourceManager->Release();
		}
		else
		{
			// Couldn't create the VISA-COM resource manager
			hr = AtlReportError(__uuidof(ResourceManager), _T("Could not create instance of VISA-COM Global Resource Manager Component. Make sure it is installed properly."), __uuidof(IResourceManager), hr);
		}
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvInitializeIOProvider(CObjectModelNodeBase* pObjectModelNode, CErrorManagerBase* pErrorManager, CPerfMonManager* pPerfMonManager, IVisaSession* pVisaSession, IMessage* pMessage, IFormattedIO488* pFormatted) 
{
	if (pErrorManager == NULL)
		return E_INVALIDARG;

	if (pPerfMonManager == NULL)
		return E_INVALIDARG;

	if (pVisaSession == NULL)
		return E_INVALIDARG;

	if (pMessage == NULL)
		return E_INVALIDARG;

	if (pFormatted == NULL)
		return E_INVALIDARG;

	HRESULT hr = S_OK;

	hr = __super::ioprvInitializeIOProvider(pObjectModelNode, pErrorManager, pPerfMonManager, CComBSTR(""));
	if (SUCCEEDED(hr))
	{
		(m_pSession = pVisaSession)->AddRef(); 
		(m_pMessage = pMessage)->AddRef();
		(m_pFormatted = pFormatted)->AddRef();

		// IRegister not being present is not a fatal error, since the driver
		// developer may not need the wrappers we expose for these functions
		HRESULT hr2 = m_pSession->QueryInterface(__uuidof(IRegister), (void**)&m_pRegister);
		if (FAILED(hr2))
		{
			m_pRegister = NULL;
		}
	}

	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvCloseIOProvider()
{
	HRESULT hr = S_OK;

	if (m_pFormatted != NULL)
	{
		m_pFormatted->Release();
		m_pFormatted = NULL;
	}

	if (m_pSession != NULL)
	{
		m_pSession->Release();
		m_pSession = NULL;
	}
	
	if (m_pMessage != NULL)
	{
		m_pMessage->Release();
		m_pMessage = NULL;
	}

	if (m_pRegister != NULL)
	{
		m_pRegister->Release();
		m_pRegister = NULL;
	}

	hr = __super::ioprvCloseIOProvider();

	return TranslateErrorCode(hr);
}

inline IOProviderType CVisaComIOProvider::ioprvGetIOProviderType()
{
	return VisaComIOProvider;
}

inline HRESULT CVisaComIOProvider::ioprvGetIVisaSessionPointer(IVisaSession** ppVisaSession)
{
	if (ppVisaSession == NULL) 
		return E_POINTER;

	HRESULT hr = S_OK;

	if (m_pSession == NULL)
	{
		*ppVisaSession = NULL;
	}
	else
	{
		(*ppVisaSession = m_pSession)->AddRef();
	}

	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvGetIMessagePointer(IMessage** ppMessage)
{
	if (ppMessage == NULL) 
		return E_POINTER;

	HRESULT hr = S_OK;
	
	if (m_pMessage == NULL)
	{
		*ppMessage = NULL;
	}
	else
	{
		(*ppMessage = m_pMessage)->AddRef();
	}

	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvGetIRegisterPointer(IRegister** ppRegister)
{
	if (ppRegister == NULL) 
		return E_POINTER;

	HRESULT hr = S_OK;
	
	if (m_pRegister == NULL)
	{
		*ppRegister = NULL;
	}
	else
	{
		(*ppRegister = m_pRegister)->AddRef();
	}

	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvGetIFormattedIO488Pointer(IFormattedIO488** ppFormattedIO)
{
	if (ppFormattedIO == NULL) 
		return E_POINTER;

	HRESULT hr = S_OK;

	if (m_pFormatted == NULL)
	{
		*ppFormattedIO = NULL;
		hr = S_FALSE;		
	}
	else
	{
		(*ppFormattedIO = m_pFormatted)->AddRef();
	}

	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvMessageIORead(BYTE* pBuf, long cbDesired, long* plActualLength)
{
	if (pBuf == NULL)
		return E_POINTER;

	if (cbDesired < 0)
		return E_INVALIDARG;

	if (plActualLength == NULL)
		return E_POINTER;

	*plActualLength = 0;

	SAFEARRAY* psa;
	HRESULT hr = ioprvMessageIORead(cbDesired, &psa);
	if (SUCCEEDED(hr))
	{
		hr = CSafeArray<BYTE>::Write(psa, pBuf, cbDesired, plActualLength);

		::SafeArrayDestroy(psa);
	}
	
	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvMessageIORead(long cbDesired, SAFEARRAY** ppsa)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pMessage->Read(cbDesired, ppsa);

	IncrementIOByteCount(*ppsa);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOReadString(long cchDesired, BSTR* pbstrBuf)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pMessage->ReadString(cchDesired, pbstrBuf);

	IncrementIOByteCount(*pbstrBuf);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOWrite(BYTE* pBuf, long cbDesired, long* pcbActual)
{
	IO_METHOD_START();

	if (pBuf == NULL)
		return E_POINTER;

	if (cbDesired < 0)
		return E_INVALIDARG;

	if (pcbActual == NULL)
		return E_POINTER;

	SAFEARRAY* psa = NULL;
	HRESULT hr = CSafeArray<BYTE>::CreateFromArray(pBuf, cbDesired, VT_UI1, &psa);
	if (SUCCEEDED(hr))
	{
		hr = ioprvMessageIOWrite(psa, cbDesired, pcbActual);
		::SafeArrayDestroy(psa);
	}

	return hr;
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOWrite(SAFEARRAY* psa, long cbDesired, long* pcbActual)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pMessage->Write(&psa, cbDesired, pcbActual);

	IncrementIOByteCount(*pcbActual);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOWriteString(BSTR bstrBuf, long* pcchActual)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pMessage->WriteString(bstrBuf, pcchActual);

	IncrementIOByteCount(*pcchActual * 2);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOClear()
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pMessage->Clear();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOReadSTB(long* plStatus)
{
	IO_METHOD_START();

	if (plStatus == NULL)
		return E_POINTER;
	*plStatus = 0;

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	short stb;
	hr = m_pMessage->ReadSTB(&stb);
	if (SUCCEEDED(hr))
	{
		*plStatus = (long)stb;
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOSetSendEndEnabled(bool bEnable)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = m_pMessage->put_SendEndEnabled(bEnable ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOGetSendEndEnabled(bool* pbEnable)
{
	IO_METHOD_START();

	if (pbEnable == NULL)
		return E_POINTER;

	if (m_pMessage == NULL)
		return E_FAIL;

	VARIANT_BOOL bValue;
	HRESULT hr = m_pMessage->get_SendEndEnabled(&bValue);
	if (SUCCEEDED(hr))
	{
		*pbEnable = bValue != VARIANT_FALSE;
	}

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOSetTerminationCharacter(BYTE val)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = m_pMessage->put_TerminationCharacter(val);

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOGetTerminationCharacter(BYTE* pVal)
{
	IO_METHOD_START();

	if (pVal == NULL)
		return E_POINTER;

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = m_pMessage->get_TerminationCharacter(pVal);

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOSetTerminationCharacterEnabled(bool bEnable)
{
	IO_METHOD_START();

	if (m_pMessage == NULL)
		return E_FAIL;

	HRESULT hr = m_pMessage->put_TerminationCharacterEnabled(bEnable ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOGetTerminationCharacterEnabled(bool* pbEnable)
{
	IO_METHOD_START();

	if (pbEnable == NULL)
		return E_POINTER;

	if (m_pMessage == NULL)
		return E_FAIL;

	VARIANT_BOOL bValue;
	HRESULT hr = m_pMessage->get_TerminationCharacterEnabled(&bValue);
	if (SUCCEEDED(hr))
	{
		*pbEnable = bValue != VARIANT_FALSE;
	}

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOSetTimeout(long lTimeout)
{
	IO_METHOD_START();

	if (m_pSession == NULL)
		return E_FAIL;

	HRESULT hr = m_pSession->put_Timeout(lTimeout);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvMessageIOGetTimeout(long* plTimeout)
{
	IO_METHOD_START();

	if (m_pSession == NULL)
		return E_FAIL;

	HRESULT hr = m_pSession->get_Timeout(plTimeout);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOSetInstrumentBigEndian(bool bBigEndian)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = m_pFormatted->put_InstrumentBigEndian(bBigEndian ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOGetInstrumentBigEndian(bool* pbBigEndian)
{
	IO_METHOD_START();

	if (pbBigEndian == NULL)
		return E_POINTER;

	if (m_pFormatted == NULL)
		return E_FAIL;

	VARIANT_BOOL bValue;
	HRESULT hr = m_pFormatted->get_InstrumentBigEndian(&bValue);
	if (SUCCEEDED(hr))
	{
		*pbBigEndian = bValue != VARIANT_FALSE;
	}

	IncrementIOByteCount();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOWriteString(const CString& strData, bool bFlushAndEnd)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->WriteString(CT2OLE(strData), bFlushAndEnd ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount(strData);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOWriteNumber(VARIANT data, NtlAsciiType type, bool bFlushAndEnd)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->WriteNumber(data, TranslateAsciiType(type), bFlushAndEnd ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount(data);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOWriteList(VARIANT data, NtlAsciiType type, const CString& strListSeparator, bool bFlushAndEnd)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->WriteList(&data, TranslateAsciiType(type), CT2OLE(strListSeparator), bFlushAndEnd ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount(data);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOWriteIEEEBlock(const CString& strCommand, VARIANT data, bool bFlushAndEnd)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->WriteIEEEBlock(CComBSTR(CT2OLE(strCommand)), data, bFlushAndEnd ? VARIANT_TRUE : VARIANT_FALSE);

	IncrementIOByteCount(strCommand);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOReadString(CString& strData)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	CComBSTR bstr;
	HRESULT hr = m_pFormatted->ReadString(&bstr);
	if (SUCCEEDED(hr))
	{
		strData = COLE2T(bstr);

		IncrementIOByteCount(bstr);
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOReadNumber(NtlAsciiType type, VARIANT* pData, bool bFlushToEnd)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->ReadNumber(TranslateAsciiType(type), bFlushToEnd ? VARIANT_TRUE : VARIANT_FALSE, pData);

	IncrementIOByteCount(*pData);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOReadList(NtlAsciiType type, const CString& strListSeparator, VARIANT* pData)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->ReadList(TranslateAsciiType(type), CComBSTR(CT2OLE(strListSeparator)), pData);

	IncrementIOByteCount(*pData);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOReadIEEEBlock(NtlBinaryType type, VARIANT* pData, bool bSeekToBlock, bool bFlushToEnd)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->ReadIEEEBlock(TranslateBinaryType(type), bSeekToBlock ? VARIANT_TRUE : VARIANT_FALSE, bFlushToEnd ? VARIANT_TRUE : VARIANT_FALSE, pData);

	IncrementIOByteCount(*pData);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOFlushWrite(bool bSendEND)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->FlushWrite(bSendEND ? VARIANT_TRUE : VARIANT_FALSE);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOFlushRead()
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->FlushRead();

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvFormattedIOSetBufferSize(NtlBufferMask mask, long lSize)
{
	IO_METHOD_START();

	if (m_pFormatted == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pFormatted->SetBufferSize(TranslateBufferMask(mask), lSize);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterIn8(UINT16 space, UINT32 offset, UINT8* val)
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	BYTE temp;
	hr = m_pRegister->In8((short)space, (long)offset, &temp);
	if (SUCCEEDED(hr))
	{
		*val = temp;
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterOut8(UINT16 space, UINT32 offset, UINT8 val)
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pRegister->Out8((short)space, (long)offset, (BYTE)val);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterIn16(UINT16 space, UINT32 offset, UINT16* val)
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	short temp;
	hr = m_pRegister->In16((short)space, (long)offset, &temp);
	if (SUCCEEDED(hr))
	{
		*val = (UINT16)temp;
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterOut16(UINT16 space, UINT32 offset, UINT16 val)
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pRegister->Out16((short)space, (long)offset, (short)val);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterIn32(UINT16 space, UINT32 offset, UINT32* val)
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	long temp;
	hr = m_pRegister->In32((short)space, (long)offset, &temp);
	if (SUCCEEDED(hr))
	{
		*val = (UINT32)temp;
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterOut32(UINT16 space, UINT32 offset, UINT32 val)
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	hr = m_pRegister->Out32((short)space, (long)offset, (long)val);

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterMoveIn8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[])
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	SAFEARRAY* psa = NULL;
	hr = m_pRegister->MoveIn8((short)space, (long)offset, (long)length, &psa);
	if (SUCCEEDED(hr))
	{
		long actual = 0;
		hr = CSafeArray<BYTE>::Write(psa, buf, length, &actual);

		::SafeArrayDestroy(psa);
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterMoveOut8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[])
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	SAFEARRAY* psa = NULL;
	hr = CSafeArray<BYTE>::CreateFromArray(buf, length, VT_UI1, &psa);
	if (SUCCEEDED(hr))
	{
		hr = m_pRegister->MoveOut8((short)space, (long)offset, (long)length, &psa);

		::SafeArrayDestroy(psa);
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterMoveIn16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[])
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	SAFEARRAY* psa = NULL;
	hr = m_pRegister->MoveIn16((short)space, (long)offset, (long)length, &psa);
	if (SUCCEEDED(hr))
	{
		long actual = 0;
		hr = CSafeArray<short>::Write(psa, (short*)buf, length, &actual);

		::SafeArrayDestroy(psa);
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterMoveOut16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[])
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	SAFEARRAY* psa = NULL;
	hr = CSafeArray<short>::CreateFromArray((short*)buf, length, VT_I2, &psa);
	if (SUCCEEDED(hr))
	{
		hr = m_pRegister->MoveOut16((short)space, (long)offset, (long)length, &psa);

		::SafeArrayDestroy(psa);
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterMoveIn32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[])
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	SAFEARRAY* psa = NULL;
	hr = m_pRegister->MoveIn32((short)space, (long)offset, (long)length, &psa);
	if (SUCCEEDED(hr))
	{
		long actual = 0;
		hr = CSafeArray<long>::Write(psa, (long*)buf, length, &actual);

		::SafeArrayDestroy(psa);
	}

	return TranslateErrorCode(hr);
}

inline HRESULT CVisaComIOProvider::ioprvRegisterMoveOut32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[])
{
	IO_METHOD_START();

	if (m_pRegister == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;

	SAFEARRAY* psa = NULL;
	hr = CSafeArray<short>::CreateFromArray((short*)buf, length, VT_I4, &psa);
	if (SUCCEEDED(hr))
	{
		hr = m_pRegister->MoveOut32((short)space, (long)offset, (long)length, &psa);

		::SafeArrayDestroy(psa);
	}

	return TranslateErrorCode(hr);
}

inline BufferMask CVisaComIOProvider::TranslateBufferMask(NtlBufferMask mask)
{
	BufferMask visaMask = IO_IN_AND_OUT_BUFS;

	switch (mask)
	{
		case NTLIO_IN_BUF:			visaMask = IO_IN_BUF;			break;
		case NTLIO_OUT_BUF:			visaMask = IO_OUT_BUF;			break;
		case NTLIO_IN_AND_OUT_BUFS:	visaMask = IO_IN_AND_OUT_BUFS;	break;
	}

	return visaMask;
}

inline IEEEASCIIType CVisaComIOProvider::TranslateAsciiType(NtlAsciiType type)
{
	IEEEASCIIType visaType = ASCIIType_I2;

	switch (type)
	{
		case NtlAsciiType_I2:			visaType = ASCIIType_I2;	break;
		case NtlAsciiType_I4:			visaType = ASCIIType_I4;	break;
		case NtlAsciiType_R4:			visaType = ASCIIType_R4;	break;
		case NtlAsciiType_R8:			visaType = ASCIIType_R8;	break;
		case NtlAsciiType_BSTR:			visaType = ASCIIType_BSTR;	break;
		case NtlAsciiType_Any:			visaType = ASCIIType_Any;	break;
		case NtlAsciiType_UI1:			visaType = ASCIIType_UI1;	break;
	}

	return visaType;
}

inline IEEEBinaryType CVisaComIOProvider::TranslateBinaryType(NtlBinaryType type)
{
	IEEEBinaryType visaType = BinaryType_I2;

	switch (type)
	{
		case NtlBinaryType_I2:			visaType = BinaryType_I2;	break;
		case NtlBinaryType_I4:			visaType = BinaryType_I4;	break;
		case NtlBinaryType_R4:			visaType = BinaryType_R4;	break;
		case NtlBinaryType_R8:			visaType = BinaryType_R8;	break;
		case NtlBinaryType_UI1:			visaType = BinaryType_UI1;	break;
	}

	return visaType;
}

inline HRESULT CVisaComIOProvider::TranslateErrorCode(HRESULT hr)
{
	// Translate VISA-COM specific error codes into NTL error codes
	if (hr == E_VISA_TMO)
	{
		hr = E_NTL_IO_TIMEOUT;
	}

	return hr;
}

#endif // #endif __NTLIOPROVIDERVISACOM_INCLUDED
