// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// This file contains the implementation of the Simulator TSY Data Call functionality.  
// The Call classes process the Call-based requests made by ETel clients 
// and passed down to the TSY by the ETel Server.
// 
//

/**
 @file
*/

#include <testconfigfileparser.h>
#include "CSimDataCall.h"
#include "CSimPhone.h"
#include "Simlog.h"

CSimDataCall* CSimDataCall::NewL(CSimLine* aLine,const TDesC& aName, CSimPhone* aPhone)
/**
 * Standard two phase constructor.
 *
 * @param aLine pointer to the Line object.
 * @param aName name of the call to be constructed
 * @return CSimDataCall  pointer to the data call object created
 * @leave Leaves if no memory or object is not created for any reason
 */
	{
	CSimDataCall* dataCall=new(ELeave) CSimDataCall(aLine,aName,aPhone);
	TCleanupItem newCallDataClose(CloseCall,dataCall);
	CleanupStack::PushL(newCallDataClose);
	dataCall->ConstructL();
	CleanupStack::Pop();
	return dataCall;
	}

CSimDataCall::CSimDataCall(CSimLine* aLine,const TName& aName, CSimPhone* aPhone)
	: CSimCall(aLine,aName,aPhone), iCommPortLoaned(EFalse)
/**
 * Trivial constructor. Calls CSimCall to initialise its members
 */
	{
	iCaps=Caps();
	}

