|
1 // Copyright (c) 2008-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 base class for |
|
15 // protocol states used in the SUPL Protocol Module. |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalTechnology |
|
22 @deprecated |
|
23 */ |
|
24 |
|
25 #include "suplstatehandlerbase.h" |
|
26 #include "supldevloggermacros.h" |
|
27 #include "suplend.h" |
|
28 #include "suplgatewayinterface.h" |
|
29 |
|
30 /** Standard constructor. |
|
31 @param aMachine A reference to the parent state machine. |
|
32 */ |
|
33 CSuplStateHandlerBase::CSuplStateHandlerBase(CSuplFsmSessionBase& aMachine) |
|
34 : iMachine(aMachine) |
|
35 { |
|
36 SUPLLOG(ELogP1, "CSuplStateHandlerBase::CSuplStateHandlerBase() Begin\n"); |
|
37 SUPLLOG(ELogP1, "CSuplStateHandlerBase::CSuplStateHandlerBase() End\n"); |
|
38 } |
|
39 |
|
40 |
|
41 /** Standard destructor. |
|
42 */ |
|
43 CSuplStateHandlerBase::~CSuplStateHandlerBase() |
|
44 { |
|
45 SUPLLOG(ELogP1, "CSuplStateHandlerBase::~CSuplStateHandlerBase() Begin\n"); |
|
46 SUPLLOG(ELogP1, "CSuplStateHandlerBase::~CSuplStateHandlerBase() End\n"); |
|
47 } |
|
48 |
|
49 |
|
50 /** |
|
51 Utility method to retrieve the location Id in from the store |
|
52 @param Pointer to the location Id. Caller owns the heap object created. |
|
53 */ |
|
54 TBool CSuplStateHandlerBase::BuildLocationIdL(CSuplLocationId*& aLocationId) |
|
55 { |
|
56 SUPLLOG(ELogP1, "CSuplStateHandlerBase::BuildLocationIdL() Begin\n"); |
|
57 TBool ret = EFalse; |
|
58 CSuplLocationId* ptr = NULL; |
|
59 |
|
60 // Location ID is constructed with network information |
|
61 // stored by the state machine. |
|
62 |
|
63 RMobilePhone::TMobilePhoneNetworkInfoV1 networkInfo; |
|
64 RMobilePhone::TMobilePhoneLocationAreaV1 locationArea; |
|
65 |
|
66 if(iMachine.IsNetworkInfoAvailable()) |
|
67 { |
|
68 iMachine.RetrieveStoredNetworkInfo(networkInfo, locationArea); |
|
69 |
|
70 switch(networkInfo.iMode) |
|
71 { |
|
72 case RMobilePhone::ENetworkModeGsm: |
|
73 { |
|
74 RMobilePhone::TMobilePhoneCellInfoV9 cellInfo; |
|
75 ptr = CSuplLocationId::NewL(ESuplLocationTypeGsm); |
|
76 aLocationId = ptr; |
|
77 TLex(networkInfo.iCountryCode).Val(aLocationId->iGsmCellInfo->iRefMCC); |
|
78 TLex(networkInfo.iNetworkId).Val(aLocationId->iGsmCellInfo->iRefMNC); |
|
79 aLocationId->iGsmCellInfo->iRefLAC = locationArea.iAreaKnown?locationArea.iLocationAreaCode:0; |
|
80 aLocationId->iGsmCellInfo->iRefCI = locationArea.iCellId; |
|
81 if(iMachine.RetrieveStoredCellInfo(cellInfo)) |
|
82 { |
|
83 aLocationId->iGsmCellInfo->iTA = cellInfo.iTimingAdvance; |
|
84 } |
|
85 ret = ETrue; |
|
86 } |
|
87 break; |
|
88 |
|
89 case RMobilePhone::ENetworkModeWcdma: |
|
90 ptr = CSuplLocationId::NewL(ESuplLocationTypeWcdma); |
|
91 aLocationId = ptr; |
|
92 TLex(networkInfo.iCountryCode).Val(aLocationId->iWcdmaCellInfo->iRefMCC); |
|
93 TLex(networkInfo.iNetworkId).Val(aLocationId->iWcdmaCellInfo->iRefMNC); |
|
94 aLocationId->iWcdmaCellInfo->iRefUC = locationArea.iCellId; |
|
95 ret = ETrue; |
|
96 break; |
|
97 |
|
98 default: // only GSM and WCDMA networks are supported |
|
99 ret = EFalse; |
|
100 break; |
|
101 } |
|
102 |
|
103 } |
|
104 |
|
105 if(ptr != NULL) |
|
106 { |
|
107 RMobilePhone::TMobilePhoneCellInfoV9 cellInfo; |
|
108 if(iMachine.RetrieveStoredCellInfo(cellInfo)) |
|
109 { |
|
110 switch(cellInfo.iStatus) |
|
111 { |
|
112 case RMobilePhone::ECellInfoStatusNotCurrent: |
|
113 ptr->iStatus = ESuplLocStatusStale; |
|
114 break; |
|
115 case RMobilePhone::ECellInfoStatusCurrent: |
|
116 ptr->iStatus = ESuplLocStatusCurrent; |
|
117 break; |
|
118 default: |
|
119 case RMobilePhone::ECellInfoStatusUnknown: |
|
120 ptr->iStatus = ESuplLocStatusUnknown; |
|
121 break; |
|
122 } |
|
123 } |
|
124 else |
|
125 { |
|
126 ptr->iStatus = ESuplLocStatusCurrent; |
|
127 } |
|
128 } |
|
129 |
|
130 SUPLLOG(ELogP1, "CSuplStateHandlerBase::BuildLocationIdL() End\n"); |
|
131 return ret; |
|
132 } |
|
133 |
|
134 /** Actions on entering state EStatePositioningInProgress |
|
135 Events conductive to (re)entering this state are a SUPL POS |
|
136 message received from the SLP or a request from the positioning |
|
137 state machine for sending a SUPL POS with a positining protocol |
|
138 payload. |
|
139 */ |
|
140 TBool CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() |
|
141 { |
|
142 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() Begin\n"); |
|
143 TBool actionsTaken = EFalse; |
|
144 |
|
145 // Check first if a positioning payload is available in the event |
|
146 // store for sending out |
|
147 const CSuplPosPayload* constPosPayload = iMachine.RetrievePosPayload(); |
|
148 CSuplPosPayload* posPayload = const_cast <CSuplPosPayload*> (constPosPayload); |
|
149 if (posPayload) |
|
150 { |
|
151 ASSERT(iMachine.IsSessionConnected()); |
|
152 |
|
153 // Set payload in a SUPL POS |
|
154 CSuplPos* suplPos = CSuplPos::NewLC(ETrue); |
|
155 suplPos->SetPosPayload(posPayload); |
|
156 |
|
157 CSuplSessionId* msgId = iMachine.MessageSessionId(); |
|
158 |
|
159 suplPos->SetSessionId(*msgId); |
|
160 |
|
161 CleanupStack::Pop(suplPos); |
|
162 // Ask the Connection Manager to send the SUPL POS message |
|
163 iMachine.Observer().ConnectionManager().SendMessage(suplPos, iMachine.SessionId().SessionNum()); |
|
164 |
|
165 // If this was the last of the SUPL POS messages (positioning state machine |
|
166 // has terminated), start the SUPL END timer. |
|
167 if (iMachine.RetrievePositioningSessionEnded()) |
|
168 { |
|
169 iMachine.StartSuplEndTimer(); |
|
170 } |
|
171 |
|
172 actionsTaken = ETrue; |
|
173 } |
|
174 else |
|
175 { |
|
176 // There must be a SUPL POS in the event store |
|
177 CSuplMessageBase* suplMessage = const_cast <CSuplMessageBase*> (iMachine.RetrieveSuplMessage()); |
|
178 ASSERT(suplMessage != NULL); |
|
179 ASSERT(CSuplMessageBase::ESuplPos == suplMessage->MessageType()); |
|
180 |
|
181 if ((suplMessage != NULL) && (CSuplMessageBase::ESuplPos == suplMessage->MessageType())) |
|
182 { |
|
183 CSuplPos* suplPosMessage = static_cast <CSuplPos*>(suplMessage); |
|
184 |
|
185 // make sure the session id matches the one received in earlier messages |
|
186 CSuplSessionId *sessId = CSuplSessionId::NewLC(); |
|
187 suplPosMessage->GetSessionId(*sessId); |
|
188 if (! ((*(iMachine.MessageSessionId())) == (*sessId))) |
|
189 { |
|
190 iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId); |
|
191 // Store received session Id for sending later in SUPL END as per SUPL specification |
|
192 CleanupStack::Pop(sessId); |
|
193 iMachine.SetMessageSessionId(sessId); // ownership transferred |
|
194 delete suplPosMessage; |
|
195 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() End\n"); |
|
196 return actionsTaken; |
|
197 } |
|
198 else |
|
199 { |
|
200 CleanupStack::PopAndDestroy(sessId); |
|
201 } |
|
202 // Extract the payload |
|
203 posPayload = suplPosMessage->PosPayload(); |
|
204 ASSERT(posPayload != NULL); |
|
205 if (posPayload) |
|
206 { |
|
207 // send the payload to the positioning fsm |
|
208 iMachine.PositioningFsm()->ProcessPositioningMessage(posPayload); |
|
209 } |
|
210 |
|
211 // Delete the SUPL POS message |
|
212 delete suplPosMessage; |
|
213 actionsTaken = ETrue; |
|
214 } |
|
215 } |
|
216 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() End\n"); |
|
217 return actionsTaken; |
|
218 } |
|
219 |
|
220 /** Actions on entering state EStatePositionReceived |
|
221 This method extracts a position from a SUPL END message and |
|
222 sends it to LBS. |
|
223 */ |
|
224 TBool CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() |
|
225 { |
|
226 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() Begin\n"); |
|
227 TBool actionsTaken = EFalse; |
|
228 |
|
229 // Extract the position from the SUPL END in the event store and send to |
|
230 // LBS in a ProcessLocationUpdate method |
|
231 TPosition position; |
|
232 |
|
233 // There must be a SUPL END in the store |
|
234 CSuplMessageBase* suplMessage = const_cast <CSuplMessageBase*> (iMachine.RetrieveSuplMessage()); |
|
235 |
|
236 ASSERT(suplMessage != NULL); |
|
237 ASSERT(CSuplMessageBase::ESuplEnd == suplMessage->MessageType()); |
|
238 |
|
239 if ((suplMessage != NULL) && (CSuplMessageBase::ESuplEnd == suplMessage->MessageType())) |
|
240 { |
|
241 |
|
242 CSuplEnd* suplEndPtr = static_cast <CSuplEnd*>(suplMessage); |
|
243 |
|
244 // make sure the session id matches the one received in earlier messages |
|
245 CSuplSessionId *sessId = CSuplSessionId::NewLC(); |
|
246 suplEndPtr->GetSessionId(*sessId); |
|
247 |
|
248 // Compare only the SET session ID as this may be the first message we get from |
|
249 // the SLP and the SLP session ID is not yet known. |
|
250 CSuplSetSessionId* receivedSetSessId = (*(iMachine.MessageSessionId())).iSetSessionId; |
|
251 CSuplSetSessionId* storedSetSessId = (*sessId).iSetSessionId; |
|
252 if (! ((*receivedSetSessId)== (*storedSetSessId))) |
|
253 { |
|
254 iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId); |
|
255 // Store received session Id for sending later in SUPL END as per SUPL specification |
|
256 CleanupStack::Pop(sessId); |
|
257 iMachine.SetMessageSessionId(sessId); // ownership transferred |
|
258 delete suplEndPtr; |
|
259 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() End\n"); |
|
260 return actionsTaken; |
|
261 } |
|
262 else |
|
263 { |
|
264 CleanupStack::PopAndDestroy(sessId); |
|
265 } |
|
266 |
|
267 // There must be a position in the SUPL END |
|
268 ASSERT(suplEndPtr->PositionPresent()); |
|
269 if (suplEndPtr->PositionPresent()) |
|
270 { |
|
271 suplEndPtr->GetPosition(position); |
|
272 |
|
273 // Use position to build a TPositionInfo object |
|
274 // and send it to LBS |
|
275 TPositionInfo pos; |
|
276 pos.SetPosition(position); |
|
277 const TPositionModuleId id = {KSuplv1UidValue}; |
|
278 pos.SetModuleId(id); |
|
279 pos.SetUpdateType(EPositionUpdateGeneral); |
|
280 pos.SetPositionModeReason(EPositionModeReasonNone); |
|
281 |
|
282 // If the position has been received and no positioning session |
|
283 // has taken place, then the position is the reference location |
|
284 // calculated based on cell-id. |
|
285 if (!iMachine.PosSessionConducted()) |
|
286 { |
|
287 pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork); |
|
288 } |
|
289 else |
|
290 { |
|
291 // Position calculated in Terminal Assisted mode unless the |
|
292 // SUPL END has an error code, in which case the position is |
|
293 // the reference location. |
|
294 if(suplEndPtr->StatusCodePresent()) |
|
295 { |
|
296 pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork); |
|
297 } |
|
298 else |
|
299 { |
|
300 pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted); |
|
301 } |
|
302 } |
|
303 |
|
304 iMachine.Observer().Gateway().NetworkLocationInd(iMachine.LbsSessionId(), pos); |
|
305 |
|
306 actionsTaken = ETrue; |
|
307 } |
|
308 |
|
309 // SUPL POS message no longer needed |
|
310 delete suplEndPtr; |
|
311 } |
|
312 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() End\n"); |
|
313 return actionsTaken; |
|
314 } |
|
315 |
|
316 |
|
317 /** Actions on entering state EStateSuplSessionEnded |
|
318 |
|
319 Send a SUPL END message to the SUPL server. This state is reached |
|
320 after the state machine was cancelled for some reason. |
|
321 */ |
|
322 TBool CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() |
|
323 { |
|
324 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() Begin\n"); |
|
325 TBool verRequired = EFalse; |
|
326 TBool statusCodeRequired = ETrue; |
|
327 // Send a SUPL END to the SLP. Most likely reason to be here is |
|
328 // that the machine is cancelling due to explicit client cancel, a |
|
329 // client privacy rejection, an error or a timeout. If so, the |
|
330 // cancel source and reason can be taken from the event store. |
|
331 // |
|
332 // The only other use case where we end up in here is for MTLRs |
|
333 // where the SUPL INIT has specified "no Position". |
|
334 |
|
335 |
|
336 // Take cancel source and reason from the event store |
|
337 CSuplFsmSessionBase::TCancelSource source; |
|
338 CSuplFsmSessionBase::TCancelReason reason; |
|
339 iMachine.RetrieveCancelInfo(source,reason); |
|
340 |
|
341 // work out the reason code to set in a SUPL END |
|
342 TSuplStatusCode statusCode = ESuplStatusUnspecified; |
|
343 switch (source) |
|
344 { |
|
345 case CSuplFsmSessionBase::ECancelNone: |
|
346 // Not here after a cancel...assuming |
|
347 // there has been a SUPL INIT with "no position" |
|
348 // and we are here to send a SUPL END with privacy |
|
349 // acceptance. |
|
350 |
|
351 verRequired = ETrue; |
|
352 statusCodeRequired = ETrue; |
|
353 statusCode = ESuplStatusConsentGrantedByUser; |
|
354 |
|
355 break; |
|
356 case CSuplFsmSessionBase::ECancelNetwork: |
|
357 |
|
358 switch (reason) |
|
359 { |
|
360 case CSuplFsmSessionBase::EReasonInsuficcientSecurity: |
|
361 // no matching supl status code |
|
362 statusCode = ESuplStatusUnspecified; |
|
363 break; |
|
364 // Since the connection manager performs the decoding |
|
365 // of received SUPL messages, all of the errors in decoding |
|
366 // show as having ECancelNetwork source, hence: |
|
367 case CSuplFsmSessionBase::EReasonParsingError: |
|
368 statusCode = ESuplStatusProtocolError; |
|
369 break; |
|
370 case CSuplFsmSessionBase::EReasonDataMissing: |
|
371 statusCode = ESuplStatusDataMissing; |
|
372 break; |
|
373 case CSuplFsmSessionBase::EReasonUnexpectedDataValue: |
|
374 statusCode = ESuplStatusUnexpectedDataValue; |
|
375 break; |
|
376 default: |
|
377 statusCode = ESuplStatusUnspecified; |
|
378 break; |
|
379 } |
|
380 break; |
|
381 |
|
382 case CSuplFsmSessionBase::ECancelPosProt: |
|
383 statusCode = ESuplStatusPosMethodFailure; |
|
384 break; |
|
385 |
|
386 case CSuplFsmSessionBase::ECancelSuplProt: |
|
387 switch (reason) |
|
388 { |
|
389 case CSuplFsmSessionBase::EReasonMethodMismatch: |
|
390 statusCode = ESuplStatusPosMethodMismatch; |
|
391 break; |
|
392 case CSuplFsmSessionBase::EReasonInvalidSessId: |
|
393 statusCode = ESuplStatusInvalidSessionId; |
|
394 break; |
|
395 case CSuplFsmSessionBase::EReasonUnexpectedMessage: |
|
396 statusCode = ESuplStatusUnexpectedMessage; |
|
397 break; |
|
398 default: |
|
399 statusCode = ESuplStatusUnspecified; |
|
400 break; |
|
401 } |
|
402 break; |
|
403 |
|
404 case CSuplFsmSessionBase::ECancelClient: |
|
405 // no matching status code in SUPL |
|
406 if (CSuplFsmSessionBase:: EReasonPrivacyRejected == reason) |
|
407 { |
|
408 statusCode = ESuplStatusConsentDeniedByUser; |
|
409 verRequired = ETrue; |
|
410 } |
|
411 else if (CSuplFsmSessionBase::EReasonFutilePosCalc == reason) |
|
412 { |
|
413 statusCode = ESuplStatusPosMethodFailure; |
|
414 } |
|
415 else |
|
416 { |
|
417 statusCode = ESuplStatusUnspecified; |
|
418 } |
|
419 break; |
|
420 |
|
421 case CSuplFsmSessionBase::ECancelClosing: |
|
422 default: |
|
423 //No other source of cancel should result in this method being called |
|
424 ASSERT(EFalse); |
|
425 break; |
|
426 } |
|
427 |
|
428 // Build and send a SUPL END |
|
429 CSuplEnd* suplEndPtr = CSuplEnd::NewLC(ETrue); |
|
430 |
|
431 if (statusCodeRequired) |
|
432 { |
|
433 suplEndPtr->SetStatusCode(statusCode); |
|
434 } |
|
435 |
|
436 if (verRequired) |
|
437 { |
|
438 // Set the Ver field in SUPL END |
|
439 TBuf8<8> ver; |
|
440 iMachine.RetrieveVer(ver); |
|
441 User::LeaveIfError(suplEndPtr->SetVer(ver)); |
|
442 } |
|
443 |
|
444 // Set the session Id |
|
445 CSuplSessionId* msgId = iMachine.MessageSessionId(); |
|
446 suplEndPtr->SetSessionId(*msgId); |
|
447 |
|
448 CleanupStack::Pop(suplEndPtr); |
|
449 iMachine.Observer().ConnectionManager().SendMessage(suplEndPtr, iMachine.SessionId().SessionNum()); |
|
450 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() End\n"); |
|
451 return ETrue; |
|
452 } |
|
453 |
|
454 |
|
455 /** Actions on entering state EStateLbsSessionEnded |
|
456 |
|
457 This method informs LBS that the session has ended. |
|
458 */ |
|
459 TBool CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() |
|
460 { |
|
461 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() Begin\n"); |
|
462 TBool actionsTaken = EFalse; |
|
463 |
|
464 TInt sessionCompletionReason = KErrNone; // reason sent to LBS |
|
465 |
|
466 // Check the event store to see in the completion reason |
|
467 // has to be different from KErrNone |
|
468 // Take cancel source and reason from the event store. |
|
469 // |
|
470 CSuplFsmSessionBase::TCancelSource cancelSource; |
|
471 CSuplFsmSessionBase::TCancelReason cancelReason; |
|
472 iMachine.RetrieveCancelInfo(cancelSource,cancelReason); |
|
473 |
|
474 if (cancelSource != CSuplFsmSessionBase::ECancelNone) |
|
475 { |
|
476 // Session was cancelled. Error code is KErrCancel |
|
477 // except if network connection is down (KErrDisconnected). |
|
478 if ((cancelSource == CSuplFsmSessionBase::ECancelNetwork) |
|
479 && (cancelReason == CSuplFsmSessionBase::EReasonDisconnected)) |
|
480 { |
|
481 sessionCompletionReason = KErrDisconnected; |
|
482 } |
|
483 else |
|
484 { |
|
485 sessionCompletionReason = KErrCancel; |
|
486 } |
|
487 actionsTaken = ETrue; |
|
488 } |
|
489 |
|
490 // Check if the session was terminated after an unexpected |
|
491 // SUPL END or a SUPL END with reason code indicating an error |
|
492 else if (iMachine.IsUnexpectedSuplEndStored()) |
|
493 { |
|
494 // Complete with KErrPositionProtocolErr |
|
495 sessionCompletionReason = KErrPositionProtocolErr; |
|
496 actionsTaken = ETrue; |
|
497 } |
|
498 else |
|
499 { |
|
500 // If the session has not been cancelled, there could be a |
|
501 // SUPL END message in the store (there won't be one if the |
|
502 // SUPL END carried position information as it is dealt with |
|
503 // in a previous state). |
|
504 const CSuplMessageBase* suplEnd = iMachine.RetrieveSuplMessage(); |
|
505 |
|
506 if ((suplEnd != NULL) && (CSuplMessageBase::ESuplEnd == (const_cast <CSuplMessageBase*>(suplEnd))->MessageType())) |
|
507 { |
|
508 delete suplEnd; |
|
509 } |
|
510 |
|
511 sessionCompletionReason = KErrNone; |
|
512 actionsTaken = ETrue; |
|
513 } |
|
514 |
|
515 if (actionsTaken) |
|
516 { |
|
517 iMachine.Observer().Gateway().SessionCompleteInd(iMachine.LbsSessionId(), sessionCompletionReason); |
|
518 } |
|
519 iMachine.SetSessionInProgress(EFalse); |
|
520 SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() End\n"); |
|
521 return actionsTaken; |
|
522 } |
|
523 |
|
524 |
|
525 /** Utility method to convert a numeric string to Binary Coded Decimal string |
|
526 |
|
527 Taken from section 8.3 of the OMA SUPL document UserPlane Location Protocol OMA-TS-ULP-V1-0-20070615-A |
|
528 The BCD string is stored in an 8 octet buffer with 2 digits per octet. |
|
529 Each digit is encoded 0000 to 1001 ( 0 to 9). |
|
530 Bits 8765 of octet n encoding digit 2n |
|
531 Bits 4321 of octet n encoding digit 2(n-1)+1 |
|
532 Unused digits in the string are filled with 0xFF |
|
533 |
|
534 */ |
|
535 void CSuplStateHandlerBase::ConvertToBcd(TDes8& aBcdString) |
|
536 { |
|
537 |
|
538 const TUint8 KMaxBcdStringLength = 8; |
|
539 const TUint8 fillBuffer[KMaxBcdStringLength] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
|
540 |
|
541 TBool LeastSignificantNibble(ETrue); |
|
542 TInt OctetCount = 0; |
|
543 TChar nextChar; |
|
544 TUint8 nextOctet = 0; |
|
545 TLex lexString(*iMachine.Msisdn()); |
|
546 |
|
547 aBcdString.Zero(); |
|
548 while (!lexString.Eos()) |
|
549 { |
|
550 nextChar = lexString.Get(); |
|
551 if (nextChar.IsDigit()) // ignore any non-numeric characters |
|
552 { |
|
553 if (LeastSignificantNibble) |
|
554 { |
|
555 nextOctet = nextChar.GetNumericValue(); //store digit in L.S. nibble |
|
556 LeastSignificantNibble = EFalse; |
|
557 } |
|
558 else |
|
559 { |
|
560 nextOctet |= (nextChar.GetNumericValue()<<4); //store digit in M.S. nibble |
|
561 aBcdString.Append(nextOctet); |
|
562 OctetCount++; |
|
563 LeastSignificantNibble = ETrue; |
|
564 } |
|
565 } |
|
566 } |
|
567 |
|
568 // All of the decimal string has been converted - deal with an half filled octet |
|
569 if (!LeastSignificantNibble) |
|
570 { |
|
571 nextOctet |= 0xF0; |
|
572 aBcdString.Append(nextOctet); |
|
573 OctetCount++; |
|
574 } |
|
575 |
|
576 // Fill remainder of string with 0xFF values |
|
577 aBcdString.Append(fillBuffer, (KMaxBcdStringLength-OctetCount)); |
|
578 |
|
579 } |
|
580 |