|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // This file provides the implementation of the class for |
|
15 // the MO-LR protocol state machine. |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalTechnology |
|
22 @released |
|
23 */ |
|
24 |
|
25 #include "cmolrstatemachine.h" |
|
26 #include "cmolrstatehandler.h" |
|
27 |
|
28 |
|
29 /** KMoLrReqIssuedTimerEvent |
|
30 Identity of timer for when MO-LR request issued to network |
|
31 */ |
|
32 const TInt KMoLrReqIssuedTimerEvent = 0x100; |
|
33 |
|
34 /** KMoLrReqIssuedTimerDurationInSec |
|
35 Timer duration for when MO-LR request issued to network |
|
36 */ |
|
37 const TInt KMoLrReqIssuedTimerDurationInSec = 20; |
|
38 |
|
39 /** KLocRespTimerEvent |
|
40 Identity of timer for when location response expected by network |
|
41 */ |
|
42 const TInt KLocRespTimerEvent = 0x200; |
|
43 |
|
44 /** KLocRespTimerDurationInSec |
|
45 Timer duration for when location response expected by network |
|
46 */ |
|
47 const TInt KLocRespTimerDurationInSec = 64; |
|
48 |
|
49 /** KFacResultTimerEvent |
|
50 Identity of timer for when facility result expected from network |
|
51 */ |
|
52 const TInt KFacResultTimerEvent = 0x300; |
|
53 |
|
54 /** KFacResultTimerDurationInSec |
|
55 Timer duration for when facility result expected from network |
|
56 */ |
|
57 const TInt KFacResultTimerDurationInSec = 10; |
|
58 |
|
59 /** KMaxQueueEntry |
|
60 Maximum entries in this state machine request queue. |
|
61 */ |
|
62 const TInt KMaxQueueEntry = 5; |
|
63 |
|
64 |
|
65 /** Static constructor. |
|
66 @param aObserver Reference to state machine observer. |
|
67 @return A new instance of the CMoLrStateMachine class |
|
68 */ |
|
69 CMoLrStateMachine* CMoLrStateMachine::NewL(MStateMachineObserver& aObserver) |
|
70 { |
|
71 CMoLrStateMachine* self = new (ELeave) CMoLrStateMachine(aObserver); |
|
72 CleanupStack::PushL(self); |
|
73 self->ConstructL(); |
|
74 CleanupStack::Pop(self); |
|
75 return self; |
|
76 } |
|
77 |
|
78 |
|
79 /** Standard constructor. |
|
80 @param aObserver Reference to state machine observer. |
|
81 */ |
|
82 CMoLrStateMachine::CMoLrStateMachine(MStateMachineObserver& aObserver) |
|
83 : CStateMachineBase(aObserver) |
|
84 { |
|
85 iLocReqType = MLbsNetworkProtocolObserver::EServiceSelfLocation; |
|
86 } |
|
87 |
|
88 |
|
89 /** Standard destructor. |
|
90 */ |
|
91 CMoLrStateMachine::~CMoLrStateMachine() |
|
92 { |
|
93 delete iFacResultTimer; |
|
94 delete iLocRespTimer; |
|
95 delete iMoLrReqIssuedTimer; |
|
96 } |
|
97 |
|
98 |
|
99 /** Private second-stage constructor. |
|
100 */ |
|
101 void CMoLrStateMachine::ConstructL() |
|
102 { |
|
103 CActiveScheduler::Add(this); |
|
104 |
|
105 // Create state handler |
|
106 iStateHandler = CMoLrStateHandler::NewL(*this); |
|
107 |
|
108 // Create timers used during MO-LR protocol procedure |
|
109 iMoLrReqIssuedTimer = CLbsCallbackTimer::NewL(*this); |
|
110 iLocRespTimer = CLbsCallbackTimer::NewL(*this); |
|
111 iFacResultTimer = CLbsCallbackTimer::NewL(*this); |
|
112 iAssistDataTimer = CLbsCallbackTimer::NewL(*this); |
|
113 |
|
114 // Create request queue |
|
115 iQueue = CStateQueue::NewL(KMaxQueueEntry); |
|
116 } |
|
117 |
|
118 |
|
119 /** Retrieve current MO-Lr state |
|
120 @return TMoLrState Current MO-LR state |
|
121 */ |
|
122 CMoLrStateMachine::TMoLrState CMoLrStateMachine::CurrentState() |
|
123 { |
|
124 return iCurrentState; |
|
125 } |
|
126 |
|
127 |
|
128 /** Start MO-LR request timer |
|
129 The state handler calls this when it has issued an MO-LR request |
|
130 to the network and it requires a response before the timer expires. |
|
131 */ |
|
132 void CMoLrStateMachine::StartMoLrReqTimer() |
|
133 { |
|
134 if(iMoLrReqIssuedTimer->IsActive()) |
|
135 { |
|
136 iMoLrReqIssuedTimer->Cancel(); |
|
137 } |
|
138 iMoLrReqIssuedTimer->EventAfter(TTimeIntervalSeconds(KMoLrReqIssuedTimerDurationInSec), KMoLrReqIssuedTimerEvent); |
|
139 } |
|
140 |
|
141 |
|
142 /** Start location response timer |
|
143 The state handler calls this when it has sent a location request |
|
144 to the client and requires a response before the timer expires. |
|
145 */ |
|
146 void CMoLrStateMachine::StartLocRespTimer() |
|
147 { |
|
148 if(iLocRespTimer->IsActive()) |
|
149 { |
|
150 iLocRespTimer->Cancel(); |
|
151 } |
|
152 iLocRespTimer->EventAfter(TTimeIntervalSeconds(KLocRespTimerDurationInSec), KLocRespTimerEvent); |
|
153 } |
|
154 |
|
155 |
|
156 /** Start facility result timer |
|
157 The state handler calls this when it has sent a location report |
|
158 to the network and requires a result before the timer expires. |
|
159 */ |
|
160 void CMoLrStateMachine::StartFacResultTimer() |
|
161 { |
|
162 if(iFacResultTimer->IsActive()) |
|
163 { |
|
164 iFacResultTimer->Cancel(); |
|
165 } |
|
166 iFacResultTimer->EventAfter(TTimeIntervalSeconds(KFacResultTimerDurationInSec), KFacResultTimerEvent); |
|
167 } |
|
168 |
|
169 |
|
170 /** Indicates if location request has been sent to LBS. |
|
171 @return TBool ETrue if location request has been sent to LBS. |
|
172 */ |
|
173 TBool CMoLrStateMachine::IsLocReqSentToLbs() const |
|
174 { |
|
175 return iIsLocReqSentToLbs; |
|
176 } |
|
177 |
|
178 |
|
179 /** Network Result Location. |
|
180 This is called by state handlers to retrieve the most |
|
181 recent reported network result location. |
|
182 @return TPositionInfoBase Currently held network result position |
|
183 */ |
|
184 const TPositionInfoBase& CMoLrStateMachine::NetResultLoc() const |
|
185 { |
|
186 return iNetResultPosInfo; |
|
187 } |
|
188 |
|
189 |
|
190 /** Store network resulting location |
|
191 @param aPosInfo Network result location information |
|
192 */ |
|
193 void CMoLrStateMachine::StoreNetResultLoc(const TPositionInfoBase& aPosInfo) |
|
194 { |
|
195 iNetResultPosInfo = reinterpret_cast <const TPositionInfo&> (aPosInfo); |
|
196 } |
|
197 |
|
198 |
|
199 /** Initialise internal state attributes. |
|
200 This is used when new MO-LR procedure commences. |
|
201 */ |
|
202 void CMoLrStateMachine::InitialiseProcedure() |
|
203 { |
|
204 // Initialise state machine |
|
205 InitialiseMachineBase(); |
|
206 |
|
207 iIsLocReqSentToLbs = EFalse; |
|
208 iIsNetResultLocAvailable = EFalse; |
|
209 |
|
210 ASSERT(iStateHandler != NULL); |
|
211 iStateHandler->Initialise(); |
|
212 } |
|
213 |
|
214 |
|
215 /** Prepare state transition. |
|
216 */ |
|
217 void CMoLrStateMachine::PreStateTransition() |
|
218 { |
|
219 } |
|
220 |
|
221 |
|
222 /** State transition. |
|
223 This method determines the next state to be adopted by the state machine. |
|
224 */ |
|
225 void CMoLrStateMachine::StateTransition() |
|
226 { |
|
227 if (CancelPending()) |
|
228 { |
|
229 SetMachineAsCancelling(); |
|
230 iCurrentState = EStateCancelling; |
|
231 } |
|
232 else |
|
233 { |
|
234 // Set new state |
|
235 switch (iCurrentState) |
|
236 { |
|
237 |
|
238 case EStateNull: |
|
239 iCurrentState = EStateClientReqRecvd; |
|
240 break; |
|
241 |
|
242 case EStateClientReqRecvd: |
|
243 iCurrentState = EStateNetSessStarted; |
|
244 break; |
|
245 |
|
246 case EStateNetSessStarted: |
|
247 iCurrentState = EStateMeasureDataRecvd; |
|
248 break; |
|
249 |
|
250 case EStateMeasureDataRecvd: |
|
251 iCurrentState = EStateNetBasedLocSent; |
|
252 break; |
|
253 |
|
254 case EStateNetBasedLocSent: |
|
255 iCurrentState = EStateLocReqByNet; |
|
256 iIsMeasureControlHandled = ETrue; |
|
257 iIsLocReqSentToLbs = ETrue; |
|
258 break; |
|
259 |
|
260 case EStateLocReqByNet: |
|
261 iCurrentState = EStateLocRespRecvd; |
|
262 break; |
|
263 |
|
264 case EStateLocRespRecvd: |
|
265 iCurrentState = EStateLocSentToNet; |
|
266 break; |
|
267 |
|
268 case EStateLocSentToNet: |
|
269 iCurrentState = EStateNetSessToClose; |
|
270 break; |
|
271 |
|
272 case EStateNetSessToClose: |
|
273 // If a network result is provided then it is sent to LBS |
|
274 // otherwise the LBS client session closes |
|
275 iCurrentState = iIsNetResultLocAvailable ? EStateNetResultSent : EStateClientSessToClose; |
|
276 break; |
|
277 |
|
278 case EStateNetResultSent: |
|
279 iCurrentState = EStateClientSessToClose; |
|
280 break; |
|
281 |
|
282 case EStateClientSessToClose: |
|
283 iCurrentState = EStateSessionsClosed; |
|
284 break; |
|
285 |
|
286 case EStateSessionsClosed: |
|
287 // Procedure has completed |
|
288 CompleteProcedure(); |
|
289 break; |
|
290 |
|
291 case EStateCancelling: |
|
292 iCurrentState = EStateNetSessToClose; |
|
293 break; |
|
294 |
|
295 default: |
|
296 User::Panic(KProtocolModulePanic, EProtocolModuleMoLrState); |
|
297 break; |
|
298 }; |
|
299 } |
|
300 |
|
301 } |
|
302 |
|
303 |
|
304 /** Complete the procedure. |
|
305 */ |
|
306 void CMoLrStateMachine::CompleteProcedure() |
|
307 { |
|
308 iCurrentState = EStateNull; |
|
309 // Complete state machine |
|
310 CompleteMachineBase(); |
|
311 } |
|
312 |
|
313 |
|
314 /** Complete a state transition. |
|
315 This is called by the base class when a state transition has |
|
316 concluded and it provides an opportunity for the state machine |
|
317 to perform actions required immediately after this transition. |
|
318 |
|
319 The method can also initiate a further change of state. This is |
|
320 relevant when the state machine is required to perform an autonomous |
|
321 transition from one state to another e.g. this occurs when several |
|
322 interactions are required arising from a single external trigger. |
|
323 */ |
|
324 void CMoLrStateMachine::PostStateTransition() |
|
325 { |
|
326 // Some states are transitory i.e. they require |
|
327 // an automatic transition to the next state |
|
328 if ( CancelPending() || |
|
329 (EStateClientReqRecvd == iCurrentState) || |
|
330 (EStateMeasureDataRecvd == iCurrentState) || |
|
331 (EStateNetBasedLocSent == iCurrentState) || |
|
332 (EStateLocRespRecvd == iCurrentState) || |
|
333 (EStateNetSessToClose == iCurrentState) || |
|
334 (EStateNetResultSent == iCurrentState) || |
|
335 (EStateClientSessToClose == iCurrentState) || |
|
336 (EStateSessionsClosed == iCurrentState) || |
|
337 (EStateCancelling == iCurrentState) |
|
338 ) |
|
339 { |
|
340 // Perform a state transition |
|
341 PerformStateTransition(); |
|
342 } |
|
343 } |
|
344 |
|
345 |
|
346 /** Do actions required for a queued request. |
|
347 This currently only initiates another state change but it |
|
348 has the scope for further actions to be carried out according |
|
349 to the nature of a queued request. |
|
350 */ |
|
351 void CMoLrStateMachine::DoQueuedRequest(TInt aRequest) |
|
352 { |
|
353 switch (aRequest) |
|
354 { |
|
355 case EQueueLocResponse: |
|
356 case EQueueMeasurementControl: |
|
357 case EQueueNetworkResult: |
|
358 // Perform a state transition |
|
359 PerformStateTransition(); |
|
360 break; |
|
361 |
|
362 default: |
|
363 User::Panic(KProtocolModulePanic, EProtocolModuleQueueRequestId); |
|
364 break; |
|
365 }; |
|
366 |
|
367 } |
|
368 |
|
369 |
|
370 /** Cancel the active procedure |
|
371 */ |
|
372 void CMoLrStateMachine::CancelProcedure() |
|
373 { |
|
374 // Kill all timers |
|
375 iMoLrReqIssuedTimer->Cancel(); |
|
376 iLocRespTimer->Cancel(); |
|
377 iFacResultTimer->Cancel(); |
|
378 iAssistDataTimer->Cancel(); |
|
379 } |
|
380 |
|
381 |
|
382 /** Timer expired callback. |
|
383 This is called by a CStateTimer object when the timer |
|
384 has expired - the event is identified by aEvent parameter. |
|
385 @param aTimerId The timer event identifier. |
|
386 */ |
|
387 void CMoLrStateMachine::OnTimerEventL(TInt aTimerId) |
|
388 { |
|
389 // Perform relevant action for the expired timer |
|
390 switch (aTimerId) |
|
391 { |
|
392 |
|
393 // MO-LR request timer |
|
394 case KMoLrReqIssuedTimerEvent: |
|
395 // Inform protocol manager |
|
396 Observer().MeasurementControlTimeout(); |
|
397 break; |
|
398 |
|
399 // Additional assistance data timer |
|
400 case KAssistDataTimerEvent: |
|
401 iLocRespReason = KErrTimedOut; |
|
402 // Inform protocol manager |
|
403 Observer().MeasurementControlTimeout(); |
|
404 break; |
|
405 |
|
406 // Facility result timer |
|
407 case KFacResultTimerEvent: |
|
408 CancelMachine(ECancelNetworkTimeout); |
|
409 break; |
|
410 |
|
411 // Location response timer |
|
412 case KLocRespTimerEvent: |
|
413 iLocRespReason = KErrTimedOut; |
|
414 CancelMachine(ECancelClientTimeout); |
|
415 break; |
|
416 |
|
417 // Ignore unknown timer events |
|
418 default: |
|
419 break; |
|
420 |
|
421 }; |
|
422 |
|
423 } |
|
424 |
|
425 |
|
426 /** Timer callback error handler. |
|
427 This is called if the timer expiry callback leaves. |
|
428 @see CMoLrStateMachine::OnTimerEventL() |
|
429 @param aTimerId The timer event identifier. |
|
430 @param aError Error value. |
|
431 */ |
|
432 TInt CMoLrStateMachine::OnTimerError(TInt /*aTimerId*/, TInt aError) |
|
433 { |
|
434 return aError; |
|
435 } |
|
436 |
|
437 |
|
438 /** Handle Measurement Control timeout |
|
439 */ |
|
440 void CMoLrStateMachine::MeasurementControlTimeout() |
|
441 { |
|
442 // Ensure assistance data action is performed upon cancellation |
|
443 iAssistanceDataActionRequired = ETrue; |
|
444 |
|
445 // Cancel procedure |
|
446 CancelMachine(ECancelNetworkTimeout); |
|
447 } |
|
448 |
|
449 |
|
450 /** Handle LBS request for MO-LR |
|
451 @param aSessionId The session ID supplied by LBS. |
|
452 */ |
|
453 void CMoLrStateMachine::MoLrReq(const TLbsNetSessionId& aSessionId) |
|
454 { |
|
455 // Store the supplied ID information |
|
456 SessionId(aSessionId); |
|
457 |
|
458 // Initialise the new procedure |
|
459 InitialiseProcedure(); |
|
460 |
|
461 // This state machine requires assistance data actions |
|
462 // to be performed immediately immediate |
|
463 iObserver.DoAssistanceDataActions(); |
|
464 |
|
465 // Perform a state transition |
|
466 PerformStateTransition(); |
|
467 } |
|
468 |
|
469 |
|
470 /** Queue an LBS request for MO-LR |
|
471 @param aSessionId The session ID supplied by LBS. |
|
472 */ |
|
473 void CMoLrStateMachine::QueueMoLrReq(const TLbsNetSessionId& aSessionId) |
|
474 { |
|
475 // Store the session ID |
|
476 QueueSessionId(aSessionId); |
|
477 |
|
478 CStateMachineBase::SetMachineAsQueued(); |
|
479 } |
|
480 |
|
481 |
|
482 /** Start previously queued state machine. |
|
483 */ |
|
484 void CMoLrStateMachine::StartQueuedMachine() |
|
485 { |
|
486 MoLrReq(iQueueSessionId); |
|
487 } |
|
488 |
|
489 |
|
490 /** Handle LBS Location response |
|
491 @param aReason Location response error reason. |
|
492 @param aPosInfo The location information response from LBS. |
|
493 */ |
|
494 void CMoLrStateMachine::LocationResp(TInt aReason, const TPositionInfoBase& aPosInfo) |
|
495 { |
|
496 // Store location response data |
|
497 StoreLocationResp(aReason, aPosInfo); |
|
498 |
|
499 // Kill the timer related to location response expected by network |
|
500 iLocRespTimer->Cancel(); |
|
501 |
|
502 // Is the state machine inactive? |
|
503 if (!IsActive()) |
|
504 { |
|
505 // Perform a state transition |
|
506 PerformStateTransition(); |
|
507 } |
|
508 else |
|
509 { |
|
510 // Queue the request |
|
511 iQueue->AddRequest(EQueueLocResponse); |
|
512 } |
|
513 } |
|
514 |
|
515 |
|
516 /** Handle Network Measurement Control indication. |
|
517 A measurement control indication has been received from the network. |
|
518 Note: At this stage the assistance data has already been stored by the |
|
519 protocol manager and is thus not passed into this method. |
|
520 |
|
521 @param aPosInfo Reference location information provided in the measurement control |
|
522 @param aQuality Location request quality specified in the measuerment control |
|
523 */ |
|
524 void CMoLrStateMachine::MeasurementControlInd(const TPositionInfoBase& aPosInfo, |
|
525 const TLbsNetPosRequestQuality& aQuality, const TLbsNetPosRequestMethod& aPosMethod) |
|
526 { |
|
527 // Kill timer related to the MO-LR request |
|
528 iMoLrReqIssuedTimer->Cancel(); |
|
529 |
|
530 // Perform base class actions |
|
531 CStateMachineBase::MeasurementControlInd(aPosInfo, aQuality, aPosMethod); |
|
532 |
|
533 // Is the state machine inactive? |
|
534 if (!IsActive()) |
|
535 { |
|
536 // Perform a state transition |
|
537 PerformStateTransition(); |
|
538 } |
|
539 else |
|
540 { |
|
541 // Queue the request |
|
542 iQueue->AddRequest(EQueueMeasurementControl); |
|
543 } |
|
544 } |
|
545 |
|
546 |
|
547 /** Handle Network Measurement Control Error indication |
|
548 This is called by the protocol manager durinq an active MO-LR when |
|
549 a measurement control error is received from the network. |
|
550 */ |
|
551 void CMoLrStateMachine::MeasurementControlErrorInd(TInt aReason) |
|
552 { |
|
553 TBool cancelRequired = EFalse; |
|
554 TBool assistActionRequired = ETrue; |
|
555 |
|
556 // If there is no outstanding assistance data request then |
|
557 // inhibit assistance data error responses. |
|
558 if (!iMoLrReqIssuedTimer->IsActive() && |
|
559 !iAssistDataTimer->IsActive()) |
|
560 { |
|
561 assistActionRequired = EFalse; |
|
562 } |
|
563 |
|
564 // Is this the first measurement control received? |
|
565 if (!IsLocReqReceived() || (KErrCancel == aReason)) |
|
566 { |
|
567 // Kill timer related to the MO-LR request |
|
568 iMoLrReqIssuedTimer->Cancel(); |
|
569 cancelRequired = ETrue; |
|
570 } |
|
571 |
|
572 // Perform base class actions |
|
573 CStateMachineBase::HandleMeasureControlError(cancelRequired, aReason); |
|
574 |
|
575 // Ensure assistance data action only happens if necessary |
|
576 iAssistanceDataActionRequired = assistActionRequired; |
|
577 } |
|
578 |
|
579 |
|
580 /** Handle Network Session Result |
|
581 @param aResult The error result from network session closure. |
|
582 @param aPosInfo A pointer to final result location information from the network. |
|
583 This can be null if there is not final position provided. |
|
584 */ |
|
585 void CMoLrStateMachine::SessionResult(TInt aResult, const TPositionInfoBase* aPosInfo) |
|
586 { |
|
587 // Kill timer related to the facility result |
|
588 iFacResultTimer->Cancel(); |
|
589 |
|
590 iNetSessionResult = aResult; |
|
591 |
|
592 // Is a position provided? |
|
593 if (aPosInfo) |
|
594 { |
|
595 // Store network resulting location |
|
596 StoreNetResultLoc(*aPosInfo); |
|
597 iIsNetResultLocAvailable = ETrue; |
|
598 } |
|
599 else |
|
600 { |
|
601 iIsNetResultLocAvailable = EFalse; |
|
602 } |
|
603 |
|
604 // Is state machine inactive? |
|
605 if (!IsActive()) |
|
606 { |
|
607 // Perform a state transition |
|
608 PerformStateTransition(); |
|
609 } |
|
610 else |
|
611 { |
|
612 // Queue request |
|
613 iQueue->AddRequest(EQueueNetworkResult); |
|
614 } |
|
615 } |
|
616 |
|
617 |
|
618 /** Handle a network error indication. |
|
619 */ |
|
620 void CMoLrStateMachine::NetworkErrorInd() |
|
621 { |
|
622 // Do we need to report assistance data errors? |
|
623 if (!IsLocReqReceived()) |
|
624 { |
|
625 iAssistanceDataActionRequired = ETrue; |
|
626 } |
|
627 |
|
628 // Perform base class actions |
|
629 CStateMachineBase::NetworkErrorInd(); |
|
630 } |
|
631 |