void CSimDataCall::ConstructL()
/**
 * Second phase of 2-Phase Constructor
 * Retrieves all the pausing duration tags from the config file
 *
 * @param aName name of the data call to be constructed
 */
	{
	LOGDATA1("Starting to parse Data Call config parameters...");

	iDiallingPause=iLine->CfgFile()->ItemValue(KDiallingPauseDuration,KDefaultDiallingPauseDuration);
	iConnectingPause=iLine->CfgFile()->ItemValue(KConnectingPauseDuration,KDefaultConnectingPauseDuration);
	iDisconnectingPause=iLine->CfgFile()->ItemValue(KDisconnectingPauseDuration,KDefaultDisconnectingPauseDuration);
	iAnswerIncomingPause=iLine->CfgFile()->ItemValue(KAnswerIncomingPauseDuration,KDefaultAnswerIncomingPauseDuration);
	iRemoteHangupPause=iLine->CfgFile()->ItemValue(KRemoteHangupPauseDuration,KDefaultRemoteHangupPauseDuration);

// Read in the CommPort setup

	const CTestConfigItem* item=iLine->CfgFile()->Item(KDataCallCaps);
	if(item)
		{
		TPtrC8 speedCaps, protocolCaps, serviceCaps, qosCaps, codingCaps, asymmetryCaps;
		TPtrC8 rlpVersionCaps, v42bisCaps;
		TBool   hscsdSupport, userInitUpgrade;
		TInt mClass, MaxRxTimeslots, MaxTxTimeslots, totalRxTxTimeslots;
		TUint8 digit = 0;
		
		TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,speedCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("speedCaps",ret,0,&KDataCallCaps);
			}
		else
			if(AsciiToNum(speedCaps, digit)==KErrNone)
				iMobileCallCaps.iSpeedCaps = digit;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,protocolCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("protocolCaps",ret,1,&KDataCallCaps);
			}
		else
			if(AsciiToNum(protocolCaps, digit)==KErrNone)
				iMobileCallCaps.iProtocolCaps = digit;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,serviceCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("serviceCaps",ret,2,&KDataCallCaps);
			}
		else
			if(AsciiToNum(serviceCaps, digit)==KErrNone)
				iMobileCallCaps.iServiceCaps = digit;

		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,qosCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("qosCaps",ret,3,&KDataCallCaps);
			}
		else
			if(AsciiToNum(qosCaps, digit)==KErrNone)
				iMobileCallCaps.iQoSCaps = digit;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,hscsdSupport);
		if(ret!=KErrNone)
			{
			LOGPARSERR("hscsdSupport",ret,4,&KDataCallCaps);
			}
		else
			iMobileCallCaps.iHscsdSupport = hscsdSupport;
	
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,5,mClass);
		if(ret!=KErrNone)
			{
			LOGPARSERR("mClass",ret,5,&KDataCallCaps);
			}
		else
			iMobileCallCaps.iMClass = mClass;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,6,MaxRxTimeslots);
		if(ret!=KErrNone)
			{
			LOGPARSERR("MaxRxTimeslots",ret,6,&KDataCallCaps);
			}
		else
			iMobileCallCaps.iMaxRxTimeSlots = MaxRxTimeslots;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,7,MaxTxTimeslots);
		if(ret!=KErrNone)
			{
			LOGPARSERR("MaxTxTimeslots",ret,7,&KDataCallCaps);
			}
		else
			iMobileCallCaps.iMaxTxTimeSlots = MaxTxTimeslots;

		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,8,totalRxTxTimeslots);
		if(ret!=KErrNone)
			{
			LOGPARSERR("totalRxTxTimeslots",ret,8,&KDataCallCaps);
			}
		else
			iMobileCallCaps.iTotalRxTxTimeSlots = totalRxTxTimeslots;

		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,9,codingCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("codingCaps",ret,9,&KDataCallCaps);
			}
		else
			if(AsciiToNum(codingCaps, digit)==KErrNone)
				iMobileCallCaps.iCodingCaps = digit;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,10,asymmetryCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("asymmetryCaps",ret,10,&KDataCallCaps);
			}
		else
			if(AsciiToNum(asymmetryCaps, digit)==KErrNone)
				iMobileCallCaps.iAsymmetryCaps = digit;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,11,userInitUpgrade);
		if(ret!=KErrNone)
			{
			LOGPARSERR("userInitUpgrade",ret,11,&KDataCallCaps);
			}
		else
			iMobileCallCaps.iUserInitUpgrade = userInitUpgrade;

		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,10,rlpVersionCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("rlpVersionCaps",ret,10,&KDataCallCaps);
			}
		else
			if(AsciiToNum(rlpVersionCaps, digit)==KErrNone)
				iMobileCallCaps.iRLPVersionCaps = digit;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,10,v42bisCaps);
		if(ret!=KErrNone)
			{
			LOGPARSERR("v42bisCaps",ret,10,&KDataCallCaps);
			}
		else
			if(AsciiToNum(v42bisCaps, digit)==KErrNone)
				iMobileCallCaps.iV42bisCaps  = digit;
		}
		else //Default Values for Caps
			{
			iMobileCallCaps.iSpeedCaps=RMobileCall::KCapsSpeedAutobauding;
			iMobileCallCaps.iProtocolCaps=RMobileCall::KCapsProtocolV32;
			iMobileCallCaps.iServiceCaps=(RMobileCall::KCapsDataCircuitAsynchronous | RMobileCall::KCapsPacketAccessSyncUDI);
			iMobileCallCaps.iQoSCaps=RMobileCall::KCapsTransparentPreferred;
			iMobileCallCaps.iHscsdSupport=(TBool)(ETrue);
			iMobileCallCaps.iMClass=1;
			iMobileCallCaps.iMaxRxTimeSlots=5;
			iMobileCallCaps.iMaxTxTimeSlots=5;
			iMobileCallCaps.iTotalRxTxTimeSlots=10;
			iMobileCallCaps.iCodingCaps=(RMobileCall::KCapsAiurCoding48 | RMobileCall::KCapsAiurCoding96);
			iMobileCallCaps.iAsymmetryCaps=(RMobileCall::EAsymmetryUplink);
			iMobileCallCaps.iUserInitUpgrade=(TBool)(ETrue);
			iMobileCallCaps.iRLPVersionCaps = 1;
			iMobileCallCaps.iV42bisCaps = 1;
		}

	TInt count = iLine->CfgFile()->ItemCount(KDataRLPparams);
	TMobileCallRLPItem iMobileCallRLPItem;
	iMobileCallRLPList = new(ELeave) CArrayFixFlat<TMobileCallRLPItem>(5);

	if(count!=0)
		{
		for(TInt i=0;i<count;i++)
			{

			item = iLine->CfgFile()->Item(KDataRLPparams,i);
			if(!item)
				break;

			TInt iRlpVersion,iIWSMax,iIWSMin,iMWSMax,iMWSMin;
			TInt iT1Max,iT1Min,iN2Max,iN2Min,iT4Max,iT4Min;

			TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,iRlpVersion);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iRlpVersion",ret,0,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iRlpVersion = iRlpVersion;
			
			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,iIWSMax);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iIWSMax",ret,0,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iIWSMax = iIWSMax;
			
			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,iIWSMin);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iIWSMin",ret,1,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iIWSMin = iIWSMin;

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,iMWSMax);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iMWSMax",ret,2,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iMWSMax = iMWSMax;
			

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,iMWSMin);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iMWSMin",ret,3,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iMWSMin = iMWSMin;
			
			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,iT1Max);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iT1Max",ret,4,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iT1Max = iT1Max;

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,5,iT1Min);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iT1Min",ret,5,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iT1Min = iT1Min;

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,6,iN2Max);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iN2Max",ret,6,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iN2Max = iN2Max;

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,7,iN2Min);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iN2Min",ret,7,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iN2Min = iN2Min;

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,8,iT4Max);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iT4Max",ret,8,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iT4Max = iT4Max;

			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,9,iT4Min);
			if(ret!=KErrNone)
				{
				LOGPARSERR("iT4Min",ret,9,&KDataRLPparams);
				}
			else
				iMobileCallRLPItem.iMobileCallRLP.iT4Min = iT4Min;
			
			iMobileCallRLPList->AppendL(iMobileCallRLPItem);		
			}
		}
	else 
		{
		iMobileCallRLPItem.iRlpVersion=1;
		iMobileCallRLPItem.iMobileCallRLP.iIWSMax=10;
		iMobileCallRLPItem.iMobileCallRLP.iIWSMin=5;
		iMobileCallRLPItem.iMobileCallRLP.iMWSMax=8;
		iMobileCallRLPItem.iMobileCallRLP.iMWSMin=4;
		iMobileCallRLPItem.iMobileCallRLP.iT1Max=4;
		iMobileCallRLPItem.iMobileCallRLP.iT1Min=2;
		iMobileCallRLPItem.iMobileCallRLP.iN2Max=12;
		iMobileCallRLPItem.iMobileCallRLP.iN2Min=1;
		iMobileCallRLPItem.iMobileCallRLP.iT4Max=10;
		iMobileCallRLPItem.iMobileCallRLP.iT4Min=2;
		iMobileCallRLPList->AppendL(iMobileCallRLPItem);
		}
	
	item=iLine->CfgFile()->Item(KDynamicHSCSDInfo);
	if(item)
		{		
		TPtrC8 iAiur,iCodings;
		TInt iRxTimeSlots,iTxTimeSlots;
		
		TUint8 digit=0;
	
		TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,iAiur);
		if(ret!=KErrNone)
			{
			LOGPARSERR("iAiur",ret,0,&KDynamicHSCSDInfo);
			}
		else
			if(AsciiToNum(iAiur, digit)==KErrNone)
				iHscsdInfo.iAiur = (RMobileCall::TMobileCallAiur) digit;
		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,iRxTimeSlots);
		if(ret!=KErrNone)
			{
			LOGPARSERR("iRxTimeSlots",ret,1,&KDynamicHSCSDInfo);
			}
		else
			iHscsdInfo.iRxTimeSlots = iRxTimeSlots;
		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,iTxTimeSlots);
		if(ret!=KErrNone)
			{
			LOGPARSERR("iTxTimeSlots",ret,2,&KDynamicHSCSDInfo);
			}
		else
			iHscsdInfo.iTxTimeSlots = iTxTimeSlots;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,iCodings);
		if(ret!=KErrNone)
			{
			LOGPARSERR("iCodings",ret,3,&KDynamicHSCSDInfo);
			}
		else
			if(AsciiToNum(iCodings, digit)==KErrNone)
				iHscsdInfo.iCodings = (RMobileCall::TMobileCallTchCoding) digit;
	}
	else 
		{
		iHscsdInfo.iAiur=RMobileCall::EAiurBps9600;
		iHscsdInfo.iRxTimeSlots=5;
		iHscsdInfo.iTxTimeSlots=10;
		iHscsdInfo.iCodings=RMobileCall::ETchCoding48;
	}

	item=iLine->CfgFile()->Item(KCommSetup);
	if(item)
		{
		TPtrC8 portName,csyName;
		TInt err=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,csyName);	// The 3rd parameter (0) represents the index of the variable on the config file line
		if (err!=KErrNone)
			{
			LOGPARSERR("csyName",err,0,&KCommSetup);
			iCsyName.Copy(KDefaultCsyName);
			}
		else
			iCsyName.Copy(csyName);

		err=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,portName);		// The 3rd parameter (1) represents the index of the variable on the config file line
		if (err!=KErrNone)
			{
			LOGPARSERR("portName",err,1,&KCommSetup);
			iPortName.Copy(KDefaultPortName);
			}
		else
			iPortName.Copy(portName);

		TInt dataRate,handshake;
		err=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,dataRate);		// The 3rd parameter (2) represents the index of the variable on the config file line
		if (err!=KErrNone)
			{
			LOGPARSERR("dataRate",err,2,&KCommSetup);
			iConfig.iRate=KDefaultCommPortRate;
			}
		else
			iConfig.iRate=(TBps)dataRate;

		err=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,handshake);		// The 3rd parameter (3) represents the index of the variable on the config file line
		if (err!=KErrNone)
			{
			LOGPARSERR("handshake",err,3,&KCommSetup);
			iConfig.iHandshake=KDefaultHandshake;
			}
		else
			iConfig.iHandshake=(TUint)handshake;
		}
	else
		{
		iCsyName.Copy(KDefaultCsyName);
		iPortName.Copy(KDefaultPortName);
		iConfig.iRate=KDefaultCommPortRate;
		iConfig.iHandshake=KDefaultHandshake;
		}

