--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/atcommands/modematplugin/src/atcopscmd.cpp Wed Mar 31 21:51:05 2010 +0300
@@ -0,0 +1,1120 @@
+/*
+* Copyright (c) 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: Handles the commands "AT+COPS?", "AT+COPS=?" and "AT+COPS=..."
+*
+*/
+
+
+#include <mmtsy_names.h>
+#include "atcopscmd.h"
+#include "cmdpluginobserver.h"
+#include "debug.h"
+
+_LIT8( KCOPSTestCmd, "AT+COPS=?");
+_LIT8( KCOPSReadCmd, "AT+COPS?");
+_LIT8( KCOPSSetCmd, "AT+COPS=");
+
+_LIT8(KSupportedModesStr, ",(0,1,3,4)");
+_LIT8(KSupportedFormatsStr, ",(0,1,2)");
+
+// The parameters are in predefined indexes in an incoming AT command.
+const TInt KModeParameterIndex = 0;
+const TInt KFormatParameterIndex = 1;
+const TInt KOperatorParameterIndex = 2;
+const TInt KAccessTechnologyParameterIndex = 3;
+
+const TInt KMinimumParameterCountWhenModePresent = 1;
+const TInt KMinimumParameterCountWhenFormatPresent = 2;
+const TInt KMinimumParameterCountWhenOperatorPresent = 3;
+const TInt KMinimumParameterCountWhenAccTechPresent = 4;
+
+// These parameter lengths are derived from 3GPP TS 27.007 V8.4.1
+const TInt KShortOperatorNameFormatLength = 10;
+const TInt KLongOperatorNameFormatLength = 20;
+const TInt KNumericOperatorNameFormatLength = 5;
+const TInt KMaxNetworkTestResponseAdditionalSize = 17; // The maximun length of parts of fixed length.
+const TInt KMaxNetworkReadResponseAdditionalSize = 28 ; // The maximun length of parts fixed length.
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CATCOPSCmd* CATCOPSCmd::NewL( MCmdPluginObserver* aCallback )
+ {
+ CATCOPSCmd* self = new (ELeave) CATCOPSCmd( aCallback );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CATCOPSCmd::~CATCOPSCmd()
+ {
+ iParamArray.ResetAndDestroy();
+ iParamArray.Close();
+ iPacketService.Close();
+ iCustomApi.Close();
+ iPhone.Close();
+ iServer.Close();
+ delete iDetectedNetworks;
+ delete iRetrieveDetectedNetworks;
+ }
+
+// ---------------------------------------------------------------------------
+// CATCOPSCmd::CATCOPSCmd
+// ---------------------------------------------------------------------------
+//
+CATCOPSCmd::CATCOPSCmd( MCmdPluginObserver* aCallback ) :
+ CActive(EPriorityStandard),
+ iCallback( aCallback ),
+ iFormat(RMmCustomAPI::EOperatorNameMccMnc),
+ iRegistrationMode(EModeAutomatic),
+ iAccTech(EAccTechNotSet),
+ iCurrentOperation(EIdle)
+ {
+ iCmdHandlerType = ECmdHandlerTypeUndefined;
+ }
+
+// ---------------------------------------------------------------------------
+// CATCOPSCmd::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::ConstructL()
+ {
+ if ( !iCallback )
+ {
+ User::Leave( KErrGeneral );
+ }
+ CActiveScheduler::Add(this);
+ LEAVE_IF_ERROR(iServer.Connect());
+ LEAVE_IF_ERROR(iServer.LoadPhoneModule(KMmTsyModuleName));
+ LEAVE_IF_ERROR(iPhone.Open(iServer, KMmTsyPhoneName));
+ LEAVE_IF_ERROR(iCustomApi.Open(iPhone));
+ LEAVE_IF_ERROR(iPacketService.Open(iPhone));
+ iRetrieveDetectedNetworks = CRetrieveMobilePhoneDetectedNetworks::NewL(iPhone);
+ }
+
+// ---------------------------------------------------------------------------
+// Reports the support status of an AT command. This is a synchronous API.
+// ---------------------------------------------------------------------------
+//
+TBool CATCOPSCmd::IsCommandSupported( const TDesC8& aCmd )
+ {
+ TRACE_FUNC_ENTRY
+ TInt retTemp = KErrNone;
+
+ // First test if "test" command, because the pattern is similar with the "set" command,
+ // this is just one extra question mark longer than that.
+ retTemp = aCmd.Compare( KCOPSTestCmd );
+ if ( retTemp == 0 )
+ {
+ iCmdHandlerType = ECmdHandlerTypeTest;
+ TRACE_FUNC_EXIT
+ return ETrue;
+ }
+
+ retTemp = aCmd.Compare( KCOPSReadCmd );
+ if ( retTemp == 0 )
+ {
+ iCmdHandlerType = ECmdHandlerTypeRead;
+ TRACE_FUNC_EXIT
+ return ETrue;
+ }
+
+ // Test if the beginning matches the test command pattern. We're skipping parameters
+ // here on purpose, because "set" handler will create an error reply later if
+ // parameters are not valid.
+ retTemp = aCmd.Left(KCOPSSetCmd().Length()).Compare(KCOPSSetCmd);
+ if ( retTemp == 0 )
+ {
+ iCmdHandlerType = ECmdHandlerTypeSet;
+ TRACE_FUNC_EXIT
+ return ETrue;
+ }
+
+ iCmdHandlerType = ECmdHandlerTypeUndefined;
+ TRACE_FUNC_EXIT
+ return EFalse;
+ }
+
+// ---------------------------------------------------------------------------
+// Handles an AT command. Cancelling of the pending request is done by
+// HandleCommandCancel(). The implementation in the extension plugin should
+// be asynchronous.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::HandleCommand( const TDesC8& aCmd,
+ RBuf8& aReply,
+ TBool aReplyNeeded )
+ {
+ TRACE_FUNC_ENTRY
+
+ if ( !aReplyNeeded )
+ {
+ TRACE_FUNC_EXIT
+ return;
+ }
+
+ if(iCurrentOperation != EIdle)
+ {
+ // only one call at time allowed. If another one is passed in,
+ // then cancel the previous and reply with an error.
+ HandleCommandCancel();
+ CreateReply(EFalse);
+ }
+
+ if ( iCmdHandlerType == ECmdHandlerTypeUndefined )
+ {
+ CreateReply(EFalse);
+ }
+
+ if ( iCmdHandlerType == ECmdHandlerTypeTest )
+ {
+ // Collect network data and complete in RunL
+ iRetrieveDetectedNetworks->StartV2(iStatus);
+ iCurrentOperation = EListAvailableNetworkOperators;
+ SetActive();
+ TRACE_FUNC_EXIT
+ return;
+ }
+
+/*
+Read command returns the current mode, the currently selected operator
+and the current Access Technology. If no operator is selected, <format>,
+<oper> and < AcT> are omitted.
+*/
+ if ( iCmdHandlerType == ECmdHandlerTypeRead )
+ {
+ // Collect data in two steps. First read operator name. Continue in RunL()
+ RMobilePhone::TMobilePhoneNetworkSelectionV1 selection;
+ RMobilePhone::TMobilePhoneNetworkSelectionV1Pckg nwSelectionSetting(selection);
+ iPhone.GetNetworkSelectionSetting(nwSelectionSetting);
+ switch(selection.iMethod)
+ {
+ case RMobilePhone::ENetworkSelectionAutomatic:
+ iRegistrationMode = EModeAutomatic;
+ break;
+ case RMobilePhone::ENetworkSelectionManual:
+ iRegistrationMode = EModeManual;
+ break;
+ default:
+ // Cannot get a known selection mode!
+ TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- Cannot get a known selection mode!"));
+ CreateReply(EFalse);
+ TRACE_FUNC_EXIT
+ return;
+ }
+ RMobilePhone::TMobilePhoneNetworkInfoV2Pckg nwInfo(iNetworkInfo);
+ iPhone.GetCurrentNetwork(iStatus, nwInfo);
+ iCurrentOperation = EGetNetworkInfoOperatorName;
+ SetActive();
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation));
+ TRACE_FUNC_EXIT
+ return;
+ }
+
+ // Getting this far means ECmdHandlerTypeSet. There must be parameter(s), too.
+ TRAPD(err, ExtractParametersL(aCmd));
+
+ // Check that we got some parameters, at least the "mode". If not, return an error:
+ if(iParamArray.Count() < KMinimumParameterCountWhenModePresent)
+ {
+ // Return error response, there were no parameters!
+ TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- no parameters!"));
+ CreateReply(EFalse);
+ TRACE_FUNC_EXIT
+ return;
+ }
+
+ // At least the mode parameter is present at this point. Inspect it and check other parameters.
+ TNetworkRegistrationMode mode;
+ err = GetModeAndCheckParameterCount(iParamArray[KModeParameterIndex]->Des(), mode);
+ if(err != KErrNone)
+ {
+ // Return error response, invalid mode or other parameters!
+ TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- invalid mode or other parameters!"));
+ CreateReply(EFalse);
+ TRACE_FUNC_EXIT
+ return;
+ }
+
+ // At this point the iRegistrationMode is stored and the parameters are valid.
+ iRegistrationMode = mode;
+ TRACE_INFO(( _L("CATCOPSCmd::HandleCommand() mode stored (%d)"), iRegistrationMode));
+
+ if(iParamArray.Count() > 1)
+ {
+ // If also format is present, extract it and store for later reference.
+ RMmCustomAPI::TOperatorNameType format;
+ err = GetFormatFromParameter(iParamArray[KFormatParameterIndex]->Des(), format);
+ if(err != KErrNone)
+ {
+ // Return an error, invalid format.
+ // Previously set format is still in use.
+ TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- invalid format!"));
+ CreateReply(EFalse);
+ TRACE_FUNC_EXIT
+ return;
+ }
+ // Format parameter is OK, keep it.
+ iFormat = format;
+ TRACE_INFO(( _L("CATCOPSCmd::HandleCommand() format stored (%d)"), iFormat));
+ }
+
+ // We're done with the required parameters, it's time to start processing the command.
+ // So do a self complete and continue in RunL():
+ iReply = &aReply; // Store the reply for later reference in RunL.
+ iCurrentOperation = EInspectModeAndProcessCommand;
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation));
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Parses the aCmd parameter and stores results in iParamArray.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::ExtractParametersL(const TDesC8& aCmd)
+ {
+ TRACE_FUNC_ENTRY
+
+ TRACE_INFO(( _L8("CATCOPSCmd::ExtractParameters() extracting (%S)"), &aCmd));
+
+ TPtrC8 parameters = aCmd.Right(aCmd.Length() - KCOPSSetCmd().Length());
+
+ iParamArray.ResetAndDestroy();
+
+ // Parse the parameters into the parameter array:
+ TInt separatorPos;
+ while((separatorPos = parameters.Locate(',')) != KErrNotFound)
+ {
+ TRACE_INFO(( _L("CATCOPSCmd::ExtractParameters() separator position (%d)"), separatorPos));
+ TPtrC8 param = parameters.Left(separatorPos);
+ parameters.Set(parameters.Right(parameters.Length() - (separatorPos + 1))); // Remove the extracted part + separator
+ HBufC8 *heapParam = param.AllocL();
+ CleanupStack::PushL( heapParam );
+ // Strip the quotation marks from the parameter:
+ TPtr8 ptr = heapParam->Des();
+ RemoveQuotationMarks(ptr);
+ TRACE_INFO(( _L8("CATCOPSCmd::ExtractParameters() appending (%S)"), &ptr));
+ iParamArray.Append(heapParam);
+ CleanupStack::Pop( heapParam );
+ }
+
+ // Finally append the last piece of parameters:
+ HBufC8 *param = parameters.AllocL();
+ CleanupStack::PushL( param );
+ TPtr8 ptr = param->Des();
+ RemoveQuotationMarks(ptr);
+ TRACE_INFO(( _L8("CATCOPSCmd::ExtractParameters() appending (%S)"), &ptr));
+ iParamArray.Append(param);
+ CleanupStack::Pop( param );
+
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Strips all quotation parms from the string passed in.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::RemoveQuotationMarks(TPtr8& aParameter)
+ {
+ TRACE_FUNC_ENTRY
+ // Strip the quotation marks from the parameter:
+ TInt quotePos;
+ while((quotePos = aParameter.Locate('"')) != KErrNotFound)
+ {
+ aParameter.Delete(quotePos,1);
+ }
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// Returns the selected mode in aMode and checks the parameter count.
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::GetModeAndCheckParameterCount(const TDesC8& aParameter, TNetworkRegistrationMode &aMode)
+ {
+ TRACE_FUNC_ENTRY
+ TLex8 lex;
+ lex.Assign(aParameter);
+ TInt mode(0);
+
+ TInt err = lex.Val(mode);
+ TRACE_INFO(( _L("CATCOPSCmd::GetModeAndCheckParameterCount() mode (%d)"), mode));
+
+ if( err != KErrNone )
+ {
+ TRACE_INFO(_L("CATCOPSCmd::GetModeAndCheckParameterCount() TLex error!)"));
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ if(mode < EModeAutomatic || mode > EModeManualAutomatic || mode == EModeDeregister)
+ {
+ // Not a valid mode.
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ if( (mode == EModeManual || mode == EModeManualAutomatic) && iParamArray.Count() < KMinimumParameterCountWhenOperatorPresent )
+ {
+ // Valid modes but not enough parameters. At least format and operator needed.
+ TRACE_INFO(( _L("CATCOPSCmd::GetModeAndCheckParameterCount() not enough parameters (%d)"), iParamArray.Count()));
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+ if( mode == EModeSetFormatParameter && iParamArray.Count() < KMinimumParameterCountWhenFormatPresent )
+ {
+ // Valid mode, but not enough parameters. Format is needed.
+ TRACE_INFO(_L("CATCOPSCmd::GetModeAndCheckParameterCount() no format parameter)"));
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ // Valid mode and enough parameters.
+ aMode = static_cast<TNetworkRegistrationMode>(mode);
+
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Converts an AT command parameter to numeric format value and checks it is valid.
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::GetFormatFromParameter(const TDesC8& aParameter, RMmCustomAPI::TOperatorNameType &aFormat)
+ {
+ TRACE_FUNC_ENTRY
+ TLex8 lex;
+ lex.Assign(aParameter);
+ TInt format(0);
+ TInt err = lex.Val(format);
+
+ if(err != KErrNone)
+ {
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+ switch(format)
+ {
+ case EFormatLong: // long by 3GPP TS 27.007 V8.4.1
+ TRACE_INFO(_L("Format is long by 3GPP TS 27.007 V8.4.1"));
+ aFormat = RMmCustomAPI::EOperatorNameNitzFull;
+ break;
+ case EFormatShort: // short by 3GPP TS 27.007 V8.4.1
+ TRACE_INFO(_L("Format is short by 3GPP TS 27.007 V8.4.1"));
+ aFormat = RMmCustomAPI::EOperatorNameNitzShort;
+ break;
+ case EFormatNumeric: // numeric by 3GPP TS 27.007 V8.4.1
+ TRACE_INFO(_L("Format is numeric by 3GPP TS 27.007 V8.4.1"));
+ aFormat = RMmCustomAPI::EOperatorNameMccMnc;
+ // Operator is numeric, conver it into S60 style.
+ break;
+ default:
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Converts an AT command parameter to numeric access technology value and checks it is valid.
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::GetAccTechFromParameter(const TDesC8& aParameter, TAccessTechnology& aAccTech)
+ {
+ TRACE_FUNC_ENTRY
+ TLex8 lex;
+ lex.Assign(aParameter);
+ TInt accTech(0);
+ TInt err = lex.Val(accTech);
+
+ if(err != KErrNone)
+ {
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ if(accTech != EGSM && accTech != EUDMA) // The only allowed access technologies.
+ {
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ aAccTech = static_cast<TAccessTechnology>(accTech);
+
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Converts an AT command parameter to ETel compatible operator values
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::ConvertOperatorToMccMnc(const CMobilePhoneNetworkListV2 *aDetectedNetworks,
+ const RMmCustomAPI::TOperatorNameType aFormat,
+ const TBuf<KMaxOperatorNameLength>& aOperatorParameter,
+ RMobilePhone::TMobilePhoneNetworkCountryCode& aMcc,
+ RMobilePhone::TMobilePhoneNetworkIdentity& aMnc)
+ {
+ TRACE_FUNC_ENTRY
+
+ if(aFormat == RMmCustomAPI::EOperatorNameMccMnc)
+ {
+ // Check first that there are at least five characters passed in.
+ TChar nextChar;
+ if(aOperatorParameter.Length() < 5)
+ {
+ return KErrArgument;
+ }
+ for(int i = 0; i < 5; ++i)
+ {
+ nextChar = aOperatorParameter[i];
+ if(!nextChar.IsDigit())
+ {
+ return KErrArgument;
+ }
+ }
+ // Operator is in three digit country code + two digit network code format.
+ // Must be converted to ETel style. The possible extra will be simply discarded.
+ TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() operator is all digits, convert it into ETel data types."));
+ aMcc.Copy(aOperatorParameter.Left(3));
+ aMnc.Copy(aOperatorParameter.Right(2));
+ }
+ else // The short or long text string formats.
+ {
+ // Find the requested operator from the operator array.
+ // If array is empty, return an error.
+ if(!aDetectedNetworks)
+ {
+ TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() No detected networks!"));
+ TRACE_FUNC_EXIT
+ return KErrNotFound;
+ }
+
+ RMobilePhone::TMobilePhoneNetworkInfoV2 nwInfo;
+ for(TInt i=0; i < iDetectedNetworks->Enumerate(); ++i)
+ {
+ TRAPD(err, nwInfo = iDetectedNetworks->GetEntryL(i))
+ if(err != KErrNone)
+ {
+ return KErrNotFound;
+ }
+
+ if(aFormat == RMmCustomAPI::EOperatorNameNitzShort)
+ {
+ TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Operator is in short format, comparing."));
+ if(nwInfo.iShortName.Compare(aOperatorParameter) == 0)
+ {
+ TRACE_INFO(_L("Match found."));
+ aMcc = nwInfo.iCountryCode;
+ aMnc = nwInfo.iNetworkId;
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+ }
+ else if(aFormat == RMmCustomAPI::EOperatorNameNitzFull)
+ {
+ TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Operator is in long format, comparing."));
+ if(nwInfo.iLongName.Compare(aOperatorParameter) == 0)
+ {
+ TRACE_INFO(_L("Match found."));
+ aMcc = nwInfo.iCountryCode;
+ aMnc = nwInfo.iNetworkId;
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+ }
+ else
+ {
+ TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Unknown operator format!"));
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+ }
+ TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Operator was not found in list!"));
+ TRACE_FUNC_EXIT
+ return KErrNotFound;
+ }
+
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Initiates an automatic network registration.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::AutomaticNetworkRegistration()
+ {
+ TRACE_FUNC_ENTRY
+ RMobilePhone::TMobilePhoneNetworkManualSelection nwInfo;
+ iCurrentOperation = EAutomaticallyRegisterToNetwork;
+ nwInfo.iCountry = KNullDesC;
+ nwInfo.iNetwork = KNullDesC;
+ iPhone.SelectNetwork(iStatus, EFalse, nwInfo);
+ SetActive(); // Response will be sent in RunL
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation));
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Initiates a manual network registration.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::ManualNetworkRegistration(const RMobilePhone::TMobilePhoneNetworkCountryCode& aMcc,
+ const RMobilePhone::TMobilePhoneNetworkIdentity& aMnc)
+ {
+ TRACE_FUNC_ENTRY
+ RMobilePhone::TMobilePhoneNetworkManualSelection nwInfo;
+ iCurrentOperation = EManuallyRegisterToNetwork;
+ nwInfo.iCountry.Append(aMcc);
+ nwInfo.iNetwork.Append(aMnc);
+ iPhone.SelectNetwork(iStatus, ETrue, nwInfo);
+ SetActive(); // Response will be sent in RunL
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation));
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Initiates a manual network registration and access technology selection.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::ManualNetworkRegistration(const RMobilePhone::TMobilePhoneNetworkCountryCode& aMcc,
+ const RMobilePhone::TMobilePhoneNetworkIdentity& aMnc,
+ const TAccessTechnology aAccTech)
+ {
+ TRACE_FUNC_ENTRY
+ // Store access technology for later reference:
+ iAccTech = aAccTech;
+ // Call another overload to start the first phase of the operation:
+ ManualNetworkRegistration(aMcc, aMnc);
+ // Set the state again so the RunL knows to launch the next phase:
+ iCurrentOperation = EManuallyRegisterToNetworkAndChooseAccTech;
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation));
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// CATCOPSCmd::RunL
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::RunL()
+ {
+ TRACE_FUNC_ENTRY
+ TInt err = KErrNone;
+ if(iStatus != KErrNone)
+ {
+ HandleError();
+ TRACE_FUNC_EXIT
+ return;
+ }
+ // Proceed to next step or return a response if all is done.
+ switch(iCurrentOperation)
+ {
+ case EListAvailableNetworkOperators:
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation));
+ if(iDetectedNetworks)
+ {
+ delete iDetectedNetworks;
+ iDetectedNetworks = NULL;
+ }
+ iDetectedNetworks = iRetrieveDetectedNetworks->RetrieveListV2L();
+ // Then create a response.
+ TRAP(err, ConstructNetworkListResponseL());
+ if(err != KErrNone)
+ {
+ // An error here means that no response has been sent. Reply with an error.
+ CreateReply(EFalse);
+ }
+ break;
+
+ case EInspectModeAndProcessCommand:
+ // Check the mode and act accordingly
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation));
+ err = InspectModeAndProcessCommand();
+ if(err != KErrNone)
+ {
+ CreateReply(EFalse);
+ }
+ break;
+
+ case EGetNetworkInfoOperatorName:
+ if(ConstructNetworkInfoResponse() != KErrNone)
+ {
+ // An error means that no response has been sent. Reply with an error.
+ CreateReply(EFalse);
+ }
+ break;
+
+ case EManuallyRegisterToNetworkAndChooseAccTech:
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation));
+ switch(iAccTech)
+ {
+ case EGSM:
+ iCustomApi.SetSystemNetworkMode(iStatus, RMmCustomAPI::KCapsNetworkModeGsm);
+ iCurrentOperation = ESetSystemNetworkBand;
+ SetActive();
+ break;
+ case EUDMA:
+ iCustomApi.SetSystemNetworkMode(iStatus, RMmCustomAPI::KCapsNetworkModeUmts);
+ iCurrentOperation = ESetSystemNetworkBand;
+ SetActive();
+ break;
+ default:
+ // No automatic registering requested, so send back an error response.
+ TRACE_INFO( _L("CATCOPSCmd::RunL() incorrect acc.tech., reply an error."));
+ CreateReply(EFalse);
+ }
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation));
+ break;
+
+ case EManuallyRegisterToNetwork:
+ case EAutomaticallyRegisterToNetwork:
+ case ESetSystemNetworkBand:
+ TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation));
+ // Last step completed successfully, so create OK response.
+ CreateReply(ETrue);
+ break;
+
+ default:
+ TRACE_INFO(( _L("CATCOPSCmd::RunL() default operation (%d)!"), iCurrentOperation));
+ break;
+ }
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Handles an error in async call.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::HandleError()
+ {
+ TRACE_FUNC_ENTRY
+ TRACE_INFO(( _L("CATCOPSCmd::RunL() failure (%d) in operation (%d)!"), iStatus.Int(), iCurrentOperation));
+
+ // In case of failure check the operation. In some cases failures are OK.
+ switch(iCurrentOperation)
+ {
+ case EManuallyRegisterToNetwork:
+ if(iRegistrationMode == EModeManualAutomatic)
+ {
+ // Manual registration failed, try automatic next.
+ TRACE_INFO( _L("CATCOPSCmd::RunL() registration mode manual automatic, try automatic."));
+ AutomaticNetworkRegistration();
+ }
+ else
+ {
+ // No automatic registering requested, so send back an error response.
+ TRACE_INFO( _L("CATCOPSCmd::RunL() reply an error."));
+ CreateReply(EFalse);
+ }
+ break;
+ case ESetSystemNetworkBand:
+ case EManuallyRegisterToNetworkAndChooseAccTech:
+ if(iRegistrationMode == EModeManualAutomatic)
+ {
+ // Manual registration failed, try automatic next.
+ TRACE_INFO( _L("CATCOPSCmd::RunL() registration mode manual automatic, try automatic."));
+ AutomaticNetworkRegistration();
+ break;
+ }
+ else
+ {
+ // Cannot set the access technology, so set it back to EAccTechNotSet.
+ // This prevents replying to queries with outdated or incorrect acc tech information.
+ TRACE_INFO( _L("CATCOPSCmd::RunL() couldn't set system network band, so reset access tech."));
+ iAccTech = EAccTechNotSet;
+ // Fall through to default, because these require an error response.
+ }
+ default:
+ // In all other cases send back an error response.
+ TRACE_INFO( _L("CATCOPSCmd::RunL() reply an error."));
+ CreateReply(EFalse);
+ break;
+ }
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// Cancels a pending HandleCommand request.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::HandleCommandCancel()
+ {
+ TRACE_FUNC_ENTRY
+ Cancel();
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// CATCOPSCmd::DoCancel
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::DoCancel()
+ {
+ TRACE_FUNC_ENTRY
+ switch(iCurrentOperation)
+ {
+ case EAutomaticallyRegisterToNetwork:
+ case EManuallyRegisterToNetwork:
+ case EManuallyRegisterToNetworkAndChooseAccTech:
+ iPhone.CancelAsyncRequest(EMobilePhoneSelectNetworkCancel);
+ break;
+ case EGetNetworkInfoOperatorName:
+ iPhone.CancelAsyncRequest(EMobilePhoneGetCurrentNetworkCancel);
+ break;
+ case ESetSystemNetworkBand:
+ iCustomApi.CancelAsyncRequest(ECustomSetSystemNetworkModeIPC);
+ break;
+ case EListAvailableNetworkOperators:
+ iRetrieveDetectedNetworks->Cancel();
+ break;
+ default:
+ break;
+ }
+
+ iCurrentOperation = EIdle;
+
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Helper method for RunL()
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::InspectModeAndProcessCommand()
+ {
+ TRACE_FUNC_ENTRY
+ TBuf<KMaxOperatorNameLength> buf;
+ TInt err;
+
+ switch (iRegistrationMode)
+ {
+ case EModeAutomatic:
+ AutomaticNetworkRegistration();
+ break;
+ case EModeManual:
+ case EModeManualAutomatic: // see also RunL()
+ if(iParamArray.Count() < KMinimumParameterCountWhenOperatorPresent)
+ {
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ // At least the operator is present, so convert it into S60 format.
+ buf.Copy(iParamArray[KOperatorParameterIndex]->Des());
+ err = ConvertOperatorToMccMnc(iDetectedNetworks, iFormat, buf, iMcc, iMnc);
+ if(err != KErrNone)
+ {
+ TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- operator conversion failed!"));
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+
+ if (iParamArray.Count() >= KMinimumParameterCountWhenAccTechPresent)
+ {
+ // Also access tech. is present. Convert it to ETel compatible value.
+ TAccessTechnology accTech;
+ TInt err = GetAccTechFromParameter(iParamArray[KAccessTechnologyParameterIndex]->Des(), accTech);
+ if(err != KErrNone)
+ {
+ // Parameter problem, return an error.
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ }
+ // Register both operator and access technology manually.
+ ManualNetworkRegistration(iMcc, iMnc, accTech);
+ }
+ else
+ {
+ // No access technology parameter, so register just the operator.
+ ManualNetworkRegistration(iMcc, iMnc);
+ }
+ break;
+ case EModeDeregister: // Deregister from network
+ // Not supported, return an error.
+ TRACE_FUNC_EXIT
+ return KErrArgument;
+ case EModeSetFormatParameter:
+ // Storing format parameter was done already, so just reply OK.
+ CreateReply(ETrue);
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ default:
+ return KErrArgument;
+ }
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Converts the ETel access technology into 3GPP TS 27.007 V8.4.1 compatible format.
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::SolveAccessTechnology(RMobilePhone::TMobilePhoneNetworkAccess &aAccessTech)
+ {
+ TRACE_FUNC_ENTRY
+
+ TUint caps;
+ if(iPacketService.GetStaticCaps(caps, RPacketContext::EPdpTypePPP) != KErrNone)
+ {
+ TRACE_FUNC_EXIT
+ return KErrGeneral;
+ }
+
+ TRACE_INFO(( _L8("CATCOPSCmd::SolveAccessTechnology() static caps gotten (%b)"), caps));
+
+ switch(aAccessTech)
+ {
+ case RMobilePhone::ENetworkAccessGsm:
+ if(caps & RPacketService::KCapsEGPRSSupported)
+ {
+ iAccTech = EGSMwithEGPRS;
+ }
+ else
+ {
+ iAccTech = EGSM;
+ }
+ break;
+ case RMobilePhone::ENetworkAccessGsmCompact:
+ iAccTech = EGSMCompact;
+ break;
+ case RMobilePhone::ENetworkAccessUtran:
+ if(caps & RPacketService::KCapsHSDPASupported)
+ {
+ if(caps & RPacketService::KCapsHSUPASupported)
+ {
+ iAccTech = EUDMAwithHSDPAandHSUPA;
+ }
+ else
+ {
+ iAccTech = EHSDPA;
+ }
+ }
+ else if(caps & RPacketService::KCapsHSUPASupported)
+ {
+ iAccTech = EHSUPA;
+ }
+ else
+ {
+ iAccTech = EUDMA;
+ }
+ break;
+ default:
+ TRACE_INFO( _L("CATCOPSCmd::SolveAccessTechnology() unknown access tech!"));
+ iAccTech = EAccTechNotSet;
+ return KErrArgument;
+ }
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Contructs a response for the read command.
+// ---------------------------------------------------------------------------
+//
+TInt CATCOPSCmd::ConstructNetworkInfoResponse()
+ {
+ TRACE_FUNC_ENTRY
+ RBuf8 reply;
+ TInt size(KMaxNetworkTestResponseAdditionalSize + KLongOperatorNameFormatLength);
+ TChar carriageReturn;
+ TChar lineFeed;
+ TInt err;
+ err = reply.Create(size);
+ err |= iCallback->GetCharacterValue( ECharTypeCR, carriageReturn );
+ err |= iCallback->GetCharacterValue( ECharTypeLF, lineFeed );
+ if(err != KErrNone)
+ {
+ return err;
+ }
+
+ // Some PC Software expects and extra CR+LF, hence those are added twice:
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+ reply.Append(_L("+COPS: "));
+ reply.AppendNum(iRegistrationMode);
+ reply.Append(_L(","));
+ switch(iFormat)
+ {
+ case RMmCustomAPI::EOperatorNameNitzFull:
+ reply.AppendNum(EFormatLong);
+ reply.Append(_L(","));
+ reply.Append(_L("\""));
+ TRACE_INFO(( _L8("CATCOPSCmd::ConstructNetworkInfoResponse() appending (%S)"),
+ &iNetworkInfo.iLongName));
+ reply.Append(iNetworkInfo.iLongName);
+ break;
+ case RMmCustomAPI::EOperatorNameNitzShort:
+ reply.AppendNum(EFormatShort);
+ reply.Append(_L(","));
+ reply.Append(_L("\""));
+ TRACE_INFO(( _L8("CATCOPSCmd::ConstructNetworkInfoResponse() appending (%S)"),
+ &iNetworkInfo.iShortName));
+ reply.Append(iNetworkInfo.iShortName);
+ break;
+ case RMmCustomAPI::EOperatorNameMccMnc:
+ reply.AppendNum(EFormatNumeric);
+ reply.Append(_L(","));
+ reply.Append(_L("\""));
+ TRACE_INFO(( _L8("CATCOPSCmd::ConstructNetworkInfoResponse() appending codes (%S) and (%S)"),
+ &iNetworkInfo.iCountryCode, &iNetworkInfo.iNetworkId));
+ reply.Append(iNetworkInfo.iCountryCode);
+ reply.Append(iNetworkInfo.iNetworkId);
+ break;
+ }
+ reply.Append(_L("\""));
+
+ if(SolveAccessTechnology(iNetworkInfo.iAccess) == KErrNone && iAccTech != EAccTechNotSet)
+ {
+ TRACE_INFO((_L("CATCOPSCmd::ConstructNetworkInfoResponse() appending acc. tech. (%d)"),
+ iAccTech));
+ reply.Append(_L(","));
+ reply.AppendNum(iAccTech);
+ }
+
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+
+ CreateReply(ETrue, reply);
+
+ TRACE_FUNC_EXIT
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Contructs a response for the test command.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::ConstructNetworkListResponseL()
+ {
+ TRACE_FUNC_ENTRY
+ RBuf8 reply;
+ TChar carriageReturn;
+ TChar lineFeed;
+
+ TInt maxItemSize(KMaxNetworkReadResponseAdditionalSize
+ + KShortOperatorNameFormatLength
+ + KLongOperatorNameFormatLength
+ + KNumericOperatorNameFormatLength
+ + KSupportedModesStr().Length()
+ + KSupportedFormatsStr().Length());
+
+ CleanupClosePushL(reply);
+
+ User::LeaveIfNull(iDetectedNetworks);
+ User::LeaveIfError(reply.Create( maxItemSize * iDetectedNetworks->Enumerate()));
+ User::LeaveIfError(iCallback->GetCharacterValue( ECharTypeCR, carriageReturn ));
+ User::LeaveIfError(iCallback->GetCharacterValue( ECharTypeLF, lineFeed ));
+
+ // Some PC Software expects and extra CR+LF, hence those are added twice:
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+ reply.Append( _L("+COPS: ") );
+
+ RMobilePhone::TMobilePhoneNetworkInfoV2 nwInfo;
+ for(TInt i = 0; i < iDetectedNetworks->Enumerate(); ++i)
+ {
+ if(i > 0) // Add CR+LF after the first cycle.
+ {
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+ }
+ nwInfo = iDetectedNetworks->GetEntryL(i);
+
+ reply.Append(_L("("));
+ reply.AppendNum(nwInfo.iStatus);
+ reply.Append(_L(","));
+ reply.Append(_L("\""));
+ reply.Append(nwInfo.iLongName);
+ reply.Append(_L("\""));
+ reply.Append(_L(","));
+ reply.Append(_L("\""));
+ reply.Append(nwInfo.iShortName);
+ reply.Append(_L("\""));
+ reply.Append(_L(","));
+ reply.Append(_L("\""));
+ reply.Append(nwInfo.iCountryCode);
+ reply.Append(nwInfo.iNetworkId);
+ reply.Append(_L("\""));
+ if(SolveAccessTechnology(nwInfo.iAccess) == KErrNone && iAccTech != EAccTechNotSet)
+ {
+ TRACE_INFO((_L("CATCOPSCmd::ConstructNetworkListResponse() appending acc. tech. (%d)"), iAccTech));
+ reply.Append(_L(","));
+ reply.AppendNum(iAccTech);
+ }
+ reply.Append(_L(")"));
+ reply.Append(_L(","));
+ TRACE_INFO( _L("CATCOPSCmd::ConstructNetworkListResponse() -- entry added to reply."));
+ }
+ reply.Append(KSupportedModesStr); // Supported modes as defined in 3GPP TS 27.007 V8.4.1
+ reply.Append(KSupportedFormatsStr); // Supported formats as defined in 3GPP TS 27.007 V8.4.1
+
+ reply.Append( carriageReturn );
+ reply.Append( lineFeed );
+
+ // Finally append the "OK". CreateOkOrErrorReply returns verbose or numeric version.
+ RBuf8 okReply;
+ CleanupClosePushL(okReply);
+ iCallback->CreateOkOrErrorReply( okReply, ETrue );
+ reply.Append( okReply);
+ CreateReply(ETrue, reply);
+ CleanupStack::PopAndDestroy(&okReply);
+ CleanupStack::PopAndDestroy(&reply);
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Finalises the response and sends it.
+// ---------------------------------------------------------------------------
+//
+void CATCOPSCmd::CreateReply(TBool aIsOK, const TDesC8 &aReply)
+ {
+ if(aIsOK == EFalse)
+ {
+ iCallback->CreateReplyAndComplete( EReplyTypeError);
+ }
+ else
+ {
+ if(aReply.Length() > 0)
+ {
+ iCallback->CreateReplyAndComplete( EReplyTypeOther,
+ aReply );
+ }
+ else
+ {
+ iCallback->CreateReplyAndComplete( EReplyTypeOk);
+ }
+ }
+ iCurrentOperation = EIdle;
+ TRACE_FUNC_EXIT
+ }