--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/multimodetsy/hayes/ATBASE.CPP Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,682 @@
+// 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:
+// AT Command Base Class
+//
+//
+
+#include "PHONE.H"
+#include "ATIO.H"
+#include "mSLOGGER.H"
+#include "ATINIT.H"
+#include "ATESCAPE.H"
+#include "LINE.H"
+#include "NOTIFY.H"
+#include "sms_rx_queue.h" // for CReceiveSmsQueue
+
+// Specific GSM Error String Response
+_LIT8(KCmsErrorString,"+CMS ERROR:*");
+
+//
+// CATParamListEntry
+// A pointer to a meaningful result in the received buffer from the modem
+//
+CATParamListEntry::CATParamListEntry(const TDesC8& aDes) :
+ iResultPtr(aDes)
+ {
+ }
+
+CATParamListEntry::~CATParamListEntry()
+ {}
+
+void CATParamListEntry::Deque()
+ {
+ iLink.Deque();
+ }
+
+void CATParamListEntry::EntryValL(CATParamListEntry* aEntry,TInt& aValue)
+ {
+ if (aEntry==NULL)
+ User::Leave(KErrGeneral);
+ TLex8 lex(aEntry->iResultPtr);
+ (void)User::LeaveIfError(lex.Val(aValue));
+ aEntry->Deque();
+ delete aEntry;
+ }
+
+TInt CATParamListEntry::EntryValL(CATParamListEntry* aEntry)
+ {
+ TInt val;
+ EntryValL(aEntry,val);
+ return val;
+ }
+
+
+//
+// Async One Shot to call RelinquishOwnershipComplete().
+// If RelinquishOwnershipComplete() is called synchronously, it destroys the CATIO object
+// before the latter has finished processing.
+//
+CCompleteRelinquish* CCompleteRelinquish::New(CTelObject* aTelObject)
+//
+// Create the Relinquish Complete async one shot
+//
+ {
+ // The below TRAP is used to stop leavescan errors occurring.
+ // This is not the best solution, but I am pressed for time ;-(
+ CCompleteRelinquish* ptr=NULL;
+ TRAP_IGNORE(ptr=new(ELeave)CCompleteRelinquish(aTelObject));
+ return ptr;
+ }
+
+CCompleteRelinquish::CCompleteRelinquish(CTelObject* aTelObject)
+//
+// C'tor
+//
+ :CAsyncOneShot(CActive::EPriorityLow), iTelObject(aTelObject)
+ {
+ __DECLARE_NAME(_S("CCompleteRelinquish"));
+ }
+
+
+CCompleteRelinquish::~CCompleteRelinquish()
+ {
+ Cancel();
+ }
+
+void CCompleteRelinquish::RunL()
+//
+// Call RelinquishOwnershipCompleted() or RecoverDataPortAndRelinquishOwnershipCompleted()
+// after CATIO has finished its processing
+//
+ {
+ __ASSERT_ALWAYS(iPanicOccurred!=ENoPanicOccurred,Panic(EIllegalPanicOccurredValue));
+ if (iPanicOccurred == EPanicOccurredWithoutDataPortLoan)
+ {
+ REINTERPRET_CAST(CCallBase*,iTelObject)->RelinquishOwnershipCompleted(KErrNone);
+ }
+ if (iPanicOccurred == EPanicOccurredDuringDataPortLoan)
+ {
+ REINTERPRET_CAST(CCallBase*,iTelObject)->RecoverDataPortAndRelinquishOwnershipCompleted(KErrNone);
+ }
+ delete this;
+ }
+//
+// The Command Base Class
+//
+CATBase::CATBase(CATIO* aIo, CTelObject* aTelObject,CPhoneGlobals* aPhoneGlobals)
+ : iIo(aIo),iPhoneGlobals(aPhoneGlobals),iComplete(NULL),iTelObject(aTelObject),iCallInfo(NULL)
+ {
+ iRxResults.SetOffset(_FOFF(CATParamListEntry,iLink));
+ }
+
+CATBase::~CATBase()
+//
+// Assumes CATIO pointer is still valid
+//
+ {
+ if(!iRxResults.IsEmpty())
+ {
+ CATParamListEntry* entry;
+ TDblQueIter<CATParamListEntry> iter(iRxResults);
+ while (entry = iter++,entry!=NULL)
+ {
+ entry->Deque();
+ delete entry;
+ }
+ }
+ }
+
+void CATBase::GenericEventSignal(TEventSource aEventSource, TInt aStatus)
+//
+// If an IO error has occurred, complete this ATBase-object with the error.
+//
+ {
+ if (aStatus!=KErrNone)
+ {
+ LOGTEXT2(_L8("EventSignal received error status %d"),aStatus);
+ CompleteWithIOError(aEventSource,aStatus);
+ }
+ else
+ {
+ EventSignal(aEventSource);
+ }
+ }
+
+void CATBase::AddStdExpectStrings()
+ {
+ if (!iOKExpectString)
+ iOKExpectString=iIo->AddExpectString(this,KOkString);
+ if (!iErrorExpectString)
+ iErrorExpectString=iIo->AddExpectString(this,KErrorString);
+ }
+
+
+TInt CATBase::ValidateExpectString()
+/**
+ * New version ValidateExpectStringL which returns an error code
+ * as opposed to leaving.
+ * Use of this new code should hopefully remove alot of
+ * unesseccary TRAP harness in the TSY.
+ */
+ {
+ TInt ret(KErrNone);
+
+ if(iIo->FoundChatString()!=iOKExpectString)
+ {
+ if(iIo->FoundChatString()==iErrorExpectString)
+ {
+ LOGTEXT(_L8("Modem returned ERROR in response to command"));
+ ret=KErrGeneral;
+ }
+ else
+ {
+ LOGTEXT(_L8("Modem returned unexpected response to command"));
+ ret=KErrUnknown;
+ }
+ }
+
+ return ret;
+ }
+
+void CATBase::RemoveStdExpectStrings()
+ {
+ LOGTEXT(_L8("RemoveStdExpectStrings()"));
+ iIo->RemoveExpectString(iOKExpectString);
+ iOKExpectString=NULL;
+ iIo->RemoveExpectString(iErrorExpectString);
+ iErrorExpectString=NULL;
+ }
+
+void CATBase::RemoveUnsolicitedStrings()
+ {
+ LOGTEXT(_L8("RemoveUnsolicitedStrings()"));
+
+ _LIT8(KNetworkRegistration,"+CREG:"); // Network registration
+ _LIT8(KIncomingCallIndication,"RING"); // Normal Ring
+ _LIT8(KIncomingExtCallIndication,"+CRING:"); // Extended format call
+ _LIT8(KIncomingExtNTCallParameter,"REL"); // Non-Transparent parameter
+ _LIT8(KIncomingExtAlternatingCallParameter,"ALT"); // Unsupported Alternating parameter
+ _LIT8(KIncomingExtVoiceRelCallParameter,"VOICE/REL"); // NT Voice parameter
+
+ if(!iRxResults.IsEmpty())
+ {
+ TInt aQueueSteps = NULL;
+ CATParamListEntry* entry;
+ TDblQueIter<CATParamListEntry> iter(iRxResults);
+ // Step along the queue looking for an unsolicited strings
+ while (entry = iter++,entry!=NULL)
+ {
+ TPtrC8 aResult(entry->iResultPtr);
+ // If a match is found, we dequeue it and all its expected parameters
+ if (aResult==KIncomingCallIndication) // 0 Params
+ {
+ // Remove the "RING"
+ entry->Deque(); delete entry;
+ LOGTEXT2(_L8("Unsolicited >%S< Removed"),&aResult);
+ }
+ else if (aResult==KIncomingExtCallIndication) // 1/2 Params
+ {
+ // Remove the "+CRING:"
+ entry->Deque(); delete entry; entry = iter++;
+ LOGTEXT2(_L8("Unsolicited >%S< Removed"),&aResult);
+ // We know we should be getting at least one and maybee two parameters
+ TPtrC8 aFirstParameterResult(entry->iResultPtr);
+ if (aFirstParameterResult==KIncomingExtNTCallParameter
+ || aFirstParameterResult==KIncomingExtVoiceRelCallParameter
+ || aFirstParameterResult==KIncomingExtAlternatingCallParameter)
+ {
+ // We have an "ALT" or a "REL" so we have two parameters
+ entry->Deque(); delete entry; entry = iter++;
+ TPtrC8 aSecondParameterResult(entry->iResultPtr);
+ entry->Deque(); delete entry; // If recognised parameter - remove
+ LOGTEXT3(_L8("Unsolicited Parameter >%S %S< Removed"),&aFirstParameterResult,&aSecondParameterResult); aSecondParameterResult==KIncomingCallIndication; // Quick fix to remove unused parameters make warning
+ }
+ else
+ {
+ // We only have one parameter
+ entry->Deque(); delete entry; // If recognised parameter - remove
+ LOGTEXT2(_L8("Unsolicited Parameter >%S< Removed"),&aFirstParameterResult);
+ }
+ }
+ else if (aResult==KNetworkRegistration) // 2 Params
+ {
+ // Remove the "+CREG:"
+ entry->Deque(); delete entry; entry = iter++;
+ LOGTEXT2(_L8("Unsolicited >%S< Removed"),&aResult);
+ // Remove both parameters
+ TPtrC8 aFirstParameterResult(entry->iResultPtr);
+ entry->Deque(); delete entry; entry = iter++;
+ TPtrC8 aSecondParameterResult(entry->iResultPtr);
+ entry->Deque(); delete entry;
+ LOGTEXT3(_L8("Unsolicited Parameters >%S,%S< Removed"),&aFirstParameterResult,&aSecondParameterResult); aFirstParameterResult==KIncomingCallIndication; aSecondParameterResult==KIncomingCallIndication; // Quick fix to remove unused parameters make warning
+ }
+
+ // Increment the queue step counter
+ else aQueueSteps++;
+ }
+ // Now we have to retrace the list, ignoring dequeued entries
+ for (TInt aLoop=NULL;aLoop<aQueueSteps;aLoop++)
+ iter--;
+ }
+ }
+
+void CATBase::CleanupRxResults(TAny *aCATBase) // for TCleanupOperation
+ {
+ CATBase* p= reinterpret_cast<CATBase*>(aCATBase);
+ TDblQueIter<CATParamListEntry> iter(p->iRxResults);
+ CATParamListEntry* entry=iter++;
+ while (entry!=NULL)
+ {
+ entry->Deque();
+ delete entry;
+ entry=iter++;
+ }
+ }
+
+void CATBase::RxResultsPushLC()
+ {
+ TCleanupItem cleanup(CleanupRxResults,this);
+ CleanupStack::PushL(cleanup);
+ }
+
+void CATBase::ParseBufferLC(TBool aReportLists, TUint aSeparatorChar)
+//
+// Parses buffer. Treats aSeparatorChar like a comma
+//
+ {
+ LOGTEXT(_L8("Parse the Buffer List"));
+
+ if (iIo->CurrentLine()==KOkString)
+ iIo->ClearCurrentLine(); // remove trailing "OK"
+
+ iBuffer.Set(iIo->Buffer());
+ iIo->ClearBuffer();
+
+ ParseLC(aReportLists, aSeparatorChar);
+ }
+
+void CATBase::ParseLineLC(TBool aReportLists, TUint aSeparatorChar)
+//
+// Parses current line. Treats aSeparatorChar like a comma
+//
+ {
+ LOGTEXT(_L8("Parse the current line"));
+
+ iBuffer.Set(iIo->CurrentLine());
+ iIo->ClearCurrentLine();
+ ParseLC(aReportLists, aSeparatorChar);
+ }
+
+void CATBase::AddParamL(const TDesC8 &aPtr)
+ {
+ CATParamListEntry* aParamListEntry = new (ELeave) CATParamListEntry(aPtr);
+ iRxResults.AddLast(*aParamListEntry);
+ }
+
+void CATBase::ParseLC(TBool aReportLists, TUint aSeparatorChar)
+//
+// Does the actual parsing of iBuffer, set up from ParseLineLC or ParseBufferLC
+//
+ {
+_LIT8(KOpenBracket, "(");
+_LIT8(KCloseBracket, ")");
+
+#ifdef __LOGDEB__
+ TPtrC8 buf(iBuffer);
+ if (buf.Length()>180)
+ {
+ buf.Set(buf.Left(180));
+ LOGTEXT2(_L8("buffer to parse >%S< and so on ..."),&buf);
+ }
+ else
+ LOGTEXT2(_L8("buffer to parse >%S<"),&buf);
+#endif
+
+ RxResultsPushLC();
+ TLex8 yyLex(iBuffer);
+
+ // Move cursor past any spaces or open brackets
+ yyLex.SkipSpace();
+ TChar peek=yyLex.Peek();
+ if (peek=='(' || peek=='[' || peek=='{')
+ yyLex.Inc();
+
+ if (aReportLists && peek=='(')
+ {
+ AddParamL(KOpenBracket);
+ LOGTEXT2(_L8("list separator >%S<"),&iRxResults.Last()->iResultPtr);
+ }
+ do
+ {
+ // Skip all space and opening brackets
+ for (;;)
+ {
+ yyLex.SkipSpace();
+ if (yyLex.Eos())
+ return;
+ peek = yyLex.Peek();
+ if (peek!='(')
+ break;
+ if (aReportLists)
+ {
+ AddParamL(KOpenBracket);
+ LOGTEXT2(_L8("list separator >%S<"),&iRxResults.Last()->iResultPtr);
+ }
+ yyLex.Inc();
+ }
+
+ if (peek=='"') // start of quoted string
+ {
+ yyLex.Inc(); // step over the quote
+ yyLex.Mark();
+ while (!yyLex.Eos())
+ {
+ peek=yyLex.Peek();
+ if (peek=='"')
+ break;
+ yyLex.Inc();
+ }
+
+ AddParamL(yyLex.MarkedToken());
+ LOGTEXT2(_L8("quoted parameter >%S<"),&iRxResults.Last()->iResultPtr);
+ if (yyLex.Eos())
+ return;
+
+ // Skip all space and closing brackets
+ for (;;)
+ {
+ yyLex.Inc();
+ yyLex.SkipSpace();
+ if (yyLex.Eos())
+ return;
+ peek = yyLex.Peek();
+ if (peek!=')')
+ break;
+ if (aReportLists)
+ {
+ AddParamL(KCloseBracket);
+ LOGTEXT2(_L8("list separator >%S<"),&iRxResults.Last()->iResultPtr);
+ }
+ }
+
+ // Skip any following separator
+ if (peek==',' || peek==aSeparatorChar)
+ {
+ yyLex.Inc();
+ yyLex.SkipSpace();
+ if (yyLex.Eos())
+ return;
+ peek=yyLex.Peek();
+ }
+ }
+ else // if (peek!=',' && peek !='(' && peek!='"' && peek!=aSeparatorChar)
+ {
+ yyLex.Mark();
+ while (peek!=',' && !peek.IsSpace() && peek!=')' && peek!=']' && peek!='}' && peek!=aSeparatorChar)
+ {
+ yyLex.Inc();
+ if (yyLex.Eos())
+ break;
+ peek=yyLex.Peek();
+ if ((peek==':')&&(aSeparatorChar!=':'))
+ {
+ yyLex.Inc();
+ break;
+ }
+ }
+
+ AddParamL(yyLex.MarkedToken());
+ LOGTEXT2(_L8("normal parameter >%S<"),&iRxResults.Last()->iResultPtr);
+ if (yyLex.Eos())
+ return;
+ // skip any whitespace and closing brackets
+ for (;;)
+ {
+ yyLex.SkipSpace();
+ if (yyLex.Eos())
+ return;
+ peek = yyLex.Peek();
+ if (peek!=')')
+ break;
+ if (aReportLists)
+ {
+ AddParamL(KCloseBracket);
+ LOGTEXT2(_L8("list separator >%S<"),&iRxResults.Last()->iResultPtr);
+ }
+ yyLex.Inc();
+ }
+ // Skip any following separator
+ if (peek==',' || peek==aSeparatorChar)
+ {
+ yyLex.Inc();
+ yyLex.SkipSpace();
+ if (yyLex.Eos())
+ return;
+ peek=yyLex.Peek();
+ }
+ }
+ } while (peek!=')'&& peek!=']'&& peek!='}');
+ if (aReportLists && peek==')')
+ {
+ AddParamL(KCloseBracket);
+ LOGTEXT2(_L8("list separator >%S<"),&iRxResults.Last()->iResultPtr);
+ }
+
+ }
+
+void CATBase::ChangeCallStatus(RMobileCall::TMobileCallStatus aCallStatus)
+//
+// This is called from a phone-based command as it is overloaded in CATCallAlterCommands.
+//
+ {
+ if (iCallInfo->iMobileStatus != aCallStatus)
+ {
+ iCallInfo->iMobileStatus = aCallStatus;
+ if (aCallStatus == RMobileCall::EStatusIdle)
+ {
+ iCallInfo->iHookStatus = RCall::EHookStatusOn;
+ iPhoneGlobals->iNotificationStore->CheckNotification(iTelObject,EBecomeIdle);
+ }
+ else if (aCallStatus != RMobileCall::EStatusUnknown && aCallStatus != RMobileCall::EStatusRinging)
+ {
+ iCallInfo->iHookStatus = RCall::EHookStatusOff;
+ }
+ }
+ }
+
+void CATBase::ChangeLineStatus(RCall::TStatus aLineStatus)
+ {
+ iPhoneGlobals->iPhoneStatus.iLineStatus = aLineStatus;
+ }
+
+void CATBase::SetToNotInitialised()
+ {
+ iPhoneGlobals->iPhoneStatus.iMode = RPhone::EModeUnknown;
+ iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags = RPhone::KCapsUnknown;
+ iPhoneGlobals->iPhoneStatus.iInitStatus = EPhoneNotInitialised;
+ }
+
+void CATBase::StandardWriteCompletionHandler(TEventSource aSource,TInt aTimeOut)
+ {
+ __ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ iIo->SetTimeOut(this,aTimeOut * KOneSecondPause);
+ AddStdExpectStrings();
+ }
+
+void CATBase::Write(const TDesC8& aCommand,TInt aTimeOut)
+ {
+ iTxBuffer.Format(KStringFormatString,&aCommand);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,aTimeOut * KOneSecondPause);
+ }
+
+void CATBase::Write(const TDesC8& aCommand,TInt aTimeOut,TInt aValue)
+ {
+ iTxBuffer.Format(KStringAndIntegerFormatString,&aCommand,aValue);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,aTimeOut * KOneSecondPause);
+ }
+
+void CATBase::Write(const TInt aTimeOut)
+{
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,aTimeOut * KOneSecondPause);
+}
+
+void CATBase::WriteExpectingResults(const TDesC8& aCommand,TInt aTimeOut)
+ {
+ iIo->ClearBuffer();
+ Write(aCommand,aTimeOut);
+ }
+
+void CATBase::AppendWildCardChar(TDes8& aString)
+//
+// A utility function to append a '*' to aString if there's not one already there
+//
+ {
+ _LIT8(KAsterisk,"*");
+ if(aString.Right(1)!=KAsterisk)
+ aString.Append(KAsterisk);
+ }
+
+void CATBase::AddCmsErrorExpectString()
+//
+// Add the "+CMS ERROR:" expect string
+//
+ {
+ iCmsExpectString=iIo->AddExpectString(this,KCmsErrorString);
+ LOGTEXT(_L8("Added \"+CMS ERROR:\" string."));
+ }
+
+void CATBase::RemoveCmsErrorExpectString()
+//
+// Remove the "+CMS ERROR:" expect string
+//
+ {
+ iIo->RemoveExpectString(iCmsExpectString);
+ iCmsExpectString=NULL;
+ LOGTEXT(_L8("Removed \"+CMS ERROR:\" string."));
+ }
+
+CTelObject* CATBase::Owner()
+ {
+ return iTelObject;
+ }
+
+TCallInfoTSY* CATBase::CallInfo()
+ {
+ return iCallInfo;
+ }
+
+//
+// CATCommands class
+//
+CATCommands::CATCommands(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit, CPhoneGlobals* aPhoneGlobals)
+ : CATBase(aIo,aTelObject,aPhoneGlobals), iInit(aInit)
+ {}
+
+void CATCommands::ConstructL()
+ {
+ iATSetToOnlineCommandMode=CATSetToOnlineCommandMode::NewL(iIo,iTelObject,iPhoneGlobals);
+ }
+
+CATCommands::~CATCommands()
+ {
+ delete iATSetToOnlineCommandMode;
+ }
+
+void CATCommands::ExecuteCommand(TTsyReqHandle aTsyReqHandle, TAny* aParams)
+//
+// Ensures that phone is initialised and not in on-line data mode
+//
+ {
+ if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneNotInitialised)
+ {
+ iInit->StartInit(this,aTsyReqHandle,aParams);
+ }
+ else if (iPhoneGlobals->iPhoneStatus.iMode==RPhone::EModeOnlineData)
+ {
+ iATSetToOnlineCommandMode->StartEscapeSequence(this,aTsyReqHandle,aParams);
+ }
+ else
+ {
+ if (iPhoneGlobals->iEventSignalActive)
+ {
+ // Make sure request only completed if we have a valid request handle
+ // Signal that request could not be executed
+ if (aTsyReqHandle)
+ iTelObject->ReqCompleted(aTsyReqHandle, KErrInUse);
+ }
+ else
+ {
+ iPhoneGlobals->iEventSignalActive = ETrue;
+ Start(aTsyReqHandle, aParams);
+ }
+ }
+ }
+
+void CATCommands::ExecuteCommand(TTsyReqHandle aTsyReqHandle, TAny* aParams,TCallInfoTSY* aCallInfo)
+//
+// Overloaded function for CCallHayes-originated commands, so that the status can be
+// changed for CCallHayes->iCallInfo
+//
+ {
+ iCallInfo = aCallInfo;
+ ExecuteCommand(aTsyReqHandle,aParams);
+ }
+
+void CATCommands::CancelCommand(TTsyReqHandle aTsyReqHandle)
+ {
+ if(iInit->CheckActiveReqHandle(aTsyReqHandle))
+ {
+ iInit->StopInit(aTsyReqHandle);
+ }
+ else if (iPhoneGlobals->iPhoneStatus.iMode==RPhone::EModeOnlineData)
+ {
+ iATSetToOnlineCommandMode->StopEscapeSequence(aTsyReqHandle);
+ }
+ else
+ {
+ Stop(aTsyReqHandle);
+ }
+ }
+
+void CATCommands::Complete(TInt aError,TEventSource /*aSource*/)
+//
+// Should be called by all Complete()'s before ReqCompleted()
+//
+ {
+ LOGTEXT(_L8("CATCommands::Complete called"));
+
+ if (aError==KErrTimedOut)
+ {
+ LOGTEXT(_L8("CATCommands::Complete KErrTimedOut error, setting EPhoneNotIntialised"));
+ iPhoneGlobals->iPhoneStatus.iInitStatus = EPhoneNotInitialised;
+ }
+
+ // Clear the flow control flag to show no AT commands are writing to the
+ // serial port.
+ iPhoneGlobals->iEventSignalActive = EFalse;
+
+ // Allow the CReceiveSmsQueue object to read PDUs from the phones memory, if needed
+ if(iPhoneGlobals->iReceiveSmsQueuePtr)
+ iPhoneGlobals->iReceiveSmsQueuePtr->ReadPDUFromPhone();
+
+ // Check the flow control flag, as the previous lines may have started off a
+ // AT command.
+ // If the flow control is clear then allow the Check ForChangeOfNetwork to have
+ // a go at updating its status and writing to the serial port.
+ if (!(iPhoneGlobals->iEventSignalActive))
+ iPhoneGlobals->CheckForChangeOfNetwork();
+ }