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

#include "stdafx.h"
#include "CoAgilent34980A.h"


HRESULT Agilent34980A::FinalConstruct()
{
	// Use this function to perform any driver-specific initialization just AFTER object construction.
	HRESULT hr = S_OK;

    return hr;
}

void Agilent34980A::FinalRelease()
{
	// Use this function to perform any driver-specific clean-up just BEFORE object destruction.
}


HRESULT Agilent34980A::FinalInitialize(BSTR bstrResourceDescriptor, VARIANT_BOOL bIdQuery, VARIANT_BOOL bReset, BSTR bstrOptionString)
{
   HRESULT hr = S_OK;
   
   if (!GetSimulate())
   {
		hr = SwitchUtils::CComDriverSRQ<Agilent34980A>::Initialize();
   }

   return hr;
}

HRESULT Agilent34980A::FinalClose()
{
	HRESULT hr = S_OK;

	hr = SwitchUtils::CComDriverSRQ<Agilent34980A>::Close();

    return hr;
}
HRESULT Agilent34980A::_GetInstrFunction( CString &s, BSTR *channel/*=NULL*/ )
{
	HRESULT hr;
	if(channel)
		hr = InstrQueryf( "FUNC? (@%s)", s, DEFAULT_STRING_LENGTH , LPCTSTR(COLE2T(*channel)) );
	else
		hr = InstrQuery( "FUNC?", s, DEFAULT_STRING_LENGTH );
	s.Remove( '\"' );
	return hr;
}

