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

/// <summary>
/// Wait until all the signals flowing through the switch have settled.  If the
/// signals do not settle within MaxTime, the method returns a Max Time Exceeded
/// error.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="MaxTimeMilliseconds">
///	Maximum time (in milliseconds).
/// </param>
HRESULT Agilent34980A::IIviSwtchPath_WaitForDebounce(long MaxTimeMilliseconds)
{
	if( GetSimulate()==true )
		return S_OK;
	HRESULT hr = S_OK;
	short Val;
	hr = InstrQueryf( "ROUTe:MODule:WAIT? ALL", &Val, MaxTimeMilliseconds );

	return hr;
}

/// <summary>
/// Creates a path given a PathList of comma separated channel pairs.  The end channels
/// are the first and last entries in the PathList.  For intermediate channels,
/// the second channel of one pair must be the same as the first channel of the
/// following pair.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="PathList">
///	List of comma separated channel pairs indicating the path.
/// </param>
HRESULT Agilent34980A::IIviSwtchPath_SetPath(BSTR PathList)
{
	HRESULT hr = S_OK;

	hr = _SetPath( PathList );
	if( SUCCEEDED(hr) ) 
	{
		if( m_bSendCommand && !m_cacheLastPath.sChannelListSCPI.IsEmpty() )
		{
			CString sCmd = "ROUT:CLOS";
			sCmd += m_cacheLastPath.sChannelListSCPI;
			if( GetSimulate()==false )
				hr = InstrPrintf( sCmd );
		}
		_PushPath( m_cacheLastPath );
		m_cacheLastPath.Reset();
		return hr;
	}
	switch( hr )
	{
	case E_IVISWTCH_EMPTY_SWITCH_PATH:				return ReportError( IDS_E_IVISWTCH_EMPTY_SWITCH_PATH );
	case E_IVISWTCH_INVALID_SWITCH_PATH:			return ReportError( IDS_E_IVISWTCH_INVALID_SWITCH_PATH );
	case E_IVISWTCH_CHANNEL_DUPLICATED_IN_LEG:	return ReportError( IDS_E_IVISWTCH_CHANNEL_DUPLICATED_IN_LEG );
	case E_IVISWTCH_CHANNEL_DUPLICATED_IN_PATH:	return ReportError( IDS_E_IVISWTCH_CHANNEL_DUPLICATED_IN_PATH );
	case E_IVISWTCH_DISCONTINUOUS_PATH:				return ReportError( IDS_E_IVISWTCH_DISCONTINUOUS_PATH );
	case E_IVISWTCH_LEG_MISSING_FIRST_CHANNEL:	return ReportError( IDS_E_IVISWTCH_LEG_MISSING_FIRST_CHANNEL );
	case E_IVISWTCH_LEG_MISSING_SECOND_CHANNEL:	return ReportError( IDS_E_IVISWTCH_LEG_MISSING_SECOND_CHANNEL );
	case E_IVISWTCH_ATTEMPT_TO_CONNECT_SOURCES:	return ReportError( IDS_E_IVISWTCH_ATTEMPT_TO_CONNECT_SOURCES );
	case E_IVISWTCH_EXPLICIT_CONNECTION_EXISTS:	return ReportError( IDS_E_IVISWTCH_EXPLICIT_CONNECTION_EXISTS );
	case E_IVISWTCH_IS_CONFIGURATION_CHANNEL:		return ReportError( IDS_E_IVISWTCH_IS_CONFIGURATION_CHANNEL );
	case E_IVISWTCH_CANNOT_CONNECT_DIRECTLY:		return ReportError( IDS_E_IVISWTCH_CANNOT_CONNECT_DIRECTLY );
	case E_IVISWTCH_NOT_A_CONFIGURATION_CHANNEL: return ReportError( IDS_E_IVISWTCH_NOT_A_CONFIGURATION_CHANNEL );
	case E_IVISWTCH_RSRC_IN_USE:						return ReportError( IDS_E_IVISWTCH_RSRC_IN_USE );
	//case : return ReportError( IDS_ );
	default : return ReportError( E_IVISWTCH_INVALID_SWITCH_PATH );
	}
	return hr;
}

/// <summary>
/// Returns the list of comma separated channel pairs that have been connected in
/// order to create the path between the specified channels.  The only valid paths
/// that can be returned are ones that have been explicitly set via Connect and
/// SetPath methods.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	A user-allocated (for IVI-C) or driver-allocated (for IVI-COM) buffer into which
/// the driver stores the list of configuration channels used to create a path between
/// the two channels.The caller may pass VI_NULL for this parameter if the PathListBufferSize
/// parameter is 0.
/// </returns>
/// <param name="Channel1">
///	A string indicating one of the channels of the path.
/// </param>
/// <param name="Channel2">
///	A string indicating one of the channels of the path.
/// </param>
HRESULT Agilent34980A::IIviSwtchPath_GetPath(BSTR Channel1, BSTR Channel2, BSTR* Val)
{
	HRESULT hr = S_OK;

	SwitchUtils::SwitchPath path;

	if( ! _GetPath( Channel1, Channel2, path ) )
		return ReportError( IDS_E_IVISWTCH_NO_SUCH_PATH );

	*Val = path.sPath.AllocSysString();

	return S_OK;
}

/// <summary>
/// Disconnect all paths created since Initialize or Reset have been called.  If
/// any paths remain, this method returns a Path Remains warning.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	
/// </returns>
HRESULT Agilent34980A::IIviSwtchPath_DisconnectAll()
{
	HRESULT hr = S_OK;

	CAtlList<SwitchUtils::Channel> listChannelsToOpen;
	_DisconnectAll( 0, VARIANT_TRUE, listChannelsToOpen );
	if( GetSimulate()==false )
		hr = InstrPrintf( "ROUT:OPEN:ALL ALL" );
	
	return hr;
}

