fax/faxclientandserver/FAXSVR/CFAX1.CPP
changeset 20 244d7c5f118e
parent 19 1f776524b15c
child 23 6b1d113cdff3
equal deleted inserted replaced
19:1f776524b15c 20:244d7c5f118e
     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