CString Agilent34980A::CorrectChannelList( BSTR ChannelList, bool bSetter/*=true*/ )
{
	CString sCommand = PopInstrCommand();
	int nStart = sCommand.Find( '@' );
	int nEnd = sCommand.Find( ')' );
	if( ::SysStringLen( ChannelList )==0 )
	{ // channel list is empty, remove the '(@)' substring
		if( -1 != sCommand. ReverseFind( '(' ) )
		{
			sCommand.Delete( sCommand. ReverseFind( '(' ), 3 );
		}
	}
	// for setter or method multiple channels are allowed and IVI-C clients use 
	// dash to mark range; convert it to colon, only if list is not empty
	else 
	{
		if( -1 != nStart && bSetter )
		{
			int nPos = sCommand.Find( '-', nStart );
			while( nPos>nStart && nPos<nEnd )
			{
				sCommand.Delete( nPos );
				sCommand.Insert( nPos, ':' );
				nPos = sCommand.Find( '-', nStart );
			}
		}
	}
	PushInstrCommand( sCommand );
	return sCommand.Mid( nStart+1, nEnd-nStart-1 );
}
HRESULT Agilent34980A::GetDynamicRepCapNames(const CString& repCapClassName, CAtlArray<CString>& rgRepCapNames)
{
	m_bPlayWithDummy = false;
	typedef struct tagSimulationInfo
	{
		bool bUseDmmBus;
		SwitchUtils::ModuleType ModuleTable[MAX_SLOT_NUMBER];
	}SimulationInfo;
	SimulationInfo SimInfo;
	CString sSimulationFileName = getenv( "TEMP" );
	sSimulationFileName += "\\Agilent34980.sim";

	int slot = 0, bank=0, channel=0, matrix=0, row=0, col=0;
	CString sChannel;
	m_bPlayWithDummy = true;
	if( repCapClassName!="Agilent34980AChannel" )
		return ReportError( E_AGILENT34980A_MODEL_NOT_SUPPORTED );
	bool bSimulate = GetSimulate();
	
	if( bSimulate )
	{ // we're in simulation mode, read the file and set modules as they have been
		CString sDMM = GetDriverSetupOptionValue( "DMM" );
		if( sDMM=="" )
			return ReportErrorEx( IDS_E_IVI_MISSING_OPTION_VALUE, "The DMM option (DMM=true or DMM=false) is required in simulation mode but missing." );
		sDMM.MakeLower();
		m_bUseDmmBus = sDMM=="true" ? false : true;
		CString sSlot = "slot",sCard;
		bool bOption = false;
		for(  char ch='1', slot=1; ch<'9'; ch++, slot++ )
		{
			sCard = GetDriverSetupOptionValue( sSlot+ch );
			if( sCard=="" ) continue;
			else bOption = true; // there is at least 1 switch card 
			sCard.MakeUpper();
			SwitchUtils::ModuleType type = SwitchUtils::GetModuleType( sCard );
			if( type==SwitchUtils::other )
			{
				CString sMsg;
				sMsg.Format( (LPCTSTR)sCard, "Invalid/unrecognized card type \"%s=%s\"specified.", (sSlot+ch), sCard );
				return ReportErrorEx( IDS_E_IVI_BAD_OPTION_VALUE, (LPCTSTR)sMsg );
			}
			SwitchUtils::SetModuleGetType( slot, type );
		}
		if( ! bOption )
			return ReportErrorEx( IDS_E_IVI_MISSING_OPTION_VALUE, "At least one switch card must be specified in simulation mode" );
		SwitchUtils::SetModuleGetType( 0, SwitchUtils::ModuleTypeDmm ); 
	}
	else
	{
		long nRes = -1;
		HRESULT hr = InstrQueryf( ":INST:DMM:INST?", &nRes );
		m_bUseDmmBus = nRes ? false : true;
		SimInfo.bUseDmmBus = m_bUseDmmBus;
		if( !m_bUseDmmBus )
		{ // internal DMM is present, check if is disconnected
			hr = InstrQueryf( ":INST:DMM:CONN?", &nRes );
			m_bUseDmmBus = nRes ? false : true;
		}
		// fill in info strucures
		// set the Dmm info - don't query for it
		SimInfo.ModuleTable[0] = SwitchUtils::SetModuleGetType( 0, SwitchUtils::ModuleTypeDmm ); 

		for( slot=1; slot<MAX_SLOT_NUMBER; slot++ )
		{
			CString sResp;
			hr = InstrQueryf( "SYST:CTYP? %d", sResp, 1024, slot );
			if( FAILED(hr) ) continue;

			int number = sResp.FindOneOf( "0123456789" );
			int count = sResp.Find( ',', number );
			sResp = sResp.Mid( number, count-number );

			SwitchUtils::ModuleType type = SwitchUtils::SetModuleGetType( slot, sResp );
			SimInfo.ModuleTable[slot] = type;
			if( SwitchUtils::other == type || 
				SwitchUtils::empty == type	 ) 
				continue;
		}
	}
	if( m_bPlayWithDummy )
	{
		m_bUseDmmBus = true;
	}
	for( char c='1'; c<='4'; c++ )
	{
		sChannel = "abus";
		if( m_bPlayWithDummy )
		{
			rgRepCapNames.Add( sChannel+c ); // remove
			//GetRoot()->m_listConfigChannels.AddTail( SwitchUtils::Channel( sChannel+c, CString("000")+c ) );
		}
		else
		{
			GetRoot()->m_listConstConfigChannels.AddTail( SwitchUtils::Channel( sChannel+c, CString("000")+c ) );
		}
	}
	if( m_bPlayWithDummy || m_bUseDmmBus )
	{ // these 2 represent the capability of MUX & matrix channels to connect to the DMM - only when it is present  & connected
		rgRepCapNames.Add( "DmmMeasure" );
		rgRepCapNames.Add( "DmmSense" );
	}
	for( slot=1; slot<MAX_SLOT_NUMBER; slot++ )
	{
		SwitchUtils::PModuleInfo pInfo = SwitchUtils::GetModuleInfo( slot );
		SwitchUtils::GenericType genType = SwitchUtils::GetGenericType( slot );
		if( pInfo==NULL ) 
			continue; // not a switch at this slot
		else if( genType==SwitchUtils::GenericTypeMatrix)
		{// matrices
			for( row=pInfo->config.Min1; row<=pInfo->config.Max1; row++ )
			{ // add config channels for the matrices; they have 4 bus ports
				 sChannel.Format( "%d92%d", slot, row );
				 m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );
			}
			for( matrix=1; matrix<= (pInfo->bSingleWire? 4 : 2); matrix++ ) 
			{// this cycle is just in case this is 34933 in 1 wire mode
				if( pInfo->bSingleWire )
				{
					for( row=pInfo->config.Min1; row<=pInfo->config.Max1; row++ )
					{
						sChannel.Format("s%dm%dr%d", slot, matrix, row );
						rgRepCapNames.Add( sChannel );
					}
				}
				else
				{
					int rowMin = matrix==1 ? pInfo->config.Min1 : pInfo->config.Max1/2+1;
					int rowMax = matrix==1 ? pInfo->config.Max1/2 : pInfo->config.Max1;
					for( row=rowMin; row<=rowMax; row++ )
					{
						sChannel.Format("s%dm%dr%d", slot, matrix, row );
						rgRepCapNames.Add( sChannel );
					}
				}
				for( int col=pInfo->config.Min2; col<=pInfo->config.Max2; col++ )
				{
					sChannel.Format("s%dm%dc%d", slot, matrix, col );
					rgRepCapNames.Add( sChannel );
				}
			}
		}
		else if( genType==SwitchUtils::GenericTypeRFmux )
		{ // RF muxes have more than 2 banks represented by Min1 (channel). Also, they have no config channels
			for( bank=pInfo->config.Min1; bank<=pInfo->config.Max1; bank++ )
			{
				sChannel.Format("%d%d00COM", slot, bank );
				rgRepCapNames.Add( sChannel );
				for( channel=pInfo->config.Min2; channel<=pInfo->config.Max2; channel++ )
				{
					sChannel.Format("%d%d0%d", slot, bank, channel );
					rgRepCapNames.Add( sChannel );
				}
			}
		}
		else if( genType==SwitchUtils::GenericTypeMWswitch )
		{ // MW switches, the have 2 or 3 banks each with 2 channels. No config channels
			for( bank=pInfo->config.Min1; bank<=pInfo->config.Max1; bank++ )
			{
				sChannel.Format("%d%d00COM", slot, bank );
				rgRepCapNames.Add( sChannel );
				sChannel.Format("%d%d01", slot, bank );
				rgRepCapNames.Add( sChannel );
				sChannel.Format("%d%d02", slot, bank );
				rgRepCapNames.Add( sChannel );
			}
		}
		else if( genType==SwitchUtils::GenericTypeMux  )
		{// this code applies to MUX and GP switch
			if( pInfo->type==SwitchUtils::ModuleType34921 )
			{ // 34921 has special bus port for high current channels
				sChannel.Format( "%d931", slot );
				m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );
			}
			// all 92x series mux have these bus ports (relays)
			for( row=1; row<=4; row++ )
			{
				sChannel.Format( "%d91%d", slot, row );
				m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );

				sChannel.Format( "%d92%d", slot, row );
				m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );
				if( pInfo->type==SwitchUtils::ModuleType34921 )
				{ // exclude the high current from paths -
					sChannel.Format( "%d04%d", slot, row );
					m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );
				}
			}
			// the COM channels in a mux
			sChannel.Format( "slot%dcom1", slot );
			if( m_bPlayWithDummy )
			{
				rgRepCapNames.Add( sChannel );
				//m_listConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );
			}
			else
				m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );

			sChannel.Format( "slot%dcom2", slot );
			if( m_bPlayWithDummy )
			{
				rgRepCapNames.Add( sChannel );
				//m_listConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );
			}
			else
				m_listConstConfigChannels.AddTail( SwitchUtils::Channel( TranslatePhysicalName(sChannel), sChannel ) );

			for( channel = pInfo->config.Min1; channel<=pInfo->config.Max2; channel++ )
			{
				if( channel>9 )	sChannel.Format("%d0%d", slot, channel );
				else					sChannel.Format("%d00%d", slot, channel );
				rgRepCapNames.Add( sChannel );
			}
		}
		else if( genType==SwitchUtils::GenericTypeGPswitch )
		{
			for( channel = pInfo->config.Min1; channel<=pInfo->config.Max2; channel++ )
			{
				if( channel>9 )	sChannel.Format("%d0%d", slot, channel );
				else					sChannel.Format("%d00%d", slot, channel );
				rgRepCapNames.Add( sChannel+"NO" );
				rgRepCapNames.Add( sChannel+"COM" );
				if( pInfo->type==SwitchUtils::ModuleType34937 && channel<29 )
				{
					rgRepCapNames.Add( sChannel+"NC" ); // 34937 only - first 28 GPs are Form C with additional NC
				}
			}
		}
		else ATLASSERT( 0 );
	}
	return S_OK;
}