/******************************************************************************
 *                                                                         
 *               Copyright 2004-2006 Agilent Technologies
 *               All rights reserved.
 *
 *****************************************************************************/
 
#include "stdafx.h"
#include "CoAgilent34951A.h"




/// <summary>
/// Sets the level for the specified function (CURRent or VOLTage) and closes
/// the output relay on the specified channel(s)
/// </summary>
/// <remarks>
/// This also changes the OperationMode to Level, which will stop a trace that was 
/// running on the same channel.
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.  
///	Select from s001, s002, s003, or s004
/// </param>
/// <param name="Function">
///	Function Type {Current|Voltage}.
/// </param>
/// <param name="Level">
///	Desired signal level in Amps or Volts DC, depending on the Function parameter.
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_ApplyLevel(BSTR ChannelList, Agilent34951AFunctionTypeEnum Function, double Level)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}

/// <summary>
/// Configures a previously defined trace to the specified settings and outputs
/// the trace.
/// </summary>
/// <remarks>
/// This function also halts any previously outputting trace or level, puts the
/// card in Trace OperationMode, sets the trigger source to immediate, and sets
/// up the clock to the internal source and at the period value required to accomplish
/// the specified frequency. An error occurs if the frequency is too large or too
/// small to be accomplished with the number of points in the waveform, otherwise,
/// it sets frequency to the value closest to the desired frequency.
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is
/// the channel number.  Select from s001, s002, s003, or s004.
/// </param>
/// <param name="TraceName">
///	A previously defined trace name consisting of up to 12 characters.
/// </param>
/// <param name="Function">
///	Function Type {Current|Voltage}.
/// </param>
/// <param name="Gain">
///	The gain for scaled trace outputs on the specified channels on the 34951A Isolated
/// DAC Module; used according to the equation: Scaled value = (Gain x Trace Data)
/// + Offset.  Legal values for Voltage traces: 0 to 16 Volts; for Current traces:
/// 0 to 0.020 mA.
/// </param>
/// <param name="Offset">
///	The offset for scaled trace outputs on the specified channels on the 34951A
/// Isolated DAC Module; used according to the equation: Scaled value = (Gain x
/// Trace Data) + Offset. Legal values for Voltage traces: -16 to 16 Volts; for
/// Current traces: -0.020 to 0.020 mA.
/// </param>
/// <param name="Frequency">
///	Desired frequency in Hz.
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_ApplyTrace(	BSTR ChannelList, 
																			BSTR TraceName, 
																			Agilent34951AFunctionTypeEnum Function, 
																			double Gain, 
																			double Offset, 
																			double Frequency)
{
	HRESULT hr = S_OK;
	CString sChannelList(ChannelList);
	/*
		ApplyTrace Sequence 
		SOUR:<CURR | VOLT>:LEV 0.0,(@<chan>)        // outputs a safe level; Replaces HALT
		SOUR:FUNC:TRACe <name>,(@<chan>)
		SOUR:MODE <CURR | VOLT>,(@<chan>)
		SOUR:FUNC:<CURR | VOLT>:OFFS 0,(@<chan>)   // needed due to a coupling issue
		SOUR:FUNC:<CURR | VOLT>:GAIN <gain>,(@<chan>)
		SOUR:FUNC:<CURR | VOLT>:OFFS <offset>,(@<chan>)
		SOUR:FUNC:TRAC:SIND 0,(@<chan>)
		SOUR:FUNC:CLOC:SOUR INT,(@<chan>)
		SOUR:FUNC:FREQ <freq>,(@<chan>)
		SOUR:FUNC:TRAC:NCYC INF,(@<chan>)
		SOUR:FUNC:TRIG:SOUR IMM,(@<chan>)
		OUTP:STAT ON,(@<chan>)                             // reversed order with ENAB
		SOUR:FUNC:ENAB ON,(@<chan>)               // moved to be after the OUTP:STAT ON
	*/
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:%s:LEV 0.0, (@%s)", EnumToString<Agilent34951AFunctionTypeEnum>(Function), LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRAC %s, (@%s)", LPCTSTR(COLE2T(TraceName)), LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:MODE %s, (@%s)", EnumToString<Agilent34951AFunctionTypeEnum>(Function), LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( 
		":SOUR:FUNC:%s:OFFS 0, (@%s); GAIN %.15g, (@%s); OFFS %.15g, (@%s);", 
		EnumToString<Agilent34951AFunctionTypeEnum>(Function), LPCTSTR(sChannelList),
		Gain, LPCTSTR(sChannelList), 
		Offset, LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRAC:SIND 0, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:CLOC:SOUR INT, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:FREQ %.15g, (@%s)", Frequency, LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRAC:NCYC INF, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRIG:SOUR IMM, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":OUTP:STAT ON, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:ENAB ON, (@%s)", LPCTSTR(sChannelList) ) );


	return hr;
}







