--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/multimodetsy/Multimode/mnetwork.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,935 @@
+// Copyright (c) 2000-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:
+// \file mnetwork.cpp
+// Basic GSM Network and Operator information Implementation file.
+// This file contains the implementation of the CATNetworkInfo, CATDetectNetwork,
+// CNotifyNetworkRegistrationStatusChange and CCurrentNetworkChangedNotify classes.
+// Find the current Network Operator in Numeric, Long and Short formats.
+// NB - Some phones do not fully support all the formats, if any. The commands are
+// sent in sequence starting with the query command (AT+COPS?). All the phones currently
+// supported implement this command. Valid responses are set in the TMobilePhoneLocationAreaV1
+// and the TMobilePhoneNetworkInfoV1 structures and the Network's status is set to Current.
+//
+//
+
+#include <et_phone.h>
+#include "mnetwork.h"
+#include "mSLOGGER.H"
+#include "ATIO.H"
+#include "Matstd.h"
+#include "mPHONE.H"
+
+const TInt KSettlingPause=1; //< This pause is used at the end of the network information queries. The Nokia 8210 has been shown to require this, if it is not to error the next command.
+
+_LIT8(KSetAndReadOperatorCommandNumeric, "AT+COPS=3,2;+COPS?\r");
+_LIT8(KSetAndReadOperatorCommandShort, "AT+COPS=3,1;+COPS?\r");
+_LIT8(KSetAndReadOperatorCommandLong, "AT+COPS=3,0;+COPS?\r");
+
+_LIT8(KGetCurrentOperatorCommand, "AT+COPS?\r");
+_LIT8(KOperatorResponse,"+COPS:");
+
+_LIT8(KDetectNetworkCommand,"AT+COPS=?");
+
+
+static TInt NetworkIdL(const TDesC8& aCode,
+ RMobilePhone::TMobilePhoneNetworkCountryCode& aCountryCode,
+ RMobilePhone::TMobilePhoneNetworkIdentity& aNetworkIdentity)
+ {
+/**
+ * Utility function to translate the 5 digit ASCII network identification returned by the ME
+ * into Mobile Country Code (aCountryCode) and a Mobile Network Code (aNetworkIdentity) strings.
+ * Tbe format returned by the ME is XXXYY, where XXX represents the Mobile Country Code and YY
+ * represents the Mobile Network Code.
+ */
+ if (aCode.Length()!=5)
+ {
+ return KErrGeneral;
+ }
+
+ aCountryCode.SetLength(3);
+ aCountryCode[0] = aCode[0];
+ aCountryCode[1] = aCode[1];
+ aCountryCode[2] = aCode[2];
+
+ aNetworkIdentity.SetLength(2);
+ aNetworkIdentity[0] = aCode[3];
+ aNetworkIdentity[1] = aCode[4];
+ return KErrNone;
+ }
+
+
+CATNetworkInfo* CATNetworkInfo::NewL(CATIO* aIo,CTelObject* aTelObject,CATInit* aInit,CPhoneGlobals* aPhoneGlobals)
+/**
+ * Standard two-phase constructor.
+ */
+ {
+ CATNetworkInfo* netInfo = new(ELeave) CATNetworkInfo(aIo, aTelObject, aInit, aPhoneGlobals);
+ CleanupStack::PushL(netInfo);
+ netInfo->ConstructL();
+ CleanupStack::Pop();
+ return netInfo;
+ }
+
+CATNetworkInfo::CATNetworkInfo(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit,CPhoneGlobals* aPhoneGlobals)
+ : CATCommands(aIo,aTelObject,aInit,aPhoneGlobals)
+ ,iPhoneGlobals(aPhoneGlobals)
+ {}
+
+CATNetworkInfo::~CATNetworkInfo()
+/**
+ * Standard Destructor.
+ * Note the NULLing of the iATNetworkInfo pointer. This should prevent any unwanted calling
+ * of this function from the "end of command" sequence after the class' destruction.
+ */
+ {
+ iIo->RemoveExpectStrings(this);
+ iPhoneGlobals->iATNetworkInfo=NULL;
+ }
+
+void CATNetworkInfo::Start(TTsyReqHandle aTsyReqHandle,TAny* aParam)
+/**
+ * This is the standard entry point for retrieving the Network Information.
+ */
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tStarting Operator Info."));
+ iReqHandle = aTsyReqHandle;
+ if (aParam!=NULL)
+ {
+ TTsyNetworkInfo* info = static_cast<TTsyNetworkInfo*>(aParam);
+ iNetworkInfo.iNetworkInfoPckg = info->iNetworkInfoPckg;
+ iNetworkInfo.iArea = info->iArea;
+ }
+
+ //
+ // This object is not always started thru the CATBase::ExecuteCommand
+ // So we sometimes have to manually control the flow control of iEventSignalActive
+ iPhoneGlobals->iEventSignalActive = ETrue;
+ iCancelled=EFalse;
+
+ if (iReqHandle==0)
+ iTelObject->FlowControlSuspend();
+ StartGetOperator();
+ }
+
+void CATNetworkInfo::CheckOperator()
+/**
+ * This function is called whenever an EventSignal Completes. It is a second entry point for the command.
+ * It checks CPhoneGlobals iPhoneStatus.iNetworkChanged and calls this function if it detects that the
+ * networking information has changed and therefore the CPhoneGlobals data may be out of date and needs
+ * to be refreshed.
+ */
+ {
+ Start(0,0);
+ }
+
+
+void CATNetworkInfo::EventSignal(TEventSource aSource)
+/**
+ * This function contains the state machine for the command. The states flow consecutively and are
+ * described below.
+ *
+ * \par EATGetCurrentOperatorWriteComplete
+ * Wait for the "AT+COPS?" write to complete
+ *
+ * \par EATGetCurrentOperatorReadComplete
+ * Parse the "AT+COPS?" response. If it gets an "ERROR" back it assume that no COPS commands are
+ * supported, so complete the request with an error. If it is supported, parse the result and proceed
+ * to retrieve the numeric network code with "AT+COPS=3,2;+COPS?"
+ *
+ * \par EATNumericOperatorWaitForWriteComplete
+ * Wait for the "AT+COPS=3,2;+COPS?" to complete
+ *
+ * \par EATSetNumericOperatorReadComplete
+ * Parse the numeric network code if available. Proceed to retrieve the short network code with
+ * "AT+COPS=3,1;+COPS?".
+ *
+ * \par EATShortOperatorWaitForWriteComplete
+ * Wait for the "AT+COPS=3,1;+COPS?" write to complete.
+ *
+ * \par EATSetShortOperatorReadComplete
+ * Parse the short network name if available. Proceed to retrieve the long network name with
+ * "AT+COPS=3,0;+COPS?".
+ *
+ * \par EATLongOperatorWaitForWriteComplete
+ * Wait for the "AT+COPS=3,0;+COPS?" write to complete.
+ *
+ * \par EATSetLongOperatorReadComplete
+ * Parse the long network name if available. Proceed to complete the request.
+ * Check for outstanding current network operator notifications at this point.
+ *
+ * \par EATWaitForStopState
+ * This state is used when stopping the state machine to ensure that a pending modem response has been
+ * retrieved before freeing up the Multimode TSY to send more commands. Prematurely stopping the state machine
+ * is usually forced by a client cancel request.
+ *
+ * \par EATWaitForSettlingTimeout
+ * This state is used to provide a pause at the end of the network information queries. The Nokia 8210
+ * has been shown to require this, if it is not to arbitrarily error the next command.
+ */
+ {
+ if ((aSource==ETimeOutCompletion)&&(iState!=EATWaitForSettlingTimeout))
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tTimeout Error during Operator read"));
+ RemoveStdExpectStrings();
+ Complete(KErrTimedOut,aSource);
+ return;
+ }
+
+ switch(iState)
+ {
+ case EATGetCurrentOperatorWriteComplete:
+ __ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ StandardWriteCompletionHandler(aSource, 5);
+ iState=EATGetCurrentOperatorReadComplete;
+ }
+ break;
+
+ case EATGetCurrentOperatorReadComplete:
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ TInt ret(ValidateExpectString());
+ RemoveStdExpectStrings();
+ if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\t+COPS? not supported"));
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tSet Operator Command not supported")); // An assumption
+ Complete(ret, aSource); // No point in sending the Set Command.
+ }
+ else if (iCancelled)
+ {
+ Complete(KErrCancel, aSource); // Cancel state machine in safe place
+ }
+ else
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\t+COPS? supported"));
+ TRAPD(ret,ParseOperatorResponseL());
+ if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tError parsing +COPS?"));
+ }
+ iTxBuffer.Copy(KSetAndReadOperatorCommandNumeric); // AT+COPS=3,2;+COPS?
+ iIo->Write(this, iTxBuffer);
+ iIo->SetTimeOut(this, 5000);
+ iState=EATNumericOperatorWaitForWriteComplete;
+ }
+ }
+ break;
+
+ case EATNumericOperatorWaitForWriteComplete:
+ __ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ StandardWriteCompletionHandler(aSource, 5);
+ iState=EATSetNumericOperatorReadComplete;
+ }
+ break;
+
+ case EATSetNumericOperatorReadComplete:
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ TInt ret(ValidateExpectString());
+ RemoveStdExpectStrings();
+ if (iCancelled)
+ {
+ Complete(KErrCancel, aSource); // Cancel state machine in safe place
+ return;
+ }
+ else if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tAT+COPS=3,2 not supported"));
+ }
+ else // Set Operator Command was successful, Read the Current Operator
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\t AT+COPS=3,2 supported"));
+ TRAPD(ret,ParseOperatorResponseL());
+ if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tError parsing +COPS=3,2"));
+ }
+ }
+ iTxBuffer.Copy(KSetAndReadOperatorCommandShort); // AT+COPS=3,1;+COPS?
+ iIo->Write(this, iTxBuffer);
+ iIo->SetTimeOut(this, 5000);
+ iState=EATShortOperatorWaitForWriteComplete;
+ }
+ break;
+
+ case EATShortOperatorWaitForWriteComplete:
+ __ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ StandardWriteCompletionHandler(aSource, 5);
+ iState=EATSetShortOperatorReadComplete;
+ }
+ break;
+
+ case EATSetShortOperatorReadComplete:
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ TInt ret(ValidateExpectString());
+ RemoveStdExpectStrings();
+ if (iCancelled)
+ {
+ Complete(KErrCancel, aSource); // Cancel state machine in safe place
+ return;
+ }
+ else if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tAT+COPS=3,1 not supported"));
+ }
+ else// Set Operator Command was successful, Read the Current Operator
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\t AT+COPS=3,1 supported"));
+ TRAPD(ret,ParseOperatorResponseL());
+ if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tError parsing +COPS=3,1"));
+ }
+ }
+ iTxBuffer.Copy(KSetAndReadOperatorCommandLong); // AT+COPS=3,0;+COPS?
+ iIo->Write(this, iTxBuffer);
+ iIo->SetTimeOut(this, 5000);
+ iState=EATLongOperatorWaitForWriteComplete;
+ }
+ break;
+
+ case EATLongOperatorWaitForWriteComplete:
+ __ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ StandardWriteCompletionHandler(aSource, 5);
+ iState=EATSetLongOperatorReadComplete;
+ }
+ break;
+
+ case EATSetLongOperatorReadComplete:
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ TInt ret(ValidateExpectString());
+ RemoveStdExpectStrings();
+ if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\t+COPS=3,0 not supported"));
+ }
+ else // Set Operator cmd was successful, Read the Current Operator
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tAT+COPS=3,0 supported"));
+ TRAPD(ret,ParseOperatorResponseL());
+ if (ret != KErrNone)
+ {
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tError parsing +COPS=3,0"));
+ }
+ }
+
+ // Check outstanding current network operator notifications
+ iPhoneGlobals->iNotificationStore->CheckNotification(iTelObject,ECurrentNetworkChanged);
+
+ iIo->SetTimeOut(this, KSettlingPause*1000);
+ iState=EATWaitForSettlingTimeout;
+ }
+ break;
+
+ case EATWaitForSettlingTimeout:
+ __ASSERT_ALWAYS((aSource==ETimeOutCompletion),Panic(EATCommand_IllegalCompletionWriteExpected));
+ Complete(KErrNone,aSource);
+ break;
+
+ case EATWaitForStopState:
+ __ASSERT_ALWAYS(aSource==EReadCompletion, Panic(EATCommand_IllegalCompletionReadExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ Complete(KErrCancel, aSource);
+ }
+ break;
+
+ default:
+ break;
+ }//switch
+ }//EventSignal
+
+void CATNetworkInfo::Stop(TTsyReqHandle aTsyReqHandle)
+/**
+ * This function is used to prematurely stop the state machine. This would usually occur following a
+ * client cancel request.
+ */
+{
+ __ASSERT_ALWAYS(aTsyReqHandle == iReqHandle, Panic(EIllegalTsyReqHandle));
+ LOGTEXT(_L8("MMTsy:\tCATNetworkInfo:\tCancel called."));
+ iCancelled=ETrue;
+}
+
+
+void CATNetworkInfo::Complete(TInt aError,TEventSource aSource)
+/**
+ * This function completes the client's request.
+ */
+ {
+ iIo->WriteAndTimerCancel(this);
+ iIo->RemoveExpectStrings(this);
+ iOKExpectString = NULL;
+ iErrorExpectString = NULL;
+ if (aSource==EWriteCompletion)
+ iIo->Read();
+ iState = EATNotInProgress;
+ LOGTEXT2(_L8("MMTsy:CATNetworkInfo:\tCATNetworkInfo completed with error code : %d"), aError);
+ //
+ // BEWARE: The next command will be started from inside ReqCompleted or FlowControlResume
+ //
+ //
+ // This object is not always started thru the CATBase::ExecuteCommand
+ // So we sometimes have to manually control the flow control of iEventSignalActive
+ iPhoneGlobals->iEventSignalActive = EFalse;
+
+ if (iReqHandle)
+ {
+ // Explicit call from a client
+ if (aError==KErrNone)
+ {
+ GetCurrentNetworkInfo(&iNetworkInfo);
+ }
+ iTelObject->ReqCompleted(iReqHandle, aError);
+ }
+ else
+ {
+ // CheckOperator() call from CATCommands::Complete
+ iTelObject->FlowControlResume();
+ }
+ CATCommands::Complete(aError,aSource);
+ }
+
+void CATNetworkInfo::CompleteWithIOError(TEventSource /*aSource*/,TInt aStatus)
+/**
+ * This function handles I/O errors that may occur during any of the stages of the state machine.
+ */
+ {
+ if (iState!=EATNotInProgress)
+ {
+ iIo->WriteAndTimerCancel(this);
+ if (iReqHandle)
+ {
+ iTelObject->ReqCompleted(iReqHandle, aStatus);
+ }
+ else
+ {
+ // CheckOperator() call from CATCommands::Complete
+ iTelObject->FlowControlResume();
+ }
+ iState = EATNotInProgress;
+ }
+ }
+
+void CATNetworkInfo::StartGetOperator()
+/**
+ * This function kicks off the state machine by transmitting the first command, "AT+COPS?" and
+ * setting the state.
+ */
+ {
+ iPhoneGlobals->iPhoneStatus.iNetworkChanged=EFalse;
+ InitializeNetworkInfo(); // Initialize the TNetworkInfo struct that will contain the mobile's responses
+ iTxBuffer.Copy(KGetCurrentOperatorCommand);
+ iIo->Write(this, iTxBuffer);
+ iIo->SetTimeOut(this, 5000);
+ iState=EATGetCurrentOperatorWriteComplete;
+ }
+
+void CATNetworkInfo::InitializeNetworkInfo()
+/**
+ * This function is used to initialize (to zero) the network information elements in the CPhoneGlobals
+ * structure.
+ */
+ {
+ RMobilePhone::TMobilePhoneNetworkInfoV1& networkinfo = iPhoneGlobals->iPhoneStatus.iCurrentNetwork;
+
+ networkinfo.iMode = RMobilePhone::ENetworkModeUnknown;
+ networkinfo.iCountryCode.Zero(); // Unknown, MCC
+ networkinfo.iNetworkId.Zero(); // MNC
+ networkinfo.iCdmaSID.Zero(); // Unused CDMA field
+ networkinfo.iAnalogSID.Zero(); // Unused CDMA field
+ networkinfo.iShortName.Zero();
+ networkinfo.iLongName.Zero();
+ networkinfo.iStatus = RMobilePhone::ENetworkStatusUnknown;
+ networkinfo.iDisplayTag.Zero();
+ }
+
+void CATNetworkInfo::ParseOperatorResponseL()
+/**
+ * This function is used to parse the ME responses to commands to retrieve numeric, short name
+ * or long name network information. Possible responses are:
+ * +COPS: mode, 0, "long format name"
+ * +COPS: mode, 1, "short format name"
+ * +COPS: mode, 2, "operator ID in hex"
+ * +COPS: mode (no network information available)
+ *
+ * Relevant information is retrieved and written into the CPhoneGlobals class.
+ */
+ {
+ RMobilePhone::TMobilePhoneNetworkInfoV1& networkInfo = iPhoneGlobals->iPhoneStatus.iCurrentNetwork;
+
+ ParseBufferLC(); // Parse the buffer and create a linked list with the phone's response
+
+ CATParamListEntry* entry;
+ TDblQueIter<CATParamListEntry> iter(iRxResults);
+
+ // The 1st item in the list should be the +COPS: response
+ entry=iter++;
+ if (entry && entry->iResultPtr.MatchF(KOperatorResponse)!=0)
+ User::Leave(KErrGeneral);
+
+ // The next item is the mode (this information is not used)
+ entry=iter++;
+ if (!entry)
+ User::Leave(KErrGeneral);
+
+ // The next item should be the format. If there is no network information then this item
+ // would be empty. The network status is consequently updated.
+ entry=iter++;
+ if (!entry) // Not connected, so the response is "+COPS: 0"
+ networkInfo.iStatus=RMobilePhone::ENetworkStatusUnknown;
+ else
+ {
+ TInt format=CATParamListEntry::EntryValL(entry);
+
+ // If the format is available, the network name is the next item in the list
+ entry=iter++;
+ if (!entry)
+ User::Leave(KErrGeneral);
+ switch (format)
+ {
+ case 0:
+ if((entry->iResultPtr).Length() > networkInfo.iLongName.MaxLength())
+ networkInfo.iLongName.Copy((entry->iResultPtr).Mid(0,networkInfo.iLongName.MaxLength()));
+ else
+ networkInfo.iLongName.Copy(entry->iResultPtr);
+ break;
+ case 1:
+ if((entry->iResultPtr).Length() > networkInfo.iShortName.MaxLength())
+ networkInfo.iShortName.Copy((entry->iResultPtr).Mid(0,networkInfo.iShortName.MaxLength()));
+ else
+ networkInfo.iShortName.Copy(entry->iResultPtr);
+ break;
+ case 2:
+ User::LeaveIfError(NetworkIdL(entry->iResultPtr,networkInfo.iCountryCode, networkInfo.iNetworkId));
+ break;
+ default:
+ User::Leave(KErrGeneral);
+ break;
+ }
+
+ // We've got an answer, so this must be the current network
+ networkInfo.iStatus=RMobilePhone::ENetworkStatusCurrent;
+ }
+ CleanupStack::PopAndDestroy();
+ }
+
+void CATNetworkInfo::GetCurrentNetworkInfo(CATNetworkInfo::TTsyNetworkInfo* aNetworkInfo)
+/**
+ * This function checks to see if the network registration information in CPhoneGlobals is valid,
+ * and, if it is, it copies the CPhoneGlobals network information into the waiting client request
+ * buffer.
+ */
+ {
+ RMobilePhone::TMobilePhoneNetworkInfoV1& networkInfo = (*(aNetworkInfo->iNetworkInfoPckg))();
+ RMobilePhone::TMobilePhoneLocationAreaV1& areaInfo = *(aNetworkInfo->iArea);
+ RMobilePhone::TMobilePhoneRegistrationStatus status = iPhoneGlobals->iPhoneStatus.iRegistrationStatus;
+
+ if (status == RMobilePhone::ERegisteredOnHomeNetwork
+ || status == RMobilePhone::ERegisteredRoaming
+ || status == RMobilePhone::ERegistrationUnknown) // AT+CREG? is not supported, but info obtained during initialization is still valid. NickyM
+ {
+ RMobilePhone::TMobilePhoneNetworkInfoV1& info = iPhoneGlobals->iPhoneStatus.iCurrentNetwork;
+ RMobilePhone::TMobilePhoneLocationAreaV1& locationInfo = iPhoneGlobals->iPhoneStatus.iLocationArea;
+
+ networkInfo.iStatus = info.iStatus;
+ networkInfo.iCountryCode = info.iCountryCode;
+ networkInfo.iNetworkId = info.iNetworkId;
+ networkInfo.iCdmaSID = info.iCdmaSID; // for CDMA
+ networkInfo.iAnalogSID = info.iAnalogSID; // for CDMA
+ networkInfo.iShortName = info.iShortName;
+ networkInfo.iLongName = info.iLongName;
+ networkInfo.iDisplayTag = info.iLongName; // This TSY handles the display tag as the same as longname
+ networkInfo.iMode = iPhoneGlobals->iNetworkMode;
+ areaInfo.iAreaKnown = locationInfo.iAreaKnown;
+ areaInfo.iLocationAreaCode = locationInfo.iLocationAreaCode;
+ areaInfo.iCellId = locationInfo.iCellId;
+ }
+ else
+ {
+ networkInfo.iStatus = RMobilePhone::ENetworkStatusUnknown;
+ networkInfo.iShortName.Zero(); // Should this be .Zero() ?
+ networkInfo.iLongName.Zero(); // Should this be .Zero() ?
+ areaInfo.iAreaKnown = EFalse;
+ areaInfo.iLocationAreaCode = 0;
+ areaInfo.iCellId = 0;
+
+ }
+ return;
+ }
+
+
+// class CNotifyNetworkRegistrationStatusChange
+
+CNotifyNetworkRegistrationStatusChange* CNotifyNetworkRegistrationStatusChange::NewL(TTsyReqHandle aReqHandle,CTelObject* aTelObject,
+ RMobilePhone::TMobilePhoneRegistrationStatus* aRegStatus)
+ {
+ return new(ELeave) CNotifyNetworkRegistrationStatusChange(aReqHandle,aTelObject,aRegStatus);
+ }
+
+CNotifyNetworkRegistrationStatusChange::CNotifyNetworkRegistrationStatusChange(TTsyReqHandle aReqHandle,CTelObject* aTelObject,
+ RMobilePhone::TMobilePhoneRegistrationStatus* aRegStatus)
+ : CNotifyBase(aReqHandle,aTelObject)
+ {
+ iRegStatus = aRegStatus;
+ }
+
+CNotifyNetworkRegistrationStatusChange::~CNotifyNetworkRegistrationStatusChange()
+ {}
+
+TBool CNotifyNetworkRegistrationStatusChange::CheckAndCompleteNotification(CTelObject* aTelObject, TEvent aEvent, TEvent /*aLastEvent*/)
+/**
+ * This function completes a Registration status Notification.
+ */
+ {
+ if (aEvent!=ERegistrationStatusChanged)
+ return EFalse;
+
+ LOGTEXT2(_L8("Event %d:\tRegistration Status Changed Notification completed"),aEvent);
+ *iRegStatus = reinterpret_cast<CPhoneMobile*>(aTelObject)->RegistrationStatus();
+ iTelObject->ReqCompleted(iReqHandle,KErrNone);
+ return ETrue;
+ }
+
+// class CCurrentNetworkChangedNotify
+
+CNotifyCurrentNetworkChange* CNotifyCurrentNetworkChange::NewL(TTsyReqHandle aReqHandle,CTelObject* aTelObject,TInt* aInfo)
+ {
+ return new(ELeave) CNotifyCurrentNetworkChange(aReqHandle,aTelObject,aInfo);
+ }
+
+CNotifyCurrentNetworkChange::CNotifyCurrentNetworkChange(TTsyReqHandle aReqHandle,CTelObject* aTelObject,TInt* aInfo)
+ : CNotifyBase(aReqHandle,aTelObject)
+ {
+ CATNetworkInfo::TTsyNetworkInfo* info = reinterpret_cast<CATNetworkInfo::TTsyNetworkInfo*>(aInfo);
+ iNetworkInfo.iNetworkInfoPckg = info->iNetworkInfoPckg;
+ iNetworkInfo.iArea = info->iArea;
+ }
+
+CNotifyCurrentNetworkChange::~CNotifyCurrentNetworkChange()
+ {}
+
+TBool CNotifyCurrentNetworkChange::CheckAndCompleteNotification(CTelObject* aTelObject,TEvent aEvent,TEvent /*aLastEvent*/)
+/**
+ * This function completes a Current Network Change Notification.
+ */
+ {
+ if (aEvent!=ECurrentNetworkChanged)
+ return EFalse;
+
+ LOGTEXT2(_L8("Event %d:\tCurrent Network Changed Notification completed"),aEvent);
+// REINTERPRET_CAST(CPhoneMobile*,aTelObject)->CurrentNetworkInfo(&iNetworkInfo);
+ reinterpret_cast<CPhoneMobile*>(aTelObject)->CurrentNetworkInfo(&iNetworkInfo);
+ iTelObject->ReqCompleted(iReqHandle,KErrNone);
+ return ETrue;
+ }
+
+// Class CATDetectNetwork
+//
+// Detect all available networks.
+
+CATDetectNetwork::CATDetectNetwork(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit,CPhoneGlobals* aPhoneGlobals)
+ : CATCommands(aIo,aTelObject,aInit,aPhoneGlobals)
+ {}
+
+CATDetectNetwork* CATDetectNetwork::NewL(CATIO* aIo,CTelObject* aTelObject,CATInit* aInit,CPhoneGlobals* aPhoneGlobals)
+/**
+ * Standard 2 phase constructor.
+ */
+ {
+ CATDetectNetwork* self = new(ELeave) CATDetectNetwork(aIo, aTelObject, aInit, aPhoneGlobals);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+CATDetectNetwork::~CATDetectNetwork()
+/**
+ * Destructor.
+ */
+ {
+ iIo->RemoveExpectStrings(this);
+ }
+
+void CATDetectNetwork::Start(TTsyReqHandle aTsyReqHandle,TAny* aParam)
+/**
+ * This is the standard entry point for retrieving the detected Operator Information.
+ */
+ {
+ LOGTEXT(_L8("MMTsy:\tCATDetectNetwork:\tStarting Network detection"));
+ if (aParam != NULL)
+ {
+ TTsyDetectedNetworks* info = static_cast<TTsyDetectedNetworks* >(aParam);
+ iDetectedNetworks.iBufSize = info->iBufSize;
+ iDetectedNetworks.iBufPtr = info->iBufPtr;
+ }
+
+ iReqHandle = aTsyReqHandle;
+
+ WriteExpectingResults(KDetectNetworkCommand, 3);
+ __ASSERT_ALWAYS(iIo->AddExpectString(this,KNotifyMeIfErrorString) != NULL,Panic(EGeneral));
+ iState=EATDetectWaitForWriteComplete;
+ }
+
+void CATDetectNetwork::EventSignal(TEventSource aSource)
+/**
+ * This function contains the state machine for the command. The states flow consecutively and are
+ * described below.
+ *
+ * \par EATDetectWaitForWriteComplete
+ * Wait for the "AT+COPS=?" write to complete
+ *
+ * \par EATDetectReadComplete
+ * Reads the Modem's response to the AT+COPS=? command. If it gets an "ERROR" back it resets the
+ * timer and sets a new state (EATDetectExtendedReadComplete) and waits for another response.
+ *
+ * \par EATDetectExtendedReadComplete
+ * Reads the phone's response to the AT+COPS=? command and parses the response. Completes the
+ * request.
+ *
+ * \par EATWaitForStopState
+ * This state is used when stopping the state machine to ensure that a pending modem response has been
+ * retrieved before freeing up the Multimode TSY to send more commands. Prematurely stopping the state machine
+ * is usually forced by a client cancel request.
+ */
+ {
+ if (aSource==ETimeOutCompletion)
+ {
+ if (iState!=EATDetectExtendedReadComplete)
+ {
+ LOGTEXT(_L8("MmTsy:\tCATDetectNetwork:\tTimeout Error during Network Detect read"));
+ RemoveStdExpectStrings();
+ Complete(KErrTimedOut,aSource);
+ return;
+ }
+ else
+ {
+ // the phone really does not support +COPS=?, so report that error
+ RemoveStdExpectStrings();
+ Complete(KErrNotSupported,EReadCompletion);
+ return;
+ }
+ }
+
+ switch(iState)
+ {
+ case EATDetectWaitForWriteComplete:
+ __ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ iIo->SetTimeOut(this,45 * KOneSecondPause); // Some phones take a long time to detect all the networks
+ AddStdExpectStrings();
+ iState=EATDetectReadComplete;
+ }
+ break;
+
+ case EATDetectReadComplete:
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ iIo->WriteAndTimerCancel(this);
+ if (iIo->FoundChatString()==iErrorExpectString)
+ {
+ LOGTEXT(_L8("Modem returned ERROR - waiting for further response"));
+ iIo->ClearCurrentLine();
+ iIo->SetTimeOut(this,45 * KOneSecondPause);
+ iState = EATDetectExtendedReadComplete;
+ break;
+ }
+ // fall through ...
+
+ case EATDetectExtendedReadComplete:
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ iIo->WriteAndTimerCancel(this);
+ {
+ TInt ret(ValidateExpectString());
+ RemoveStdExpectStrings();
+ if (ret==KErrNone)
+ TRAP(ret,ParseResponseL());
+ Complete(ret,aSource); // The return value is set in the Complete methode
+ }
+ break;
+
+ case EATWaitForStopState:
+ __ASSERT_ALWAYS(aSource==EReadCompletion, Panic(EATCommand_IllegalCompletionReadExpected));
+ {
+ iIo->WriteAndTimerCancel(this);
+ Complete(KErrCancel, aSource);
+ }
+ break;
+
+ default:
+ break;
+ }//switch
+ }//EventSignal
+
+void CATDetectNetwork::Stop(TTsyReqHandle aTsyReqHandle)
+/**
+ * This function is used to prematurely stop the state machine. This would usually occur following a
+ * client cancel request.
+ */
+ {
+ __ASSERT_ALWAYS(aTsyReqHandle == iReqHandle, Panic(EIllegalTsyReqHandle));
+ LOGTEXT(_L8("MMTsy:\tCATDetectNetwork:\tCancel called."));
+ switch(iState)
+ {
+ case EATNotInProgress:
+ case EATDetectWaitForWriteComplete:
+ {
+ LOGTEXT2(_L8("Current state TSY is cancelling from %d"), iState);
+ Complete(KErrCancel, EReadCompletion);
+ }
+ break;
+
+ default:
+ {
+ LOGTEXT(_L8("MmTsy:\tCATDetectNetwork:\tStop, now waiting for expected modem response"));
+ AddStdExpectStrings();
+ iIo->SetTimeOut(this);
+ iState = EATWaitForStopState;
+ }
+ break;
+ }
+ }
+
+
+void CATDetectNetwork::Complete(TInt aError,TEventSource aSource)
+/**
+ * This function completes the client request.
+ */
+ {
+ iState = EATNotInProgress;
+ iIo->WriteAndTimerCancel(this);
+ iIo->RemoveExpectStrings(this);
+ iOKExpectString = NULL;
+ iErrorExpectString = NULL;
+ CATCommands::Complete(aError,aSource);
+
+ LOGTEXT2(_L8("MMTsy:CATDetectNetwork:\tCATDetectNetwork completed with error code : %d"), aError);
+ if (aError==KErrCancel)
+ {
+ CPhoneMobile* phone = static_cast<CPhoneMobile*>(iTelObject);
+ phone->CompleteDetectedNetworksCancel(iReqHandle);
+ }
+ else
+ iTelObject->ReqCompleted(iReqHandle, aError);
+ }
+
+void CATDetectNetwork::CompleteWithIOError(TEventSource /*aSource*/,TInt aStatus)
+/**
+ * This function handles I/O errors that may occur during any of the stages of the state machine.
+ */
+ {
+ if (iState!=EATNotInProgress)
+ {
+ iIo->WriteAndTimerCancel(this);
+ iState = EATNotInProgress;
+ iTelObject->ReqCompleted(iReqHandle, aStatus);
+ }
+ }
+
+void CATDetectNetwork::ParseResponseL()
+/**
+ * This function parses the phone's response to the Detect Networks command.
+ */
+ {
+ // should be
+ //
+ // +COPS: (status,"longname","shortname",code),... ,,(list),(list)
+ //
+ // but SH888 gives
+ //
+ // +COPS: (status,"longname","shortname",code)<cr><lf>
+ // +COPS: ...
+ //
+
+ CMobilePhoneNetworkList* list=CMobilePhoneNetworkList::NewL();
+ CleanupStack::PushL(list);
+
+ ParseBufferLC();
+
+ RMobilePhone::TMobilePhoneNetworkInfoV1 info;
+ // This TSY only supports GSM mode so we can hardcode this
+ info.iMode=RMobilePhone::ENetworkModeGsm;
+ TDblQueIter<CATParamListEntry> iter(iRxResults);
+ CATParamListEntry* entry=iter++;
+ if (entry)
+ {
+ if (entry->iResultPtr!=KOperatorResponse)
+ User::Leave(KErrGeneral);
+ //
+ entry=iter++;
+ if (!entry)
+ User::Leave(KErrGeneral);
+ for (;;)
+ {
+ info.iStatus = RMobilePhone::TMobilePhoneNetworkStatus(CATParamListEntry::EntryValL(entry));
+ //
+ entry=iter++;
+ if (!entry)
+ User::Leave(KErrGeneral);
+ info.iLongName.Copy(entry->iResultPtr);
+ //
+ entry=iter++;
+ if (!entry)
+ User::Leave(KErrGeneral);
+ if((entry->iResultPtr).Length() > info.iShortName.MaxLength())
+ info.iShortName.Copy((entry->iResultPtr).Mid(0,info.iShortName.MaxLength()));
+ else
+ info.iShortName.Copy(entry->iResultPtr);
+ //
+ entry=iter++;
+ if (!entry)
+ User::Leave(KErrGeneral);
+ User::LeaveIfError(NetworkIdL(entry->iResultPtr,info.iCountryCode, info.iNetworkId)); // MNC and MCC
+
+ list->AddEntryL(info);
+
+ entry=iter++;
+ if (!entry)
+ break;
+ if (entry->iResultPtr.Length()==0)
+ break;
+ if (entry->iResultPtr!=KOperatorResponse)
+ continue;
+ entry=iter++;
+ if (!entry)
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // results
+
+ *(iDetectedNetworks.iBufPtr) = list->StoreLC(); // Stream the list to optimice the size of it.
+ *(iDetectedNetworks.iBufSize) = (*(iDetectedNetworks.iBufPtr))->Size(); // Store the size of the streamed list to be passed back to the client.
+
+ CleanupStack::Pop(); // pop the CBufBase allocated by StoreLC
+ CleanupStack::PopAndDestroy(); // pop AND detroy the list.
+
+ } // End of ParseResponseL()
+
+
+