/******************************************************************************
 *                                                                         
 *               Copyright 2004-2006 Agilent Technologies
 *               All rights reserved.
 *
 *****************************************************************************/

#include "stdafx.h"

#include "ag34980a.h"
#include "ntlvisatypeconversion.h"
#include "ntlivicdriver.h"
#include "CoAgilent34980A.h"

// Add user-defined IVI-C driver functions and attributes here.  
// These will automatically be added to the DLL export list as well as
// to the .fp and .sub files generated by Nimbus.


// We must manually implement the following IVI-C only function.
IMPLEMENT_EXPORT()
ViStatus _VI_FUNC  ag34980a_IsDebounced ( ViSession Vi, ViBoolean* IsDebounced )
{
	IVIC_TRACE(_T("ag34980a_IsDebounced\n"));

	ViStatus status = ag34980a_GetAttributeViBoolean(Vi, "", AG34980A_ATTR_IS_DEBOUNCED, IsDebounced);

	return status;
}

//////////////////

/// <summary>
/// This function provides direct write access to the underlying I/O interface.
/// </summary>
/// <returns>
///	
/// </returns>
ADD_FUNCTION_EXPORT("\System\System Write\SystemWrite")
ViStatus _VI_FUNC  ag34980a_SystemWrite( ViSession Vi, ViConstString CommandString )
{
	ViStatus status = VI_SUCCESS;

	IVIC_TRACE(_T("ag34980a_SystemWrite\n"));

	IUnknown* pDriver = NULL;
	status = GetDriver(Vi, &pDriver);
	if (status == VI_SUCCESS)
	{
		HRESULT hr;

		IAgilent34980ASystem * pSystem = NULL;
		hr = pDriver->QueryInterface(&pSystem);
		status = TranslateHRESULT(Vi, hr);
		ATLASSERT(SUCCEEDED(hr));
		if (SUCCEEDED(hr))
		{
			IFormattedIO488* pIO = NULL;
			hr = pSystem->get_IO( &pIO );
			if (SUCCEEDED(hr))
			{
				IMessage* pMsg= NULL;
				hr = pIO->get_IO( &pMsg );
				if (SUCCEEDED(hr))
				{
					CBSTR command(CommandString);
					long count = 0;
					hr = pMsg->WriteString( command.GetVal(), &count );
					status = TranslateHRESULT(Vi, hr);
					pMsg->Release();
				}
				pIO->Release();
			}
			status = TranslateHRESULT(Vi, hr);
			pSystem->Release();
		}
		pDriver->Release();
	}
	return status;
}

ViStatus _VI_FUNC  _Reader( ViSession Vi, ViConstString ChannelList, ViInt32 DataBufferSize, ViChar Data[], ViInt32* DataActualSize, bool bRead )
{
	ViStatus status = VI_SUCCESS;
	*DataActualSize = 0;
 
	IUnknown* pDriver = NULL;
	status = GetDriver(Vi, &pDriver);
	if(status != VI_SUCCESS)
	{
		return status;
	}
	HRESULT hr;

	IAgilent34980AMeasurement *pMeasurement = NULL;
	hr = pDriver->QueryInterface(&pMeasurement);
	status = TranslateHRESULT(Vi, hr);
	ATLASSERT(SUCCEEDED(hr));
	if (SUCCEEDED(hr))
	{
		SAFEARRAY *psa;
		long count = 0;
		if( SUCCEEDED(hr)) 
		{
			CBSTR _ChannelList(ChannelList);
			if( bRead )
				hr = pMeasurement->Read( _ChannelList.GetVal(), &psa );
			else
				hr = pMeasurement->Fetch( &psa );
			if( SUCCEEDED(hr)) 
			{
				if( SUCCEEDED(hr)) 
				{
					count = psa->rgsabound[0].cElements;
					BSTR *bsData = (BSTR*)psa->pvData;
					int nCurrSize = 1+SysStringLen( *bsData ); // count the newline char at end
					try
					{ // we'll be touching pointers here
						for( int i=0; i<count && (*DataActualSize+nCurrSize < DataBufferSize); i++ )
						{
								*DataActualSize += sprintf( Data+*DataActualSize, "%s\n", (LPCTSTR)CString(*bsData) );
								if( i<count-1 ) // the last round bsData will point to no mans land
									nCurrSize = 1+SysStringLen( *bsData++ ); // count the newline char at end
						}
					}
					catch(...)
					{
						status = AG34980A_ERROR_UNEXPECTED_RESPONSE;
					}
				}
			}
			::SafeArrayDestroy(psa);
		}
		pMeasurement->Release();
	}
	pDriver->Release();
	status = TranslateHRESULT( Vi, hr );
	return status;
}

