telephonyserverplugins/multimodetsy/hayes/ATWAIT.CPP
changeset 0 3553901f7fa8
child 24 6638e7f4bd8f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/multimodetsy/hayes/ATWAIT.CPP	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,434 @@
+// Copyright (c) 1997-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:
+// Wait for Incoming Call
+// 
+//
+
+#include "NOTIFY.H"
+#include "mSLOGGER.H"
+#include "LINE.H"
+#include "CALL.H"
+#include "ATCALL.H"
+#include "ATIO.H"
+#include "PHONE.H"
+
+_LIT8(KIncomingExtCallIndication,"+CRING:*");
+_LIT8(KIncomingCallIndication,"RING");
+_LIT8(KNetworkRegistration,"+CREG:*");
+
+//
+// CTimer-derived class to switch line status to idle a fixed period after the last 
+// RING arrives. Use this rather than CATIO::SetTimeOut() because that has only one 
+// timer which could be cancelled by another concurrently running AT command
+//
+CSetLineToIdle* CSetLineToIdle::NewL(CATWaitForCall* aWait)
+//
+//	Create the SetLineToIdle async one shot
+//
+	{
+	CSetLineToIdle* setLineToIdle=new(ELeave) CSetLineToIdle(aWait);
+	CleanupStack::PushL(setLineToIdle);
+	setLineToIdle->ConstructL();
+	CleanupStack::Pop();
+	return setLineToIdle;
+	}
+
+CSetLineToIdle::CSetLineToIdle(CATWaitForCall* aWait)
+//
+// C'tor
+//
+	:CTimer(CActive::EPriorityLow), iWait(aWait)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+CSetLineToIdle::~CSetLineToIdle()
+	{
+	Cancel();
+	}
+
+void CSetLineToIdle::RunL()
+	{
+	iWait->EndRing();
+	}
+
+void CSetLineToIdle::Start()
+	{
+	if (IsActive())
+		Cancel();
+	After(KTimeBetweenRings);	
+	}
+
+void CSetLineToIdle::Stop()
+	{
+	Cancel();
+	}
+
+//
+//  CATWaitForCall. Expects a RING constantly, and upon receiving one checks if either line 
+//	wants to be notified. Sets all lines and calls ringing anyway, and a timer to switch
+//	them back to idle after a specified time has elapsed since the last RING.
+//
+
+CATWaitForCall* CATWaitForCall::NewL(CATIO* aIo,CTelObject* aTelObject,CPhoneGlobals* aPhoneGlobals)
+	{
+	CATWaitForCall* waitForCall=new(ELeave) CATWaitForCall(aIo,aTelObject,aPhoneGlobals);
+	CleanupStack::PushL(waitForCall);
+	waitForCall->ConstructL();
+	CleanupStack::Pop();
+	return waitForCall;
+	}
+
+CATWaitForCall::CATWaitForCall(CATIO* aIo,CTelObject* aTelObject,CPhoneGlobals* aPhoneGlobals) 
+								: CATBase(aIo,aTelObject,aPhoneGlobals)
+	{}
+
+void CATWaitForCall::ConstructL()
+	{
+	iSetLineToIdle = CSetLineToIdle::NewL(this);
+	iRingExpectString=NULL;
+	iCRingExpectString=NULL;
+	iRegExpectString=NULL;
+	iTailExpectString=NULL;
+	}
+
+CATWaitForCall::~CATWaitForCall()
+	{
+	iIo->RemoveExpectStrings(this);
+	iRingExpectString=NULL;
+	iCRingExpectString=NULL;
+	iRegExpectString=NULL;
+	iTailExpectString=NULL;
+	iIo->WriteAndTimerCancel(this);	
+	delete iSetLineToIdle;
+	}
+
+void CATWaitForCall::StartWait()
+	{
+	if (iRingExpectString==NULL)
+		{
+		LOGTEXT(_L8("WaitForCall:\tStarting wait for incoming call"));
+		iCRingExpectString=iIo->AddExpectString(this,KIncomingExtCallIndication);
+		iRingExpectString=iIo->AddExpectString(this,KIncomingCallIndication);
+		iRegExpectString=iIo->AddExpectString(this,KNetworkRegistration);
+		iState=EATWaitForUnsolicited;
+		}
+	}
+
+void CATWaitForCall::EndRing()
+//
+//	Only called from the RunL of CSetLineToIdle, which occurs a fixed period after the
+//	last RING. StopBothLinesRinging() sets the calls on both lines to idle
+//
+	{
+	LOGTEXT(_L8("WaitForCall:\tRinging has stopped"));
+	ChangeLineStatus(RCall::EStatusIdle);
+	STATIC_CAST(CPhoneHayes*,iTelObject)->StopRinging(); 
+	iRingCounter = 0;
+	iPhoneGlobals->iNotificationStore->CheckNotification(iTelObject,ERingStopped);
+	}
+
+void CATWaitForCall::ResetRingCounter()
+	{
+	iRingCounter = 0;
+	iSetLineToIdle->Stop();
+	}
+
+void CATWaitForCall::CompleteWithIOError(TEventSource /*aSource*/,TInt /*aStatus*/)
+//
+//	CATIO removes expect strings in event of IO error
+//
+	{
+	iRingExpectString=NULL;
+	iCRingExpectString=NULL;
+	iRegExpectString=NULL;
+	iTailExpectString=NULL;
+	}
+
+void CATWaitForCall::EventSignal(TEventSource aSource)
+//
+//	Completes Incoming Call Notification for every ring.
+//	This is different from the previous TSY, but is needed for the Nokia 7110 which does
+//  not supply multiple RING notifications.
+//
+	{
+	__ASSERT_ALWAYS(aSource!=EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteNotExpected));
+	if (aSource!=EReadCompletion)
+		return;
+	switch (iState)
+		{
+	case EATWaitForUnsolicited:
+		if (iIo->FoundChatString()==iCRingExpectString)
+			{
+			LOGTEXT(_L8("CATWaitForCall::EventSignal +CRING detected"));
+			LOGTEXT(_L8("CATWaitForCall::EventSignal Will only process +CRING if phone is initialised..."));
+			if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneInitialised)
+				{
+				LOGTEXT(_L8("CATWaitForCall::EventSignal Processing +CRING"));
+				TInt index=KErrNotFound;
+				TRAPD(ret,index=ParseIncomingCallIndicationL());
+				if (ret==KErrNone)
+					{
+					iRingCounter+=1;
+					if (iRingCounter==1)
+						{
+						LOGTEXT(_L8("CATWaitForCall::EventSignal This is 1st +CRING"));
+						// Only do this once
+						ChangeLineStatus(RCall::EStatusRinging);
+						STATIC_CAST(CPhoneHayes*,iTelObject)->SetCallRinging(index); 
+						}
+					iSetLineToIdle->Start();
+					}
+				}
+			}
+		else if (iIo->FoundChatString()==iRingExpectString)
+			{
+			LOGTEXT(_L8("WaitForCall:\tRING detected"));
+			if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneInitialised)
+				{
+				iRingCounter+=1;
+				if (iRingCounter==1)
+					{
+					// Only do this once
+					ChangeLineStatus(RCall::EStatusRinging);
+					STATIC_CAST(CPhoneHayes*,iTelObject)->SetAmbiguousDataFaxCallRinging(); 
+					}
+				iSetLineToIdle->Start();
+				}
+			}
+		else if (iIo->FoundChatString()==iRegExpectString)
+			{
+			LOGTEXT(_L8("WaitForCall:\t+CREG detected"));
+			TRAPD(ret,ParseNetworkRegistrationL());
+			if (ret!=KErrNone)
+				{
+				LOGTEXT(_L8("WaitForCall:\tBad +CREG response?"));
+				}
+			}
+		else
+			{
+			LOGTEXT(_L8("WaitForCall:\tUnexpected string"));
+			iTelObject->ReqCompleted(iReqHandle,KErrGeneral);
+			iReqHandle = NULL;
+			break;
+			}
+		break;
+
+	default:
+		break;
+		}
+	}
+
+// Compare with +CMTI handling in GSMSNOTI.CPP
+// which has a similar problem
+/**
+*	Parse incoming call indication string and return a value corresponding to the call type.
+*
+* @note		modified by Dmitry Lyokhin 24.04.02
+* 
+* @return	KFaxLineIndex	for fax call
+*       	KVoiceLineIndex	for voice call
+*       	KDataLineIndex	for data call or if call modifier is not recognized
+*
+* @note		This function can leave with code KErrUnknown 
+*			if 'RING' token not found 
+*/
+TInt CATWaitForCall::ParseIncomingCallIndicationL()
+	{
+	//-- possible incoming call indication strings that can be parsed correctly
+	//-- string					corresponds to
+
+	//	+CRING: VOICE		   -> voice call
+	//	+CRING: FAX			   -> fax call
+	//	+CRING: DATA		   -> data call
+	//	+CRING: VOICE/xxx	   -> voice call
+	//	 RING				   -> data call	
+
+	//-- alternating mode calls
+	//	+CRING: ALT FAX/VOICE  -> fax call
+	//	+CRING: ALT DATA/VOICE -> data call
+	//	+CRING: ALT VOICE/FAX  -> fax call
+	//	+CRING: ALT VOICE/DATA -> data call
+
+
+	iBuffer.Set(iIo->CurrentLine());
+
+	TInt	index = KErrNotFound;
+	TLex8	Lex1(iBuffer);
+	
+	Lex1.SkipSpace();
+	
+	//-- the first token must be '+CRING' or 'RING'
+	if( Lex1.NextToken().Find(_L8("RING")) < 0 )
+	{	//-- the token not found, leave
+		LOGTEXT(_L8("CATWaitForCall::ParseIncomingCallIndicationL *RING not found"));		
+		User::Leave(KErrUnknown); 
+    }
+	
+	Lex1.SkipSpaceAndMark();
+	Lex1.SkipCharacters();
+
+	//-- try to find 'ALT' token that indicates the alternatng mode call
+	if( Lex1.MarkedToken().Find(_L8("ALT")) >=0 ) 
+	{//-- Alternating mode call, skip the token "ALT"
+	}
+	else  Lex1.UnGetToMark();
+
+	Lex1.SkipSpace();
+
+	TPtrC8 CallStr=Lex1.RemainderFromMark();
+	
+	_LIT8(KDataToken,	"DATA");
+	_LIT8(KFaxToken,	"FAX");
+	_LIT8(KVoiceToken,	"VOICE");
+
+	   if(CallStr.Find(KDataToken) >= 0)		index=KDataLineIndex;	//-- Data call detected
+	   else
+		 if(CallStr.Find(KFaxToken) >= 0)		index=KFaxLineIndex;	//-- Fax call detected
+		 else
+		   if(CallStr.Find(KVoiceToken) >= 0)	index=KVoiceLineIndex;	//-- Voice call detected
+			else 
+			{//-- unmatched call type, assume data call by default
+				LOGTEXT(_L8("CATWaitForCall::ParseIncomingCallIndicationL +CRING has unmatched type!, assuming data"));
+				index=KDataLineIndex;	
+				//User::Leave(KErrUnknown); 		
+			}
+
+	iIo->ClearCurrentLine();
+	LOGTEXT2(_L8("+CRING for line %d"),index);
+	
+	return index;
+	}
+
+
+void CATWaitForCall::ParseNetworkRegistrationL()
+	{
+	// +CREG:    <n>, <stat> [, <lac>, <ci>  ] 		-- solicited
+	// +CREG:         <stat> [, <lac>, <ci>  ]		-- unsolicited
+	//        number, number [, "hex", "hex" ]
+
+	RMobilePhone::TMobilePhoneLocationAreaV1& locationInfo = iPhoneGlobals->iPhoneStatus.iLocationArea;
+	locationInfo.iAreaKnown= EFalse;
+	locationInfo.iLocationAreaCode=0;
+	locationInfo.iCellId=0;
+
+	ParseLineLC();
+	CATParamListEntry* entry;
+	TDblQueIter<CATParamListEntry> iter(iRxResults);
+
+	entry=iter++;
+	if (entry==NULL)
+		User::Leave(KErrGeneral);
+	// should be +CREG:
+
+	entry=iter++;
+	if (entry==NULL)
+		User::Leave(KErrGeneral);
+	TLex8 lex(entry->iResultPtr);
+	TInt number;
+	(void)User::LeaveIfError(lex.Val(number));
+
+	entry=iter++;
+	if (entry!=NULL)
+		{ // is this <status> in a solicited +CREG?
+		lex.Assign(entry->iResultPtr);
+		if (lex.Val(number)==KErrNone)
+			entry=iter++; // yes - <n> has been replaced by <status>
+		}
+
+	// optional <lac> and <ci>
+	if (entry != NULL)
+		{
+		lex.Assign(entry->iResultPtr);
+		(void)User::LeaveIfError(lex.Val(locationInfo.iLocationAreaCode,EHex));
+		locationInfo.iAreaKnown = ETrue;
+		entry=iter++;
+		}
+	if (entry!=NULL)
+		{
+		lex.Assign(entry->iResultPtr);
+		(void)User::LeaveIfError(lex.Val(locationInfo.iCellId,EHex));
+		locationInfo.iAreaKnown = ETrue;
+		}
+   
+	
+
+	if (number<0 || number > RMobilePhone::ERegisteredRoaming)
+		User::Leave(KErrGeneral);
+
+	RMobilePhone::TMobilePhoneRegistrationStatus regstatus;
+	regstatus = MappingRegistrationStatusFromETSIToMM(&number); //Mapp the ETSI value number to MM enum for network registration status.
+
+	RMobilePhone::TMobilePhoneRegistrationStatus newstatus = regstatus;// change number to be of type MobilePhone...
+	RMobilePhone::TMobilePhoneRegistrationStatus oldstatus = iPhoneGlobals->iPhoneStatus.iRegistrationStatus;
+
+	if (oldstatus != newstatus)
+		{
+		LOGTEXT3(_L8("MmTsy:CATWaitForCall:\tRegistrationStatus changed %d->%d"), oldstatus, newstatus);
+		iPhoneGlobals->iPhoneStatus.iRegistrationStatus = newstatus;
+
+		iPhoneGlobals->iNotificationStore->CheckNotification(iTelObject,ERegistrationStatusChanged);
+
+		if (   (newstatus == RMobilePhone::ERegisteredOnHomeNetwork || newstatus == RMobilePhone::ERegisteredRoaming)
+			|| (oldstatus == RMobilePhone::ERegisteredOnHomeNetwork || oldstatus == RMobilePhone::ERegisteredRoaming)
+			)
+			{
+			// interesting transition - need new operator details
+			LOGTEXT(_L8("MmTsy:CATWaitForCall:\tCurrent Network has changed"));
+			iPhoneGlobals->iPhoneStatus.iNetworkChanged=ETrue;
+			if (iPhoneGlobals->iPhoneStatus.iInitStatus == EPhoneInitialised &&
+				!iPhoneGlobals->iEventSignalActive)
+				{
+				// no current activity - fire up +COPS stuff immediately
+				LOGTEXT(_L8("MmTsy:CATWaitForCall:\tNo activity - Checking current network immediately"));
+				iPhoneGlobals->CheckForChangeOfNetwork();
+				}
+			}
+		}
+
+	CleanupStack::PopAndDestroy();
+	}
+
+RMobilePhone::TMobilePhoneRegistrationStatus CATWaitForCall::MappingRegistrationStatusFromETSIToMM(TInt *aNumber) 
+	// This function is mapping the ETSI standard format for the registartion status of the phone to multimode representation.
+	// TINT *number is the ETSI value for the registration value to be converted.
+
+	{ 
+	RMobilePhone::TMobilePhoneRegistrationStatus regstatus = RMobilePhone::ERegistrationUnknown;
+	switch (*aNumber)
+		{
+		case 0:
+			regstatus = RMobilePhone::ENotRegisteredNoService;
+			break;
+		case 1:
+			regstatus = RMobilePhone::ERegisteredOnHomeNetwork;
+			break;
+		case 2:
+			regstatus = RMobilePhone::ENotRegisteredSearching;
+			break;
+		case 3:
+			regstatus = RMobilePhone::ERegistrationDenied;
+			break;
+		case 4:
+			regstatus = RMobilePhone::ERegistrationUnknown;
+			break;
+		case 5:
+			regstatus = RMobilePhone::ERegisteredRoaming;
+			break;
+		default:
+			break;
+		}
+	return regstatus;
+	}