--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocolmodules/suplprotocolmodule/SuplProtocol/src/suplmolrstatehandler.cpp Tue Feb 02 01:50:39 2010 +0200
@@ -0,0 +1,548 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// This file provides the implementation of the class for
+// the SUPL MO-LR procedure state handler
+//
+//
+
+/**
+ @file
+ @internalTechnology
+ @deprecated
+*/
+
+#include "suplmolrfsmsession.h"
+#include "suplmolrstatehandler.h"
+#include "suplgatewayinterface.h"
+#include "suplmessagebase.h"
+#include "suplstart.h"
+#include "suplpos.h"
+#include "suplposinit.h"
+#include "suplresponse.h"
+#include "suplend.h"
+#include <etelmm.h>
+#include "supldevloggermacros.h"
+
+
+/** Static constructor.
+@param aMachine A reference to the parent state machine.
+@return A new instance of the CSuplMoLrStateHandler class
+*/
+CSuplMoLrStateHandler* CSuplMoLrStateHandler::NewL(CSuplFsmSessionBase& aMachine)
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::NewL()\n");
+ CSuplMoLrStateHandler* self = new (ELeave) CSuplMoLrStateHandler(aMachine);
+ return self;
+ }
+
+/** Standard constructor.
+@param aMachine A reference to the parent state machine.
+*/
+CSuplMoLrStateHandler::CSuplMoLrStateHandler(CSuplFsmSessionBase& aMachine)
+: CSuplStateHandlerBase(aMachine)
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::CSuplMoLrStateHandler() Begin\n");
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::CSuplMoLrStateHandler() End\n");
+ }
+
+
+/** Standard destructor.
+*/
+CSuplMoLrStateHandler::~CSuplMoLrStateHandler()
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::~CSuplMoLrStateHandler() Begin\n");
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::~CSuplMoLrStateHandler() End\n");
+ }
+
+/** Perform entry actions.
+This is called from the state machine to perform any actions
+associated with entering the current state following an external
+event or an autonomous state transition.
+
+For some states, there is only one possible course of action.
+For other states, the event store has to be checked to see what
+events have occurred and what actions have to be taken to handle
+such events.
+
+If an event conductive to cancelling the state machine had occurred
+(e.g, an explicit client cancel, an error, or a timeout), then the
+state machine would have been set in an state that terminates the
+session before this method is called (either EStateSuplSessionEnded
+or EStatePosSessionEnded).
+
+@return TBool ETrue if any actions have been taken
+*/
+TBool CSuplMoLrStateHandler::EntryActionsL()
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsL() Begin\n");
+ TBool actionsTaken = ETrue;
+ // Retrieve current state and act accordingly
+ switch(iMachine.CurrentState())
+ {
+ case CSuplFsmSessionBase::EStateProcedureNull:
+ // No action
+ break;
+
+ case CSuplFsmSessionBase::EStateNetConnectionStarted:
+ actionsTaken = EntryActionsFromNetConnectionStarted();
+ break;
+
+ case CSuplFsmSessionBase::EStateStartSent:
+ // Build and send a SUPL START message
+ actionsTaken = EntryActionsFromStartSentStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStateResponseReceived:
+ // Handle a received SUPL RESPONSE message
+ actionsTaken = EntryActionsFromResponseReceivedStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStatePosInitSent:
+ // Build and send a SUPL POS INIT
+ actionsTaken = EntryActionsFromPosInitSentStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStatePositioningInProgress:
+ actionsTaken = EntryActionsFromPositioningInProgressStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStatePositionReceived:
+ actionsTaken = EntryActionsFromPositionReceivedStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStateSuplSessionEnded:
+ // Send SUPL END
+ actionsTaken = EntryActionsFromSuplSessionEndedStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStatePosSessionEnded:
+ // Send to Positioning FSM an instruction to terminate silently
+ //
+ iMachine.PositioningFsm()->CancelMachine(CSuplPositioningProtocolFsm::ESuplFsmCancel, CSuplFsmSessionBase::EReasonNone);
+ break;
+
+ case CSuplFsmSessionBase::EStateLbsSessionEnded:
+ // Send session complete indication to LBS
+ actionsTaken = EntryActionsFromLbsSessionEndedStateL();
+ break;
+
+ case CSuplFsmSessionBase::EStateNetConnectionClosed:
+ // Close the network connection
+ iMachine.CompleteProcedure();
+ break;
+
+ default:
+ ASSERT(EFalse);
+ break;
+ }
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsL() End\n");
+ return actionsTaken;
+ }
+//---------------------------------------------------------------------------------------------------------------------
+// ----------------------- METHODS FOR ACTIONS AFTER ENTERING STATES ---------------------------------------------
+//---------------------------------------------------------------------------------------------------------------------
+
+/** Actions on entering state EStateNetConnectionStarted
+
+This method obtains an SLP Id from the Host Settings store
+and asks the Connection Manager to provide a connection with it.
+*/
+TBool CSuplMoLrStateHandler::EntryActionsFromNetConnectionStarted()
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromNetConnectionStarted() Begin\n");
+ TLbsHostSettingsId hostId = TUid::Uid(0);
+ TLbsNetSessionId::TSessionNum sessIdNum = 0;
+ TInt err = iMachine.GetHostId(hostId);
+
+ if (KErrNone == err)
+ {
+ // Request a connection from the Connection Manager
+ //
+ sessIdNum = iMachine.SessionId().SessionNum();
+ iMachine.Observer().ConnectionManager().Connect(sessIdNum, hostId, CSuplSessionRecord::EServiceMolr, iMachine);
+ // start the timer that oversees connection creation
+ iMachine.StartConnectionTimer();
+ }
+ else
+ {
+ // Cancel session as a SUPL server could not be determined
+ iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt, CSuplFsmSessionBase::EReasonSlpSettingsMissing);
+ }
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromNetConnectionStarted() End\n");
+ return ETrue;
+ }
+
+/** Actions on entering state EStateStartSent
+
+This method builds a SUPL START and passes it on to
+the Connection Manager for sending to the SUPL server
+
+*/
+TBool CSuplMoLrStateHandler::EntryActionsFromStartSentStateL()
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromStartSentStateL() Begin\n");
+
+ TLbsNetPosRequestQuality quality;
+ TLbsNetPosCapabilities capabilities;
+
+ ASSERT(iMachine.IsSessionConnected()); // should not have transitioned into this state without a connection
+
+ // A SUPL START message must contain a Location ID with
+ // network information (cell ID, etc). If such data has
+ // not been made available to the state machine then
+ // cancel ongoing session
+ CSuplLocationId* locationId ;
+ if (BuildLocationIdL(locationId))
+ {
+ CleanupStack::PushL(locationId);
+ }
+ else
+ {
+ iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt, CSuplFsmSessionBase::EReasonNone);
+ return EFalse;
+ }
+
+ // Create a SUPL message common part.
+ // Set the SET session ID only in CSuplSessionId.
+ CSuplSessionId* sessionId = CSuplSessionId::NewL();
+ CleanupStack::PushL(sessionId);
+ sessionId->iSetSessionIdPresent = ETrue;
+ sessionId->iSetSessionId->iSessionId = iMachine.SessionId().SessionNum();
+ sessionId->iSetSessionId->iSetId->iSetIdType = ESuplSetIdTypeMsisdn; // TSuplSetIdType
+
+ const TUint8 KMaxMsisdnLength = 8;
+ TDes8& des = sessionId->iSetSessionId->iSetId->iSetId;
+ if(iMachine.Msisdn())
+ {
+ ConvertToBcd(des);
+ }
+ else
+ {
+ //Fill the descriptor with all bits set to 0, then append a 0xFF to the end to indicate the end of the MSISDN
+ des.SetLength(KMaxMsisdnLength);
+ des.Fill(0x00, (KMaxMsisdnLength -1)); //7 0's
+ des.Append(0xFF); //Final 1 FF
+ }
+
+ //The commented code can be used when the set id type selection from the Host Settings API is implemented
+ //TUint32 ipAddr = iMachine.RetrieveLocalIpAddress().Address();
+ //sessionId->iSetSessionId->iSetId->iIpAddress->iIpAddressType = ESuplIpAddressTypeV4;
+ //sessionId->iSetSessionId->iSetId->iIpAddress->iIpAddress.Copy(reinterpret_cast<unsigned char*>(&ipAddr), 4);
+
+ // Keep session Id for future reference
+ iMachine.SetMessageSessionId(sessionId); // ownership transferred
+ CleanupStack::Pop(sessionId);
+
+ // positioning capabilities and request quality to be set in SUPL START
+ // are built using the stored Request Options
+ if (CSuplMolrFsmSession::ESuplMolrCellBased == (reinterpret_cast <CSuplMolrFsmSession&> (iMachine)).MachineType())
+ {
+ TLbsNetPosRequestOptions locReqOptions;
+ iMachine.RetrieveLocationRequestOptions(locReqOptions);
+
+ TLbsNetPosMethod posMethods[1];
+ posMethods[0].SetPosMethod(KLbsPositioningMeansCell, TPositionModuleInfo::ETechnologyNetwork);
+ capabilities.SetPosMethods(posMethods, 1);
+
+ locReqOptions.GetRequestQuality(quality);
+ }
+ else // Not Cell-Based only
+ {
+ // Send all of LBS' capabilities in the SUPL START
+ BuildCapabilitiesL(capabilities,quality);
+ }
+
+ // Create the SUPL START Message
+ CSuplStart* suplStart = CSuplStart::NewLC();
+ TInt err = suplStart->SetCapabilities(capabilities);
+ err = suplStart->SetLocationId(*locationId);
+ err= suplStart->SetSessionId(*sessionId);
+ err = suplStart->SetQoP(quality);
+
+ CleanupStack::Pop(suplStart);
+ CleanupStack::PopAndDestroy(locationId);
+
+ // Ask the Connection Manager to send the SUPL START message to the server
+ iMachine.Observer().ConnectionManager().SendMessage(suplStart, iMachine.SessionId().SessionNum());
+
+ iMachine.SetSessionInProgress(ETrue);
+
+ // start the timer that oversees the arrival of SUPL RESPONSE
+ (reinterpret_cast <CSuplMolrFsmSession&> (iMachine)).StartSuplResponseTimer();
+
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromStartSentStateL() End\n");
+ return ETrue;
+ }
+
+/** Actions on entering state EStateResponseReceived
+
+This method extracts the positioning method from SUPL RESPONSE and
+sends a new location request to LBS.
+*/
+TBool CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL()
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() Begin\n");
+ TBool actionsTaken = EFalse;
+
+ // A SUPL RESPONSE must be the oldest SUPL message in the
+ // event store at this point.
+
+ CSuplMessageBase* suplMessage = const_cast <CSuplMessageBase*> (iMachine.RetrieveSuplMessage());
+
+ ASSERT(suplMessage != NULL);
+ ASSERT(CSuplMessageBase::ESuplResponse == suplMessage->MessageType());
+
+ if ((suplMessage != NULL) && (CSuplMessageBase::ESuplResponse == suplMessage->MessageType()))
+ {
+ CSuplResponse* responsePtr = static_cast <CSuplResponse*>(suplMessage);
+
+ // Check that the SetId is the same that was sent in the SUPL START
+ CSuplSessionId *sessId = CSuplSessionId::NewLC();
+ responsePtr->GetSessionId(*sessId);
+ if (! ((*(iMachine.MessageSessionId()->iSetSessionId)) == (*(sessId->iSetSessionId))))
+ {
+ iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId);
+ // Store received session Id for sending later in SUPL END as per SUPL specification
+ CleanupStack::Pop(sessId);
+ iMachine.SetMessageSessionId(sessId); // ownership transferred
+ delete responsePtr;
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() End\n");
+ return actionsTaken;
+ }
+ else
+ {
+ CleanupStack::Pop(sessId);
+ // Store received session Id for later use
+ iMachine.SetMessageSessionId(sessId); // ownership transferred
+ }
+
+ // Extract the Positioning Method that SHALL (as per SUPL specification)
+ // be used for the SUPL POS session
+ TLbsNetPosRequestMethod posMethod;
+ TLbsNetPosMethod selectedMethod; // only one to send to LBS
+ TInt err = responsePtr->GetPosMethod(posMethod);
+ TLbsNetPosCapabilities capabilities;
+ iMachine.Observer().Gateway().GetCapabilities(capabilities);
+ if ((KErrNone != err) || !iMachine.PosMethodSupported(posMethod, selectedMethod,capabilities))
+ {
+ //Cancel with error code posMethodMistmach
+ iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonMethodMismatch);
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() End\n");
+ delete responsePtr;
+ return actionsTaken;
+ }
+
+ // send request to LBS
+ if (CSuplMolrFsmSession::ESuplMolrCellBased != (reinterpret_cast <CSuplMolrFsmSession&> (iMachine)).MachineType())
+ {
+ // Methods to be requested from LBS
+ posMethod.SetPosMethods(&selectedMethod, 1);
+
+ // Quality to be requested from LBS. The SUPL RESPONSE constains no quality requirements.
+ // Use the quality originally requested by LBS
+ TLbsNetPosRequestOptionsAssistance locReqAssistOptions;
+ TLbsNetPosRequestQuality quality;
+ iMachine.RetrieveLocationRequestOptions(locReqAssistOptions);
+ locReqAssistOptions.GetRequestQuality(quality);
+
+ iMachine.Observer().LocationReq(iMachine.LbsSessionId(), iMachine.LocReqType(),
+ quality, posMethod);
+ }
+
+ delete responsePtr;
+ actionsTaken = ETrue;
+ }
+
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() End\n");
+ return actionsTaken;
+ }
+
+
+/** Actions on entering state EStatePosInitSent
+This method builds a SUPL POS INIT message and hands it over to
+the Connection Manager for sending to the SUPL server.
+*/
+TBool CSuplMoLrStateHandler::EntryActionsFromPosInitSentStateL()
+ {
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromPosInitSentStateL() Begin\n");
+ TBool err = EFalse;
+ TLbsNetPosRequestQuality quality;
+ TLbsNetPosCapabilities capabilities;
+ TBool actionsTaken = EFalse;
+
+ // There should be an assistance data request from LBS in the event store
+ //
+ if (iMachine.IsAssistanceDataRequestStored())
+ {
+ ASSERT(iMachine.IsSessionConnected()); // should not have transitioned into this state without a connection
+
+ // Create the SUPL POS INIT Message
+ CSuplPosInit* suplPosInit = CSuplPosInit::NewL();
+ CleanupStack::PushL(suplPosInit);
+
+ // Set the Location Id in the message
+ CSuplLocationId* locationId;
+ if (BuildLocationIdL(locationId))
+ {
+ CleanupStack::PushL(locationId);
+
+ suplPosInit->SetLocationId(*locationId);
+ CleanupStack::PopAndDestroy(locationId);
+
+ // Set Capabilities in the message
+ BuildCapabilitiesL(capabilities,quality);
+ User::LeaveIfError(suplPosInit->SetCapabilities(capabilities));
+
+ // Set assistance data request in the message if any data
+ // is actually required
+ TLbsAsistanceDataGroup assitDataReqMask;
+ TBool assitDataReqPresent = iMachine.RetrieveAssistanceDataRequest(assitDataReqMask);
+ if (assitDataReqMask != 0)
+ {
+ User::LeaveIfError(suplPosInit->SetRequestedAssistanceData(assitDataReqMask));
+ }
+ else
+ {
+ // No need to set assistance data request parameter
+ // in SUPL POS INIT when request is empty.
+ // (intentionally no action taken here)
+ }
+
+ // Set in message header the stored session id
+ CSuplSessionId* msgId = iMachine.MessageSessionId();
+ User::LeaveIfError(suplPosInit->SetSessionId(*msgId));
+
+ CleanupStack::Pop(suplPosInit);
+
+ // Ask the Connection Manager to send the SUPL POS INIT message
+ iMachine.Observer().ConnectionManager().SendMessage(suplPosInit, iMachine.SessionId().SessionNum());
+
+ // Start the timer that oversees the arrival of SUPL POS
+ iMachine.StartSuplPosTimer();
+
+ actionsTaken = ETrue;
+ }
+ else
+ {
+ // Failed to build Location Id
+ err = ETrue;
+ CleanupStack::PopAndDestroy(suplPosInit);
+ }
+ }
+ else
+ {
+ // An unexpected event must have happened (e.g. SUPL Message received)
+ // that triggered the transition to this state.
+ err = ETrue;
+ }
+
+ if (err)
+ {
+ iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt, CSuplFsmSessionBase::EReasonNone);
+ }
+
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromPosInitSentStateL() End\n");
+ return actionsTaken;
+ }
+
+/**
+Utility method that obtains the capabilities in the stored location request options
+and adds to them the preferred positioning method also stored in the location request
+option
+*/
+TBool CSuplMoLrStateHandler::BuildCapabilitiesL(TLbsNetPosCapabilities& aCapabilities, TLbsNetPosRequestQuality& aQuality)
+{
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::BuildCapabilitiesL() Begin\n");
+ TLbsNetPosRequestOptionsAssistance locReqAssistOptions;
+ TLbsNetPosMethod prefMethod;
+ TInt numMethods;
+ TInt index;
+ TBool ecidSupported = EFalse;
+ TInt additionalMethods = 0;
+
+ // The positioning method preferred by LBS was sent in the call to
+ // RequestSelfLocation and was kept in the event store.
+ iMachine.Observer().Gateway().GetCapabilities(aCapabilities);
+ numMethods = aCapabilities.NumPosMethods();
+ iMachine.RetrieveLocationRequestOptions(locReqAssistOptions);
+ prefMethod.SetPosMethod(KLbsPositioningMeansGps, locReqAssistOptions.PosMode());
+ additionalMethods ++;
+
+ // Check if E-CID is possible
+ // (currently this mean Timing Advance only)
+ if(iMachine.IsNetworkInfoAvailable())
+ {
+ RMobilePhone::TMobilePhoneNetworkInfoV1 networkInfo;
+ RMobilePhone::TMobilePhoneLocationAreaV1 locationArea;
+ iMachine.RetrieveStoredNetworkInfo(networkInfo, locationArea);
+ if (RMobilePhone::ENetworkModeGsm == networkInfo.iMode)
+ {
+ RMobilePhone::TMobilePhoneCellInfoV9 cellInfo;
+ if(iMachine.RetrieveStoredCellInfo(cellInfo))
+ {
+ // Timing Advance not supported if negative
+ ecidSupported = (cellInfo.iTimingAdvance >= 0);
+ additionalMethods++;
+ }
+ }
+ }
+
+ // The preferred method has to be added at the end of the array of methods in "capabilities"
+ // because that is where the ASN1 encoder expects it to be.
+ // If E-CID is supported and there is room for it in the array, it will also be added to the
+ // array.
+ TLbsNetPosMethod* methods;
+ if (numMethods + additionalMethods < KLbsMaxNetPosMethods)
+ {
+ TLbsNetPosMethod ecidMethod;
+ ecidMethod.SetPosMethod(KLbsPositioningMeansCell, TPositionModuleInfo::ETechnologyNetwork);
+ methods = new (ELeave) TLbsNetPosMethod[numMethods + additionalMethods];
+
+ for (index =0; index < numMethods; index++)
+ {
+ aCapabilities.GetPosMethod(index, methods[index]);
+ }
+
+ if (ecidSupported)
+ {
+ methods[numMethods] = ecidMethod;
+ }
+
+ // Add preferred method at the end
+ methods[numMethods + additionalMethods - 1] = prefMethod;
+ aCapabilities.SetPosMethods(methods, numMethods + additionalMethods);
+ }
+ else
+ {
+ // There is only additional room for 1 or 0 methods.
+ methods = new (ELeave) TLbsNetPosMethod[KLbsMaxNetPosMethods];
+
+ for (index =0; index < KLbsMaxNetPosMethods; index++)
+ {
+ aCapabilities.GetPosMethod(index, methods[index]);
+ }
+
+ // Set the preferred method at the end (even if it
+ // overwrites current entry)
+ methods[KLbsMaxNetPosMethods-1] = prefMethod;
+ aCapabilities.SetPosMethods(methods, KLbsMaxNetPosMethods);
+ }
+
+ delete[] methods;
+ locReqAssistOptions.GetRequestQuality(aQuality);
+
+ SUPLLOG(ELogP1, "CSuplMoLrStateHandler::BuildCapabilitiesL() End\n");
+ return ETrue;
+}
+