/// <summary>
/// This routine does most of what ApplyTrace does, with a few notable exceptions
/// listed in the Remarks.
/// </summary>
/// <remarks>
/// This routine will halt a currently running trace and select the new trace specified.
/// The clock source and clock period are not modified (since there is no frequency
/// parameter). The intent is for the user to use this routine to set up a trace,
/// and then possibly modify some trigger (or other) settings before outputting
/// the trace.
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is
/// the channel number.  Select from s001, s002, s003, or s004.
/// </param>
/// <param name="Function">
///	Function Type {Current|Voltage}.
/// </param>
/// <param name="TraceName">
///	A previously-defined trace name consisting of up to 12 characters.
/// </param>
/// <param name="Gain">
///	The gain for scaled trace outputs on the specified channels on the 34951A Isolated
/// DAC Module; used according to the equation:	  Scaled value =  (Gain x Trace
/// Data) + Offset
/// </param>
/// <param name="Offset">
///	The offset for scaled trace outputs on the specified channels on the 34951A
/// Isolated DAC Module; used according to the equation:	  Scaled value =  (Gain
/// x Trace Data) + Offset
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_ConfigureTrace(BSTR ChannelList, Agilent34951AFunctionTypeEnum Function, BSTR TraceName, double Gain, double Offset)
{
	HRESULT hr = S_OK;
	CString sChannelList(ChannelList);
	/*
	ConfigureTrace Sequence
		-SOUR:FUNC:ENAB ON,(@<chan>)               // Delete this
		SOUR:<CURR | VOLT>:LEV 0.0,(@<chan>)        // outputs a safe level; Replaces HALT
		SOUR:FUNC:TRACe <name>,(@<chan>)
		-SOUR:FUNC:TRAC:NCYC INF,(@<chan>)    // Delete this, StartTrace sets this
		-SOUR:FUNC:TRAC:SIND 0,(@<chan>)    // Delete this, StartTrace sets this
		SOUR:FUNC:TRIG:SOUR IMM,(@<chan>)
		SOUR:FUNC:CLOC:SOUR INT,(@<chan>)
		SOUR:MODE <CURR | VOLT>,(@<chan>)
		SOUR:FUNC:<CURR | VOLT>:OFFS 0,(@<chan>)   // needed due to a coupling issue
		SOUR:FUNC:<CURR | VOLT>:GAIN <gain>,(@<chan>)
		SOUR:FUNC:<CURR | VOLT>:OFFS <offset>,(@<chan>)
		-SOUR:FUNC:STAT? (@<chan>)     // Delete this – not sure why it is here.
	*/
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:%s:LEV 0.0, (@%s);", EnumToString<Agilent34951AFunctionTypeEnum>(Function), LPCTSTR(sChannelList) ) );
	// tracename must be without quotes!  isntrument responds with 'trace does not exist' if trace aws not created first
	// with CreateStandard or other
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRAC %s, (@%s)", LPCTSTR(COLE2T(TraceName)), LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRIG:SOUR IMM, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:CLOC:SOUR INT, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:MODE %s, (@%s)", EnumToString<Agilent34951AFunctionTypeEnum>(Function), LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( 
		":SOUR:FUNC:%s:OFFS 0, (@%s); GAIN %.15g, (@%s); OFFS %.15g, (@%s);", 
		EnumToString<Agilent34951AFunctionTypeEnum>(Function), LPCTSTR(sChannelList),
		Gain, LPCTSTR(sChannelList), 
		Offset, LPCTSTR(sChannelList) ) );

	return hr;
}