// Read in the Bearer Service information
	item=iLine->CfgFile()->Item(KBearerService);
	if(item)
		{
		TInt bearerCaps,bearerSpeed;
		TInt err=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,bearerCaps);	// The 3rd parameter (0) represents the index of the variable on the config file line
		if (err!=KErrNone)
			{
			LOGPARSERR("bearerCaps",err,0,&KBearerService);
			iBearerService.iBearerCaps=KDefaultBearerCaps;
			}
		else
			iBearerService.iBearerCaps=bearerCaps;
		
		err=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,bearerSpeed);		// The 3rd parameter (1) represents the index of the variable on the config file line
		if (err!=KErrNone)
			{
			LOGPARSERR("bearerSpeed",err,1,&KBearerService);
			iBearerService.iBearerSpeed=KDefaultBearerSpeed;
			}
		else
			iBearerService.iBearerSpeed=(RCall::TCallBearerSpeed)bearerSpeed;
		
		}
	else
		{
		iBearerService.iBearerCaps=KDefaultBearerCaps;
		iBearerService.iBearerSpeed=KDefaultBearerSpeed;
		}

	iTimer=CSimTimer::NewL(iLine->iPhone);
	iNtRas=CSimNtRas::NewL(iLine->iPhone);
	CSimCall::ConstructL();
	
	//If present read in remote party info tag
 	TPtrC8 callingname, remotenumber;
 	TInt delay=0;
 	
 	item=iLine->CfgFile()->Item(KNotifyRemotePartyInfo);
 	
 	TInt ret;
 	
 	if (item)
 		{
 		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,delay);
 		if(ret!=KErrNone)
 			{
 			LOGPARSERR("delay",ret,0,&KNotifyRemotePartyInfo);
 			}
 		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,callingname);
 		if(ret!=KErrNone)
 			{
 			LOGPARSERR("callingname",ret,1,&KNotifyRemotePartyInfo);
 			}
 		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,remotenumber);
 		if(ret!=KErrNone)
 			{
 			LOGPARSERR("remotenumber",ret,2,&KNotifyRemotePartyInfo);
 			}
 		
 		iNotifyRemotePartyInfoTimer->iDelay = delay;
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EDirectionUnknown;
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iCallingName.Copy(callingname);
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iTelNumber.Copy(remotenumber);	
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iTypeOfNumber = RMobilePhone::EInternationalNumber;
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iNumberPlan = RMobilePhone::EIsdnNumberPlan;
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus = RMobileCall::ERemoteIdentityAvailable;					
 		}
 	else
 		{
 		iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus = RMobileCall::ERemoteIdentityUnknown;
 		}
	
	LOGDATA1("...Finished parsing Data Call config parameters...");
	}

CSimDataCall::~CSimDataCall()
/**
 * Destroy all the objects constructed.
 * CSimTimer and CSimSysAgent objects are destroyed here
 */
	{
	delete iNtRas;
	delete iTimer;
	if(iAnswerIncomingCall.iNotifyPending)
		iLine->ResetAutoAnswerCallObject(this);
	if(iMobileCallRLPList)
		{
		iMobileCallRLPList->Delete(0,iMobileCallRLPList->Count());
		delete iMobileCallRLPList; 
		}
	}

TInt CSimDataCall::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc,const TDataPackage& aPackage)
/**
 * ExtFunc is called by the server when it has a "extended", i.e. non-core ETel request 
 * for the TSY to process
 * A request handle, request type and request data are passed to the TSY
 *
 * @param aTsyReqHandle
 * @param aIpc IPc number representing the request
 * @param aPackage data for the request
 * @return KErrNone
 */
	{
	TAny* dataPtr=aPackage.Ptr1();
	TAny* dataPtr2=aPackage.Ptr2();

	LOGDATA2("CSimDataCall::ExtFunc: IPC Number is %d",aIpc);
	// The request data has to extracted from TDataPackage and the TAny* pointers have to
	// be "cast" to the expected request data type

	switch (aIpc)
		{
	//
	// No Flow Control NOR Multiple Completion
	//
	case EMobileCallGetMobileCallCaps:
		return GetMobileCallCaps(aTsyReqHandle,aPackage.Des1n());
	
	case EMobileCallGetMobileDataCallCaps:
		return GetMobileDataCallCaps(aTsyReqHandle,aPackage.Des1n());

	case EMobileCallGetMobileDataCallRLPRange:
		return GetMobileDataCallRLPRange(aTsyReqHandle,
				REINTERPRET_CAST(TInt*,dataPtr),
				REINTERPRET_CAST(TDes8*,dataPtr2));

	case EMobileCallSetDynamicHscsdParams:
		return SetDynamicHSCSDParams(aTsyReqHandle,
				REINTERPRET_CAST(RMobileCall::TMobileCallAiur*,dataPtr),
				REINTERPRET_CAST(TInt*,dataPtr2));

	case EMobileCallGetCurrentHscsdInfo:
		return GetCurrentHSCSDInfo(aTsyReqHandle, aPackage.Des1n());

	case EMobileCallGetMobileCallStatus:
		return GetMobileCallStatus(aTsyReqHandle,
			REINTERPRET_CAST(RMobileCall::TMobileCallStatus*,dataPtr));

	case EMobileCallGetMobileCallInfo:
		return GetMobileCallInfo(aTsyReqHandle,aPackage.Des1n());

	//
	// Multiple Completion Services with Immediate Server Repost
	// (Usually Notifications)
	//
	case EMobileCallNotifyMobileCallStatusChange:
		return NotifyMobileCallStatusChange(aTsyReqHandle,
			REINTERPRET_CAST(RMobileCall::TMobileCallStatus*, dataPtr));

	case EMobileCallNotifyMobileCallCapsChange:
		return NotifyMobileCallCapsChange(aTsyReqHandle, aPackage.Des1n());

	case EMobileCallNotifyMobileDataCallCapsChange:
		return NotifyMobileDataCapsChange(aTsyReqHandle, aPackage.Des1n());
	
	case EMobileCallNotifyHscsdInfoChange:
		return NotifyHSCSDInfoChange(aTsyReqHandle, aPackage.Des1n());
	
	case EMobileCallNotifyRemotePartyInfoChange:
 		return NotifyRemotePartyInfoChange(aTsyReqHandle, aPackage.Des1n());

	default:
		LOGDATA2("CSimDataCall::ExtFunc: Unsupported IPC detected - number %d",aIpc);
		break;
		}

	return KErrNotSupported;
	}

