|
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 // |
|
15 |
|
16 #include "FAXSERV.H" |
|
17 #include "fax_reversebytes.h" |
|
18 #include "FAXMDRV.H" |
|
19 #include "FAXMODEM.H" |
|
20 |
|
21 |
|
22 // this module has three parts |
|
23 // first receive routines rx |
|
24 // second transmit routines tx |
|
25 // third utilities |
|
26 |
|
27 /********************************************************************/ |
|
28 |
|
29 CFaxModemDriver *CFaxClass1::NewLC (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress) |
|
30 { |
|
31 CFaxModemDriver *self = new (ELeave) CFaxClass1; |
|
32 CleanupStack::PushL (self); |
|
33 self->ConstructL (aFaxServerSessionSettings, aProgress); |
|
34 return self; |
|
35 } |
|
36 |
|
37 CFaxModemDriver *CFaxClass1::NewL (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress) |
|
38 { |
|
39 CFaxModemDriver *self = NewLC (aFaxServerSessionSettings, aProgress); |
|
40 CleanupStack::Pop (); |
|
41 return self; |
|
42 } |
|
43 /********************************************************************/ |
|
44 |
|
45 // here we set up a fax receive - Phase A |
|
46 // this does require HDLC frames to be sent |
|
47 |
|
48 TInt CFaxClass1::RxConnectL () |
|
49 { |
|
50 TInt faxIdFcf; // CSI or CIG |
|
51 TInt capabilityFcf; // DIS or DTC |
|
52 TBuf8 < 3 > faxIdTxt; // CSI or CIG |
|
53 TBuf8 < 3 > capabilityTxt; // DIS or DTC |
|
54 |
|
55 TInt i, x; |
|
56 iDisBytes = 3; |
|
57 iOldFrame.Zero (); |
|
58 |
|
59 // we query the modem to find out what its speed capabilities are |
|
60 |
|
61 CheckCadenceExportL (_L8 ("AT+FRM=?\r")); |
|
62 // coverity[check_return] |
|
63 iModem->ImportL (iResults, 2); |
|
64 iModem->iOurMessage.Format (_L8 ("%S"), &iResults); |
|
65 iModem->ProgressUpdateL (); |
|
66 iModem->GetMatchL (_L8 ("OK"), 1); |
|
67 |
|
68 // the available speeds are stored in iResults |
|
69 // we set our proposed speed to the highest compatible with faxini settings |
|
70 |
|
71 if ((iResults.FindF (_L8 ("24"))) >= 0) |
|
72 iActualFaxSpeed = 24; |
|
73 else |
|
74 return (KFaxErrModemNotWorking); |
|
75 if ((iFaxServerSessionSettings->iMaxSpeed) > 2400) |
|
76 if ((iResults.FindF (_L8 ("48"))) >= 0) |
|
77 iActualFaxSpeed = 48; |
|
78 if ((iFaxServerSessionSettings->iMaxSpeed) > 4800) |
|
79 if ((iResults.FindF (_L8 ("96"))) >= 0) |
|
80 iActualFaxSpeed = 96; |
|
81 if ((iFaxServerSessionSettings->iMaxSpeed) > 9600) |
|
82 if ((iResults.FindF (_L8 ("145"))) >= 0) |
|
83 iActualFaxSpeed = 145; |
|
84 |
|
85 // we now prepare our DIS/DTC answer capabilities frame |
|
86 // the resolution and compression are taken from our settings |
|
87 |
|
88 for (x = 0; x < 5; x++) |
|
89 iDisFrame.byte[x] = 0; |
|
90 iDisFrame.bit.b09 = 0; |
|
91 iDisFrame.bit.b10 = 1; |
|
92 iDisFrame.bit.b20 = 1; |
|
93 iDisFrame.bit.b21 = 1; |
|
94 iDisFrame.bit.b22 = 1; |
|
95 iDisFrame.bit.b23 = 1; |
|
96 if (iFaxServerSessionSettings->iRxResolution == EFaxFine) |
|
97 iDisFrame.bit.b15 = 1; |
|
98 if (iFaxServerSessionSettings->iRxCompression == EModifiedRead) |
|
99 iDisFrame.bit.b16 = 1; |
|
100 |
|
101 // if (iFaxServerSessionSettings->iMode & KFaxWaitForRing) |
|
102 // { |
|
103 // while ((iModem->GetMatchL (_L8 ("RING"), 3)) == 0); |
|
104 // iTimeOfLastRing.UniversalTime(); |
|
105 // } |
|
106 // else |
|
107 // { |
|
108 if (((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) && (!(iFaxServerSessionSettings->iMode & KFaxWaitForRing))) |
|
109 // if ((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) |
|
110 DialFaxOnDemandL (); |
|
111 // } |
|
112 |
|
113 // if we a trying to poll, we've dialled, so we wait for a DIS from the answerer |
|
114 // otherwise we do an answer ourselves |
|
115 |
|
116 if (iFaxServerSessionSettings->iMode & KFaxPoll) |
|
117 { |
|
118 faxIdFcf = KT30_CIG; |
|
119 faxIdTxt.Copy (_L8 ("CIG")); |
|
120 capabilityFcf = KT30_DTC; |
|
121 capabilityTxt.Copy (_L8 ("DTC")); |
|
122 iModem->iOurMessage.Format (_L8 ("about to poll fax")); |
|
123 |
|
124 } |
|
125 else |
|
126 { |
|
127 faxIdFcf = KT30_CSI; |
|
128 faxIdTxt.Copy (_L8 ("CSI")); |
|
129 capabilityFcf = KT30_DIS; |
|
130 capabilityTxt.Copy (_L8 ("DIS")); |
|
131 CheckCadenceExportL (_L8 ("ATA\r")); |
|
132 iModem->iOurMessage.Format (_L8 ("about to receive fax")); |
|
133 } |
|
134 |
|
135 iModem->iProgress.iPhase = ECallEstablishment; |
|
136 iModem->ProgressUpdateL (); |
|
137 |
|
138 for (;;) |
|
139 { |
|
140 if (!(iModem->ImportL (iResults, KT30_T1))) |
|
141 return (KFaxErrCannotConnect); |
|
142 iModem->iOurMessage.Format (_L8 ("%S"), &iResults); |
|
143 iModem->ProgressUpdateL (); |
|
144 if ((iResults.FindF (_L8 ("NO DIALTONE"))) >= 0 || |
|
145 iResults.FindF (_L8 ("NO DIAL TONE")) >= 0) |
|
146 return (KFaxErrNoDialTone); |
|
147 if ((iResults.FindF (_L8 ("BUSY"))) >= 0) |
|
148 return (KFaxErrBusy); |
|
149 if ((iResults.FindF (_L8 ("NO ANSWER"))) >= 0) |
|
150 return (KFaxErrNoAnswer); |
|
151 if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0) |
|
152 return (KFaxErrNoCarrier); |
|
153 if ((iResults.FindF (_L8 ("CONNECT"))) >= 0) |
|
154 break; |
|
155 } |
|
156 |
|
157 if (iFaxServerSessionSettings->iMode & KFaxPoll) |
|
158 User::LeaveIfError (RxPrePollL ()); |
|
159 else |
|
160 { |
|
161 iModem->iOurMessage.Format (_L8 ("Fax call detected")); |
|
162 iModem->ProgressUpdateL (); |
|
163 } |
|
164 |
|
165 iModem->iOurMessage.Format (_L8 ("sending %S"), &faxIdTxt); |
|
166 iModem->ProgressUpdateL (); |
|
167 iFrame.Zero (); |
|
168 iFrame.Append (KT30_CTLNXT); |
|
169 iFrame.Append (faxIdFcf); |
|
170 for (i = 20; i > iFaxServerSessionSettings->iFaxId.Length (); i--) |
|
171 iFrame.Append (0x20); |
|
172 for (i = iFaxServerSessionSettings->iFaxId.Length (); i;) |
|
173 iFrame.Append (iFaxServerSessionSettings->iFaxId[--i]); |
|
174 if (SendframeL (iFrame) != 1) |
|
175 return (KFaxErrCSIorCIG); |
|
176 |
|
177 // we follow that with our DIS frame |
|
178 |
|
179 iModem->iOurMessage.Format (_L8 ("sending %S"), &capabilityTxt); |
|
180 iModem->iProgress.iPhase = ESessionNegotiation; |
|
181 iModem->ProgressUpdateL (); |
|
182 iDisFrame.byte[1] &= 0xc3; |
|
183 switch (iActualFaxSpeed) |
|
184 { |
|
185 case 48: |
|
186 iDisFrame.byte[1] |= 0x08; |
|
187 break; /* V.27 4800+2400 */ |
|
188 case 96: |
|
189 iDisFrame.byte[1] |= 0x0c; |
|
190 break; /* & V.29 9600+7200 */ |
|
191 case 145: |
|
192 iDisFrame.byte[1] |= 0x2c; |
|
193 break; /* & V.17 14400+1200+9600+7200 */ |
|
194 default: |
|
195 iDisFrame.byte[1] |= 0x00; /* V.27 fallback 2400 only */ |
|
196 } |
|
197 iFrame.Zero (); |
|
198 iFrame.Append (KT30_CTLLST); |
|
199 iFrame.Append (capabilityFcf); |
|
200 for (i = 0; i < iDisBytes; i++) |
|
201 iFrame.Append (iDisFrame.byte[i]); |
|
202 if (SendframeL (iFrame) != 1) |
|
203 return (KFaxErrDISorDTC); |
|
204 |
|
205 // and now we await the negotiation from the caller |
|
206 // note that we'll resend the last frame (DIS or DTC) if we get no reply |
|
207 // until we get a TSI or a DCS (which show the DIS or DTC was received) |
|
208 |
|
209 return (RxPrePageL ()); |
|
210 } |
|
211 |
|
212 /********************************************************************/ |
|
213 |
|
214 // here we prepare for receiving via a poll |
|
215 // we have received a DIS in iResults, so check the polling bit |
|
216 // iResults[0] is the address |
|
217 // iResults[1] is the control |
|
218 // iResults[2] is the FCF |
|
219 // iResults[3] has bits 1-8 of the FIF |
|
220 // iResults[4] has bits 9-16 of the FIF |
|
221 // the polling bit is bit 9 |
|
222 |
|
223 TInt CFaxClass1::RxPrePollL () |
|
224 { |
|
225 TInt pollDocsAvailable = 0; |
|
226 TInt i; |
|
227 iResults.Copy (_L8 ("CALL JUST ANSWERED")); |
|
228 for (;;) |
|
229 { |
|
230 if (GetframeL (iResults) == 0) |
|
231 return (KFaxErrFrameFail); |
|
232 iModem->ProgressUpdateL (); |
|
233 |
|
234 // the third byte in the frame is the FCF (fax control field) |
|
235 |
|
236 switch ((TUint8) iResults[2]) |
|
237 { |
|
238 case 0x20: // this marks a non-standard frame, which we ignore |
|
239 iModem->iOurMessage.Format (_L8 ("NSF nonstandard facilities Frame")); |
|
240 iModem->ProgressUpdateL (); |
|
241 break; |
|
242 |
|
243 case 0x40: // this marks the receiver ID |
|
244 iModem->iOurMessage.Format (_L8 ("CSI identity Frame")); |
|
245 iModem->ProgressUpdateL (); |
|
246 iModem->iProgress.iAnswerback.Zero (); |
|
247 for (i = 22; i > 2; i--) |
|
248 iModem->iProgress.iAnswerback.Append (iResults[i]); |
|
249 iModem->iOurMessage.Format (_L8 ("Remote fax ID is %S"), &iModem->iProgress.iAnswerback); |
|
250 iModem->ProgressUpdateL (); |
|
251 break; // the capability frame should follows |
|
252 |
|
253 case 0x80: // this marks the receiver capability frame |
|
254 iModem->iOurMessage.Format (_L8 ("DIS capability Frame")); |
|
255 iModem->ProgressUpdateL (); |
|
256 iFcfXbit = 1; // we've received a DIS, so set the X bit |
|
257 pollDocsAvailable = iResults[4] & 0x01; // and record the polling bit too |
|
258 break; |
|
259 |
|
260 case 0xfa: // this means we were asked to disconnect |
|
261 RxDCNL (); |
|
262 return (KFaxErrRemoteDCN); |
|
263 |
|
264 default:; |
|
265 } |
|
266 |
|
267 // if a final frame we return |
|
268 // else we just issue AT+FRH=3 and continue |
|
269 |
|
270 if (iResults[1] & 0x10) |
|
271 break; |
|
272 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
273 } |
|
274 |
|
275 if (pollDocsAvailable) |
|
276 { |
|
277 iModem->iOurMessage.Format (_L8 ("Polling bit set")); |
|
278 iModem->ProgressUpdateL (); |
|
279 return (KErrNone); |
|
280 } |
|
281 return (KFaxNothingToPoll); // if the other machine isn't pollable we exit |
|
282 } |
|
283 /********************************************************************/ |
|
284 |
|
285 // here we negotiate a fax reception - Phase B |
|
286 // this function is always called after we have connected. However, |
|
287 // it can be called at other times if we have requested a renegotiation |
|
288 // or if the sender want to change the fax parameters |
|
289 |
|
290 TInt CFaxClass1::RxPrePageL () |
|
291 { |
|
292 TInt x, z, i, nullCounter; |
|
293 TUint8 thisChar, lastChar; |
|
294 TInt ticks; |
|
295 |
|
296 for (;;) |
|
297 { |
|
298 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
299 if (GetframeL (iResults) == 0) |
|
300 return (KFaxErrFrameFail); |
|
301 iModem->iOurMessage.Format (_L8 ("Response received")); |
|
302 iModem->ProgressUpdateL (); |
|
303 |
|
304 // analyse the possible responses |
|
305 |
|
306 switch ((TUint8) iResults[2]) |
|
307 { |
|
308 case 0x42: // this is the sender ID - their capability should follow |
|
309 |
|
310 iModem->iOurMessage.Format (_L8 ("TSI identity Frame")); |
|
311 iModem->ProgressUpdateL (); |
|
312 iModem->iProgress.iAnswerback.Zero (); |
|
313 for (i = 22; i > 2; i--) |
|
314 iModem->iProgress.iAnswerback.Append (iResults[i]); |
|
315 iModem->iOurMessage.Format (_L8 ("Remote fax ID is %S"), &iModem->iProgress.iAnswerback); |
|
316 iModem->ProgressUpdateL (); |
|
317 break; |
|
318 |
|
319 case 0x82: // here's the sender capability frame - the most complex case |
|
320 |
|
321 iModem->iOurMessage.Format (_L8 ("DCS capability Frame")); |
|
322 iModem->ProgressUpdateL (); |
|
323 for (i = 0; i < 5; i++) |
|
324 iDcsFrame.byte[i] = (TUint8) iResults[i + 3]; |
|
325 |
|
326 // we have the DCS saved - we analyse it for speed and resolution and compression |
|
327 |
|
328 if (iDcsFrame.bit.b24 == 0) |
|
329 iDcsFrame.byte[3] = 0; |
|
330 |
|
331 iModem->iProgress.iResolution = TFaxResolution (iDcsFrame.bit.b15); |
|
332 iModem->iProgress.iCompression = TFaxCompression (iDcsFrame.bit.b16); |
|
333 |
|
334 switch (iDcsFrame.byte[1] & 0x3c) |
|
335 { |
|
336 case 0x08: |
|
337 iActualFaxSpeed = 48; |
|
338 break; /* 4800 V.27 */ |
|
339 case 0x04: |
|
340 iActualFaxSpeed = 96; |
|
341 break; /* 9600 V.29 */ |
|
342 case 0x0c: |
|
343 iActualFaxSpeed = 72; |
|
344 break; /* 7200 V.29 */ |
|
345 case 0x24: |
|
346 iActualFaxSpeed = 97; |
|
347 break; /* 9600 V.17 */ |
|
348 case 0x2c: |
|
349 iActualFaxSpeed = 73; |
|
350 break; /* 7200 V.17 */ |
|
351 case 0x20: |
|
352 iActualFaxSpeed = 145; |
|
353 break; /* 14400 V.17 */ |
|
354 case 0x28: |
|
355 iActualFaxSpeed = 121; |
|
356 break; /* 12000 V.17 */ |
|
357 default: |
|
358 iActualFaxSpeed = 24; /* 2400 V.27 */ |
|
359 } |
|
360 |
|
361 i = (iActualFaxSpeed & (~1)); |
|
362 |
|
363 // now we prepare to recieve the training frame that follows the DCS |
|
364 // we try to get the carrier at this speed three times before giving up |
|
365 |
|
366 for (x = 0; x < 3; x++) |
|
367 { |
|
368 iModem->iOurMessage.Format (_L8 ("setting %d00"), i); |
|
369 iModem->iProgress.iSpeed = (i * 100); |
|
370 iModem->ProgressUpdateL (); |
|
371 |
|
372 iResults.Copy (_L8 ("AT+FRM=")); |
|
373 iResults.AppendNum (iActualFaxSpeed); |
|
374 iResults.Append (_L8 ("\r")); |
|
375 iModem->ExportL (iResults); |
|
376 z = FramestatL (); |
|
377 if (z == 1) |
|
378 break; |
|
379 if (z != 0) |
|
380 { |
|
381 iModem->TxcharL (Kcan); |
|
382 if (FramestatL () < 0) |
|
383 iModem->TxcharL (Kreturn); |
|
384 ReceiveSilenceL (); |
|
385 iModem->iOurMessage.Format (_L8 ("sending FTT")); |
|
386 iModem->ProgressUpdateL (); |
|
387 iFrame.Append (KT30_FTT); |
|
388 if (SendframeL (iFrame) == 0) |
|
389 return (KFaxErrTrainFail); |
|
390 break; |
|
391 } |
|
392 } |
|
393 if (x == 3) |
|
394 return (KFaxErrAtNegotiatedSpeed); |
|
395 |
|
396 // once we have a carrier, we start receiving the training frame |
|
397 // we look for a clear 750 milliseconds of zeros ending in <dle><etx> |
|
398 // this is determined by calculating the number of number of null bytes |
|
399 // taken at any given speed |
|
400 |
|
401 iModem->iOurMessage.Format (_L8 ("training .... ")); |
|
402 iModem->ProgressUpdateL (); |
|
403 |
|
404 ticks = (CLK_TCK * 165) / 100; // bug fix - was originally "CLK_TICK * (165/100)" |
|
405 // This failed because 165/100 is rounded to 1 because |
|
406 // ticks is an integer and that made the fax server |
|
407 // training for 1 second instead of 1.5 |
|
408 for (lastChar = 0, nullCounter = 0;;) |
|
409 { |
|
410 if (iModem->RxcharWaitL (ticks) == 0) |
|
411 { |
|
412 break; |
|
413 } |
|
414 thisChar = iModem->iReadone[0]; |
|
415 if (nullCounter != (i * 75 / 8)) |
|
416 { |
|
417 if (thisChar != 0) |
|
418 nullCounter = 0; |
|
419 else |
|
420 ++nullCounter; |
|
421 } |
|
422 if ((thisChar == Ketx) && (lastChar == Kdle)) |
|
423 break; |
|
424 lastChar = thisChar; |
|
425 } |
|
426 if (FramestatL () < 0) |
|
427 { |
|
428 iModem->TxcharL (Kcan); |
|
429 if (FramestatL () < 0) |
|
430 iModem->TxcharL (Kreturn); |
|
431 } |
|
432 |
|
433 // now we check the count of null bytes and either send FTT |
|
434 // (in which case the sender will send a new DCS and try again) |
|
435 // or else send CFR confirmation and wait for the first page |
|
436 |
|
437 iFrame.Zero (); |
|
438 iFrame.Append (KT30_CTLLST); |
|
439 if (nullCounter == (i * 75 / 8)) |
|
440 { |
|
441 iModem->iOurMessage.Format (_L8 ("training OK")); |
|
442 iModem->ProgressUpdateL (); |
|
443 } |
|
444 else |
|
445 { |
|
446 ReceiveSilenceL (); |
|
447 iModem->iOurMessage.Format (_L8 ("sending FTT")); |
|
448 iModem->ProgressUpdateL (); |
|
449 iFrame.Append (KT30_FTT); |
|
450 if (SendframeL (iFrame) == 0) |
|
451 return (KFaxErrTrainFail); |
|
452 break; |
|
453 } |
|
454 |
|
455 iModem->iOurMessage.Format (_L8 ("sending CFR")); |
|
456 iModem->ProgressUpdateL (); |
|
457 |
|
458 iFrame.Append (KT30_CFR); |
|
459 if (SendframeL (iFrame) == 0) |
|
460 return (KFaxErrCFR); |
|
461 |
|
462 // after we send a CFR, we interpret a failure to |
|
463 // establish a high-speed carrier as an indication |
|
464 // that the sender didn't get our CFR, and will |
|
465 // act as if they received an FTT |
|
466 |
|
467 if (RxSetHighSpeedL () != KErrNone) |
|
468 break; |
|
469 return (KErrNone); |
|
470 |
|
471 // lastly, we cater for the sender disconnecting us, |
|
472 // either because we couldn't train or because our |
|
473 // capabilities were wrong, or because they were only trying |
|
474 // to hack our fax machine |
|
475 |
|
476 case 0xfa: |
|
477 RxDCNL (); |
|
478 return (KFaxErrRemoteDCN); |
|
479 |
|
480 default:; |
|
481 } |
|
482 } |
|
483 } |
|
484 /********************************************************************/ |
|
485 |
|
486 // this is a small function to set a class 1 fax modem to phase C |
|
487 // reception speed (found in iActualFaxSpeed) in preparation for |
|
488 // receiving data. This is called before the first page and also |
|
489 // between pages. If the modem can't find a high speed carrier, we |
|
490 // leave the caller to decide what action to take - if we'd just sent a |
|
491 // page confirmation we should try resending our last negotiating frame |
|
492 // in case it was lost, but if we have just sent a CFR, we wait for the |
|
493 // sender to retrain. |
|
494 |
|
495 // If the protocol is out of sync and we get a low speed carrier |
|
496 // then we'll get a +FCERROR response (same as ERROR) |
|
497 |
|
498 TInt CFaxClass1::RxSetHighSpeedL () |
|
499 { |
|
500 TInt x, portSpeed; |
|
501 switch (iActualFaxSpeed) |
|
502 { |
|
503 case 145: |
|
504 x = 144; |
|
505 portSpeed = 146; |
|
506 break; |
|
507 case 121: |
|
508 x = 120; |
|
509 portSpeed = 122; |
|
510 break; |
|
511 case 97: |
|
512 x = 96; |
|
513 portSpeed = 98; |
|
514 break; |
|
515 case 73: |
|
516 x = 72; |
|
517 portSpeed = 74; |
|
518 break; |
|
519 default: |
|
520 x = portSpeed = iActualFaxSpeed; |
|
521 } |
|
522 |
|
523 iModem->iOurMessage.Format (_L8 ("setting %d00"), x); |
|
524 iModem->iProgress.iSpeed = (x * 100); |
|
525 iModem->ProgressUpdateL (); |
|
526 |
|
527 iResults.Copy (_L8 ("AT+FRM=")); |
|
528 iResults.AppendNum (portSpeed); |
|
529 iResults.Append (_L8 ("\r")); |
|
530 iModem->ExportL (iResults); |
|
531 |
|
532 x = FramestatL (KT30_T2); // always wait 6 seconds before a timeout |
|
533 if (x == 1) |
|
534 { |
|
535 return (RxStartPageL ()); |
|
536 } |
|
537 if (x != 0) |
|
538 { |
|
539 iModem->TxcharL (Kcan); |
|
540 if (FramestatL () < 0) |
|
541 iModem->TxcharL (Kreturn); |
|
542 } |
|
543 return (KFaxErrAtNegotiatedSpeed); |
|
544 } |
|
545 /********************************************************************/ |
|
546 |
|
547 // after page data has been received, we go back to 300 bps negotiation |
|
548 // for the post-page message which the transmitter sends 75ms after the |
|
549 // end of the data |
|
550 |
|
551 TInt CFaxClass1::RxPostPageL () |
|
552 { |
|
553 TInt i, x = 0; |
|
554 iOldFrame.Zero (); |
|
555 iModem->iProgress.iPhase = EPostPageStatus; |
|
556 iModem->ProgressUpdateL (); |
|
557 |
|
558 // wait for the modem to react to the end of fax data before proceeding |
|
559 |
|
560 if ((iModem->GetMatchL (_L8 ("NO CARRIER"), 5)) == 0) |
|
561 return (KFaxErrCannotEndData); |
|
562 |
|
563 for (;;) |
|
564 { |
|
565 |
|
566 // we start by requesting a frame |
|
567 |
|
568 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
569 if (GetframeL (iResults) == 0) |
|
570 { |
|
571 if (x++ == 3) |
|
572 return (KFaxErrFrameFail); |
|
573 continue; |
|
574 } |
|
575 |
|
576 iModem->iOurMessage.Format (_L8 ("Response received")); |
|
577 iModem->ProgressUpdateL (); |
|
578 |
|
579 // now we work out what it is |
|
580 |
|
581 switch ((TUint8) iResults[2]) |
|
582 { |
|
583 |
|
584 // the first case is where the last page was the end of the fax |
|
585 |
|
586 case 0x3e: // we recognize PRI-Q frames but treat them like non-PRI-Q variants |
|
587 iModem->iOurMessage.Format (_L8 ("PRI-Q bit set")); |
|
588 iModem->ProgressUpdateL (); |
|
589 // fallthrough |
|
590 case 0x2e: |
|
591 iModem->iOurMessage.Format (_L8 ("EOP end of page %u and transmission"), iModem->iProgress.iPage); |
|
592 iModem->ProgressUpdateL (); |
|
593 iModem->iOurMessage.Format (_L8 ("sending MCF")); |
|
594 iModem->ProgressUpdateL (); |
|
595 iFrame.Zero (); |
|
596 iFrame.Append (KT30_CTLLST); |
|
597 iFrame.Append (KT30_MCF); |
|
598 if (SendframeL (iFrame) == 0) |
|
599 return (KFaxErrMCF); |
|
600 |
|
601 // now it isn't an error if get a DCN and hang up |
|
602 // so, loop and wait for it |
|
603 |
|
604 iModem->iProgress.iPhase = EDisconnection; |
|
605 continue; |
|
606 |
|
607 // the second case is where the sender demands a renegotiation |
|
608 |
|
609 case 0x9e: // we recognize PRI-Q frames but treat them like non-PRI-Q variants |
|
610 iModem->iOurMessage.Format (_L8 ("PRI-Q bit set")); |
|
611 iModem->ProgressUpdateL (); |
|
612 // fallthrough |
|
613 case 0x8e: |
|
614 iModem->iOurMessage.Format (_L8 ("EOM end of page %u and document"), iModem->iProgress.iPage); |
|
615 iModem->ProgressUpdateL (); |
|
616 iModem->iOurMessage.Format (_L8 ("sending MCF")); |
|
617 iModem->ProgressUpdateL (); |
|
618 iFrame.Zero (); |
|
619 iFrame.Append (KT30_CTLLST); |
|
620 iFrame.Append (KT30_MCF); |
|
621 if (SendframeL (iFrame) == 0) |
|
622 return (KFaxErrMCF); |
|
623 iModem->iProgress.iPhase = ESessionNegotiation; |
|
624 iOldFrame.Zero (); |
|
625 iOldFrame.Append (KT30_CTLLST); |
|
626 iOldFrame.Append (KT30_DIS); |
|
627 for (i = 0; i < iDisBytes; i++) |
|
628 iOldFrame.Append (iDisFrame.byte[i]); |
|
629 return (RxPrePageL ()); |
|
630 |
|
631 // the third case is where another page is going to follow |
|
632 |
|
633 case 0x5e: // we recognize PRI-Q frames but treat them like non-PRI-Q variants |
|
634 |
|
635 iModem->iOurMessage.Format (_L8 ("PRI-Q bit set")); |
|
636 iModem->ProgressUpdateL (); |
|
637 // fallthrough |
|
638 case 0x4e: |
|
639 iModem->iOurMessage.Format (_L8 ("MPS end of page %u"), iModem->iProgress.iPage); |
|
640 iModem->ProgressUpdateL (); |
|
641 |
|
642 iModem->iOurMessage.Format (_L8 ("sending MCF")); |
|
643 iModem->ProgressUpdateL (); |
|
644 |
|
645 iFrame.Zero (); |
|
646 iFrame.Append (KT30_CTLLST); |
|
647 iFrame.Append (KT30_MCF); |
|
648 if (SendframeL (iFrame) == 0) |
|
649 return (KFaxErrMCF); |
|
650 |
|
651 for (x = 0; x < 3; x++) |
|
652 { |
|
653 if (RxSetHighSpeedL () == KErrNone) |
|
654 return (KErrNone); |
|
655 iModem->iOurMessage.Format (_L8 ("Resending last response .... ")); |
|
656 iModem->ProgressUpdateL (); |
|
657 if (SendframeL (iOldFrame) == 0) |
|
658 return (KFaxErrMCF); |
|
659 } |
|
660 return (KFaxErrMCF); |
|
661 |
|
662 // the fourth case is where we are told to disconnect |
|
663 // it's an error if we hadn't been expecting it |
|
664 |
|
665 case 0xfa: |
|
666 if (iModem->iProgress.iPhase == EDisconnection) |
|
667 { |
|
668 RxDCNL (); |
|
669 return (KErrNone); |
|
670 } |
|
671 |
|
672 RxDCNL (); |
|
673 return (KFaxErrRemoteDCN); |
|
674 |
|
675 // the fifth case is where we see a negotiation frame |
|
676 // the sixth case is where we see a negotiation frame |
|
677 // our supposed page may have been a mistake |
|
678 // just go back to phase B and try to recover that way |
|
679 |
|
680 case 0x42: // TSI frame |
|
681 case 0x82: // DCS frame |
|
682 if ((TUint8) iResults[2] == 0x42) |
|
683 iModem->iOurMessage.Format (_L8 ("TSI identity")); |
|
684 else |
|
685 iModem->iOurMessage.Format (_L8 ("DCS capability")); |
|
686 iModem->iOurMessage.Append (_L8 (" Frame - renegotiating session parameters")); |
|
687 iModem->ProgressUpdateL (); |
|
688 iModem->iProgress.iPhase = ESessionNegotiation; |
|
689 return (RxPrePageL ()); |
|
690 |
|
691 // the last case is where we see an unsupported frame |
|
692 // if it is a final frame we ask for a repeat via CRP |
|
693 |
|
694 default: |
|
695 if (SendCRPL () != KErrNone) |
|
696 return (KFaxErrCRP); |
|
697 } |
|
698 } |
|
699 } |
|
700 /********************************************************************/ |
|
701 |
|
702 // here we have detected a disconnection frame so we hang up the modem |
|
703 |
|
704 void CFaxClass1::RxDCNL () |
|
705 { |
|
706 iModem->iOurMessage.Format (_L8 ("DCN disconnect Frame")); |
|
707 iModem->iProgress.iPhase = EDisconnection; |
|
708 iModem->ProgressUpdateL (); |
|
709 } |
|
710 /********************************************************************/ |
|
711 |
|
712 // here we send a DCN disconnect frame and then hang up the modem |
|
713 |
|
714 TInt CFaxClass1::TxDCNL () |
|
715 { |
|
716 iModem->iOurMessage.Format (_L8 ("sending DCN")); |
|
717 iModem->iProgress.iPhase = EDisconnection; |
|
718 iModem->ProgressUpdateL (); |
|
719 ReceiveSilenceL (); |
|
720 iFrame.Zero (); |
|
721 iFrame.Append (KT30_CTLLST); |
|
722 iFrame.Append (KT30_DCN); |
|
723 if (SendframeL (iFrame) == 0) |
|
724 return (KFaxErrDCN); |
|
725 return (KErrNone); |
|
726 } |
|
727 /********************************************************************/ |
|
728 |
|
729 // here we set up a fax transmit - Phase A |
|
730 // there's no HDLC stuff here |
|
731 |
|
732 TInt CFaxClass1::TxConnectL () |
|
733 { |
|
734 |
|
735 // we query the modem to find out what its speed capabilities are |
|
736 iModem->ExportL (_L8 ("AT+FTM=?\r")); |
|
737 // coverity[check_return] |
|
738 iModem->ImportL (iResults, 2); |
|
739 iModem->iOurMessage.Format (_L8 ("%S"), &iResults); |
|
740 iModem->ProgressUpdateL (); |
|
741 iModem->GetMatchL (_L8 ("OK"), 1); |
|
742 |
|
743 // the available speeds are stored in iResults |
|
744 // we set our proposed speed to the highest compatible with faxini settings |
|
745 |
|
746 if ((iResults.FindF (_L8 ("24"))) >= 0) |
|
747 iActualFaxSpeed = 24; |
|
748 else |
|
749 return (KFaxErrModemNotWorking); |
|
750 if ((iFaxServerSessionSettings->iMaxSpeed) > 2400) |
|
751 if ((iResults.FindF (_L8 ("48"))) >= 0) |
|
752 iActualFaxSpeed = 48; |
|
753 if ((iFaxServerSessionSettings->iMaxSpeed) > 4800) |
|
754 if ((iResults.FindF (_L8 ("96"))) >= 0) |
|
755 iActualFaxSpeed = 96; |
|
756 if ((iFaxServerSessionSettings->iMaxSpeed) > 9600) |
|
757 if ((iResults.FindF (_L8 ("145"))) >= 0) |
|
758 iActualFaxSpeed = 145; |
|
759 |
|
760 // we now issue our ATD command, and if we aren't in immediate |
|
761 // transmit mode (already off hook) then we dial a number |
|
762 |
|
763 iModem->ExportL (_L8 ("ATD")); |
|
764 if ((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) |
|
765 iModem->ExportL (iFaxServerSessionSettings->iPhoneNumber); |
|
766 iModem->TxcharL (Kreturn); |
|
767 iModem->iOurMessage.Format (_L8 ("Call has been dialled")); |
|
768 iModem->iProgress.iPhase = ECallEstablishment; |
|
769 iModem->ProgressUpdateL (); |
|
770 |
|
771 // now we wait up to KDialTimeout seconds for the modem to connect |
|
772 |
|
773 for (;;) |
|
774 { |
|
775 if (!(iModem->ImportL (iResults, KDialTimeout))) |
|
776 return (KFaxErrNoDial); |
|
777 iModem->iOurMessage.Format (_L8 ("%S"), &iResults); |
|
778 iModem->ProgressUpdateL (); |
|
779 if ((iResults.FindF (_L8 ("NO DIALTONE"))) >= 0 || |
|
780 iResults.FindF (_L8 ("NO DIAL TONE")) >= 0) |
|
781 return (KFaxErrNoDialTone); |
|
782 if ((iResults.FindF (_L8 ("BUSY"))) >= 0) |
|
783 return (KFaxErrBusy); |
|
784 if ((iResults.FindF (_L8 ("NO ANSWER"))) >= 0) |
|
785 return (KFaxErrNoAnswer); |
|
786 if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0) |
|
787 return (KFaxErrNoCarrier); |
|
788 if ((iResults.FindF (_L8 ("CONNECT"))) >= 0) |
|
789 break; |
|
790 } |
|
791 |
|
792 // we can now go on to phase B |
|
793 |
|
794 iResults.Copy (_L8 ("CALL JUST ANSWERED")); |
|
795 return (TxPrePageL ()); |
|
796 } |
|
797 /********************************************************************/ |
|
798 |
|
799 // here we negotiate a fax transmission, or a polled reception - Phase B |
|
800 // this function is always called after we have connected. However, |
|
801 // it can be called at other times if the receiver has requested a |
|
802 // renegotiation or if we want to change the fax parameters, in which |
|
803 // case we would enter with iModem->iProgress.iPhase == RFax::EPostPageStatus |
|
804 |
|
805 TInt CFaxClass1::TxPrePageL () |
|
806 { |
|
807 TInt i; |
|
808 //TInt x; |
|
809 TInt successiveErrors = 0; |
|
810 TInt trainingAttempts = 0; |
|
811 iDcsBytes = 3; |
|
812 iOldFrame.Zero (); |
|
813 TInt ticks; |
|
814 TInt trainbytes; |
|
815 |
|
816 // this routine is one big frame waiting loop - note that on first entry |
|
817 // here we have set the length of the last frame stored in iOldFrame to |
|
818 // zero, so we don't resend any last frame on first entry here. |
|
819 // Subsequent iterations of our receive loop will resend the iOldFrame |
|
820 // if nothing is received, in an attempt at error recovery, unless of |
|
821 // course we have deliberately reset iOldFrame to zero again |
|
822 |
|
823 //x = 0; |
|
824 for (;;) |
|
825 { |
|
826 if (iModem->iProgress.iPhase != EPostPageStatus) |
|
827 { |
|
828 if (GetframeL (iResults) == 0) |
|
829 { |
|
830 if (successiveErrors++ > 3) |
|
831 return (KFaxErrFrameFail); |
|
832 |
|
833 if (iModem->iProgress.iPhase == ECallEstablishment) |
|
834 // no point in carrying on without any capability frame |
|
835 { |
|
836 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
837 continue; |
|
838 } |
|
839 // if (iModem->iProgress.iPhase == ECallEstablishment) |
|
840 // { |
|
841 // if (x++ == 3) |
|
842 // return (KFaxErrFrameFail); |
|
843 // |
|
844 // iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
845 // continue; |
|
846 // } |
|
847 |
|
848 // no point in carrying on without any capability frame |
|
849 // else |
|
850 |
|
851 iResults[1] = 0x10; |
|
852 iResults[2] = 0xff; |
|
853 |
|
854 // this is a nonexistent response |
|
855 // the effect of this is to force a retransmission of the TSI and DCS |
|
856 // with (hopefully) a subsequent retrain in an attempt to resync |
|
857 } |
|
858 else |
|
859 successiveErrors = 0; |
|
860 |
|
861 |
|
862 |
|
863 if (iResults[2] != 0xff) |
|
864 { |
|
865 |
|
866 iModem->iOurMessage.Format (_L8 ("Response received")); |
|
867 iModem->ProgressUpdateL (); |
|
868 |
|
869 // the third byte in the frame is the FCF (fax control field) |
|
870 |
|
871 switch ((TUint8) iResults[2]) |
|
872 { |
|
873 case 0xff: // this is our dummy octet to force a restart |
|
874 break; |
|
875 |
|
876 case 0x40: // this marks the receiver ID |
|
877 iModem->iOurMessage.Format (_L8 ("CSI identity Frame")); |
|
878 iModem->ProgressUpdateL (); |
|
879 iModem->iProgress.iAnswerback.Zero (); |
|
880 for (i = 22; i > 2; i--) |
|
881 iModem->iProgress.iAnswerback.Append (iResults[i]); |
|
882 iModem->iOurMessage.Format (_L8 ("Remote fax ID is %S"), &iModem->iProgress.iAnswerback); |
|
883 iModem->ProgressUpdateL (); |
|
884 break; // the capability frame should follows |
|
885 |
|
886 case 0x80: // this marks the receiver capability frame |
|
887 iFcfXbit = 1; // we've received a DIS, so set the X bit |
|
888 iModem->iOurMessage.Format (_L8 ("DIS capability Frame")); |
|
889 iModem->ProgressUpdateL (); |
|
890 AnalyseDISL (); // analyse the DIS and compose a DCS |
|
891 if (iDisFrame.bit.b10 != 1) |
|
892 return (KFaxErrRemoteCannotReceive); // if the other machine can't receive we exit |
|
893 break; |
|
894 |
|
895 case 0x84: // this marks a good train and is the normal exit from this loop |
|
896 iModem->iOurMessage.Format (_L8 ("CFR confirmation Frame")); |
|
897 iModem->ProgressUpdateL (); |
|
898 return (TxSetHighSpeedL ()); |
|
899 |
|
900 case 0x44: // this marks a failed train so we drop the speed |
|
901 iModem->iOurMessage.Format (_L8 ("FTT failure to train Frame")); |
|
902 iModem->ProgressUpdateL (); |
|
903 if (++trainingAttempts & 1) // train down on failures 2 4 6 8 |
|
904 break; |
|
905 if (iActualFaxSpeed == 73) |
|
906 iActualFaxSpeed = 96; |
|
907 else |
|
908 iActualFaxSpeed -= 24; |
|
909 if (iActualFaxSpeed < (iFaxServerSessionSettings->iMinSpeed / 100)) |
|
910 { |
|
911 TxDCNL (); |
|
912 return (KFaxBelowMinSpeed); |
|
913 } |
|
914 break; |
|
915 |
|
916 case 0xfa: // this means we were asked to disconnect |
|
917 RxDCNL (); |
|
918 return (KFaxErrRemoteDCN); |
|
919 |
|
920 case 0x20: // this marks a non-standard frame, which we ignore |
|
921 iModem->iOurMessage.Format (_L8 ("NSF nonstandard facilities Frame")); |
|
922 iModem->ProgressUpdateL (); |
|
923 break; |
|
924 |
|
925 // the last case is where we see an unsupported frame |
|
926 // if it is a final frame we ask for a repeat via CRP |
|
927 |
|
928 default: |
|
929 if (SendCRPL () != KErrNone) |
|
930 return (KFaxErrCRP); |
|
931 } |
|
932 |
|
933 // if not a final frame we just issue AT+FRH=3 and continue |
|
934 |
|
935 if (!(iResults[1] & 0x10)) |
|
936 { |
|
937 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
938 continue; |
|
939 } |
|
940 // otherwise we send our proposals, starting with our own ID |
|
941 |
|
942 iModem->iOurMessage.Format (_L8 ("Final frame received")); |
|
943 iModem->ProgressUpdateL (); |
|
944 } |
|
945 }// if (iResults[2] !=0) statement |
|
946 if (iModem->iProgress.iPhase == ECallEstablishment) |
|
947 { |
|
948 iModem->iOurMessage.Format (_L8 ("sending TSI")); |
|
949 iModem->ProgressUpdateL (); |
|
950 iFrame.Zero (); |
|
951 iFrame.Append (KT30_CTLNXT); |
|
952 iFrame.Append (KT30_TSI); |
|
953 for (i = 20; i > iFaxServerSessionSettings->iFaxId.Length (); i--) |
|
954 iFrame.Append (0x20); |
|
955 for (i = iFaxServerSessionSettings->iFaxId.Length (); i;) |
|
956 iFrame.Append (iFaxServerSessionSettings->iFaxId[--i]); |
|
957 if (SendframeL (iFrame) != 1) |
|
958 return (KFaxErrHDLC); |
|
959 } |
|
960 else |
|
961 { |
|
962 iModem->ExportL (_L8 ("AT+FTH=3\r")); |
|
963 if (FramestatL () != 1) |
|
964 return (KFaxErrHDLC); |
|
965 } |
|
966 |
|
967 iModem->iProgress.iPhase = ESessionNegotiation; |
|
968 |
|
969 // before sending our DCS frame we ensure the speeds bits match what we want |
|
970 |
|
971 iDcsFrame.byte[1] &= 0xc3; |
|
972 switch (iActualFaxSpeed) |
|
973 { |
|
974 case 48: |
|
975 iDcsFrame.byte[1] |= 0x08; |
|
976 break; /* 4800 */ |
|
977 case 96: |
|
978 iDcsFrame.byte[1] |= 0x04; |
|
979 break; /* 9600 V.29 */ |
|
980 case 97: |
|
981 iDcsFrame.byte[1] |= 0x24; |
|
982 break; /* 9600 V.17 */ |
|
983 case 72: |
|
984 iDcsFrame.byte[1] |= 0x0c; |
|
985 break; /* 7200 V.29 */ |
|
986 case 73: |
|
987 iDcsFrame.byte[1] |= 0x2c; |
|
988 break; /* 7200 V.17 */ |
|
989 case 145: |
|
990 iDcsFrame.byte[1] |= 0x20; |
|
991 break; /* 14400 */ |
|
992 case 121: |
|
993 iDcsFrame.byte[1] |= 0x28; |
|
994 break; /* 12000 */ |
|
995 default: |
|
996 iDcsFrame.byte[1] |= 0x00; /* 2400 */ |
|
997 } |
|
998 iModem->iOurMessage.Format (_L8 ("sending DCS ")); |
|
999 iModem->ProgressUpdateL (); |
|
1000 iFrame.Zero (); |
|
1001 iFrame.Append (KT30_CTLLST); |
|
1002 iFrame.Append (KT30_DCS); |
|
1003 //x = 3; |
|
1004 for (i = 0; i < iDcsBytes; i++) |
|
1005 iFrame.Append (iDcsFrame.byte[i]); |
|
1006 if (SendframeL (iFrame) != 1) |
|
1007 return (KFaxErrHDLC); |
|
1008 |
|
1009 // after sending our DCS frame we wait fot 75 ms before training |
|
1010 // |
|
1011 // Note on the 75 millisecond delays |
|
1012 // ================================= |
|
1013 // At this point we need to introduce a 75 ms delay (+-20%). |
|
1014 // this is usually done with the AT+FTS=8 command and the code |
|
1015 // would normally run as follows : |
|
1016 // |
|
1017 // iModem->ExportL (_L8 ("AT+FTS=8\r")); |
|
1018 // if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) |
|
1019 // return (KFaxErrStopAndWait); |
|
1020 // |
|
1021 // or, alternatively, we could use our own routines to delay |
|
1022 // for this amount of time using |
|
1023 // |
|
1024 // iModem->Silence (75000); |
|
1025 // |
|
1026 // However, the innards of the comms driver in EPOC32 introduces |
|
1027 // 2-tick delays on timed reads and writes - in other words, there |
|
1028 // was a 2-tick delay before the OK from our last frame was received |
|
1029 // and there will also be a 2-tick delay before the next command |
|
1030 // reaches the modem. Note that a 2-tick delay could be from 15 |
|
1031 // to 30 ms - we want a delay from 60ms to 90 ms (75 ms +- 20%) - |
|
1032 // which must be between 4 and 6 ticks. All the delays we use |
|
1033 // here are empirically arrived at via Faxlab testing rather |
|
1034 // than being worked out in advance. |
|
1035 |
|
1036 // NOTE : these delays are really applicable ONLY to Protea/ARM7100 |
|
1037 // the machine dependency is unavoidable under the |
|
1038 // circumstances. Protea ticks @ 64 Hz, which gives |
|
1039 // us 15.625 ms per tick. WINS ticks @ 10 Hz, |
|
1040 // which gives us 100 microseconds per tick - clearly a |
|
1041 // significant difference - the delta timers in the comms |
|
1042 // kernel are therefore also very different |
|
1043 |
|
1044 iModem->iOurMessage.Format (_L8 ("delaying for 75 ms")); |
|
1045 iModem->ProgressUpdateL (); |
|
1046 |
|
1047 // iModem->Silence ((iModem->iGranularity - 125) * 4); // 4 ticks pre-TCF - below iModem->iGranularity x 1 |
|
1048 |
|
1049 TInt delay=iModem->iCalls*37; //iCalls for 2ms *37 to get an approximatelly 75ms delay |
|
1050 TInt k=0; |
|
1051 |
|
1052 for (k=0;k<delay;k++) // this loop will generate the 75ms delay |
|
1053 iModem->clock(); |
|
1054 |
|
1055 i = (iActualFaxSpeed & 0xfe); |
|
1056 iModem->iOurMessage.Format (_L8 ("setting %d00"), i); |
|
1057 iModem->iProgress.iSpeed = (i * 100); |
|
1058 iModem->ProgressUpdateL (); |
|
1059 iResults.Copy (_L8 ("AT+FTM=")); |
|
1060 iResults.AppendNum (iActualFaxSpeed); |
|
1061 iResults.Append (_L8 ("\r")); |
|
1062 iModem->ExportL (iResults); |
|
1063 |
|
1064 // say how many bytes in the 1.5 second TCF |
|
1065 // prepare a null filled transmit buffer length and get length to maxnulls |
|
1066 // calculate minimum scan line times |
|
1067 // wait for the modem CONNECT |
|
1068 |
|
1069 trainbytes = (i * 150 / 8); |
|
1070 iModem->iOurMessage.Format (_L8 ("training sequence for %d bytes"), trainbytes); |
|
1071 |
|
1072 iModem->iTransmitBuffer.SetMax (); |
|
1073 iModem->iTransmitBuffer.FillZ (); |
|
1074 TInt maxnulls = iModem->iTransmitBuffer.Length (); |
|
1075 iModem->ProgressUpdateL (); |
|
1076 if (iMinscan == 0) |
|
1077 iMinlinelength = 0; |
|
1078 else |
|
1079 iMinlinelength = ((iModem->iProgress.iSpeed / (1000 / iMinscan)) / 8) + 1; |
|
1080 if ((iModem->GetMatchL (_L8 ("CONNECT"), 5)) == 0) |
|
1081 return (KFaxErrAtNegotiatedSpeed); |
|
1082 |
|
1083 // now we send our TCF with flow control |
|
1084 |
|
1085 iModem->Xonon (); |
|
1086 |
|
1087 iModem->iOurMessage.Format (_L8 ("Entering training loop")); |
|
1088 iModem->ProgressUpdateL (); |
|
1089 |
|
1090 while (trainbytes != 0) |
|
1091 { |
|
1092 if (maxnulls > trainbytes) |
|
1093 { |
|
1094 iModem->iTransmitBuffer.SetLength (trainbytes); |
|
1095 trainbytes = 0; |
|
1096 } |
|
1097 else |
|
1098 { |
|
1099 iModem->iTransmitBuffer.SetMax (); |
|
1100 trainbytes -= maxnulls; |
|
1101 } |
|
1102 iModem->CommitTransmitBufferL (); |
|
1103 } |
|
1104 |
|
1105 iModem->iTransmitBuffer.Append (Kdle); |
|
1106 iModem->iTransmitBuffer.Append (Ketx); |
|
1107 iModem->CommitTransmitBufferL (); |
|
1108 |
|
1109 |
|
1110 iModem->iOurMessage.Format (_L8 ("Train complete")); |
|
1111 iModem->ProgressUpdateL (); |
|
1112 |
|
1113 // now wait for the modem to return to command mode |
|
1114 |
|
1115 while (iModem->Rxstat () != 0) |
|
1116 { |
|
1117 ticks = CLK_TCK; |
|
1118 iModem->RxcharWaitL (ticks); |
|
1119 } |
|
1120 if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0) |
|
1121 return (KFaxErrTrainStop); |
|
1122 |
|
1123 iModem->Xonoff (); |
|
1124 // there's no frame to resend, so we prepare a CRP in case of |
|
1125 // any errors before looping for the response |
|
1126 |
|
1127 iOldFrame.Zero (); |
|
1128 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
1129 } |
|
1130 } |
|
1131 /********************************************************************/ |
|
1132 |
|
1133 // this is a small function to set a class 1 fax modem to phase C |
|
1134 // transmission speed (found in iActualFaxSpeed) in preparation for |
|
1135 // sending data. This function is called before the first page |
|
1136 // and also between pages. Class 1 modems require that we delay for |
|
1137 // 75 ms before going to phase C transmission - see the note |
|
1138 // earlier on method of achieving a 75 ms delay here |
|
1139 |
|
1140 TInt CFaxClass1::TxSetHighSpeedL () |
|
1141 { |
|
1142 TInt x, portSpeed; |
|
1143 iFrame.SetMax (); |
|
1144 iModem->iOurMessage.Format (_L8 ("delaying for 75 ms")); |
|
1145 iModem->ProgressUpdateL (); |
|
1146 // iModem->Silence ((iModem->iGranularity - 125) * 4); // 4 ticks pre-T4 - below iModem->iGranularity x 3 |
|
1147 |
|
1148 TInt delay=iModem->iCalls*37; //iCalls for 2ms *37 to get an approximatelly 75ms delay |
|
1149 TInt k=0; |
|
1150 |
|
1151 for (k=0;k<delay;k++) // this loop will generate the 75ms delay |
|
1152 iModem->clock(); |
|
1153 |
|
1154 switch (iActualFaxSpeed) |
|
1155 { |
|
1156 case 145: |
|
1157 x = 144; |
|
1158 portSpeed = 146; |
|
1159 break; |
|
1160 case 121: |
|
1161 x = 120; |
|
1162 portSpeed = 122; |
|
1163 break; |
|
1164 case 97: |
|
1165 x = 96; |
|
1166 portSpeed = 98; |
|
1167 break; |
|
1168 case 73: |
|
1169 x = 72; |
|
1170 portSpeed = 74; |
|
1171 break; |
|
1172 default: |
|
1173 x = portSpeed = iActualFaxSpeed; |
|
1174 } |
|
1175 iModem->iOurMessage.Format (_L8 ("setting %d00"), x); |
|
1176 iModem->iProgress.iSpeed = (x * 100); |
|
1177 iModem->ProgressUpdateL (); |
|
1178 iResults.Copy (_L8 ("AT+FTM=")); |
|
1179 iResults.AppendNum (portSpeed); |
|
1180 iResults.Append (_L8 ("\r")); |
|
1181 iModem->ExportL (iResults); |
|
1182 if (FramestatL () != 1) |
|
1183 return (KFaxErrAtNegotiatedSpeed); |
|
1184 return (TxStartPageL ()); |
|
1185 } |
|
1186 /********************************************************************/ |
|
1187 |
|
1188 // here's where we wait after sending a page and the postpage |
|
1189 // message to see what the receiver thought - there are five responses |
|
1190 // MCF RTP PIP = good page RTN PIN = bad page |
|
1191 // |
|
1192 // TxPostPage should return either with |
|
1193 // |
|
1194 // a) an error code and iPhase set to RFax::EPostPageStatus, in which case the send returns with the error |
|
1195 // b) KErrNone and iPhase set to RFax::EDataTransfer, in which case we send the next page |
|
1196 // c) KErrNone and iPhase set to RFax::EDisconnection, in which case the send returns with KErrNone |
|
1197 // |
|
1198 |
|
1199 TInt CFaxClass1::TxPostPageL () |
|
1200 { |
|
1201 if (iModem->iProgress.iCompression == EModifiedRead) |
|
1202 { |
|
1203 iModem->iTransmitBuffer.Append (0x00); |
|
1204 iModem->iTransmitBuffer.Append (0x60); |
|
1205 iModem->iTransmitBuffer.Append (0x00); |
|
1206 iModem->iTransmitBuffer.Append (0x0C); |
|
1207 iModem->iTransmitBuffer.Append (0x80); |
|
1208 iModem->iTransmitBuffer.Append (0x01); |
|
1209 iModem->iTransmitBuffer.Append (0x30); |
|
1210 iModem->iTransmitBuffer.Append (0x00); |
|
1211 iModem->iTransmitBuffer.Append (0x06); |
|
1212 iModem->iTransmitBuffer.Append (0xC0); |
|
1213 } |
|
1214 else |
|
1215 { |
|
1216 for (TInt x = 3; x; x--) |
|
1217 { |
|
1218 iModem->iTransmitBuffer.Append (0x0); |
|
1219 iModem->iTransmitBuffer.Append (0x08); |
|
1220 iModem->iTransmitBuffer.Append (0x80); |
|
1221 } |
|
1222 } |
|
1223 iModem->iTransmitBuffer.Append (Kdle); |
|
1224 iModem->iTransmitBuffer.Append (Ketx); |
|
1225 iModem->CommitTransmitBufferL (); |
|
1226 |
|
1227 iModem->iOurMessage.Format (_L8 ("<dle><etx> transmitted after %d lines"), iModem->iProgress.iLines); |
|
1228 iModem->iProgress.iPhase = EPostPageStatus; |
|
1229 iModem->ProgressUpdateL (); |
|
1230 while (iModem->Txstat () != 0) |
|
1231 ; |
|
1232 |
|
1233 // we've just ended phase C data, so we need to wait for the modem to respond with OK |
|
1234 |
|
1235 if (iModem->GetMatchL (_L8 ("OK"), (32 * 1024) / (iModem->iProgress.iSpeed / 10)) == 0) |
|
1236 return (KFaxErrCannotEndData); |
|
1237 |
|
1238 iModem->Xonoff (); |
|
1239 |
|
1240 iModem->iOurMessage.Format (_L8 ("delaying for 75 ms")); |
|
1241 iModem->ProgressUpdateL (); |
|
1242 |
|
1243 |
|
1244 /************************************* NOTE ******************************************************* |
|
1245 // see the note earlier on reason for the lack of an explicit 75 ms delay here |
|
1246 |
|
1247 |
|
1248 // iModem->Silence ((iModem->iGranularity - 125) * 4); 4 ticks post-T4 - below iModem->iGranularity x 1 |
|
1249 // The above line of code was removed because the Silence function calls User::After which is fairly inaccurate |
|
1250 // Faxlab revealed that we were actually waiting for 432 ms !!! instead of the recomended 75ms +- 20% |
|
1251 // The delay is now generated using the timing callibration loop |
|
1252 // This is more CPU intensive than the User::After call because essentially is a aoftware delay loop but |
|
1253 // will enhance the reliability of fax class 1 especially over GSM |
|
1254 *****************************************************************************************************************/ |
|
1255 TInt delay=iModem->iCalls*30; //iCalls for 2ms *37 to get an approximatelly 75ms delay |
|
1256 TInt k=0; |
|
1257 |
|
1258 for (k=0;k<delay;k++) // this loop will generate the 75ms delay |
|
1259 iModem->clock(); |
|
1260 |
|
1261 iOldFrame.Zero (); |
|
1262 iFrame.Zero (); |
|
1263 iFrame.Append (KT30_CTLLST); |
|
1264 |
|
1265 |
|
1266 if ((iFaxServerSessionSettings->iTxPages) == iModem->iProgress.iPage) |
|
1267 { |
|
1268 iModem->iOurMessage.Format (_L8 ("sending EOP")); |
|
1269 iModem->ProgressUpdateL (); |
|
1270 |
|
1271 iFrame.Append ((KT30_EOP)); |
|
1272 if (SendframeL (iFrame) == 0) |
|
1273 return (KFaxErrEOP); |
|
1274 |
|
1275 iModem->iOurMessage.Format (_L8 ("End of document transmitted")); |
|
1276 iModem->ProgressUpdateL (); |
|
1277 } |
|
1278 else |
|
1279 { |
|
1280 iModem->iOurMessage.Format (_L8 ("sending MPS")); |
|
1281 iModem->ProgressUpdateL (); |
|
1282 |
|
1283 iFrame.Append ((KT30_MPS)); |
|
1284 if (SendframeL (iFrame) == 0) |
|
1285 return (KFaxErrMPS); |
|
1286 |
|
1287 iModem->iOurMessage.Format (_L8 ("End of page %u transmitted"), iModem->iProgress.iPage); |
|
1288 iModem->ProgressUpdateL (); |
|
1289 } |
|
1290 |
|
1291 // now we await the post-page response from the receiver |
|
1292 // we loop here because we need a final frame |
|
1293 |
|
1294 for (;;) |
|
1295 { |
|
1296 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
1297 if (GetframeL (iResults) == 0) |
|
1298 return (KFaxErrFrameFail); |
|
1299 iModem->iOurMessage.Format (_L8 ("Response received")); |
|
1300 iModem->ProgressUpdateL (); |
|
1301 |
|
1302 // the third byte in the frame is the FCF (fax control field) |
|
1303 // for those we recognize straight off, we say so |
|
1304 // for any others, we either loop immediately or after a CRP request |
|
1305 |
|
1306 switch ((TUint8) iResults[2]) |
|
1307 { |
|
1308 case 0x8c: |
|
1309 iModem->iOurMessage.Format (_L8 ("MCF")); |
|
1310 break; |
|
1311 case 0xcc: |
|
1312 iModem->iOurMessage.Format (_L8 ("RTP")); |
|
1313 break; |
|
1314 case 0xac: |
|
1315 iModem->iOurMessage.Format (_L8 ("PIP")); |
|
1316 break; |
|
1317 case 0x4c: |
|
1318 iModem->iOurMessage.Format (_L8 ("RTN")); |
|
1319 break; |
|
1320 case 0x2c: |
|
1321 iModem->iOurMessage.Format (_L8 ("PIN")); |
|
1322 break; |
|
1323 |
|
1324 // the last case is where we see an unsupported frame |
|
1325 // if it is a final frame we ask for a repeat via CRP |
|
1326 |
|
1327 default: |
|
1328 if (SendCRPL () != KErrNone) |
|
1329 return (KFaxErrCRP); |
|
1330 continue; |
|
1331 } |
|
1332 |
|
1333 // now back to look at the FCF some more |
|
1334 switch ((TUint8) iResults[2]) |
|
1335 { |
|
1336 case 0x8c: |
|
1337 case 0xcc: // for good pages we say confirmed |
|
1338 case 0xac: |
|
1339 iModem->iOurMessage.Append (_L8 (" message confirmation")); |
|
1340 iModem->ProgressUpdateL (); |
|
1341 break; |
|
1342 |
|
1343 case 0x4c: // for bad pages we say no good |
|
1344 case 0x2c: // if we haven't done so, resent last page |
|
1345 iModem->iOurMessage.Append (_L8 (" : page not confirmed")); |
|
1346 iModem->ProgressUpdateL (); |
|
1347 if (iRepeatPage == 0) |
|
1348 { |
|
1349 iRepeatPage++; |
|
1350 iModem->iProgress.iPage--; |
|
1351 return (TxPrePageL ()); |
|
1352 } |
|
1353 |
|
1354 default:; |
|
1355 } |
|
1356 |
|
1357 // we aren't going to resend the last page now |
|
1358 |
|
1359 iRepeatPage = 0; |
|
1360 |
|
1361 // if we've reached the end, we just quit |
|
1362 |
|
1363 if ((iFaxServerSessionSettings->iTxPages) == iModem->iProgress.iPage) |
|
1364 { |
|
1365 return (TxDCNL ()); |
|
1366 } |
|
1367 |
|
1368 // if we've received an MCF we carry on with phase C |
|
1369 |
|
1370 if (iResults[2] == KT30_MCF) // carry on with phase C only if MCF |
|
1371 |
|
1372 { |
|
1373 return (TxSetHighSpeedL ()); |
|
1374 } |
|
1375 |
|
1376 // we renegotiate if PIP or RTP, or PIN or RTN with no resend |
|
1377 |
|
1378 iModem->iOurMessage.Format (_L8 ("Renegotiating session parameters")); |
|
1379 iModem->ProgressUpdateL (); |
|
1380 return (TxPrePageL ()); |
|
1381 } |
|
1382 } |
|
1383 /********************************************************************/ |
|
1384 |
|
1385 // the analysis of the DIS frame and composition of the DCS frame |
|
1386 // has been moved here for readability |
|
1387 |
|
1388 inline void CFaxClass1::AnalyseDISL () |
|
1389 { |
|
1390 TInt i; |
|
1391 |
|
1392 // we copy iResults to our iDisFrame and compose our reply in iDcsFrame |
|
1393 |
|
1394 for (i = 0; i < 5; i++) |
|
1395 iDisFrame.byte[i] = (TUint8) iResults[i + 3]; |
|
1396 |
|
1397 for (i = 0; i < 5; i++) |
|
1398 iDcsFrame.byte[i] = 0; |
|
1399 |
|
1400 // we always set T.4 |
|
1401 |
|
1402 iDcsFrame.bit.b10 = 1; |
|
1403 |
|
1404 // we check the speed capability next and reset our iActualFaxSpeed |
|
1405 |
|
1406 switch (iDisFrame.byte[1] & 0x3c) |
|
1407 { |
|
1408 case 0x08: |
|
1409 i = 48; |
|
1410 break; /* V.27 ter 4800 2400 */ |
|
1411 case 0x0c: |
|
1412 i = 96; |
|
1413 break; /* V.29 9600 7200 + V.27 */ |
|
1414 case 0x2c: |
|
1415 i = 145; |
|
1416 break; /* V.17 14400 + V.29 + V.27 */ |
|
1417 default: |
|
1418 i = 24; /* V.27 fallback 2400 only */ |
|
1419 } |
|
1420 if (i < (iActualFaxSpeed)) |
|
1421 iActualFaxSpeed = i; |
|
1422 |
|
1423 // we set our resolution to that of the fax we want to send |
|
1424 // but if the receiver can only understand normal resolution |
|
1425 // then we send all our faxes as normal and resign ourselves |
|
1426 // to stretching them to double length |
|
1427 |
|
1428 iDcsFrame.bit.b15 = iFaxServerSessionSettings->iTxResolution; |
|
1429 if (iDisFrame.bit.b15 == 0) |
|
1430 iDcsFrame.bit.b15 = 0; |
|
1431 iModem->iProgress.iResolution = TFaxResolution (iDcsFrame.bit.b15); |
|
1432 |
|
1433 // we set our compression to that of the fax we want to send |
|
1434 // unless the receiver can only understand 1D compression - in |
|
1435 // which case the sender should be able to compensate from the |
|
1436 // progress settings |
|
1437 |
|
1438 iDcsFrame.bit.b16 = iFaxServerSessionSettings->iTxCompression; |
|
1439 if (iDisFrame.bit.b16 == 0) |
|
1440 { |
|
1441 iDcsFrame.bit.b16 = 0; |
|
1442 } |
|
1443 |
|
1444 if ((iDisFrame.bit.b16==1) && ((iFaxServerSessionSettings->iTxCompression==EModifiedRead))) |
|
1445 { |
|
1446 iDcsFrame.bit.b16 = 1; |
|
1447 } |
|
1448 |
|
1449 iModem->iProgress.iCompression = TFaxCompression (iDcsFrame.bit.b16); |
|
1450 |
|
1451 if (iModem->iProgress.iCompression==0) |
|
1452 { |
|
1453 iModem->iOurMessage.Format (_L8("DCS frame set to 1D")); |
|
1454 iModem->ProgressUpdateL(); |
|
1455 } |
|
1456 else |
|
1457 { |
|
1458 iModem->iOurMessage.Format (_L8("DCS frame set to 2D")); |
|
1459 iModem->ProgressUpdateL(); |
|
1460 } |
|
1461 |
|
1462 |
|
1463 // we set the minumum scan line time to that of the receiver |
|
1464 |
|
1465 iDcsFrame.byte[2] &= 0x8f; |
|
1466 switch (iDisFrame.byte[2] & 0x70) |
|
1467 { |
|
1468 case 0x70: |
|
1469 iMinscan = 0; |
|
1470 iDcsFrame.byte[2] |= 0x70; |
|
1471 break; /* b21=1 b22=1 b23=1 */ |
|
1472 case 0x50: |
|
1473 if (iDcsFrame.bit.b15 == 0) |
|
1474 { |
|
1475 iMinscan = 40; |
|
1476 iDcsFrame.byte[2] |= 0x40; |
|
1477 } |
|
1478 else |
|
1479 { |
|
1480 iMinscan = 20; |
|
1481 } |
|
1482 break; /* b21=1 b22=0 b23=1 - for fine res, /by 2 */ |
|
1483 case 0x30: |
|
1484 if (iDcsFrame.bit.b15 == 0) |
|
1485 { |
|
1486 iMinscan = 20; |
|
1487 } |
|
1488 else |
|
1489 { |
|
1490 iMinscan = 10; |
|
1491 iDcsFrame.byte[2] |= 0x20; |
|
1492 } |
|
1493 break; /* b21=1 b22=1 b23=0 - for fine res, /by 2 */ |
|
1494 case 0x60: |
|
1495 if (iDcsFrame.bit.b15 == 0) |
|
1496 { |
|
1497 iMinscan = 10; |
|
1498 iDcsFrame.byte[2] |= 0x20; |
|
1499 } |
|
1500 else |
|
1501 { |
|
1502 iMinscan = 5; |
|
1503 iDcsFrame.byte[2] |= 0x10; |
|
1504 } |
|
1505 break; /* b21=0 b22=1 b23=1 - for fine res, /by 2 */ |
|
1506 case 0x10: |
|
1507 iMinscan = 5; |
|
1508 iDcsFrame.byte[2] |= 0x10; |
|
1509 break; /* b21=1 b22=0 b23=0 */ |
|
1510 case 0x20: |
|
1511 iMinscan = 10; |
|
1512 iDcsFrame.byte[2] |= 0x20; |
|
1513 break; /* b21=0 b22=1 b23=0 */ |
|
1514 case 0x40: |
|
1515 iMinscan = 40; |
|
1516 iDcsFrame.byte[2] |= 0x40; |
|
1517 break; /* b21=0 b22=0 b23=1 */ |
|
1518 default: |
|
1519 iMinscan = 20; /* b21=0 b22=0 b23=0 */ |
|
1520 } |
|
1521 |
|
1522 // lastly, we always match our page length to the receiver page length |
|
1523 |
|
1524 iDcsFrame.bit.b19 = iDisFrame.bit.b19; |
|
1525 iDcsFrame.bit.b20 = iDisFrame.bit.b20; |
|
1526 } |
|
1527 /********************************************************************/ |
|
1528 |
|
1529 // this is where we wait for modem responses |
|
1530 |
|
1531 // this function can be called either with a timeout in seconds |
|
1532 // or with nothing, in which case we use a default as follows : |
|
1533 |
|
1534 // when we wait for the frame data we use a 6 second timeout |
|
1535 // as specified in T.30 as timer T2 if we are waiting for |
|
1536 // a command or a 3 second timer as specified in timer T4 |
|
1537 // if we are waiting for a response, with the presence of |
|
1538 // a resendable frame in iOldFrame being the test |
|
1539 |
|
1540 // notice that importL() takes a timeout specified in seconds |
|
1541 |
|
1542 // normally OK and CONNECT are good with ERROR or NO CARRIER being bad |
|
1543 // we save the actual result for inspection as ERROR codes after |
|
1544 // frame reception with AT+FRH needs special handling via GETFRAMESTAT |
|
1545 |
|
1546 TInt CFaxClass1::FramestatL () |
|
1547 { |
|
1548 TInt ticks; |
|
1549 if (iOldFrame.Length () == 0) |
|
1550 ticks = KT30_T2; |
|
1551 else |
|
1552 ticks = KT30_T4; |
|
1553 return (FramestatL (ticks)); |
|
1554 } |
|
1555 /********************************************************************/ |
|
1556 |
|
1557 TInt CFaxClass1::FramestatL (TInt aTicks) |
|
1558 { |
|
1559 for (;;) |
|
1560 { |
|
1561 iModemString.SetMax (); |
|
1562 if (iModem->ImportL (iModemString, aTicks) == 0) |
|
1563 return (-1);; |
|
1564 |
|
1565 iModem->iOurMessage.Format (_L8 ("%S"), &iModemString); |
|
1566 iModem->ProgressUpdateL (); |
|
1567 |
|
1568 if ((iModemString.FindF (_L8 ("OK"))) >= 0) |
|
1569 return (1); |
|
1570 if ((iModemString.FindF (_L8 ("CONNECT"))) >= 0) |
|
1571 return (1); |
|
1572 if ((iModemString.FindF (_L8 ("ERROR"))) >= 0) |
|
1573 return (0); |
|
1574 if ((iModemString.FindF (_L8 ("NO CARRIER"))) >= 0) |
|
1575 return (0); |
|
1576 } |
|
1577 } |
|
1578 /********************************************************************/ |
|
1579 |
|
1580 // if we have an ERROR result on receiving a frame it means that |
|
1581 // the CRC was incorrect - the action is to wait until 200 ms of |
|
1582 // silence have elapsed before resending the last frame - we use |
|
1583 // the ReceiveSilenceL function for this |
|
1584 |
|
1585 TInt CFaxClass1::GetFramestatL () |
|
1586 { |
|
1587 TInt code = FramestatL (); |
|
1588 if ((iModemString.FindF (_L8 ("ERROR"))) >= 0) |
|
1589 ReceiveSilenceL (); |
|
1590 return (code); |
|
1591 } |
|
1592 /********************************************************************/ |
|
1593 |
|
1594 // this is the HDLC frame reception handler after AT+FRH commands |
|
1595 |
|
1596 TInt CFaxClass1::GetframeL (TDes8 & aResult) |
|
1597 { |
|
1598 TInt i, retries = 0, frameStatus = 1; |
|
1599 TInt ticks; |
|
1600 TUint8 thisChar, lastChar; |
|
1601 TBuf8 < 4 > iHexchar; |
|
1602 |
|
1603 iModem->iOurMessage.Format (_L8 ("Waiting for Frame")); |
|
1604 iModem->ProgressUpdateL (); |
|
1605 |
|
1606 // framestat is set to 1 for no error before entry to the loop |
|
1607 |
|
1608 for (;;) |
|
1609 { |
|
1610 |
|
1611 // we only try three times before giving up |
|
1612 |
|
1613 retries++; |
|
1614 if (retries > 3) |
|
1615 return (0); |
|
1616 |
|
1617 // if we timed out, cancel the frame before proceeding |
|
1618 |
|
1619 if (frameStatus < 0) |
|
1620 { |
|
1621 iModem->TxcharL (Kcan); |
|
1622 iModem->iOurMessage.Format (_L8 ("Frame timed out")); |
|
1623 iModem->ProgressUpdateL (); |
|
1624 GetFramestatL (); |
|
1625 } |
|
1626 |
|
1627 // on any error, we resend the last frame if possible before |
|
1628 // waiting for another go |
|
1629 |
|
1630 if (frameStatus != 1) |
|
1631 { |
|
1632 if (SendframeL (iOldFrame) == 0) |
|
1633 { |
|
1634 iModem->iOurMessage.Format (_L8 ("Cannot resend Frame")); |
|
1635 iModem->ProgressUpdateL (); |
|
1636 return (0); |
|
1637 } |
|
1638 iModem->iOurMessage.Format (_L8 ("Frame has been resent")); |
|
1639 iModem->ProgressUpdateL (); |
|
1640 iModem->ExportL (_L8 ("AT+FRH=3\r")); |
|
1641 } |
|
1642 |
|
1643 // if we've just answered the phone, we don't wait for a result |
|
1644 // otherwise we must have an OK or CONNECT before proceeding |
|
1645 |
|
1646 if ((aResult.Compare (_L8 ("CALL JUST ANSWERED"))) == 0) |
|
1647 { |
|
1648 frameStatus = 1; |
|
1649 } |
|
1650 else |
|
1651 { |
|
1652 frameStatus = GetFramestatL (); |
|
1653 } |
|
1654 |
|
1655 aResult.FillZ (); |
|
1656 aResult.SetMax (); |
|
1657 |
|
1658 // if we got NO CARRIER or ERROR then we have to try again |
|
1659 |
|
1660 if (frameStatus != 1) |
|
1661 continue; |
|
1662 |
|
1663 // when we wait for the frame data we use a 6 second timeout |
|
1664 // as specified in T.30 as timer T2 if we are waiting for |
|
1665 // a command or a 3 second timer as specified in timer T4 |
|
1666 // if we are waiting for a response, with the presence of |
|
1667 // a resendable frame in iOldFrame being the test |
|
1668 |
|
1669 // note that RxcharWaitL () takes a timeout in microseconds |
|
1670 |
|
1671 if (iOldFrame.Length () == 0) |
|
1672 ticks = CLK_TCK * KT30_T2; |
|
1673 else |
|
1674 ticks = CLK_TCK * KT30_T4; |
|
1675 |
|
1676 // we expect data with dle shielding, ending with dle etx, |
|
1677 // and with a hex dump for our session log |
|
1678 |
|
1679 // there is a 3 second maximum length to a frame but |
|
1680 // the modem will detect bad HDLC frames for us and |
|
1681 // flag with ERROR |
|
1682 |
|
1683 for (i = 0, lastChar = 0; i < 64;) |
|
1684 { |
|
1685 if ((iModem->RxcharWaitL (ticks)) == 0) |
|
1686 { |
|
1687 frameStatus = (-1); |
|
1688 break; |
|
1689 } |
|
1690 thisChar = iModem->iReadone[0]; |
|
1691 if (lastChar == Kdle) |
|
1692 { |
|
1693 if (thisChar == Ketx) |
|
1694 break; |
|
1695 lastChar = 0; |
|
1696 if (thisChar != Kdle) |
|
1697 continue; |
|
1698 } |
|
1699 else if (thisChar == Kdle) |
|
1700 { |
|
1701 lastChar = Kdle; |
|
1702 continue; |
|
1703 } |
|
1704 aResult[i++] = thisChar; |
|
1705 |
|
1706 iHexchar.Format (_L8 ("%x "), thisChar); |
|
1707 if ((iModem->iOurMessage.Length () + iHexchar.Length ()) + 18 < iModem->iOurMessage.MaxLength ()) |
|
1708 iModem->iOurMessage.Append (iHexchar); |
|
1709 } |
|
1710 |
|
1711 iModem->ProgressUpdateL (); |
|
1712 |
|
1713 // if we timed out during the wait, then go round again and handle it |
|
1714 |
|
1715 if (frameStatus != 1) |
|
1716 continue; |
|
1717 |
|
1718 // otherwise we wait for the result code following the dle etx |
|
1719 // and handle any errors from that |
|
1720 |
|
1721 frameStatus = GetFramestatL (); |
|
1722 if (frameStatus != 1) |
|
1723 continue; |
|
1724 |
|
1725 // the third byte in the frame is the FCF (fax control field) |
|
1726 // we don't care whether we originated or answered the call |
|
1727 // so we always knock off the T.30 X bit (LSB) |
|
1728 |
|
1729 aResult[2] &= 0xfe; |
|
1730 |
|
1731 // if we have been asked for a frame repeat we do that in here |
|
1732 |
|
1733 if (aResult[2] == 0x1a) |
|
1734 { |
|
1735 iModem->iOurMessage.Format (_L8 ("CRP command repeat Frame")); |
|
1736 iModem->ProgressUpdateL (); |
|
1737 ReceiveSilenceL (); |
|
1738 frameStatus = 0; // treat as a timeout and resend |
|
1739 continue; |
|
1740 } |
|
1741 |
|
1742 // otherwise we can now return with success |
|
1743 |
|
1744 return (1); |
|
1745 } |
|
1746 } |
|
1747 /********************************************************************/ |
|
1748 |
|
1749 // this is the send HDLC frame handler following AT+FTH commands |
|
1750 |
|
1751 TInt CFaxClass1::SendframeL (TDes8 & newframe) |
|
1752 { |
|
1753 TUint8 i; |
|
1754 TInt frameSize; |
|
1755 TBuf8 < 4 > iHexchar; |
|
1756 |
|
1757 // we take a copy of the frame we've been passed in case we want |
|
1758 // to resend for error recovery during GetFrame - it's the copy |
|
1759 // we work with |
|
1760 |
|
1761 if (&newframe != &iOldFrame) |
|
1762 iOldFrame.Copy (newframe); |
|
1763 frameSize = iOldFrame.Length (); |
|
1764 if (frameSize < 2) |
|
1765 return (0); |
|
1766 |
|
1767 // all frames must be at least three characters |
|
1768 // note that calling SendframeL with an empty frame disables |
|
1769 // resends - iOldFrame.Zero() is rather quicker though |
|
1770 |
|
1771 // we don't need to tell the modem that we're going to send a frame |
|
1772 // if we're sending DCS or CSI or DIS/DTC for the first time after a CONNECT response |
|
1773 // (not a resend) - in all other cases we need to send AT+FTH |
|
1774 |
|
1775 iOldFrame[1] |= iFcfXbit; // combine the FCF with the X bit |
|
1776 i = iOldFrame[1]; |
|
1777 |
|
1778 if (!((&newframe != &iOldFrame) && (i == (KT30_DCS|iFcfXbit)) || (i == KT30_CSI) || (i == (KT30_DIS|iFcfXbit)))) |
|
1779 { |
|
1780 iModem->ExportL (_L8 ("AT+FTH=3\r")); |
|
1781 if (FramestatL () != 1) |
|
1782 return (0); |
|
1783 } |
|
1784 |
|
1785 // we have a short delay before sending data here after any modem response |
|
1786 |
|
1787 iModem->ExportL (_L8 ("")); |
|
1788 |
|
1789 // we now send the frame, starting with the fixed address followed |
|
1790 // by the data we have been passed. We use dle shielding and end |
|
1791 // with dle etx and a hex dump before returning with the modem |
|
1792 // response code |
|
1793 |
|
1794 iModem->TxcharL (KT30_ADDR); |
|
1795 iModem->iOurMessage.Format (_L8 ("%x "), KT30_ADDR); |
|
1796 for (i = 0; i < frameSize; i++) |
|
1797 { |
|
1798 iModem->TxcharL (iOldFrame[i]); |
|
1799 iHexchar.Format (_L8 ("%x "), iOldFrame[i]); |
|
1800 if ((iModem->iOurMessage.Length () + iHexchar.Length ()) + 18 < iModem->iOurMessage.MaxLength ()) |
|
1801 iModem->iOurMessage.Append (iHexchar); |
|
1802 if (iOldFrame[i] == Kdle) |
|
1803 iModem->TxcharL (Kdle); |
|
1804 } |
|
1805 iModem->TxcharL (Kdle); |
|
1806 iModem->TxcharL (Ketx); |
|
1807 iModem->ProgressUpdateL (); |
|
1808 return (FramestatL ()); |
|
1809 } |
|
1810 /********************************************************************/ |
|
1811 |
|
1812 // this is short routine to request a resend of a frame |
|
1813 |
|
1814 TInt CFaxClass1::SendCRPL () |
|
1815 { |
|
1816 iModem->iOurMessage.Format (_L8 ("Inappropriate frame %x"), (TUint8) iResults[2]); |
|
1817 iModem->ProgressUpdateL (); |
|
1818 if (iResults[1] & 0x10) |
|
1819 { |
|
1820 iModem->iOurMessage.Format (_L8 ("sending CRP")); |
|
1821 iModem->ProgressUpdateL (); |
|
1822 ReceiveSilenceL (); |
|
1823 iFrame.Zero (); |
|
1824 iFrame.Append (KT30_CTLLST); |
|
1825 iFrame.Append (KT30_CRP); |
|
1826 if (SendframeL (iFrame) == 0) |
|
1827 return (KFaxErrCRP); |
|
1828 iResults[1] = 0x0; |
|
1829 } |
|
1830 return (KErrNone); |
|
1831 } |
|
1832 /********************************************************************/ |
|
1833 |
|
1834 // this utility waits for 200 ms of silence before proceeding. We allow |
|
1835 // a three second timeout here in case we are waiting for a train to |
|
1836 // finish. we used the modem AT+FRS command - if it fails we'll have |
|
1837 // waited for three seconds in any case, so why bother with an error ? - |
|
1838 // this code is used mostly for error recovery purposes but note that |
|
1839 // not all modems support the +FRS command properly for example the |
|
1840 // Megahertz PCMCIA sportster |
|
1841 |
|
1842 void CFaxClass1::ReceiveSilenceL () |
|
1843 { |
|
1844 iModem->ExportL (_L8 ("AT+FRS=20\r")); |
|
1845 if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) |
|
1846 { |
|
1847 iModem->iOurMessage.Format (_L8 ("Timeout waiting for silence")); |
|
1848 iModem->ProgressUpdateL (); |
|
1849 iModem->TxcharL (Kcan); |
|
1850 if (iModem->GetMatchL (_L8 ("OK"), 1) == 0) |
|
1851 iModem->TxcharL (Kreturn); |
|
1852 } |
|
1853 } |
|
1854 /********************************************************************/ |
|
1855 |