fax/faxclientandserver/FAXSVR/CFAXMODM.CPP
branchRCL_3
changeset 65 630d2f34d719
parent 61 17af172ffa5f
child 66 07a122eea281
equal deleted inserted replaced
61:17af172ffa5f 65:630d2f34d719
     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 // CFaxModem class implementation
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 
       
    22 
       
    23 #include "FAXSERV.H"
       
    24 #include <e32hal.h>
       
    25 #include "FAXMODEM.H"
       
    26 
       
    27 #include "FAXLOG.H"
       
    28 
       
    29 // we embed this so that the session log tells us the version used
       
    30 
       
    31 #define FaxTransVersionString "FAX SERVER SESSION LOG (Release 033)" 
       
    32 
       
    33 /********************************************************************/
       
    34 
       
    35 CFaxModem::CFaxModem (RFax::TProgress & aProgress)      
       
    36 :iProgress (aProgress)
       
    37    {
       
    38    }
       
    39 /********************************************************************/
       
    40 
       
    41 CFaxModem *CFaxModem::NewLC (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress)
       
    42    {
       
    43    CFaxModem *self = new (ELeave) CFaxModem (aProgress);
       
    44    CleanupStack::PushL (self);
       
    45    self->ConstructL (aFaxServerSessionSettings);
       
    46    return self;
       
    47    }
       
    48 /********************************************************************/
       
    49 
       
    50 CFaxModem *CFaxModem::NewL (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress)
       
    51    {
       
    52    CFaxModem *self = NewLC (aFaxServerSessionSettings, aProgress);
       
    53    CleanupStack::Pop ();
       
    54    return self;
       
    55    }
       
    56 /********************************************************************/
       
    57 
       
    58 void CFaxModem::ConstructL (TFaxServerSessionSettings * aFaxServerSessionSettings)
       
    59    {
       
    60    TInt r;
       
    61 //   TBufC < 24 > logname (_L ("C:\\SYSTEM\\FAXLOG.TXT"));
       
    62 //   RFsBase closefile;
       
    63 
       
    64     __FLOG_FAXSRV( _L8("CFaxModem::ConstructL entering"));
       
    65 
       
    66    iVerbose = 1;
       
    67 
       
    68 // we start off with our timer functions
       
    69 
       
    70    iStartTime.UniversalTime();
       
    71 
       
    72 // work out the granularity of the clock
       
    73 
       
    74    TTimeIntervalMicroSeconds32 ourGranularity;
       
    75    if (UserHal::TickPeriod (ourGranularity) == KErrNotSupported)
       
    76       User::Leave (KErrNotSupported);
       
    77    iGranularity = ourGranularity.Int ();
       
    78 
       
    79 // calibrate a 2 ms timing loop - see notes at start of cfaxTransfer::ExportL
       
    80 // this is only used for class 1 when iTimingLoopDelay is true
       
    81 
       
    82    iCalls = 0;
       
    83    TInt t;
       
    84    t = clock () + iGranularity;
       
    85    while (t > clock ())
       
    86 	   ;        // wait for the clock to tick once
       
    87    t = clock () + iGranularity; // reset target
       
    88    while (t > clock ())         // wait for it to tick again
       
    89       iCalls++;                 // this time counting calls to clock
       
    90    iCalls *= (CLK_TCK / iGranularity);  // work out calls per second
       
    91    iCalls /= 500;               // and work out calls per 2 ms
       
    92    if (iCalls == 0)
       
    93       iCalls++;
       
    94 
       
    95 #if defined (__WINS__)
       
    96 #define PDD_NAME _L("ECDRV")
       
    97 #define LDD_NAME _L("ECOMM")
       
    98 #else
       
    99 #define PDD_NAME _L("EUART1")
       
   100 #define LDD_NAME _L("ECOMM")
       
   101 #endif
       
   102 
       
   103    r = iFileSession.Connect (); // we may need the RFs link for PDD/LDD loading as well as the log
       
   104    if (r)
       
   105       User::Leave (KFaxFileSessionError);
       
   106    iFileSessionOpen = ETrue;
       
   107 
       
   108    if (iVerbose)
       
   109       {
       
   110       
       
   111       
       
   112 //This is a log file that would normally only be created in debug builds, however due to the time critical nature of fax it is always generated
       
   113 //to avoid timing differences between debug and release builds.
       
   114 //With the introduction of platform security it not advisable to have a log file in a public directory so will now be created in the private dir 
       
   115 //of the fax server.
       
   116 
       
   117 	//create log in private path of server
       
   118 	TFileName logfile;
       
   119 	TDriveUnit driveUnit(EDriveC);	
       
   120 	TDriveName drive=driveUnit.Name();
       
   121 	logfile.Insert(0, drive);	
       
   122 	//append private path
       
   123 	TPath privatePath;
       
   124 	iFileSession.PrivatePath(privatePath);
       
   125 	logfile.Append(privatePath);
       
   126 	//append subdir & file name
       
   127 	logfile.Append(_L("fax\\FAXLOG.TXT"));	
       
   128 	
       
   129 	//generate dir
       
   130 	TInt kerr(iFileSession.MkDirAll(logfile)); //the directory may not exist, So create one.
       
   131 	if(kerr != KErrAlreadyExists)
       
   132 		{
       
   133 		User::LeaveIfError(kerr);
       
   134 		}
       
   135 	r = iFile.Replace(iFileSession, logfile, EFileWrite | EFileShareAny);
       
   136 	if (r)
       
   137 		{
       
   138 		User::Leave (KFaxLogCreateError);	
       
   139 		}
       
   140 	iFileOpen = ETrue;
       
   141 
       
   142       }
       
   143 /*
       
   144    r = User::LoadPhysicalDevice (PDD_NAME);
       
   145    if ((r != KErrNone) && (r != KErrAlreadyExists))
       
   146      User::Leave (KFaxPDDError);
       
   147 
       
   148    r = User::LoadLogicalDevice (LDD_NAME);
       
   149    if ((r != KErrNone) && (r != KErrAlreadyExists))
       
   150       User::Leave (KFaxLDDError);  
       
   151 */
       
   152 
       
   153    RCommServ s;
       
   154    r = s.Connect ();
       
   155    if (r)
       
   156       User::Leave (KFaxCommsServerError);
       
   157 
       
   158    
       
   159    r = s.LoadCommModule (aFaxServerSessionSettings->iPortDriverName);
       
   160    if (r)
       
   161       User::Leave (KFaxCommsPortError);   
       
   162 
       
   163    r = iCommSession.Open (s, aFaxServerSessionSettings->iCommPortName, ECommShared);
       
   164    if (r)
       
   165       User::Leave (KFaxCannotOpenPort);  
       
   166 
       
   167    iPortOpen = ETrue;
       
   168 
       
   169    iCommSession.Config (iRS232Settings);
       
   170 
       
   171    iRS232Settings ().iRate = EBps19200;
       
   172 
       
   173    iRS232Settings ().iHandshake = 0;
       
   174 
       
   175    iRS232Settings ().iTerminator[0] = Ketx;
       
   176    iRS232Settings ().iTerminator[1] = Kxon;
       
   177    iRS232Settings ().iTerminator[2] = Klinefeed;
       
   178    iRS232Settings ().iTerminatorCount = 3;
       
   179 
       
   180    r = iCommSession.SetConfig (iRS232Settings);
       
   181    if (r)
       
   182       User::Leave (KFaxConfigError);
       
   183 
       
   184    iCommSession.SetSignals (KSignalDTR, 0);
       
   185    iCommSession.SetSignals (KSignalRTS, 0);
       
   186 
       
   187    iCommSession.SetReceiveBufferLength (KBufSize);
       
   188    iCommSession.ResetBuffers();
       
   189 	
       
   190    iTransmitBuffer.Zero ();
       
   191    iSendone.Zero ();
       
   192    SendL (iSendone);            // activate port -  switch on DTR/RTS
       
   193    iSendone.SetMax ();          // we send single characters via iSendone[0]
       
   194 
       
   195    TBuf8 < 20 > thisclass;
       
   196    thisclass.SetMax ();
       
   197 
       
   198    iOurMessage.Format (_L8 (FaxTransVersionString));
       
   199    ProgressUpdateL ();
       
   200    iOurMessage.Format (_L8 ("The clock ticks at %d Hz"), CLK_TCK / iGranularity);
       
   201    ProgressUpdateL ();
       
   202    iOurMessage.Format (_L8 ("Calibration of 2 ms timer at %u calls"), iCalls);
       
   203    ProgressUpdateL ();
       
   204 
       
   205    Speed (EBps19200);
       
   206    iOurMessage.Format (_L8 ("Initialising at 19200 bps ...."));
       
   207    ProgressUpdateL ();
       
   208 
       
   209 
       
   210 // added by JerryC from faxtrans cfaxmodm.cpp
       
   211 
       
   212    
       
   213 	  Silence (CLK_TCK);
       
   214       TxcharL (Kreturn);
       
   215       Silence ();
       
   216 //	  Silence ();
       
   217 //	  Silence ();
       
   218 	  //  GetMatchL(_L8("OK"),3);
       
   219 	  
       
   220 
       
   221 //   while (iCommSession.QueryReceiveBuffer()!=0) GetMatch (_L8 ("OK"), 1);
       
   222 //   ExportL (_L8 ("AT+FCLASS=?\r"));
       
   223 //   GetMatchL (_L8 ("OK"), 3);
       
   224       
       
   225 //   GetMatchL (_L8 ("OK"), 3);
       
   226 
       
   227 
       
   228    //r = CLK_TCK;
       
   229    //while (RxcharWaitL (r));
       
   230 
       
   231 // the addition ends here
       
   232 
       
   233 //   TxcharL (Kreturn);
       
   234 
       
   235    iModemSet = ETrue;
       
   236    iTimingLoopDelay = EFalse;
       
   237 
       
   238    //-- Switch modem into command mode and clear its buffer. 
       
   239    SetModemCommandModeL(); 
       
   240 
       
   241    if ((aFaxServerSessionSettings->iFaxClass) == (TFaxClass) EClassAuto)
       
   242       {
       
   243       ExportL (_L8 ("AT+FCLASS=?\r"));
       
   244       if(0 == ImportL (thisclass, 2))
       
   245     	  {
       
   246     	  User::Leave (KFaxErrWrongModemType);
       
   247     	  }
       
   248 
       
   249       iOurMessage.Format (_L8 ("%S"), &thisclass);
       
   250       ProgressUpdateL ();
       
   251       if ((thisclass.FindF (_L8 ("ERROR"))) >= 0)
       
   252          User::Leave (KFaxErrWrongModemType);
       
   253       GetMatchL (_L8 ("OK"), 1);
       
   254 
       
   255       if ((thisclass.FindF (_L8 ("2.0"))) >= 0)
       
   256          {
       
   257          aFaxServerSessionSettings->iFaxClass = EClass2point0;
       
   258          }
       
   259       else if ((thisclass.FindF (_L8 ("2.1"))) >= 0)
       
   260          {
       
   261          aFaxServerSessionSettings->iFaxClass = EClass2point0;
       
   262          }
       
   263       else if ((thisclass.FindF (_L8 ("2"))) >= 0)
       
   264          {
       
   265          aFaxServerSessionSettings->iFaxClass = EClass2;
       
   266          }
       
   267       else if ((thisclass.FindF (_L8 ("1"))) >= 0)
       
   268          {
       
   269          aFaxServerSessionSettings->iFaxClass = EClass1;
       
   270          }
       
   271       else if ((thisclass.FindF (_L8 ("1.0"))) >= 0)
       
   272          {
       
   273          aFaxServerSessionSettings->iFaxClass = EClass1;
       
   274          }
       
   275       else
       
   276          User::Leave (KFaxErrWrongModemType);
       
   277 
       
   278       User::Leave (KFaxOnlyJustAutoDetected);
       
   279       }
       
   280 
       
   281    thisclass.Copy (_L8 ("AT+FCLASS="));
       
   282    if (aFaxServerSessionSettings->iFaxClass == EClass2point0)
       
   283       {
       
   284       thisclass.Append (_L8 ("2.0\r"));
       
   285       }
       
   286    else if (aFaxServerSessionSettings->iFaxClass == EClass2)
       
   287       {
       
   288       thisclass.Append (_L8 ("2\r"));
       
   289       }
       
   290    else if (aFaxServerSessionSettings->iFaxClass == EClass1)
       
   291       {
       
   292       thisclass.Append (_L8 ("1\r"));
       
   293       iTimingLoopDelay = ETrue;
       
   294       }
       
   295    else
       
   296       User::Leave (KFaxErrWrongModemType);
       
   297 
       
   298    Silence ();
       
   299    ExportL (thisclass);
       
   300    if ((GetMatchL (_L8 ("OK"), 1)) == 0)		
       
   301       User::Leave (KFaxErrWrongModemType);
       
   302 
       
   303    //Speed (EBps19200);
       
   304 
       
   305    if (aFaxServerSessionSettings->iFaxInitString.Length ())
       
   306       {
       
   307       ExportL (aFaxServerSessionSettings->iFaxInitString);
       
   308       ExportL (_L8 ("\r"));
       
   309       //GetMatchL (_L8 ("OK"), 3);
       
   310       }
       
   311 	else 
       
   312 		{
       
   313 		ExportL (_L8 ("AT\r"));
       
   314 		}
       
   315    if ((GetMatchL (_L8 ("OK"), 3)) == 0)
       
   316       User::Leave (KFaxBadInitialization);
       
   317    
       
   318     __FLOG_FAXSRV( _L8("CFaxModem::ConstructL exiting"));
       
   319 
       
   320    }
       
   321   
       
   322 /********************************************************************/
       
   323 
       
   324 CFaxModem::~CFaxModem ()
       
   325 	{
       
   326 //	iOurMessage.Format (_L8 ("Entering CFaxModem Destructor"));
       
   327 //	ProgressUpdateL ();
       
   328 	
       
   329     __FLOG_FAXSRV( _L8("CFaxModem::~CFaxModem"));
       
   330 
       
   331 	iCancel = 2;
       
   332 
       
   333 	if (iModemSet)
       
   334 		{
       
   335 		Xonoff ();
       
   336 		Dropdtr ();
       
   337 		
       
   338 		TRAPD(ret, SetModemCommandModeL()); //-- Switch modem into command mode and clear its buffer. 
       
   339 		TRAP (ret, HangupProcedureL());		//-- Issue hung up commands
       
   340 		
       
   341 		Silence ();
       
   342 		}
       
   343 
       
   344 	if (iPortOpen)
       
   345 		{
       
   346 		iCommSession.ResetBuffers ();
       
   347 		iCommSession.Close ();
       
   348 		}
       
   349 
       
   350 	if (iFileOpen)
       
   351 		{
       
   352 		iFile.Close ();
       
   353 		}
       
   354 
       
   355 	if (iFileSessionOpen)
       
   356 		iFileSession.Close ();
       
   357 	}
       
   358 
       
   359 /**
       
   360 * Hang up. Senda 'ATH' command to the modem and sets Echo off, fax class = 0
       
   361 *
       
   362 * @note		This function can leave
       
   363 */
       
   364 void CFaxModem::HangupProcedureL()
       
   365 	{
       
   366 	ExportL (_L8 ("ATH\r"));
       
   367 	GetMatchL (_L8 ("OK"), 2);
       
   368 	ExportL (_L8 ("ATE0+FCLASS=0\r"));  // Defect fix PBN-4ZLLX7, NM 23/07/01
       
   369 	GetMatchL (_L8 ("OK"), 2);
       
   370 	ExportL (_L8 ("\r"));
       
   371 	}
       
   372 
       
   373 
       
   374 /**
       
   375 * Switch modem into command mode and clear its buffer. 
       
   376 * LYN-585JMR defect fix. By Dmitry Lyokhin. 11.03.02
       
   377 *
       
   378 * @note		This function can leave
       
   379 */
       
   380 void CFaxModem::SetModemCommandModeL(void)
       
   381 {
       
   382 	const TInt K_uS_ComWait=500000;			//-- used in cleaning up buffer. 0.5 sec timeout.
       
   383 	
       
   384 	ExportL (_L8("+++")); //-- switch the  modem to command mode
       
   385    
       
   386   	//-- clear modem's buffer by reading data
       
   387     while(iCommSession.QueryReceiveBuffer() > 0)
       
   388 	 {
       
   389 	  iCommSession.Read (iRecstat, K_uS_ComWait ,iReceiveBuffer);    // read data from the serial port
       
   390       User::WaitForRequest (iRecstat);
       
   391 	 }
       
   392 
       
   393 	Silence();
       
   394 }
       
   395 
       
   396 /********************************************************************/
       
   397 /*
       
   398 TBool CFaxModem::CheckModemL (TFaxSettings * aFaxSettings)
       
   399    {
       
   400    TInt len = aFaxSettings->iDialStoreData.iModemInitString.Length ();
       
   401    for (TInt attempt = 0; attempt < 3; attempt++)
       
   402       {
       
   403       ExportL (_L8 ("ATH\r"));
       
   404       GetMatchL (_L8 ("OK"), 1);
       
   405       if (len)
       
   406          {
       
   407          ExportL (aFaxSettings->iDialStoreData.iModemInitString);
       
   408          ExportL (_L8 ("\r"));
       
   409          GetMatchL (_L8 ("OK"), 1);
       
   410          }
       
   411       iOurMessage.Format (_L8 ("ATE0X0Q0V1M%uL%uS0=0S8=%u\r"),
       
   412                           (TUint) aFaxSettings->iDialStoreData.iSpeaker,
       
   413                           (TUint) aFaxSettings->iDialStoreData.iSpeakerVolume,
       
   414                           aFaxSettings->iDialStoreData.iPauseTime);
       
   415       ExportL (iOurMessage);
       
   416       if (GetMatchL (_L8 ("OK"), 1) != 0)
       
   417          {
       
   418          Silence ();            // allow s-l-o-w modems to catch up with us
       
   419          return (ETrue);
       
   420          }
       
   421       }
       
   422    return (EFalse);
       
   423    }*/
       
   424 /********************************************************************/
       
   425 
       
   426 
       
   427 /**
       
   428 *
       
   429 * @return	number of microseconds elapsed since calling CFaxModem::ConstructL().
       
   430 *			
       
   431 */
       
   432 TInt CFaxModem::clock ()
       
   433    {
       
   434    TTime now;
       
   435    now.UniversalTime ();
       
   436    TInt64 runningTime = now.MicroSecondsFrom (iStartTime).Int64 ();
       
   437    return I64LOW(runningTime);
       
   438    }
       
   439 
       
   440 /********************************************************************/
       
   441 
       
   442 /**
       
   443 *	Searches for a given substring in modem's answer.
       
   444 *	also calls ProgressUpdate().
       
   445 *
       
   446 * @param	aMatstring	- sample string.
       
   447 * @param	aMattime	- timeout in seconds.
       
   448 *
       
   449 * @see	ImportL function
       
   450 *
       
   451 * @return	0 -	given string (see param aMatstring) is found in modem answer.
       
   452 *       	1 - sample not found or answer timeout.
       
   453 *
       
   454 * @leave	This function can leave
       
   455 */
       
   456 TInt CFaxModem::GetMatchL (const TDesC8 & aMatstring, TInt aMattime)
       
   457 
       
   458    {
       
   459    TBuf8 < 64 > modemstring;
       
   460    TBuf8 < 64 > copymodemstring;
       
   461    modemstring.SetMax ();
       
   462 
       
   463    while (ImportL (modemstring, aMattime))
       
   464       {
       
   465       copymodemstring.Copy (modemstring);
       
   466       iOurMessage.Format (_L8 ("%S"), &copymodemstring);
       
   467       ProgressUpdateL ();
       
   468 
       
   469       if ((modemstring.FindF (aMatstring)) >= 0)
       
   470          return (1);
       
   471 
       
   472 
       
   473       }
       
   474    ProgressUpdateL ();
       
   475    return (0);
       
   476    }
       
   477 
       
   478 
       
   479 /********************************************************************/
       
   480 /**
       
   481 *	Gets textual answer from the modem.
       
   482 *	Calls SubImportL() and ProgressUpdateL().
       
   483 *
       
   484 * @param	aLine	-	ref. to the string descriptor that will accept data from modem if any.
       
   485 						will contain string in upper case without terminating 0x0d, 0x0a. 
       
   486 * @param	aTimeout -	Timeout in seconds.
       
   487 *
       
   488 * @see	SubImport function
       
   489 *
       
   490 * @return	0 - if timeout occured or wrong input descriptor. Otherwise -
       
   491 *				number of characters in string descriptor.
       
   492 *
       
   493 * @note		This function can leave
       
   494 */
       
   495 TInt CFaxModem::ImportL (TDes8 & aLine, TInt aTimeout)
       
   496 {
       
   497 	const	TInt SubTimeout = 3; //-- modem response 3 seconds timeout 
       
   498 	TInt	linestate		= 0;
       
   499 	TInt	CurrTimeout;
       
   500 	
       
   501    while( aTimeout > 0 )
       
   502    {
       
   503    	 if (aTimeout <= SubTimeout)	CurrTimeout = aTimeout;
       
   504 	 else							CurrTimeout = SubTimeout;
       
   505 
       
   506      linestate = SubImportL (aLine, CurrTimeout);
       
   507     
       
   508 		if (linestate) 
       
   509 		{//-- a response from modem received
       
   510             __FLOG_FAXSRV2(_L8("mdm imp[%d]: %S"), aTimeout, &aLine);
       
   511 		
       
   512 			//-- look for '+CREG' or '+CGREG' answers from modem.
       
   513 			//-- if found, ignore them and continue waiting.
       
   514 			//-- these unwanted answers represent network registration status (unsolicited result code)
       
   515 			//-- and interfere with fax modem responses. For more information see mm.tsy and gprs.tsy
       
   516 			if ((aLine.FindF(_L8("REG"))) >= 0)
       
   517 			{
       
   518 				aLine.FillZ();
       
   519 				aLine.Zero ();
       
   520 			}
       
   521 			else break; 
       
   522 	 
       
   523 		}//if (linestate) 
       
   524 
       
   525 		aTimeout -= SubTimeout;
       
   526 
       
   527 		ProgressUpdateL ();
       
   528     }// while
       
   529 	
       
   530 	if (!linestate)
       
   531 		{
       
   532         __FLOG_FAXSRV2(_L8("mdm imp[%d]: %S"), aTimeout, &aLine);
       
   533 		}
       
   534 
       
   535    return (linestate);
       
   536 }
       
   537 
       
   538 
       
   539 /********************************************************************/
       
   540 
       
   541 /**
       
   542 *	Gets textual answer from the modem.
       
   543 * 
       
   544 * @param	aLine	- ref. to the string descriptor that will accept data from modem if any.
       
   545 *						will contain string in upper case without terminating 0x0d, 0x0a
       
   546 * @param	aTimeout -	Timeout in seconds.
       
   547 *
       
   548 * @see		RxcharWait function, iReadone
       
   549 *
       
   550 * @return	0 - if timeout occured or wrong input descriptor. Otherwise -
       
   551 *				number of characters in string descriptor
       
   552 *
       
   553 * @note		This function can leave
       
   554 */
       
   555 TInt CFaxModem::SubImportL (TDes8 & aLine, TInt aTimeout)
       
   556 
       
   557    {
       
   558    TInt i;
       
   559    TInt8 k;
       
   560    TInt t;
       
   561 
       
   562    if (aLine.MaxLength () == 0)
       
   563       return (0);
       
   564    aLine.FillZ ();
       
   565    aLine.Zero ();
       
   566 
       
   567    t = aTimeout * CLK_TCK;
       
   568 
       
   569    do
       
   570       {
       
   571       if ((RxcharWaitL (t)) == 0)
       
   572          return (0);
       
   573       k = iReadone[0];
       
   574       }
       
   575 
       
   576 
       
   577    while (k < 32);
       
   578 
       
   579    for (i = 0; i < aLine.MaxLength (); i++)
       
   580       {
       
   581       aLine.Append (k);
       
   582       aLine.UpperCase ();
       
   583       t = aTimeout * CLK_TCK;
       
   584       if ((RxcharWaitL (t)) == 0)
       
   585          return (0);
       
   586       k = iReadone[0];
       
   587       if (k < 32)
       
   588          break;
       
   589       }
       
   590 
       
   591    if (k == 0x0d)
       
   592       for (;;)
       
   593          {
       
   594          t = CLK_TCK;
       
   595          if ((RxcharWaitL (t)) == 0)
       
   596             break;
       
   597          if (iReadone[0] == 0x0a)
       
   598             break;
       
   599          }
       
   600 
       
   601    return (i);
       
   602    }
       
   603 /********************************************************************/
       
   604 
       
   605 /**
       
   606 Sends a textual string to the modem with delay.
       
   607 
       
   608 @param aLine - const. ref. to the string descriptor to be sent to modem.
       
   609 
       
   610 @see SendL function
       
   611 
       
   612 @return number of symbols sent to modem.
       
   613 			
       
   614 @note This function can leave
       
   615 */
       
   616 TInt CFaxModem::ExportL(const TDesC8& aLine)
       
   617 	{
       
   618 	__FLOG_FAXSRV1(_L8("mdm exp: %S"), &aLine);
       
   619 
       
   620 	TInt i = 0;
       
   621 
       
   622    // we need to guarantee a delay here before sending characters
       
   623    // lots of modems ignore commands that come in too quickly
       
   624    // we need to wait for at least twice the clock granularity to ensure
       
   625    // a decent wait interval as the clock may be just about to tick
       
   626 
       
   627    // example :
       
   628 
       
   629    // Silence ((iGranularity * 2) + 2);
       
   630 
       
   631    // BUT ...
       
   632 
       
   633    // on Protea, the clock ticks at 64 beats per second
       
   634    // that's every 15 ms or to be precise every 15625 microseconds
       
   635    // iGranularity actually does return this value of 15625
       
   636    // our maximum wait will be 30 ms (with a minumum of 15 ms)
       
   637    // there's also a maximum 35 ms overhead on any timer call or active
       
   638    // object or whatever - so we could have a delay here of up to 65 ms
       
   639 
       
   640    // with the time the modem takes to respond, this leads to too much
       
   641    // unreliability as we have a strict 75 ms +/- 20% T.30 requirement
       
   642    // for class 1 modems. (For class 2 and 2.0 modems this isn't a
       
   643    // problem so we happily delay for iGranularity*2).
       
   644 
       
   645    // this applies also to WINS on the PC ticks 10 times per second
       
   646    // this gives us a maximum delay of 200 ms, which is rather long
       
   647    // so we resort to a timing loop we calibrate on first entry
       
   648 
       
   649    for (;;)
       
   650       {
       
   651       i = Rxstat ();
       
   652       if (iTimingLoopDelay != EFalse)
       
   653          {
       
   654          for (TInt x = 0; x < iCalls; x++)
       
   655             clock ();
       
   656          }
       
   657       else
       
   658          {
       
   659          Silence ((iGranularity * 2) + 2);
       
   660          }
       
   661       if (i == Rxstat ())
       
   662          break;
       
   663       }
       
   664 
       
   665 	if (aLine.Length())
       
   666 		{
       
   667 #ifdef _DEBUG
       
   668 		TRAPD(modemUnplugged, SendL(aLine));
       
   669 		__FLOG_FAXSRV1(_L8("CFaxModem::ExportL SendL leave error code: %d"), modemUnplugged);
       
   670 #else
       
   671 		TRAP_IGNORE(SendL(aLine));
       
   672 #endif
       
   673 
       
   674 		iOurMessage.Format(_L8("%S"), &aLine);
       
   675 		i = iOurMessage.Length();
       
   676 		if ((i != 0) && (iOurMessage[i - 1] == 0x0d))
       
   677 			{
       
   678 			iOurMessage.Delete(i - 1, 1);
       
   679 			}
       
   680 		ProgressUpdateL();
       
   681 		}
       
   682 	return i;
       
   683 	}
       
   684 /********************************************************************/
       
   685 
       
   686 void CFaxModem::Dropdtr ()
       
   687    {
       
   688    
       
   689    __FLOG_FAXSRV( _L8("CFaxModem::Dropdtr"));
       
   690    
       
   691    LowerDTR ();
       
   692    Silence (CLK_TCK);
       
   693    RaiseDTR ();
       
   694    Silence (CLK_TCK);
       
   695    }
       
   696 /********************************************************************/
       
   697 
       
   698    
       
   699 /**
       
   700 * Wait approximately 75 ms
       
   701 */
       
   702 void CFaxModem::Silence ()
       
   703    {
       
   704    Silence (CLK_TCK / 13);      // wait approx 75 milliseconds
       
   705    }
       
   706 
       
   707 /********************************************************************/
       
   708 
       
   709 /**
       
   710 * Wait given number of microseconds
       
   711 */
       
   712 void CFaxModem::Silence (TInt ticks) const
       
   713    {
       
   714    User::After (ticks);         // wait however long
       
   715    }
       
   716 /********************************************************************/
       
   717 
       
   718 void CFaxModem::Speed (TBps aSpeed)
       
   719    {
       
   720    iRS232Settings ().iRate = aSpeed;
       
   721    iCommSession.SetConfig (iRS232Settings);
       
   722    }
       
   723 /********************************************************************/
       
   724 
       
   725 /**
       
   726 * Turns on obeying XON, XOFF characters and CTS signal
       
   727 */
       
   728 void CFaxModem::Xonon ()
       
   729    {
       
   730    iRS232Settings ().iHandshake = (KConfigObeyXoff | KConfigObeyCTS | KConfigWriteBufferedComplete);
       
   731    iCommSession.SetConfig (iRS232Settings);
       
   732    }
       
   733 /********************************************************************/
       
   734 
       
   735 /**
       
   736 Turns off handshaking
       
   737 */
       
   738 void CFaxModem::Xonoff()
       
   739 	{
       
   740 	iSendone.Zero(); // sending a null descriptor
       
   741 #ifdef _DEBUG
       
   742 	TRAPD(modemUnplugged, SendL(iSendone)); // waits till all pending transmits have gone
       
   743 	__FLOG_FAXSRV1(_L8("CFaxModem::Xonoff SendL leave error code: %d"), modemUnplugged);
       
   744 #else
       
   745 	TRAP_IGNORE(SendL(iSendone)); // waits till all pending transmits have gone
       
   746 #endif
       
   747 
       
   748 	iSendone.SetMax(); // we send single characters via iSendone[0]
       
   749 
       
   750 	iRS232Settings().iHandshake = 0;
       
   751 	iCommSession.SetConfig(iRS232Settings);
       
   752 	}
       
   753 /********************************************************************/
       
   754 
       
   755 void CFaxModem::LowerDTR()
       
   756    {
       
   757    iCommSession.SetSignals (0, KSignalDTR);     // SetSignals(SetMask,ClearMask) ;
       
   758    }
       
   759 /********************************************************************/
       
   760 
       
   761 void CFaxModem::RaiseDTR()
       
   762    {
       
   763    iCommSession.SetSignals (KSignalDTR, 0);     // SetSignals(SetMask,ClearMask) ;
       
   764    }
       
   765 /********************************************************************/
       
   766 
       
   767 /**
       
   768 * @return	0 - if there are no data waiting in driver's input buffer and receiver's buffer to be read.
       
   769 *        	otherwise - number of bytes to be read.
       
   770 */
       
   771 TInt CFaxModem::Rxstat (void)
       
   772    {
       
   773    if (iReceiveBuffer.Length () != 0)
       
   774       return (1);
       
   775    else
       
   776       return (iCommSession.QueryReceiveBuffer ());
       
   777    }
       
   778 /********************************************************************/
       
   779 
       
   780 /**
       
   781 * Does nothing. Just returns 0.
       
   782 */
       
   783 TInt CFaxModem::Txstat()
       
   784    {
       
   785    return 0;
       
   786    }
       
   787 /********************************************************************/
       
   788 
       
   789 /**
       
   790 * Sends 1 byte to modem. 
       
   791 *
       
   792 * @param	aChar	-Byte to be sent.
       
   793 *
       
   794 * @note		This function can leave.
       
   795 *
       
   796 * @see	SendL() function
       
   797 *
       
   798 * @return	none.
       
   799 */
       
   800 void CFaxModem::TxcharL (TUint8 aChar)
       
   801    {
       
   802    iSendone[0] = aChar;
       
   803    SendL (iSendone);
       
   804    }
       
   805 /********************************************************************/
       
   806 
       
   807 
       
   808 // this routine amended July 1998 to offer infinite timeouts when sending data in fax ECM
       
   809 
       
   810 void CFaxModem::SendL(const TDesC8 & astring)
       
   811     {
       
   812     TTimeIntervalMicroSeconds32 timeout = CLK_TCK * 10;
       
   813     if ((iProgress.iECM) && (iProgress.iPhase == EDataTransfer))
       
   814         {
       
   815         iCommSession.Write(iTranstat, timeout, astring);
       
   816         User::WaitForRequest(iTranstat);
       
   817         if (iTranstat == KErrTimedOut)
       
   818             {
       
   819             TInt ticks = 1;
       
   820             while (Rxstat() != 0)
       
   821                 {
       
   822                 RxcharWaitL(ticks);
       
   823                 if (iReadone[0] == Kcan)
       
   824                     User::Leave(KFaxErrModemDisconnect);
       
   825                 }
       
   826             }
       
   827         else if (iTranstat != KErrNone)
       
   828             iCommSession.ResetBuffers(KCommResetTx);
       
   829         }
       
   830     else
       
   831         {
       
   832         iCommSession.Write(iTranstat, timeout, astring);
       
   833         User::WaitForRequest(iTranstat);
       
   834         if (iTranstat != KErrNone)
       
   835             {
       
   836             iCommSession.ResetBuffers(KCommResetTx);
       
   837             if (iTranstat == KErrTimedOut)
       
   838                 User::Leave(KFaxTransmitterStalled);
       
   839             }
       
   840         }
       
   841     }
       
   842 /********************************************************************/
       
   843 
       
   844 /**
       
   845 *	Transmits iTransmitBuffer by calling SendL. After sending sets buffer's
       
   846 *	length to zero.
       
   847 *
       
   848 * @note		This function can leave.
       
   849 *
       
   850 * @see	SendL() function
       
   851 */
       
   852 void CFaxModem::CommitTransmitBufferL ()
       
   853    {
       
   854    SendL (iTransmitBuffer);
       
   855    iTransmitBuffer.Zero ();
       
   856    }
       
   857 /********************************************************************/
       
   858 
       
   859 
       
   860 /**
       
   861 *  Reads 1 byte from serial port (or iReceiveBuffer) and puts it to iReadone buffer.
       
   862 *
       
   863 * @param	atimeout	-	timeout in microseconds.
       
   864 *
       
   865 * @return	0 - timeout, 
       
   866 *       	1 -	byte read and put into iReadone
       
   867 *
       
   868 * @note		This function can leave. See comments in CFAXMODM.CPP 
       
   869 *
       
   870 */
       
   871 
       
   872 // this is our basic get char function with timeout
       
   873 
       
   874 // Note that this function *can* leave, despite not being named as an L
       
   875 // function.  This is because the leave is as a result of a user request
       
   876 // to end the entire fax thread and could occur at any time.  This
       
   877 // function (to read a character) is used at some point by virtually
       
   878 // every part of the fax system and consequently, were the normal
       
   879 // convention to be followed, every function would have to be an L
       
   880 // function - this destroys the whole point of having a separate
       
   881 // nomenclature.  Therefore, I declare that the possibility of a leave
       
   882 // as a result of the user cancel request is henceforth regarded as an
       
   883 // exception to the rule than a function which leaves must be called an
       
   884 // L function.  The new rule is that any fax session must be run inside
       
   885 // a trap harness - not simply because the modem and port need tidying up.
       
   886 
       
   887 // Note to the note : The check for user cancel request has been moved to
       
   888 // ProgressUpdate().  However, this function can still leave if the
       
   889 // rx buffer overruns, in which case we use the standard iCancel flag to
       
   890 // check if it is safe to leave and do so.  The original note still applies
       
   891 // but to be honest, I'm less happy about it now.
       
   892 
       
   893 TInt CFaxModem::RxcharWaitL (TInt & atimeout)
       
   894    {
       
   895    iReadone.Zero ();
       
   896    if (atimeout == 0)
       
   897       return (0);
       
   898    if (iReceiveBuffer.Length () == 0)			//iReceiveBuffer == Receive descriptor
       
   899       {
       
   900       for (;;)
       
   901          {
       
   902          TInt timeBegin = clock ();
       
   903          iCommSession.Read (iRecstat, atimeout, iReceiveBuffer, KBufSize);    // read data from the serial port
       
   904          User::WaitForRequest (iRecstat);
       
   905          if ((iRecstat == KErrCommsOverrun) && (iCancel == 0))  // check for overrun and user cancel request
       
   906             {
       
   907             iCancel = 2;
       
   908             iCommSession.ResetBuffers (KCommResetRx);			//Reset serial port buffers
       
   909             User::Leave (KErrCommsOverrun);
       
   910             }
       
   911             
       
   912 		 if ((iReceiveBuffer.Length () == 0) && (iRecstat == KErrTimedOut))
       
   913 			{
       
   914 			if (iCommSession.QueryReceiveBuffer () != 0 )
       
   915 				{
       
   916 					iCommSession.ReadOneOrMore (iRecstat, iReceiveBuffer);
       
   917 					User::WaitForRequest (iRecstat);
       
   918 				}
       
   919 			}	
       
   920 		 atimeout -= (clock () - timeBegin);					//decrement timeout 
       
   921 		 
       
   922 		 if (iReceiveBuffer.Length () != 0)
       
   923             break;
       
   924          if (atimeout > 0)
       
   925             continue;
       
   926          atimeout = 0;
       
   927          return (0);
       
   928          }
       
   929       if (atimeout < 1)
       
   930          atimeout = 1;
       
   931       }
       
   932    iReadone.Append (iReceiveBuffer[0]);
       
   933    iReceiveBuffer.Delete (0, 1);
       
   934    return (1);
       
   935    }
       
   936 /********************************************************************/
       
   937 
       
   938 void CFaxModem::ProgressUpdateL ()
       
   939    {
       
   940 // Commented out by AMC 13/3/00.  Pending complete deletion.  Not completely removed as removal of function from
       
   941 // Base has not yet propagated down Device Drivers.  Until the device drivers support it there's a chance it
       
   942 // will have to be re-introduced.
       
   943 
       
   944 //	UserHal::ResetAutoSwitchOffTimer (); // required to stop powerdown
       
   945    if (iCancel == 1)
       
   946       {
       
   947       iCancel++;
       
   948       User::Leave (KFaxCancelRequested);
       
   949       }
       
   950 
       
   951    TTime now;
       
   952    now.UniversalTime ();
       
   953 
       
   954    iProgress.iLastUpdateTime = now;
       
   955 
       
   956    if (iVerbose)
       
   957       {
       
   958       if (iOurMessage.Length ())
       
   959          {
       
   960 #ifdef _DEBUG
       
   961          //
       
   962          // Write the log message also to the main log file...
       
   963          //
       
   964          TBuf8<256> temp;
       
   965 
       
   966          temp.Copy(iOurMessage);
       
   967          __FLOG_FAXSRV1(_L8("ProgressUpdateL: %S"), &temp);
       
   968 #endif
       
   969 		 
       
   970          TDateTime dateTime;
       
   971          TBuf8 < 16 > datestamp;
       
   972          dateTime = now.DateTime ();
       
   973          datestamp.Format (_L8 ("%02d.%02d:%02d:%06d "), dateTime.Hour (), dateTime.Minute (), dateTime.Second (), dateTime.MicroSecond ());
       
   974          iOurMessage.Insert (0, datestamp);
       
   975          iOurMessage.Append (13);
       
   976          iOurMessage.Append (10);
       
   977 		 
       
   978 		 if (iFileOpen)
       
   979 			iFile.Write (iOurMessage);
       
   980 
       
   981 		 iOurMessage.Zero ();
       
   982          }
       
   983       }
       
   984    }
       
   985 /*********************************************************************/