TInt CSimDataCall::CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle)
/**
 * Cancel an outstanding request.
 * @param aIpc The IPC number of the request that must be cancelled.  Note: this is not the
 *             IPC number of the cancel request itself.
 * @param aTsyReqHandle The TSY Request Handle of the request to be cancelled.
 */
	{
	switch(aIpc)
		{
	case EMobileCallNotifyMobileCallStatusChange:
		return NotifyMobileCallStatusChangeCancel(aTsyReqHandle);

	case EMobileCallNotifyMobileCallCapsChange:
		return NotifyMobileCallCapsChangeCancel(aTsyReqHandle);
	
	case EMobileCallNotifyMobileDataCallCapsChange:
		return NotifyMobileDataCapsChangeCancel(aTsyReqHandle);

	case EMobileCallSetDynamicHscsdParams:
		return SetDynamicHSCSDParamsCancel(aTsyReqHandle);
	
	case EMobileCallGetMobileDataCallCaps:
		return GetMobileDataCallCapsCancel(aTsyReqHandle);

	case EMobileCallGetMobileDataCallRLPRange:
		return GetMobileDataCallRLPRangeCancel(aTsyReqHandle);

	case EMobileCallNotifyHscsdInfoChange:
		return NotifyHSCSDInfoChangeCancel(aTsyReqHandle);
	
	case EMobileCallNotifyRemotePartyInfoChange:
 		return NotifyRemotePartyInfoChangeCancel();

	default:
		LOGDATA1("CSimDataCall::CancelService: No match for IPC, defering to base function");
		break;
		}
	return CCallBase::CancelService(aIpc,aTsyReqHandle);
	}

TInt CSimDataCall::Dial(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* /*aTelNumber*/)
/**
 * Process a client's dial request.
 *
 * @param aTsyReqHandle
 * @param aCallParams  the call parameters
 * @param aTelNumber The telephone number to dial
 * @return KErrNone
 */
	{
	LOGDATA1(">>CSimDataCall::Dial");
	iDialRequestHandle=aTsyReqHandle;
	PopulateCallParams(aCallParams);

	TInt err=ActionEvent(ECallEventDial,KErrNone);
	if(err!=KErrNone)
		ReqCompleted(aTsyReqHandle,err);

	LOGDATA1("<<CSimDataCall::Dial");
	return KErrNone;
	}

TInt CSimDataCall::DialCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancels a dial Request
*
* @param aTsyReqHandle
* @return KErrNone if successfully cancelled
*/
	{
	LOGDATA1(">>CSimDataCall::DialCancel");
	switch(iState)
		{
	case RMobileCall::EStatusIdle:
	case RMobileCall::EStatusConnected:
		SimPanic(EIllegalCancelRequest);		// A DialCancel should never reach the TSY in this state.
		break;

	case RMobileCall::EStatusDialling:
	case RMobileCall::EStatusConnecting:
		iTimer->Cancel();
		
		TInt err;
		err = KErrNone;
		TRAP(err, ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse));
		if (err != KErrNone)
			{
			ReqCompleted(iDialRequestHandle, err);
			}		
		else
			{
			ReqCompleted(iDialRequestHandle, KErrCancel);
			}
		break;

	default:
		LOGDATA2("CSimDataCall::DialCancel: No action taken - state: %d",iState);
		break;
		}
	LOGDATA1("<<CSimDataCall::DialCancel");
	return KErrNone;
	}

TInt CSimDataCall::AnswerIncomingCall(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams)
/**
* Register a client's interest in answering the next incoming call.
* First register interest in incoming calls with the line, then, if a call
* is already ringing, start the answer procedure.
*
* @param aTsyReqHandle
* @param aCallParams  the call parameters
* @return KErrNone
*/
	{
	LOGDATA1(">>CSimDataCall::AnswerIncomingCall");
	TInt err=iLine->SetAutoAnswerCallObject(this);
	if(err!=KErrNone)
		{
		ReqCompleted(aTsyReqHandle,err);
		return KErrNone;
		}

	PopulateCallParams(aCallParams);
	iAnswerIncomingCall.iNotifyPending=ETrue;
	iAnswerIncomingCall.iNotifyHandle=aTsyReqHandle;

	TInt ret=KErrNone;
	if(iState==RMobileCall::EStatusRinging)
		ActionEvent(ECallEventAnswerIncoming,KErrNone);
	else if(iLine->iState==RMobileCall::EStatusRinging)
		{
		TRAP(ret,ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse));		
		if(ret == KErrNone)
			{
			ret = ActionEvent(ECallEventAnswerIncoming,KErrNone);	
			}
		}
	LOGDATA1("<<CSimDataCall::AnswerIncomingCall");
	return ret;
	}

TInt CSimDataCall::AnswerIncomingCallCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancels a AnswerIncomingCall Request
*
* @param aTsyReqHandle
* @return KErrNone if successfully cancelled
*/
	{
	LOGDATA1(">>CSimDataCall::AnswerIncomingCallCancel");
	if(iAnswerIncomingCall.iNotifyPending)
		{
		iAnswerIncomingCall.iNotifyPending=EFalse;
		iLine->ResetAutoAnswerCallObject(this);
		ReqCompleted(iAnswerIncomingCall.iNotifyHandle,KErrCancel);
		}
	LOGDATA1("<<CSimDataCall::AnswerIncomingCallCancel");
	return KErrNone;
	}