/// <summary>
/// Transfers readings from volatile memory to the instrument's output buffer where
/// you can read them into your computer.
/// </summary>
/// <remarks>
/// The readings are not erased from memory when you read them. You can use the
/// method multiple times to retrieve the same data in reading memory.
/// </remarks>
/// <returns>
///	
/// </returns>
ADD_FUNCTION_EXPORT("\Measurement\Low-Level Measurement\Fetch\Fetch")
ViStatus _VI_FUNC  ag34980a_Fetch( ViSession Vi, ViInt32 DataBufferSize, ViChar Data[], ViInt32* DataActualSize )
{
	IVIC_TRACE(_T("ag34980a_Fetch\n"));
	ViConstString ChannelList("");
	return _Reader( Vi, ChannelList, DataBufferSize, Data, DataActualSize, false );
}

/// <summary>
/// Changes the instrument's triggering system from the idle state to the wait-for-trigger.
/// </summary>
/// <remarks>
/// Measurements will begin when the specified trigger conditions are satisfied. 
/// Readings are then sent immediately to volatile memory and the instrument output 
/// buffer. If you supply an empty ChannelList, measurements are taken on the DMM 
/// only (no channels are scanned) or, if a scan list is currently defined, the READ with empty channel list 
/// performs a scan of the channels in the scan list.
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="ChannelList">
///	One or more channels in the form sccc.
/// </param>
ADD_FUNCTION_EXPORT("\Measurement\Low-Level Measurement\Read\Read")
ViStatus _VI_FUNC  ag34980a_Read( ViSession Vi, ViConstString ChannelList, ViInt32 DataBufferSize, ViChar Data[], ViInt32* DataActualSize )
{
	IVIC_TRACE(_T("ag34980a_Read\n"));
	return _Reader( Vi, ChannelList, DataBufferSize, Data, DataActualSize, true );
}

/// <summary>
/// This function provides direct read access to the underlying I/O interface.
/// </summary>
/// <returns>
///	
/// </returns>
ADD_FUNCTION_EXPORT("\System\System Read\SystemRead")
ViStatus _VI_FUNC  ag34980a_SystemRead( ViSession Vi, ViInt32 Size, ViChar Value [], ViInt32* ActualSize )
{
	ViStatus status = VI_SUCCESS;
	*ActualSize = 0;

	IVIC_TRACE(_T("ag34980a_SystemWrite\n"));
 
	IUnknown* pDriver = NULL;
	status = GetDriver(Vi, &pDriver);
	if (status == VI_SUCCESS)
	{
		HRESULT hr;

		IAgilent34980ASystem * pSystem = NULL;
		hr = pDriver->QueryInterface(&pSystem);
		status = TranslateHRESULT(Vi, hr);
		ATLASSERT(SUCCEEDED(hr));
		if (SUCCEEDED(hr))
		{
			IFormattedIO488* pIO = NULL;
			hr = pSystem->get_IO( &pIO );
			status = TranslateHRESULT(Vi, hr);
			if (SUCCEEDED(hr))
			{
				IMessage* pMsg= NULL;
				hr = pIO->get_IO( &pMsg );
				status = TranslateHRESULT(Vi, hr);
				if (SUCCEEDED(hr))
				{
					CBSTR _val;
					hr = pMsg->ReadString( Size, _val.GetPtr() );
					status = TranslateHRESULT(Vi, hr);
					if (SUCCEEDED(hr))
					{
						status = _val.ToViDataType( Value, Size);
						*ActualSize = ::SysStringLen( _val.GetVal() );
					}
					pMsg->Release();
				}
				pIO->Release();
			}
			pSystem->Release();
		}
	
		pDriver->Release();
	}
	return status;
}