/// <summary>
/// This method will set the starting index of the trace, set the number of cycles,
/// and start the trace.
/// </summary>
/// <remarks>
/// Note that the trace may be started but not yet
/// running, depending upon the trigger source settings (EXTernal for example). The
/// trace must have been previously selected and/or configured before calling
/// this method. This method will error if another trace is currently running on the
/// specified channel. 
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="ChannelList">
///	One or more channels in the form sccc. Select from s001, s002, s003, or s004.
/// </param>
/// <param name="NumCycles">
///	Number of trace cycles to be output from the specified channels on the 34951A Isolated DAC Module.
/// </param>
/// <param name="StartIndex">
///	Starting point (index) for trace outputs on the specified channels on the 34951A Isolated DAC Module.
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_StartTrace(BSTR ChannelList, long NumCycles, long StartIndex)
{
	HRESULT hr = S_OK;

	/*
	StartTrace Sequence
		-OUTP:STAT OFF,(@<chan>)     // Delete this
		SOUR:FUNC:TRAC:NCYC <cycles>,(@<chan>)
		SOUR:FUNC:TRAC:SIND <index>,(@<chan>)
		OUTP:STAT ON, (@<chan>)
		SOUR:FUNC:TRAC:ENAB ON, (@<chan>)
	*/
// no query for instrument status since Corrections.doc
	CString sChannelList(ChannelList);
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRAC:NCYC %d, (@%s)", NumCycles, LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":SOUR:FUNC:TRAC:SIND %d, (@%s)", StartIndex, LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( ":OUTP:STAT ON, (@%s)", LPCTSTR(sChannelList) ) );
	RETURN_IF_FAIL( InstrPrintf( "SOUR:FUNC:ENAB ON, (@%s)", LPCTSTR(sChannelList) ) );

	return hr;
}


/// <summary>
///	Disables or enables the trace output mode on the specified channels on the 34951A
/// Isolated DAC Module.
/// </summary>
/// <remarks>
///	Changing the operation mode to OFF while a trace is running will halt the\r\n
///  trace and place the channel into the mode where a single level will be output.
///  The user must either disable the output before sending this command, or else
/// set a safe level for the single level mode to avoid undesirable voltages or
/// currents from being inadvertently applied to the output.
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc. Select from s001, s002, s003, or s004.
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_get_OperationMode(BSTR ChannelList, VARIANT_BOOL* val)
{
	HRESULT hr = S_OK;

	hr = InstrQueryCommandBool(val);

	return hr;
}


/// <summary>
///	Disables or enables the trace output mode on the specified channels on the 34951A
/// Isolated DAC Module.
/// </summary>
/// <remarks>
///	Changing the operation mode to OFF while a trace is running will halt the\r\n
///  trace and place the channel into the mode where a single level will be output.
///  The user must either disable the output before sending this command, or else
/// set a safe level for the single level mode to avoid undesirable voltages or
/// currents from being inadvertently applied to the output.
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc. Select from s001, s002, s003, or s004.
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_put_OperationMode(BSTR ChannelList, VARIANT_BOOL val)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}



/// <summary>
///	Selects the voltage or current mode for the specified channels on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_get_FunctionType(BSTR ChannelList, Agilent34951AFunctionTypeEnum* Val)
{
	HRESULT hr = S_OK;

	hr = InstrQueryCommandEnum(Val);

	return hr;
}



/// <summary>
///	Selects the voltage or current mode for the specified channels on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_put_FunctionType(BSTR ChannelList, Agilent34951AFunctionTypeEnum Val)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}