TInt CSimDataCall::Connect(const TTsyReqHandle aTsyReqHandle,const TDesC8* /*aCallParams*/)
	{
	ReqCompleted(aTsyReqHandle,KErrNotSupported);
	return KErrNone;
	}

TInt CSimDataCall::ConnectCancel(const TTsyReqHandle aTsyReqHandle)
	{
	ReqCompleted(aTsyReqHandle,KErrNotSupported);
	return KErrNone;
	}

TInt CSimDataCall::HangUp(const TTsyReqHandle aTsyReqHandle)
/**
* Process a client's HangUp request.
*
* @param aTsyReqHandle
* @return KErrNone
*/
	{
	LOGDATA1(">>CSimDataCall::HangUp");
	iHangUpRequestHandle=aTsyReqHandle;
	TInt err=ActionEvent(ECallEventHangUp,KErrNone);
	if(err!=KErrNone)
		ReqCompleted(aTsyReqHandle,err);
	LOGDATA1("<<CSimDataCall::HangUp");
	return KErrNone;
	}

TInt CSimDataCall::HangUpCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancels a HangUp Request
*
* @param aTsyReqHandle
* @return KErrNone if successfully cancelled
*/
	{
	LOGDATA1(">>CSimDataCall::HangUpCancel");
	switch(iState)
		{
	case RMobileCall::EStatusIdle:
		SimPanic(EIllegalCancelRequest);		// A DialCancel should never reach the TSY in this state.
		break;

	case RMobileCall::EStatusDisconnecting:
		iTimer->Cancel();
		
		TInt err;
		err = KErrNone;
		TRAP(err, ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse));
		if (err != KErrNone)
			{
			ReqCompleted(iHangUpRequestHandle, err);
			}
		else
			{	
			ReqCompleted(iHangUpRequestHandle, KErrCancel);
			}
		break;

	default:
		LOGDATA2("CSimDataCall::HangUpCancel: No action taken - state: %d",iState);
		break;
		}
	LOGDATA1("<<CSimDataCall::HangUpCancel");
	return KErrNone;
	}

TInt CSimDataCall::RelinquishOwnership()
	{
	return KErrNotSupported;
	}

