networkprotocolmodules/suplcontrolplaneprotocols/suplrrlpprotocol/src/suplrrlpstatemachine.cpp
changeset 48 81c9bee26a45
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocolmodules/suplcontrolplaneprotocols/suplrrlpprotocol/src/suplrrlpstatemachine.cpp	Tue Jul 13 12:25:28 2010 +0100
@@ -0,0 +1,557 @@
+#include <e32debug.h>
+// 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:
+//
+
+/**
+ @file
+ @internalTechnology
+
+*/
+
+
+#include "rrlpassistancedata.h"
+#include "rrlpassistancedataack.h"
+#include "rrlpmeasureposrequest.h"
+#include "rrlpmeasureposresponse.h"
+#include "supldevloggermacros.h"
+#include "suplrrlpstatemachine.h"
+#include "suplpositioningprotocolfsm.inl"
+
+// statics
+const TInt CSuplRrlpFsm::KAssistanceDataChunkTimeout = 10; // Seconds 
+const TInt CSuplRrlpFsm::KRequestTimeout = 60; // Seconds
+const TInt CSuplRrlpFsm::KResponseDelayAddition = 1000; // Micro-Seconds
+const TInt CSuplRrlpFsm::KResponseDelayTimeout = 60; // Seconds
+const TInt CSuplRrlpFsm::KMeasureRequestWithAssistanceDataDelay = 10000; // Micro-Seconds
+
+
+// Construction
+EXPORT_C CSuplRrlpFsm* CSuplRrlpFsm::NewL(MSuplPositioningProtocolFsmObserver& aObserver, RLbsAssistanceDataBuilderSet& aDataBuilder)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::NewL() Begin\n");
+	CSuplRrlpFsm* self = new(ELeave)CSuplRrlpFsm(aObserver,aDataBuilder);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::NewL() End\n");
+	return self;
+	}
+	
+CSuplRrlpFsm::CSuplRrlpFsm(MSuplPositioningProtocolFsmObserver& aObserver, RLbsAssistanceDataBuilderSet& aDataBuilder) :
+	CSuplPositioningProtocolFsm(aObserver), iCurrentState(EStateNull), iAssistanceData(aDataBuilder)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::CSuplRrlpFsm() Begin\n");
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::CSuplRrlpFsm() End\n");
+	}
+
+void CSuplRrlpFsm::ConstructL()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ConstructL() Begin\n");
+	iAssistanceDataChunkTimer = CLbsCallbackTimer::NewL(*this);
+	iRequestTimer = CLbsCallbackTimer::NewL(*this);
+	iResponseDelayTimer = CLbsCallbackTimer::NewL(*this);
+	iMeasureRequestWithAssitanceDataDelayTimer = CLbsCallbackTimer::NewL(*this);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ConstructL() End\n");
+	}
+
+CSuplRrlpFsm::~CSuplRrlpFsm()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::~CSuplRrlpFsm() Begin\n");
+	delete iAssistanceDataChunkTimer;
+	delete iRequestTimer;
+	delete iResponseDelayTimer;
+	delete iMeasureRequestWithAssitanceDataDelayTimer;
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::~CSuplRrlpFsm() End\n");
+	}
+
+// Base class functions
+EXPORT_C void CSuplRrlpFsm::ProcessPositioningMessage(CSuplPosPayload* aMessage)
+	{
+	TInt message = aMessage->MessageType();
+	SUPLLOG2(ELogP1, "CSuplRrlpFsm::ProcessPositioningMessage() Begin. Message: %d\n", message);
+	
+	// Set the reference number
+	CRrlpMessageBase* base = static_cast<CRrlpMessageBase*>(aMessage);
+	base->GetReference(iLastReferenceNumber);
+	
+	switch (message)
+		{
+		case CSuplPosPayload::ERrlpAssistanceData:
+			{
+			CRrlpAssistanceData* pAssData = static_cast<CRrlpAssistanceData*>(aMessage);
+
+			HandleAssistanceDataMessage(pAssData);
+			break;
+			}
+		case CSuplPosPayload::ERrlpMeasurePositionReq:
+			{
+			CRrlpMeasurePositionRequest* pReq = static_cast<CRrlpMeasurePositionRequest*>(aMessage);
+			HandleMeasurementPositionRequest(pReq);
+			break;
+			}
+		case CSuplPosPayload::ERrlpProtocolError:
+			{
+			CRrlpProtocolError* pErr = static_cast<CRrlpProtocolError*>(aMessage);
+			HandleProtocolError(pErr);
+			break;
+			}
+		default:
+			{
+			iObserver.PositioningProtocolError(KErrNotFound);
+			}
+		} // switch
+
+	delete aMessage;
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ProcessPositioningMessage() End\n");
+	}
+
+EXPORT_C void CSuplRrlpFsm::CancelMachine(const TCancelSource& /*aCancelSource*/, TInt /*aReason*/)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::CancelMachine() Begin\n");
+	iResponseDelayTimer->Cancel();
+	iAssistanceDataChunkTimer->Cancel();
+	iRequestTimer->Cancel();
+	iMeasureRequestWithAssitanceDataDelayTimer->Cancel();
+	
+	TransistionTo(EStateNull);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::CancelMachine() End\n");
+	}
+
+EXPORT_C void CSuplRrlpFsm::AssistanceDataRequest(const TLbsAssistanceDataGroup& aData)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::AssistanceDataRequest() Begin\n");
+	if (TransistionTo(EStateMoreAssistDataRequested))
+		{
+		iResponseDelayTimer->Cancel();
+		CRrlpMeasurePositionResponse* pResp = NULL;
+		TRAPD(err, pResp = CRrlpMeasurePositionResponse::NewL());
+		if (err == KErrNone)
+			{
+			AddReference(*pResp);
+			pResp->SetLocationError(ERrlpLocErrorGpsAssDataMissing, aData); 
+			
+			iObserver.PositioningPayloadToNetwork(pResp);
+			pResp = NULL;
+			} // if
+		
+		if (err != KErrNone)
+			{
+			TransistionToError(err);
+			} // if
+		} // if
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::AssistanceDataRequest() End\n");
+	}
+
+EXPORT_C void CSuplRrlpFsm::LocationResp(TInt aReason, const TPositionInfoBase& aPosInfo)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::LocationResp() Begin\n");
+	// No call to TrnasistionTo as we to ignore if we are not in the correct state
+	if (iCurrentState == EStateRequestHandled) 
+		{
+		SUPLLOG(ELogP1, "iCurrentState == EStateRequestHandled\n");
+		if(aReason != KErrNone)	
+			{
+			SUPLLOG2(ELogP1, "Location error %d\n", aReason);
+			TransistionToError(aReason);
+			}
+		else
+			{
+			iCurrentState = EStateMeasureRespSent;
+			
+			// Cancel the timeout timer
+			iResponseDelayTimer->Cancel();
+			
+			CRrlpMeasurePositionResponse* pResp = NULL;
+			TRAPD(err, pResp = CRrlpMeasurePositionResponse::NewL());
+			if (err == KErrNone)
+				{
+				AddReference(*pResp);
+	
+				// Is aPosInfo measurements or position?
+				TPositionInfoBase* pBase = const_cast<TPositionInfoBase*>(&aPosInfo);
+				
+				if ((aPosInfo.PositionClassType() & EPositionGpsMeasurementInfoClass))
+					{
+					err = pResp->SetMeasurementInformation(*pBase);
+					}
+				else
+					{
+					err = pResp->SetLocationInformation(*pBase);
+					}
+				
+				if (err == KErrNone)
+					{
+					iObserver.PositioningSessionEnded();				
+					iObserver.PositioningPayloadToNetwork(pResp);
+					pResp = NULL;
+					TransistionTo(EStateNull);				
+					}
+				else
+					{
+					delete pResp;
+					}
+				} // if
+			if (err != KErrNone)
+				{
+				TransistionToError(err);
+				} // if
+			} // else
+		} // if
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::LocationResp() End\n");
+	}
+
+EXPORT_C bool CSuplRrlpFsm::IsAssistDataRequestAllowed()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::IsAssistDataRequestAllowed() Begin\n");
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::IsAssistDataRequestAllowed() End\n");
+	return ((iCurrentState == EStateNull) || (iCurrentState == EStateRequestHandled));
+	}
+
+
+// Handler functions
+void CSuplRrlpFsm::HandleAssistanceDataMessage(CRrlpAssistanceData* aData)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::HandleAssistanceDataMessage() Begin\n");
+	TLbsAsistanceDataGroup dataMask = 0;
+	if (TransistionTo(EStateAssitDataChunkRecvd))
+		{
+		// Kick off the timer
+		StartAssitanceDataChunkTimer();
+		
+		TInt err = KErrNone;
+		
+		if ((err == KErrNone) && (aData->AssistanceDataPresent())) // It is possible for an empty assistance data message
+																   			// we just ignore it
+			{
+			err = aData->BuildAssistanceData(dataMask, iAssistanceData);
+			} // if
+		
+		if (err == KErrNone)
+			{
+			iAssistanceDataMask |= dataMask;
+			// Ack the assistance data
+			CRrlpAssistanceDataAck* pAck = NULL;
+			TRAP(err, pAck = CRrlpAssistanceDataAck::NewL());
+			if (err == KErrNone)
+				{
+				if(!aData->MoreAssDataToBeSent())
+					{
+					// Inform observer that these could be the last
+					// RRLP messages sent.
+					iObserver.PositioningSessionEnded();
+					}
+				AddReference(*pAck);
+				iObserver.PositioningPayloadToNetwork(pAck);
+				pAck = NULL;
+				}
+			}
+		
+		if ((err == KErrNone) && (!aData->MoreAssDataToBeSent()))
+			{
+			TransistionTo(EStateAssitDataAcknowledged);
+			
+			// Pass the assistance data to LBS
+			iObserver.ProcessAssistanceData(iAssistanceDataMask,KErrNone);
+			iAssistanceDataMask = 0;
+			
+			// Start the request timer
+			iAssistanceDataChunkTimer->Cancel();
+			StartRequestTimer();
+ 
+			} // if
+		
+		if (err != KErrNone)
+			{
+			TransistionToError(err);
+			}
+		} // if
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::HandleAssistanceDataMessage() End\n");
+	}
+
+void CSuplRrlpFsm::HandleMeasurementPositionRequest(CRrlpMeasurePositionRequest* aReq)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::HandleMeasurementPositionRequest() Begin\n");
+	TLbsAsistanceDataGroup dataMask = 0;
+	if (TransistionTo(EStateMeasureReqRecvd))
+		{
+		// Cancel any outstanding timers
+		iAssistanceDataChunkTimer->Cancel(); // We could be expecting an assistance data chunk
+		// Is there assistance data
+		TInt delay = 0;
+		TInt err = KErrNone;
+		if (aReq->AssistanceDataPresent())
+			{
+			err = aReq->BuildAssistanceData(dataMask, iAssistanceData);
+			iAssistanceDataMask |= dataMask;
+			if (err == KErrNone)
+				{
+				// Pass the assistance data to LBS
+				iObserver.ProcessAssistanceData(iAssistanceDataMask,KErrNone);
+				iAssistanceDataMask = 0;
+				delay = KMeasureRequestWithAssistanceDataDelay;
+				} // if
+			} // if
+		
+		if (err == KErrNone)
+			{
+			// Store quality and method for later request
+			aReq->GetPositionInstruct(iLocReqQuality, iPosMethod);
+			
+			// Start a timer to give LBS a chance to handle the assistance data(this could be 0)
+			StartMeasureRequestWithAssitanceDataTimer(delay);
+			}
+		
+		if (err != KErrNone)
+			{
+			TransistionToError(err);
+			}
+		} // if
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::HandleMeasurementPositionRequest() End\n");
+	}
+
+void CSuplRrlpFsm::HandleProtocolError(CRrlpProtocolError* aError)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::HandleProtocolError() Begin\n");
+	if (TransistionTo(EStateNull))
+		{
+		TRrlpErrorCode error;
+		aError->GetProtocolError(error);
+		iObserver.PositioningProtocolError(error);
+		}
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::HandleProtocolError() End\n");
+	}
+
+// Timers
+// MLbsCallbackTimerObserver methods
+void CSuplRrlpFsm::OnTimerEventL(TInt aTimerId)
+	{
+	SUPLLOG2(ELogP1, "CSuplRrlpFsm::OnTimerEventL() Begin, aTimerId: %d\n", aTimerId);
+	switch (aTimerId)
+		{
+		case EAssitanceDataChunk:
+			ReceivedAssistanceDataChunkTimer();
+			break;
+		case ERequest:
+			ReceivedRequestTimer();
+			break;
+		case EResponseDelay:
+			ReceivedPosResultTimer();
+			break;
+		case EMeasureRequestWithAssistanceDataDelay:
+			ReceivedMeasureRequestWithAssitanceDataTimer();
+			break;
+		default:
+			ASSERT(EFalse);
+		} // switch
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::OnTimerEventL() End\n");
+	}
+
+TInt CSuplRrlpFsm::OnTimerError(TInt /*aTimerId*/, TInt aError)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::OnTimerEventL() Begin\n");
+	return aError;
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::OnTimerEventL() End\n");
+	}
+
+void CSuplRrlpFsm::StartAssitanceDataChunkTimer()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartAssitanceDataChunkTimer() Begin\n");
+	// Cancel current one if running
+	iAssistanceDataChunkTimer->Cancel();
+	
+	// Start again
+	TTimeIntervalSeconds time(KAssistanceDataChunkTimeout);
+	iAssistanceDataChunkTimer->EventAfter(time, EAssitanceDataChunk);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartAssitanceDataChunkTimer() End\n");
+	}
+
+void CSuplRrlpFsm::ReceivedAssistanceDataChunkTimer()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedAssistanceDataChunkTimer() Begin\n");
+	// If we receive this then there has been a timeout in receiving the assistance data chunks
+	// this is an error
+	iObserver.PositioningProtocolError(KErrTimedOut);
+	TransistionTo(EStateNull);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedAssistanceDataChunkTimer() End\n");
+	}
+
+void CSuplRrlpFsm::StartRequestTimer()   
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartRequestTimer() Begin\n");
+	// Cancel this it its running
+	iRequestTimer->Cancel();
+	
+	// Start timer
+	TTimeIntervalSeconds time(KRequestTimeout);
+	iRequestTimer->EventAfter(time, ERequest);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartRequestTimer() End\n");
+	}
+
+void CSuplRrlpFsm::ReceivedRequestTimer()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedRequestTimer() Begin\n");
+	// If we receive this then there has been a timeout in receiving a measurement request
+	// after receiving assistance data
+	iObserver.PositioningProtocolError(KErrTimedOut);
+	TransistionTo(EStateNull);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedRequestTimer() End\n");
+	}
+
+void CSuplRrlpFsm::StartPosResultTimer(TTimeIntervalMicroSeconds aTime) 
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartPosResultTimer() Begin\n");
+	// Add on the extra time to allow it to filter through from LBS
+	aTime = aTime.Int64() + KResponseDelayAddition;
+	
+	iResponseDelayTimer->EventAfter(aTime, EResponseDelay);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartPosResultTimer() End\n");
+	}
+
+void CSuplRrlpFsm::ReceivedPosResultTimer()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedPosResultTimer() Begin\n");
+	// If we recieve this then LBS has timed out
+	iObserver.PositioningProtocolError(KErrTimedOut);
+	TransistionTo(EStateNull);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedPosResultTimer() End\n");
+	}
+
+void CSuplRrlpFsm::StartMeasureRequestWithAssitanceDataTimer(TInt aTimer)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartMeasureRequestWithAssitanceDataTimer() Begin\n");
+	TTimeIntervalMicroSeconds time(aTimer);
+	iAssistanceDataChunkTimer->EventAfter(time, EMeasureRequestWithAssistanceDataDelay);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::StartMeasureRequestWithAssitanceDataTimer() End\n");
+	}
+void CSuplRrlpFsm::ReceivedMeasureRequestWithAssitanceDataTimer()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedMeasureRequestWithAssitanceDataTimer() Begin\n");
+	if (TransistionTo(EStateRequestHandled))
+		{
+		iObserver.ProcessPositioningRequest(iLocReqQuality, iPosMethod);
+		
+		// Expect results from LBS before the MaxFixTime elapses (allow an
+		// additional second for the results to propagate through LBS) 
+		StartPosResultTimer(iLocReqQuality.MaxFixTime().Int64() + (1000*KResponseDelayAddition));
+		}
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::ReceivedMeasureRequestWithAssitanceDataTimer() End\n");
+	}
+
+
+// Others
+TBool CSuplRrlpFsm::TransistionTo(TRrlpState aNewState)
+	{
+	SUPLLOG3(ELogP1, "CSuplRrlpFsm::TransistionTo() Begin, iCurrentState %d, aNewState %d\n", iCurrentState, aNewState);
+	
+	TBool ret = EFalse;
+	
+	if (aNewState != EStateNull)
+		{
+		switch (iCurrentState)
+			{
+			case EStateNull:
+			case EStateAssitDataChunkRecvd:
+				{
+				ret = (aNewState == EStateAssitDataChunkRecvd) ||
+				      (aNewState == EStateAssitDataAcknowledged) ||
+				      (aNewState == EStateMeasureReqRecvd);
+				break;
+				}
+			case EStateAssitDataAcknowledged:
+				{
+				ret = (aNewState == EStateMeasureReqRecvd);
+				break;
+				}
+			case EStateMeasureReqRecvd:
+				{
+				ret = (aNewState == EStateRequestHandled);
+				break;
+				}
+			case EStateRequestHandled:
+				{
+				ret = (aNewState == EStateMoreAssistDataRequested) ||
+					  (aNewState == EStateMeasureRespSent);
+				break;
+				}
+			case EStateMeasureRespSent:
+				{
+				ret = (aNewState == EStateNull);
+				break;
+				}
+			case EStateMoreAssistDataRequested:
+				{
+				ret = (aNewState == EStateMeasureReqRecvd);
+				break;	
+				}
+			}
+		}
+	else
+		{
+		ret = ETrue;
+		}
+
+	if (ret)
+		{
+		iCurrentState = aNewState;
+		}
+	else
+		{
+		TransistionToError(KErrGeneral);
+		}
+	
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::TransistionTo() End\n");
+	return ret;
+	}
+
+void CSuplRrlpFsm::TransistionToError(TInt aError)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::TransistionToError() Begin\n");
+	
+	iObserver.PositioningProtocolError(aError);
+	
+	// Prevent delayed actions from happening
+	iResponseDelayTimer->Cancel();
+	iAssistanceDataChunkTimer->Cancel();
+	iRequestTimer->Cancel();
+	iMeasureRequestWithAssitanceDataDelayTimer->Cancel();
+	
+	// Go back to null state
+	TransistionTo(EStateNull);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::TransistionToError() End\n");
+	}
+
+void CSuplRrlpFsm::AddReference(CRrlpMessageBase& aMessage)
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::AddReference() Begin\n");
+	aMessage.SetReference(iLastReferenceNumber);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::AddReference() End\n");
+	}
+
+
+// Unused functions from base class
+void CSuplRrlpFsm::RunL()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::RunL() Begin\n");
+	ASSERT(EFalse);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::RunL() End\n");
+	}
+void CSuplRrlpFsm::DoCancel()
+	{
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::DoCancel() Begin\n");
+	ASSERT(EFalse);
+	SUPLLOG(ELogP1, "CSuplRrlpFsm::DoCancel() End\n");
+	}
+