/// <summary>
/// Destroys the path between the two channels.  The order of the two channels need
/// not be the same as the connect operation.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="Channel1">
///	A string indicating one of the channels of the path.
/// </param>
/// <param name="Channel2">
///	A string indicating one of the channels of the path.
/// </param>
HRESULT Agilent34980A::IIviSwtchPath_Disconnect(BSTR Channel1, BSTR Channel2)
{
	HRESULT hr = S_OK;
	SwitchUtils::SwitchPath path;

	if( !_GetPath( Channel1, Channel2, path ) )
		return ReportError( IDS_E_IVISWTCH_NO_SUCH_PATH );

	if( !path.sChannelListSCPI.IsEmpty() )
	{
		CString sCmd = "ROUT:OPEN";
		sCmd += path.sChannelListSCPI;
		if( GetSimulate()==false )
			hr = InstrPrintf( sCmd );
	}
	if( SUCCEEDED(hr) )
		_PopPath( path.listChannels.GetHead(), path.listChannels.GetTail() );

	return hr;
}

/// <summary>
/// Creates a path between the two channels.  If the path already exists, the operation
/// does not count the number of calls.  All paths are assumed to be bi-directional.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	
/// </returns>
/// <param name="Channel1">
///	A string indicating one of the channels of the path.
/// </param>
/// <param name="Channel2">
///	A string indicating one of the channels of the path.
/// </param>
HRESULT Agilent34980A::IIviSwtchPath_Connect(BSTR Channel1, BSTR Channel2)
 {
	HRESULT hr = S_OK;

	hr = _CanConnect( Channel1, Channel2 );
	if( FAILED(hr) )
	{
		switch( hr )
		{
		case E_IVISWTCH_EXPLICIT_CONNECTION_EXISTS :		return ReportError( IDS_E_IVISWTCH_EXPLICIT_CONNECTION_EXISTS );
		case E_IVISWTCH_IS_CONFIGURATION_CHANNEL:			return ReportError( IDS_E_IVISWTCH_IS_CONFIGURATION_CHANNEL);
		case E_IVISWTCH_ATTEMPT_TO_CONNECT_SOURCES:		return ReportError( IDS_E_IVISWTCH_ATTEMPT_TO_CONNECT_SOURCES);
		case E_IVISWTCH_RSRC_IN_USE:							return ReportError( IDS_E_IVISWTCH_RSRC_IN_USE );
		default :													return ReportError( IDS_E_IVISWTCH_PATH_NOT_FOUND);
		}
	}
	if( m_bSendCommand && !m_cacheLastPath.sChannelListSCPI.IsEmpty() )
	{
		CString sCmd("ROUT:CLOS ");
		sCmd += m_cacheLastPath.sChannelListSCPI;
		if( GetSimulate()==false )
			hr = InstrPrintf( sCmd );
	}
	if( SUCCEEDED(hr) ) 
	{ 
		_PushPath( m_cacheLastPath );
		m_cacheLastPath.Reset();
	}

	return hr;
}

/// <summary>
/// Without actually creating the path, reports whether the switch module can create
/// a given path.  This method takes existing paths into account.
/// </summary>
/// <remarks>
/// 
/// </remarks>
/// <returns>
///	Indicates whether a path is valid and/or possible. See below for definitions.
/// </returns>
/// <param name="Channel1">
///	A string indicating one of the channels of the path.
/// </param>
/// <param name="Channel2">
///	A string indicating one of the channels of the path.
/// </param>
HRESULT Agilent34980A::IIviSwtchPath_CanConnect(BSTR Channel1, BSTR Channel2, IviSwtchPathCapabilityEnum* Val)
{
	HRESULT hr = S_OK;

	hr = _CanConnect( Channel1, Channel2 ); 

 	switch( hr )
	{
	case S_OK:													return *Val = IviSwtchPathAvailable, S_OK; // success
	case E_IVISWTCH_EXPLICIT_CONNECTION_EXISTS :		return *Val = IviSwtchPathExists, S_OK;
	case E_IVISWTCH_IS_CONFIGURATION_CHANNEL:			return *Val = IviSwtchPathChannelNotAvailable, S_OK;
	case E_IVISWTCH_ATTEMPT_TO_CONNECT_SOURCES:		return *Val = IviSwtchPathSourceConflict, S_OK;
	case E_IVISWTCH_RSRC_IN_USE:							return *Val = IviSwtchPathRsrcInUse, S_OK;
	default :													return *Val = IviSwtchPathUnsupported, S_OK;
	}
}

/// <summary>
///	If True, the switch module has settled from previous switching commands and
/// completed debounce.  This indicates that the signal going through the switch
/// module is valid, assuming that the switches in the path have the correct characteristics.
/// </summary>
/// <remarks>
///	
/// </remarks>
HRESULT Agilent34980A::IIviSwtchPath_get_IsDebounced(VARIANT_BOOL* Val) 
{ 
     HRESULT hr = S_OK; 
	  if( !Val )
		  return E_POINTER;
 
	  *Val = VARIANT_TRUE;
     short val; 
	  if( GetSimulate()==false )
	  {
		  hr = InstrQueryf( "ROUTe:MODule:BUSY? ALL", &val ); 
		  *Val = val==0 ? VARIANT_TRUE : VARIANT_FALSE; 
	  }
 
     return hr; 
}