TInt CSimDataCall::GetBearerServiceInfo(const TTsyReqHandle aTsyReqHandle,RCall::TBearerService* aBearerService)
/**
 * Retrieves the bearer service info.  Bearer service information is only valid
 * when the call is active.
 */
	{
	if(iState!=RMobileCall::EStatusConnected)
		{
		ReqCompleted(aTsyReqHandle,KErrEtelCallNotActive);
		return KErrNone;
		}

	*aBearerService=iBearerService;
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::GetCallParams(const TTsyReqHandle aTsyReqHandle, TDes8* aCallParams)
/**
 * Retrives the call parameters.  This function must handle both core and Multimode
 * extension versions of the function.  Call parameter information is only valid
 * when the call is active.
 */
	{
	if(iState!=RMobileCall::EStatusConnected)
		{
		ReqCompleted(aTsyReqHandle,KErrEtelCallNotActive);
		return KErrNone;
		}

	TPckg<RCall::TCallParams>* callParamPckg=(TPckg<RCall::TCallParams>*)aCallParams;
	RCall::TCallParams& callParam=(*callParamPckg)();

	if(callParam.ExtensionId()==RMobileCall::KETelMobileDataCallParamsV1)
		{
// If the passed package is MobileParams, then we can just unpackage and copy.
		RMobileCall::TMobileDataCallParamsV1Pckg* mobileCallParamPckg=(RMobileCall::TMobileDataCallParamsV1Pckg*)aCallParams;
		RMobileCall::TMobileDataCallParamsV1& mobileCallParam=(*mobileCallParamPckg)();

		// Check that the data structure is supported by the simulated TSY version
		TInt err = iPhone->CheckSimTsyVersion(mobileCallParam);
		if(err != KErrNone)
			{
			ReqCompleted(aTsyReqHandle, err);
			return KErrNone;
			}

		mobileCallParam=iMobileCallParams;
		}
	
	else if(callParam.ExtensionId()==RMobileCall::KETelMobileHscsdCallParamsV1)
		{
		TPckg<RMobileCall::TMobileHscsdCallParamsV1>* mobileCallParamPckg=(TPckg<RMobileCall::TMobileHscsdCallParamsV1>*)aCallParams;
		RMobileCall::TMobileHscsdCallParamsV1& mobileCallParam=(*mobileCallParamPckg)();

		// Check that the data structure is supported by the simulated TSY version
		TInt err = iPhone->CheckSimTsyVersion(mobileCallParam);
		if(err != KErrNone)
			{
			ReqCompleted(aTsyReqHandle, err);
			return KErrNone;
			}

		mobileCallParam=iHscsdSettings;
		}
	else
		{
// If, however, its a core (or an unrecognised extension), we must only copy the
// core parameters.
 		callParam.iSpeakerControl=iMobileCallParams.iSpeakerControl;
		callParam.iSpeakerVolume=iMobileCallParams.iSpeakerVolume;
		callParam.iInterval=iMobileCallParams.iInterval;
		callParam.iWaitForDialTone=iMobileCallParams.iWaitForDialTone;
		}

	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::LoanDataPort(const TTsyReqHandle aReqHandle,RCall::TCommPort* aCommPort)
/**
 * Loans the comm port to a client for subsequent streaming of data.
 * For the comm port to be loaned the call must be active and the port unloaned.
 */
	{
	if(iState!=RMobileCall::EStatusConnected)
		{
		ReqCompleted(aReqHandle,KErrEtelCallNotActive);
		return KErrNone;
		}

	if(iCommPortLoaned)
		{
		ReqCompleted(aReqHandle,KErrEtelPortAlreadyLoaned);
		return KErrNone;
		}

	aCommPort->iCsy.Copy(iCsyName);
	aCommPort->iPort.Copy(iPortName);
	iCommPortLoaned=ETrue;
	ReqCompleted(aReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::LoanDataPortCancel(const TTsyReqHandle)
/**
 * Cancels the LoanDataPort request.
 * The LoanDataPort function completes synchronously, so there is nothing to cancel.
 */
	{
	return KErrNone;
	}

TInt CSimDataCall::RecoverDataPort(const TTsyReqHandle aReqHandle)
/**
 * Recovers the comm port.
 * The comm port must be loaned in order to recover it.
 */
	{
	if(!iCommPortLoaned)
		{
		ReqCompleted(aReqHandle,KErrEtelPortNotLoanedToClient);
		return KErrNone;
		}

	iNtRas->Terminate();
	iCommPortLoaned=EFalse;
	ReqCompleted(aReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::ActionEvent(TCallEvent aEvent,TInt aStatus)
/**
* Entry point when an event has occured that may advance the state machine.
* The aEvent parameter describes the event.
*
* This function contains the main state machine for the data call.  The outer layer
* switches on the event type.  Where appropriate, there are inner layer switches
* or conditional statements to handle the different responses that may be required to
* the same event occurring in different states.
*
* @param aEvent The Call event to handle
* @return value represents the error state caused by the attempted state machine jump.
*/
	{
	TInt ret=KErrNone;
	__ASSERT_ALWAYS(iState!=RMobileCall::EStatusUnknown,SimPanic(ECallStatusUnknownIllegal));

	switch(aEvent)
		{
	case ECallEventDial:
		LOGDATA1(">>CSimDataCall::ActionEvent = [ECallEventDial]");
		if(iState==RMobileCall::EStatusIdle)
			{
			TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusDialling,EFalse,EFalse));
			if(ret==KErrNone)
				iTimer->Start(iDiallingPause,this);
			}
		else
			return KErrEtelCallAlreadyActive;
		break;

	case ECallEventHangUp:
		{
		LOGDATA1(">>CSimDataCall::ActionEvent = [ECallEventHangUp]");
		switch(iState)
			{
		case RMobileCall::EStatusConnected:
			iCommPortLoaned=EFalse;
			iNtRas->Terminate();
// Note: No "break;" - fall through to the rest of the discconnecting code...
		case RMobileCall::EStatusDialling:
		case RMobileCall::EStatusRinging:
		case RMobileCall::EStatusAnswering:
		case RMobileCall::EStatusConnecting:
			iTimer->Cancel();
			TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusDisconnecting,EFalse,EFalse));
			if(ret==KErrNone)
				iTimer->Start(iDisconnectingPause,this);
			break;
		default:
			return KErrEtelCallNotActive;
			}
		}
		break;

	case ECallEventIncomingCall:
		LOGDATA1(">>CSimDataCall::ActionEvent = [ECallEventIncomingCall]");
		if(iState==RMobileCall::EStatusIdle)
			{
			if(iAnswerIncomingCall.iNotifyPending)
				{
				TRAP(ret,	ret=ProcessAnswerIncomingCallL());
				}
			else
				{
				TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse));
				if(ret!=KErrNone)
					return ret;
				}
			}
		else
			return KErrEtelCallAlreadyActive;
		break;

	case ECallEventAnswerIncoming:
		LOGDATA1(">>CSimDataCall::ActionEvent = [ECallEventAnswerIncoming]");
		if(iState==RMobileCall::EStatusRinging)
			{
			TRAP(ret, ret=ProcessAnswerIncomingCallL());
			}
		else
			SimPanic(EIllegalStateInconsistancy);		// The state is checked in AnswerIncomingCall, so there's been an inconsistancy if the state is out of line.
		break;

	case ECallEventRemoteHangup:
		LOGDATA1(">>CSimDataCall::ActionEvent = [ECallEventRemoteHangup]");
		if(iState==RMobileCall::EStatusConnected)
			{
			TRAP(ret, ret=ProcessRemoteHangupL());
			}
		else
			SimPanic(EIllegalStateInconsistancy);		// The state is checked in RemoteHangup, so there's been an inconsistancy if the state is out of line.
		break;

	case ECallEventTimeOut:
			{
			LOGDATA1(">>CSimVoiceCall::ActionEvent = [ECallEventTimeOut]");
			switch(iState)
				{
			case RMobileCall::EStatusDialling:
				LOGDATA1(">>CSimDataCall::State = [EStatusDialling]");
				TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnecting,EFalse,EFalse));
				if(ret==KErrNone)
					iTimer->Start(iConnectingPause,this);
				return ret;

			case RMobileCall::EStatusConnecting:
				LOGDATA1(">>CSimDataCall::State = [EStatusConnecting]");
// If the config file has not spec'ed a CSY, then fail the dial...
				if(iCsyName.Length()==0)
					{
					ReqCompleted(iDialRequestHandle,KErrEtelNoCarrier);
					TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse));
									
					__ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalStateInconsistancy));
					return KErrNone;
					}
				ret=iNtRas->Connect(iCsyName,iPortName,iConfig,this);
				if(ret!=KErrNone)
					ReqCompleted(iDialRequestHandle,ret);
				return ret;

			case RMobileCall::EStatusDisconnecting:
				LOGDATA1(">>CSimDataCall::State = [EStatusDisconnecting]");
				TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse));
				ReqCompleted(iHangUpRequestHandle,ret);
				return ret;

			case RMobileCall::EStatusAnswering:
				LOGDATA1(">>CSimDataCall::State = [EStatusAnswering]");
				TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse));
				ReqCompleted(iAnswerIncomingCall.iNotifyHandle,ret);
				return ret;

			default:
				LOGDATA2(">>CSimDataCall::State = [%d]",iState);
				break;
				}
			}
		break;

	case ECallEventNtRasConnected:
		if(aStatus!=KErrNone)
			{
			ReqCompleted(iDialRequestHandle,aStatus);
			TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse));
			__ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalStateInconsistancy));
			return KErrNone;
			}
		else
			{
			TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse));
			ChangeDynamicInfo();
			ReqCompleted(iDialRequestHandle,ret);
			return KErrNone;
			}
	default:
		SimPanic(EIllegalStateInconsistancy);
		break;
		}

	return ret;
	}


void CSimDataCall::TimerCallBack(TInt /*aId*/)
/**
* Timer callback function.  When the timer goes off, it will call back into this
* function for further processing.
*/
	{
	LOGDATA1(">>CSimDataCall::TimerCallBack");
	TInt err=ActionEvent(ECallEventTimeOut,KErrNone);
	__ASSERT_ALWAYS(err==KErrNone,SimPanic(ETimeOutEventActionFailed));
	LOGDATA1("<<CSimDataCall::TimerCallBack");
	}