/// <summary>
///	Sets or gets the number of trace cycles to be output from the specified channels
/// on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	Number of cycles -- may be 1 through 254, or 0 (continuous).  A zero value selects
/// an infinite number of cycles.
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is
/// the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_get_NumCycles(BSTR ChannelList, long* Val)
{
	HRESULT hr = S_OK;
	// :SOUR:FUNC:NCYC %d, (@%s);  but reference CHM says :SOUR:FUNC:TRAC:NCYC and it passes???
	// make sure with Rob !!!
	hr = InstrQueryCommand(Val);

	return hr;
}


/// <summary>
///	Sets or gets the number of trace cycles to be output from the specified channels
/// on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	Number of cycles -- may be 1 through 254, or 0 (continuous).  A zero value selects
/// an infinite number of cycles.
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is
/// the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_put_NumCycles(BSTR ChannelList, long Val)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}


/// <summary>
///	Setst or gets the starting point (index) for trace outputs on the specified channels on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelLast">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_get_StartIndex(BSTR ChannelLast, long* Val)
{
	HRESULT hr = S_OK;

	hr = InstrQueryCommand(Val);

	return hr;
}


/// <summary>
///	Setst or gets the starting point (index) for trace outputs on the specified channels on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelLast">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_put_StartIndex(BSTR ChannelLast, long Val)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}


/// <summary>
///	A previously-defined trace name consisting of up to 12 characters. 
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_get_TraceName(BSTR ChannelList, BSTR* Val)
{
	HRESULT hr = S_OK;

	hr = InstrQueryCommand(Val);

	return hr;
}


/// <summary>
///	A previously-defined trace name consisting of up to 12 characters. 
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_put_TraceName(BSTR ChannelList, BSTR Val)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}




/// <summary>
///	Sets or gets the frequency of the selected trace on the specified channels on the 34951A Isolated DAC Module
/// channels on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	The firmware looks at the number of points in the trace, and modifies the clock period per point to obtain the desired 
///	frequency for the trace.  An error is generated if the specified frequency is outside the possible range of values that could 
///	be obtained on the trace.  If the specified frequency is inside the possible range, but can not be exactly obtained, the nearest 
///	value will be programmed, and when the Frequency property is queried, the actual value used will be reported
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is
/// the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_get_Frequency(BSTR ChannelList, double* Val)
{
	HRESULT hr = S_OK;

	hr = InstrQueryCommand(Val);

	return hr;
}




/// <summary>
///	Sets or gets the internal clock frequency for trace outputs on the specified
/// channels on the 34951A Isolated DAC Module.
/// </summary>
/// <remarks>
///	
/// </remarks>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is
/// the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_put_Frequency(BSTR ChannelList, double val)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}

/// <summary>
///	Retrieves a pointer to the Current interface.
/// </summary>
/// <remarks>
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </remarks>
HRESULT Agilent34951A::IAgilent34951ASource_get_Current(IAgilent34951ACurrent** Val)
{
	HRESULT hr = S_OK;

	hr = InternalQueryInterface(this, _GetEntries(), __uuidof(*Val), reinterpret_cast<void**>(Val));

	return hr;
}

/// <summary>
///	Retrieves a pointer to the Voltage interface.
/// </summary>
/// <remarks>
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </remarks>
HRESULT Agilent34951A::IAgilent34951ASource_get_Voltage(IAgilent34951AVoltage** Val)
{
	HRESULT hr = S_OK;

	hr = InternalQueryInterface(this, _GetEntries(), __uuidof(*Val), reinterpret_cast<void**>(Val));

	return hr;
}



/// <summary>
/// Stops trace outputs from the specified channels on the 34951A Isolated DAC Module. 
/// The trace will stop immediately and the location of the trace data will be set back 
/// to the specified by StartIndex property starting index.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="ChannelList">
///	One or more channels in the form sccc, where s is the slot number and ccc is the channel number.   Select from s001, s002, s003, or s004
/// </param>
HRESULT Agilent34951A::IAgilent34951ASource_HaltTrace(BSTR ChannelList)
{
	HRESULT hr = S_OK;

	hr = InstrPrintCommand();

	return hr;
}
