|
1 // Copyright (c) 1997-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 // Wait for Incoming Call |
|
15 // |
|
16 // |
|
17 |
|
18 #include "NOTIFY.H" |
|
19 #include "mSLOGGER.H" |
|
20 #include "LINE.H" |
|
21 #include "CALL.H" |
|
22 #include "ATCALL.H" |
|
23 #include "ATIO.H" |
|
24 #include "PHONE.H" |
|
25 |
|
26 _LIT8(KIncomingExtCallIndication,"+CRING:*"); |
|
27 _LIT8(KIncomingCallIndication,"RING"); |
|
28 _LIT8(KNetworkRegistration,"+CREG:*"); |
|
29 |
|
30 // |
|
31 // CTimer-derived class to switch line status to idle a fixed period after the last |
|
32 // RING arrives. Use this rather than CATIO::SetTimeOut() because that has only one |
|
33 // timer which could be cancelled by another concurrently running AT command |
|
34 // |
|
35 CSetLineToIdle* CSetLineToIdle::NewL(CATWaitForCall* aWait) |
|
36 // |
|
37 // Create the SetLineToIdle async one shot |
|
38 // |
|
39 { |
|
40 CSetLineToIdle* setLineToIdle=new(ELeave) CSetLineToIdle(aWait); |
|
41 CleanupStack::PushL(setLineToIdle); |
|
42 setLineToIdle->ConstructL(); |
|
43 CleanupStack::Pop(); |
|
44 return setLineToIdle; |
|
45 } |
|
46 |
|
47 CSetLineToIdle::CSetLineToIdle(CATWaitForCall* aWait) |
|
48 // |
|
49 // C'tor |
|
50 // |
|
51 :CTimer(CActive::EPriorityLow), iWait(aWait) |
|
52 { |
|
53 CActiveScheduler::Add(this); |
|
54 } |
|
55 |
|
56 |
|
57 CSetLineToIdle::~CSetLineToIdle() |
|
58 { |
|
59 Cancel(); |
|
60 } |
|
61 |
|
62 void CSetLineToIdle::RunL() |
|
63 { |
|
64 iWait->EndRing(); |
|
65 } |
|
66 |
|
67 void CSetLineToIdle::Start() |
|
68 { |
|
69 if (IsActive()) |
|
70 Cancel(); |
|
71 After(KTimeBetweenRings); |
|
72 } |
|
73 |
|
74 void CSetLineToIdle::Stop() |
|
75 { |
|
76 Cancel(); |
|
77 } |
|
78 |
|
79 // |
|
80 // CATWaitForCall. Expects a RING constantly, and upon receiving one checks if either line |
|
81 // wants to be notified. Sets all lines and calls ringing anyway, and a timer to switch |
|
82 // them back to idle after a specified time has elapsed since the last RING. |
|
83 // |
|
84 |
|
85 CATWaitForCall* CATWaitForCall::NewL(CATIO* aIo,CTelObject* aTelObject,CPhoneGlobals* aPhoneGlobals) |
|
86 { |
|
87 CATWaitForCall* waitForCall=new(ELeave) CATWaitForCall(aIo,aTelObject,aPhoneGlobals); |
|
88 CleanupStack::PushL(waitForCall); |
|
89 waitForCall->ConstructL(); |
|
90 CleanupStack::Pop(); |
|
91 return waitForCall; |
|
92 } |
|
93 |
|
94 CATWaitForCall::CATWaitForCall(CATIO* aIo,CTelObject* aTelObject,CPhoneGlobals* aPhoneGlobals) |
|
95 : CATBase(aIo,aTelObject,aPhoneGlobals) |
|
96 {} |
|
97 |
|
98 void CATWaitForCall::ConstructL() |
|
99 { |
|
100 iSetLineToIdle = CSetLineToIdle::NewL(this); |
|
101 iRingExpectString=NULL; |
|
102 iCRingExpectString=NULL; |
|
103 iRegExpectString=NULL; |
|
104 iTailExpectString=NULL; |
|
105 } |
|
106 |
|
107 CATWaitForCall::~CATWaitForCall() |
|
108 { |
|
109 iIo->RemoveExpectStrings(this); |
|
110 iRingExpectString=NULL; |
|
111 iCRingExpectString=NULL; |
|
112 iRegExpectString=NULL; |
|
113 iTailExpectString=NULL; |
|
114 iIo->WriteAndTimerCancel(this); |
|
115 delete iSetLineToIdle; |
|
116 } |
|
117 |
|
118 void CATWaitForCall::StartWait() |
|
119 { |
|
120 if (iRingExpectString==NULL) |
|
121 { |
|
122 LOGTEXT(_L8("WaitForCall:\tStarting wait for incoming call")); |
|
123 iCRingExpectString=iIo->AddExpectString(this,KIncomingExtCallIndication); |
|
124 iRingExpectString=iIo->AddExpectString(this,KIncomingCallIndication); |
|
125 iRegExpectString=iIo->AddExpectString(this,KNetworkRegistration); |
|
126 iState=EATWaitForUnsolicited; |
|
127 } |
|
128 } |
|
129 |
|
130 void CATWaitForCall::EndRing() |
|
131 // |
|
132 // Only called from the RunL of CSetLineToIdle, which occurs a fixed period after the |
|
133 // last RING. StopBothLinesRinging() sets the calls on both lines to idle |
|
134 // |
|
135 { |
|
136 LOGTEXT(_L8("WaitForCall:\tRinging has stopped")); |
|
137 ChangeLineStatus(RCall::EStatusIdle); |
|
138 STATIC_CAST(CPhoneHayes*,iTelObject)->StopRinging(); |
|
139 iRingCounter = 0; |
|
140 iPhoneGlobals->iNotificationStore->CheckNotification(iTelObject,ERingStopped); |
|
141 } |
|
142 |
|
143 void CATWaitForCall::ResetRingCounter() |
|
144 { |
|
145 iRingCounter = 0; |
|
146 iSetLineToIdle->Stop(); |
|
147 } |
|
148 |
|
149 void CATWaitForCall::CompleteWithIOError(TEventSource /*aSource*/,TInt /*aStatus*/) |
|
150 // |
|
151 // CATIO removes expect strings in event of IO error |
|
152 // |
|
153 { |
|
154 iRingExpectString=NULL; |
|
155 iCRingExpectString=NULL; |
|
156 iRegExpectString=NULL; |
|
157 iTailExpectString=NULL; |
|
158 } |
|
159 |
|
160 void CATWaitForCall::EventSignal(TEventSource aSource) |
|
161 // |
|
162 // Completes Incoming Call Notification for every ring. |
|
163 // This is different from the previous TSY, but is needed for the Nokia 7110 which does |
|
164 // not supply multiple RING notifications. |
|
165 // |
|
166 { |
|
167 __ASSERT_ALWAYS(aSource!=EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteNotExpected)); |
|
168 if (aSource!=EReadCompletion) |
|
169 return; |
|
170 switch (iState) |
|
171 { |
|
172 case EATWaitForUnsolicited: |
|
173 if (iIo->FoundChatString()==iCRingExpectString) |
|
174 { |
|
175 LOGTEXT(_L8("CATWaitForCall::EventSignal +CRING detected")); |
|
176 LOGTEXT(_L8("CATWaitForCall::EventSignal Will only process +CRING if phone is initialised...")); |
|
177 if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneInitialised) |
|
178 { |
|
179 LOGTEXT(_L8("CATWaitForCall::EventSignal Processing +CRING")); |
|
180 TInt index=KErrNotFound; |
|
181 TRAPD(ret,index=ParseIncomingCallIndicationL()); |
|
182 if (ret==KErrNone) |
|
183 { |
|
184 iRingCounter+=1; |
|
185 if (iRingCounter==1) |
|
186 { |
|
187 LOGTEXT(_L8("CATWaitForCall::EventSignal This is 1st +CRING")); |
|
188 // Only do this once |
|
189 ChangeLineStatus(RCall::EStatusRinging); |
|
190 STATIC_CAST(CPhoneHayes*,iTelObject)->SetCallRinging(index); |
|
191 } |
|
192 iSetLineToIdle->Start(); |
|
193 } |
|
194 } |
|
195 } |
|
196 else if (iIo->FoundChatString()==iRingExpectString) |
|
197 { |
|
198 LOGTEXT(_L8("WaitForCall:\tRING detected")); |
|
199 if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneInitialised) |
|
200 { |
|
201 iRingCounter+=1; |
|
202 if (iRingCounter==1) |
|
203 { |
|
204 // Only do this once |
|
205 ChangeLineStatus(RCall::EStatusRinging); |
|
206 STATIC_CAST(CPhoneHayes*,iTelObject)->SetAmbiguousDataFaxCallRinging(); |
|
207 } |
|
208 iSetLineToIdle->Start(); |
|
209 } |
|
210 } |
|
211 else if (iIo->FoundChatString()==iRegExpectString) |
|
212 { |
|
213 LOGTEXT(_L8("WaitForCall:\t+CREG detected")); |
|
214 TRAPD(ret,ParseNetworkRegistrationL()); |
|
215 if (ret!=KErrNone) |
|
216 { |
|
217 LOGTEXT(_L8("WaitForCall:\tBad +CREG response?")); |
|
218 } |
|
219 } |
|
220 else |
|
221 { |
|
222 LOGTEXT(_L8("WaitForCall:\tUnexpected string")); |
|
223 iTelObject->ReqCompleted(iReqHandle,KErrGeneral); |
|
224 iReqHandle = NULL; |
|
225 break; |
|
226 } |
|
227 break; |
|
228 |
|
229 default: |
|
230 break; |
|
231 } |
|
232 } |
|
233 |
|
234 // Compare with +CMTI handling in GSMSNOTI.CPP |
|
235 // which has a similar problem |
|
236 /** |
|
237 * Parse incoming call indication string and return a value corresponding to the call type. |
|
238 * |
|
239 * @note modified by Dmitry Lyokhin 24.04.02 |
|
240 * |
|
241 * @return KFaxLineIndex for fax call |
|
242 * KVoiceLineIndex for voice call |
|
243 * KDataLineIndex for data call or if call modifier is not recognized |
|
244 * |
|
245 * @note This function can leave with code KErrUnknown |
|
246 * if 'RING' token not found |
|
247 */ |
|
248 TInt CATWaitForCall::ParseIncomingCallIndicationL() |
|
249 { |
|
250 //-- possible incoming call indication strings that can be parsed correctly |
|
251 //-- string corresponds to |
|
252 |
|
253 // +CRING: VOICE -> voice call |
|
254 // +CRING: FAX -> fax call |
|
255 // +CRING: DATA -> data call |
|
256 // +CRING: VOICE/xxx -> voice call |
|
257 // RING -> data call |
|
258 |
|
259 //-- alternating mode calls |
|
260 // +CRING: ALT FAX/VOICE -> fax call |
|
261 // +CRING: ALT DATA/VOICE -> data call |
|
262 // +CRING: ALT VOICE/FAX -> fax call |
|
263 // +CRING: ALT VOICE/DATA -> data call |
|
264 |
|
265 |
|
266 iBuffer.Set(iIo->CurrentLine()); |
|
267 |
|
268 TInt index = KErrNotFound; |
|
269 TLex8 Lex1(iBuffer); |
|
270 |
|
271 Lex1.SkipSpace(); |
|
272 |
|
273 //-- the first token must be '+CRING' or 'RING' |
|
274 if( Lex1.NextToken().Find(_L8("RING")) < 0 ) |
|
275 { //-- the token not found, leave |
|
276 LOGTEXT(_L8("CATWaitForCall::ParseIncomingCallIndicationL *RING not found")); |
|
277 User::Leave(KErrUnknown); |
|
278 } |
|
279 |
|
280 Lex1.SkipSpaceAndMark(); |
|
281 Lex1.SkipCharacters(); |
|
282 |
|
283 //-- try to find 'ALT' token that indicates the alternatng mode call |
|
284 if( Lex1.MarkedToken().Find(_L8("ALT")) >=0 ) |
|
285 {//-- Alternating mode call, skip the token "ALT" |
|
286 } |
|
287 else Lex1.UnGetToMark(); |
|
288 |
|
289 Lex1.SkipSpace(); |
|
290 |
|
291 TPtrC8 CallStr=Lex1.RemainderFromMark(); |
|
292 |
|
293 _LIT8(KDataToken, "DATA"); |
|
294 _LIT8(KFaxToken, "FAX"); |
|
295 _LIT8(KVoiceToken, "VOICE"); |
|
296 |
|
297 if(CallStr.Find(KDataToken) >= 0) index=KDataLineIndex; //-- Data call detected |
|
298 else |
|
299 if(CallStr.Find(KFaxToken) >= 0) index=KFaxLineIndex; //-- Fax call detected |
|
300 else |
|
301 if(CallStr.Find(KVoiceToken) >= 0) index=KVoiceLineIndex; //-- Voice call detected |
|
302 else |
|
303 {//-- unmatched call type, assume data call by default |
|
304 LOGTEXT(_L8("CATWaitForCall::ParseIncomingCallIndicationL +CRING has unmatched type!, assuming data")); |
|
305 index=KDataLineIndex; |
|
306 //User::Leave(KErrUnknown); |
|
307 } |
|
308 |
|
309 iIo->ClearCurrentLine(); |
|
310 LOGTEXT2(_L8("+CRING for line %d"),index); |
|
311 |
|
312 return index; |
|
313 } |
|
314 |
|
315 |
|
316 void CATWaitForCall::ParseNetworkRegistrationL() |
|
317 { |
|
318 // +CREG: <n>, <stat> [, <lac>, <ci> ] -- solicited |
|
319 // +CREG: <stat> [, <lac>, <ci> ] -- unsolicited |
|
320 // number, number [, "hex", "hex" ] |
|
321 |
|
322 RMobilePhone::TMobilePhoneLocationAreaV1& locationInfo = iPhoneGlobals->iPhoneStatus.iLocationArea; |
|
323 locationInfo.iAreaKnown= EFalse; |
|
324 locationInfo.iLocationAreaCode=0; |
|
325 locationInfo.iCellId=0; |
|
326 |
|
327 ParseLineLC(); |
|
328 CATParamListEntry* entry; |
|
329 TDblQueIter<CATParamListEntry> iter(iRxResults); |
|
330 |
|
331 entry=iter++; |
|
332 if (entry==NULL) |
|
333 User::Leave(KErrGeneral); |
|
334 // should be +CREG: |
|
335 |
|
336 entry=iter++; |
|
337 if (entry==NULL) |
|
338 User::Leave(KErrGeneral); |
|
339 TLex8 lex(entry->iResultPtr); |
|
340 TInt number; |
|
341 (void)User::LeaveIfError(lex.Val(number)); |
|
342 |
|
343 entry=iter++; |
|
344 if (entry!=NULL) |
|
345 { // is this <status> in a solicited +CREG? |
|
346 lex.Assign(entry->iResultPtr); |
|
347 if (lex.Val(number)==KErrNone) |
|
348 entry=iter++; // yes - <n> has been replaced by <status> |
|
349 } |
|
350 |
|
351 // optional <lac> and <ci> |
|
352 if (entry != NULL) |
|
353 { |
|
354 lex.Assign(entry->iResultPtr); |
|
355 (void)User::LeaveIfError(lex.Val(locationInfo.iLocationAreaCode,EHex)); |
|
356 locationInfo.iAreaKnown = ETrue; |
|
357 entry=iter++; |
|
358 } |
|
359 if (entry!=NULL) |
|
360 { |
|
361 lex.Assign(entry->iResultPtr); |
|
362 (void)User::LeaveIfError(lex.Val(locationInfo.iCellId,EHex)); |
|
363 locationInfo.iAreaKnown = ETrue; |
|
364 } |
|
365 |
|
366 |
|
367 |
|
368 if (number<0 || number > RMobilePhone::ERegisteredRoaming) |
|
369 User::Leave(KErrGeneral); |
|
370 |
|
371 RMobilePhone::TMobilePhoneRegistrationStatus regstatus; |
|
372 regstatus = MappingRegistrationStatusFromETSIToMM(&number); //Mapp the ETSI value number to MM enum for network registration status. |
|
373 |
|
374 RMobilePhone::TMobilePhoneRegistrationStatus newstatus = regstatus;// change number to be of type MobilePhone... |
|
375 RMobilePhone::TMobilePhoneRegistrationStatus oldstatus = iPhoneGlobals->iPhoneStatus.iRegistrationStatus; |
|
376 |
|
377 if (oldstatus != newstatus) |
|
378 { |
|
379 LOGTEXT3(_L8("MmTsy:CATWaitForCall:\tRegistrationStatus changed %d->%d"), oldstatus, newstatus); |
|
380 iPhoneGlobals->iPhoneStatus.iRegistrationStatus = newstatus; |
|
381 |
|
382 iPhoneGlobals->iNotificationStore->CheckNotification(iTelObject,ERegistrationStatusChanged); |
|
383 |
|
384 if ( (newstatus == RMobilePhone::ERegisteredOnHomeNetwork || newstatus == RMobilePhone::ERegisteredRoaming) |
|
385 || (oldstatus == RMobilePhone::ERegisteredOnHomeNetwork || oldstatus == RMobilePhone::ERegisteredRoaming) |
|
386 ) |
|
387 { |
|
388 // interesting transition - need new operator details |
|
389 LOGTEXT(_L8("MmTsy:CATWaitForCall:\tCurrent Network has changed")); |
|
390 iPhoneGlobals->iPhoneStatus.iNetworkChanged=ETrue; |
|
391 if (iPhoneGlobals->iPhoneStatus.iInitStatus == EPhoneInitialised && |
|
392 !iPhoneGlobals->iEventSignalActive) |
|
393 { |
|
394 // no current activity - fire up +COPS stuff immediately |
|
395 LOGTEXT(_L8("MmTsy:CATWaitForCall:\tNo activity - Checking current network immediately")); |
|
396 iPhoneGlobals->CheckForChangeOfNetwork(); |
|
397 } |
|
398 } |
|
399 } |
|
400 |
|
401 CleanupStack::PopAndDestroy(); |
|
402 } |
|
403 |
|
404 RMobilePhone::TMobilePhoneRegistrationStatus CATWaitForCall::MappingRegistrationStatusFromETSIToMM(TInt *aNumber) |
|
405 // This function is mapping the ETSI standard format for the registartion status of the phone to multimode representation. |
|
406 // TINT *number is the ETSI value for the registration value to be converted. |
|
407 |
|
408 { |
|
409 RMobilePhone::TMobilePhoneRegistrationStatus regstatus = RMobilePhone::ERegistrationUnknown; |
|
410 switch (*aNumber) |
|
411 { |
|
412 case 0: |
|
413 regstatus = RMobilePhone::ENotRegisteredNoService; |
|
414 break; |
|
415 case 1: |
|
416 regstatus = RMobilePhone::ERegisteredOnHomeNetwork; |
|
417 break; |
|
418 case 2: |
|
419 regstatus = RMobilePhone::ENotRegisteredSearching; |
|
420 break; |
|
421 case 3: |
|
422 regstatus = RMobilePhone::ERegistrationDenied; |
|
423 break; |
|
424 case 4: |
|
425 regstatus = RMobilePhone::ERegistrationUnknown; |
|
426 break; |
|
427 case 5: |
|
428 regstatus = RMobilePhone::ERegisteredRoaming; |
|
429 break; |
|
430 default: |
|
431 break; |
|
432 } |
|
433 return regstatus; |
|
434 } |