TInt CSimDataCall::ProcessAnswerIncomingCallL()
/**
* Answers an Incoming Call.
* First the call state must be changed to "answering", then the flag indicating
* that an answer incoming call request is no longer pending.  Finally, a new
* call object must be assigned to receive the details of the next incoming call.
*/
	{
	LOGDATA1(">>CSimDataCall::ProcessAnswerIncomingCall");
	TInt ret=ChangeStateL(RMobileCall::EStatusAnswering,EFalse,EFalse);
	if(ret!=KErrNone)
		return ret;
	iTimer->Start(iAnswerIncomingPause,this);
	iAnswerIncomingCall.iNotifyPending=EFalse;
	iLine->ResetAutoAnswerCallObject(this);
	LOGDATA1("<<CSimDataCall::ProcessAnswerIncomingCall");
	return ret;
	}

TInt CSimDataCall::ProcessRemoteHangupL()
/**
* Hangs up a call from the remote end.
* First the call state must be changed to "disconnecting", then the flag indicating
* that a remote hangup request is no longer pending.  Finally, a new
* call object must be assigned to be the next remotely hung up call.
*/
	{
	LOGDATA1(">>CSimDataCall::ProcessRemoteHangupL");
	TInt ret=ChangeStateL(RMobileCall::EStatusDisconnecting,EFalse,EFalse);
	if(ret!=KErrNone)
		return ret;
	iTimer->Start(iRemoteHangupPause,this);
	iLine->ResetRemoteHangupCallObject(this);
	LOGDATA1("<<CSimDataCall::ProcessRemoteHangupL");
	return ret;
	}


void CSimDataCall::PopulateCallParams(const TDesC8* aCallParams)
/**
 * This function populates the call parameter member variable iMobileCallParams.
 * The function must handle core and multimode extension call parameters.
 * @param aCallParams	A pointer to the call parameter variable.
 */
	{
	TPckg<RCall::TCallParams>* callParamPckg=(TPckg<RCall::TCallParams>*)aCallParams;
	RCall::TCallParams& callParam=(*callParamPckg)();

	if(callParam.ExtensionId()==RMobileCall::KETelMobileDataCallParamsV1)
		{
// If the passed package is MobileParams, then we can just unpackage and copy.
		RMobileCall::TMobileDataCallParamsV1Pckg* mobileCallParamPckg=(RMobileCall::TMobileDataCallParamsV1Pckg*)aCallParams;
		RMobileCall::TMobileDataCallParamsV1& mobileCallParam=(*mobileCallParamPckg)();

		iHscsdCall=EFalse;
		iMobileCallParams=mobileCallParam;
		}
	else if(callParam.ExtensionId()==RMobileCall::KETelMobileHscsdCallParamsV1)
		{
		TPckg<RMobileCall::TMobileHscsdCallParamsV1>* mobileCallParamPckg=(TPckg<RMobileCall::TMobileHscsdCallParamsV1>*)aCallParams;
		RMobileCall::TMobileHscsdCallParamsV1& mobileCallParam=(*mobileCallParamPckg)();

		iHscsdCall=ETrue;
		iHscsdSettings=mobileCallParam;
		}
	else
		{
// If, however, its core (or an unrecognised extension), we must first reset the member
// member variable before copying just the core parameters.
		RMobileCall::TMobileDataCallParamsV1 mobileCallParam;

		iMobileCallParams=mobileCallParam;
		iHscsdCall=EFalse;
 		iMobileCallParams.iSpeakerControl=callParam.iSpeakerControl;
		iMobileCallParams.iSpeakerVolume=callParam.iSpeakerVolume;
		iMobileCallParams.iInterval=callParam.iInterval;
		iMobileCallParams.iWaitForDialTone=callParam.iWaitForDialTone;
		}
	}

void CSimDataCall::NTRasCallBack(TInt aStatus)
/**
 * NTRas callback function.  This function will be called when the NTRAS
 * Server has responded.
 * @param aStatus	Standard error value, indicating the success or failure of the NTRAS
 *					connection.
 */
	{
	TInt err=ActionEvent(ECallEventNtRasConnected,aStatus);
	__ASSERT_ALWAYS(err==KErrNone,SimPanic(EIllegalStateInconsistancy));
	}

TUint CSimDataCall::Caps()
/**
 * Return the current capabilities of this call.
 * @return TUint	Current call capabilities.
 */
	{
	TUint caps=RCall::KCapsData;
	GenerateCoreCallCaps(caps);
	if(iState==RMobileCall::EStatusConnected)
		{
		if(iCommPortLoaned)
			caps|=RCall::KCapsRecoverDataPort;
		else
			caps|=RCall::KCapsLoanDataPort;
		}
	return caps;
	}

TInt CSimDataCall::GetMobileDataCallCaps(const TTsyReqHandle aTsyReqHandle, TDes8* aCaps)
/**
* 
* @param aTsyReqHandle specifies the request handle.
* @param aCaps is used to return the retrieved capabilities to the client.
* @return value returns the result of this operation
*/
	{
	TPckg<RMobileCall::TMobileCallDataCapsV1>* mobileCallCapsPckg=(TPckg<RMobileCall::TMobileCallDataCapsV1>*)aCaps;
	RMobileCall::TMobileCallDataCapsV1& mobileCallCaps=(*mobileCallCapsPckg)();	
	
	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(mobileCallCaps);
	if(err != KErrNone)
		{
		ReqCompleted(aTsyReqHandle, err);
		return KErrNone;
		}

	if(mobileCallCaps.ExtensionId()==KETelExtMultimodeV1)
		{
		mobileCallCaps=iMobileCallCaps;
		ReqCompleted(aTsyReqHandle,KErrNone);
		return KErrNone;
		}
	else
		{
		ReqCompleted(aTsyReqHandle,KErrNotFound);
		return KErrNotFound;
		}
}

TInt CSimDataCall::GetMobileDataCallCapsCancel(const TTsyReqHandle aTsyReqHandle)
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @return value returns the result of this operation
*/	
	{
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::SetDynamicHSCSDParams(const TTsyReqHandle aTsyReqHandle, RMobileCall::TMobileCallAiur* aAiur, TInt* aRxTimeslots)
/**
* 
* @param aTsyReqHandle specifies the request handle.
* @param aAiur is used to dynamically change Aiur for this call
* @param aRxTimeslots is used to dynamically change RxTimeslots for this call
* @return value returns the result of this operation
*/	
	{
	iHscsdInfo.iRxTimeSlots=*aRxTimeslots;
	iHscsdInfo.iAiur=*aAiur;
	iHscsdSettings.iWantedRxTimeSlots=*aRxTimeslots;
	iHscsdSettings.iWantedAiur=*aAiur;

	if(iNotifyInfo.iNotifyPending)
		{
		*(RMobileCall::TMobileCallHscsdInfoV1*)iNotifyInfo.iNotifyData=iHscsdInfo;
		iNotifyInfo.iNotifyPending=EFalse;
		ReqCompleted(iNotifyInfo.iNotifyHandle,KErrNone);
		}
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
}

TInt CSimDataCall::SetDynamicHSCSDParamsCancel(const TTsyReqHandle aTsyReqHandle)
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @return value returns the result of this operation
*/	
	{
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::GetCurrentHSCSDInfo(const TTsyReqHandle aTsyReqHandle, TDes8* aInfo)
/**
* 
* @param aTsyReqHandle specifies the request handle.
* @param aInfo is used to return the current Hscsd information to the client
* @return value returns the result of this operation
*/		
	{
	TPckg<RMobileCall::TMobileCallHscsdInfoV1>* hscsdInfoPckg=(TPckg<RMobileCall::TMobileCallHscsdInfoV1>*)aInfo;
	RMobileCall::TMobileCallHscsdInfoV1& hscsdInfo=(*hscsdInfoPckg)();	
	
	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(hscsdInfo);
	if(err != KErrNone)
		{
		ReqCompleted(aTsyReqHandle, err);
		return KErrNone;
		}

	if(hscsdInfo.ExtensionId()==KETelExtMultimodeV1)
		{
		hscsdInfo=iHscsdInfo;
		ReqCompleted(aTsyReqHandle,KErrNone);
		return KErrNone;
		}
	else
		{
		ReqCompleted(aTsyReqHandle,KErrNotFound);
		return KErrNotFound;
		}
	}

TInt CSimDataCall::NotifyHSCSDInfoChange(const TTsyReqHandle aTsyReqHandle, TDes8* aHSCSDInfo)
/**
* 
* @param aTsyReqHandle specifies the request handle.
* @param aInfo is used to return the current Hscsd information when the notification completes
* @return value returns the result of this operation
*/		
	{
	__ASSERT_ALWAYS(!iNotifyInfo.iNotifyPending,SimPanic(ENotificationAlreadyPending));

	iNotifyInfo.iNotifyPending = ETrue;
	iNotifyInfo.iNotifyHandle = aTsyReqHandle;

	TPckg<RMobileCall::TMobileCallHscsdInfoV1>* hscsdInfo = (TPckg<RMobileCall::TMobileCallHscsdInfoV1>*)aHSCSDInfo;
	RMobileCall::TMobileCallHscsdInfoV1& hscsdInfoV1 = (*hscsdInfo)();

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(hscsdInfoV1);
	if(err != KErrNone)
		{
		ReqCompleted(aTsyReqHandle, err);
		return KErrNone;
		}

	iNotifyInfo.iNotifyData = &hscsdInfoV1;
	return KErrNone;
	}

TInt CSimDataCall::NotifyHSCSDInfoChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @return value returns the result of this operation
*/	
	{
	if(iNotifyInfo.iNotifyPending)
		{
		iNotifyInfo.iNotifyPending=EFalse;
		ReqCompleted(iNotifyInfo.iNotifyHandle,KErrCancel);
		}
	return KErrNone;
	}

TInt CSimDataCall::NotifyMobileDataCapsChange(const TTsyReqHandle aTsyReqHandle, TDes8* /*aCaps*/)
	{
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @return value returns the result of this operation
*/	
	ReqCompleted(aTsyReqHandle,KErrNotSupported);
	return KErrNotSupported;
	}	

TInt CSimDataCall::NotifyMobileDataCapsChangeCancel(const TTsyReqHandle aTsyReqHandle)
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @return value returns the result of this operation
*/	
	{
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimDataCall::GetMobileDataCallRLPRange(const TTsyReqHandle aTsyReqHandle, TInt* aRLPVersion, TDes8* aRLPRange)
	{
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @param aRLPVersion specifies the version for RLP range retrieval
* @param aRLPRange is used to return the requested RLP range to the client
* @return value returns the result of this operation
*/
	TInt ret=SearchRetrieveRlp(aRLPVersion,aRLPRange);

	ReqCompleted(aTsyReqHandle,ret);
	return ret;
	}

TInt CSimDataCall::GetMobileDataCallRLPRangeCancel(const TTsyReqHandle aTsyReqHandle)
/**
* 
* @param aTsyReqHandle specifies the request handle to be canceled
* @return value returns the result of this operation
*/		
	{
	ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	}

void CSimDataCall::ChangeDynamicInfo() 
/**
*
* Private function to alter the current Hscsd information 
*/		
	{
	if(iHscsdCall)
			{
			// Change to the requested settings
			iHscsdInfo.iAiur=iHscsdSettings.iWantedAiur;
			iHscsdInfo.iRxTimeSlots=iHscsdSettings.iWantedRxTimeSlots;
			iHscsdInfo.iTxTimeSlots=iHscsdSettings.iMaxTimeSlots-iHscsdSettings.iWantedRxTimeSlots;
			iHscsdInfo.iCodings=(RMobileCall::TMobileCallTchCoding) iHscsdSettings.iCodings;
			// Complete a pending notification event for changes in dynamic info of HSCSD
			if(iNotifyInfo.iNotifyPending)
				{
				*(RMobileCall::TMobileCallHscsdInfoV1*)iNotifyInfo.iNotifyData=(RMobileCall::TMobileCallHscsdInfoV1)iHscsdInfo;
				ReqCompleted(iNotifyInfo.iNotifyHandle,KErrNone);
				}
			}
	}

TInt CSimDataCall::SearchRetrieveRlp(TInt* aRLPVersion,TDes8* aRLPRange)
/**
*
* Private function to search the list of available RLP ranges per version
* and return the appropriate range.  
*/
	{
	TInt count = iMobileCallRLPList->Count();
	TMobileCallRLPItem item;

	for(TInt i=0; i<count; i++)
		{
		item=iMobileCallRLPList->At(i);
		if(item.iRlpVersion==*aRLPVersion)
			{
			*(RMobileCall::TMobileDataRLPRangesV1*)aRLPRange=item.iMobileCallRLP;
			return KErrNone;
			}
		}
		return KErrNotFound;
	}

