diff -r 17af172ffa5f -r 630d2f34d719 fax/faxclientandserver/FAXSVR/CFAX1.CPP --- a/fax/faxclientandserver/FAXSVR/CFAX1.CPP Thu Aug 19 11:03:36 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1855 +0,0 @@ -// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// - -#include "FAXSERV.H" -#include "fax_reversebytes.h" -#include "FAXMDRV.H" -#include "FAXMODEM.H" - - -// this module has three parts -// first receive routines rx -// second transmit routines tx -// third utilities - -/********************************************************************/ - -CFaxModemDriver *CFaxClass1::NewLC (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress) -{ - CFaxModemDriver *self = new (ELeave) CFaxClass1; - CleanupStack::PushL (self); - self->ConstructL (aFaxServerSessionSettings, aProgress); - return self; -} - -CFaxModemDriver *CFaxClass1::NewL (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress) -{ - CFaxModemDriver *self = NewLC (aFaxServerSessionSettings, aProgress); - CleanupStack::Pop (); - return self; -} -/********************************************************************/ - -// here we set up a fax receive - Phase A -// this does require HDLC frames to be sent - -TInt CFaxClass1::RxConnectL () -{ - TInt faxIdFcf; // CSI or CIG - TInt capabilityFcf; // DIS or DTC - TBuf8 < 3 > faxIdTxt; // CSI or CIG - TBuf8 < 3 > capabilityTxt; // DIS or DTC - - TInt i, x; - iDisBytes = 3; - iOldFrame.Zero (); - - // we query the modem to find out what its speed capabilities are - - CheckCadenceExportL (_L8 ("AT+FRM=?\r")); - // coverity[check_return] - iModem->ImportL (iResults, 2); - iModem->iOurMessage.Format (_L8 ("%S"), &iResults); - iModem->ProgressUpdateL (); - iModem->GetMatchL (_L8 ("OK"), 1); - - // the available speeds are stored in iResults - // we set our proposed speed to the highest compatible with faxini settings - - if ((iResults.FindF (_L8 ("24"))) >= 0) - iActualFaxSpeed = 24; - else - return (KFaxErrModemNotWorking); - if ((iFaxServerSessionSettings->iMaxSpeed) > 2400) - if ((iResults.FindF (_L8 ("48"))) >= 0) - iActualFaxSpeed = 48; - if ((iFaxServerSessionSettings->iMaxSpeed) > 4800) - if ((iResults.FindF (_L8 ("96"))) >= 0) - iActualFaxSpeed = 96; - if ((iFaxServerSessionSettings->iMaxSpeed) > 9600) - if ((iResults.FindF (_L8 ("145"))) >= 0) - iActualFaxSpeed = 145; - - // we now prepare our DIS/DTC answer capabilities frame - // the resolution and compression are taken from our settings - - for (x = 0; x < 5; x++) - iDisFrame.byte[x] = 0; - iDisFrame.bit.b09 = 0; - iDisFrame.bit.b10 = 1; - iDisFrame.bit.b20 = 1; - iDisFrame.bit.b21 = 1; - iDisFrame.bit.b22 = 1; - iDisFrame.bit.b23 = 1; - if (iFaxServerSessionSettings->iRxResolution == EFaxFine) - iDisFrame.bit.b15 = 1; - if (iFaxServerSessionSettings->iRxCompression == EModifiedRead) - iDisFrame.bit.b16 = 1; - -// if (iFaxServerSessionSettings->iMode & KFaxWaitForRing) -// { - // while ((iModem->GetMatchL (_L8 ("RING"), 3)) == 0); - // iTimeOfLastRing.UniversalTime(); -// } -// else -// { - if (((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) && (!(iFaxServerSessionSettings->iMode & KFaxWaitForRing))) -// if ((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) - DialFaxOnDemandL (); -// } - - // if we a trying to poll, we've dialled, so we wait for a DIS from the answerer - // otherwise we do an answer ourselves - - if (iFaxServerSessionSettings->iMode & KFaxPoll) - { - faxIdFcf = KT30_CIG; - faxIdTxt.Copy (_L8 ("CIG")); - capabilityFcf = KT30_DTC; - capabilityTxt.Copy (_L8 ("DTC")); - iModem->iOurMessage.Format (_L8 ("about to poll fax")); - - } - else - { - faxIdFcf = KT30_CSI; - faxIdTxt.Copy (_L8 ("CSI")); - capabilityFcf = KT30_DIS; - capabilityTxt.Copy (_L8 ("DIS")); - CheckCadenceExportL (_L8 ("ATA\r")); - iModem->iOurMessage.Format (_L8 ("about to receive fax")); - } - - iModem->iProgress.iPhase = ECallEstablishment; - iModem->ProgressUpdateL (); - - for (;;) - { - if (!(iModem->ImportL (iResults, KT30_T1))) - return (KFaxErrCannotConnect); - iModem->iOurMessage.Format (_L8 ("%S"), &iResults); - iModem->ProgressUpdateL (); - if ((iResults.FindF (_L8 ("NO DIALTONE"))) >= 0 || - iResults.FindF (_L8 ("NO DIAL TONE")) >= 0) - return (KFaxErrNoDialTone); - if ((iResults.FindF (_L8 ("BUSY"))) >= 0) - return (KFaxErrBusy); - if ((iResults.FindF (_L8 ("NO ANSWER"))) >= 0) - return (KFaxErrNoAnswer); - if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0) - return (KFaxErrNoCarrier); - if ((iResults.FindF (_L8 ("CONNECT"))) >= 0) - break; - } - - if (iFaxServerSessionSettings->iMode & KFaxPoll) - User::LeaveIfError (RxPrePollL ()); - else - { - iModem->iOurMessage.Format (_L8 ("Fax call detected")); - iModem->ProgressUpdateL (); - } - - iModem->iOurMessage.Format (_L8 ("sending %S"), &faxIdTxt); - iModem->ProgressUpdateL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLNXT); - iFrame.Append (faxIdFcf); - for (i = 20; i > iFaxServerSessionSettings->iFaxId.Length (); i--) - iFrame.Append (0x20); - for (i = iFaxServerSessionSettings->iFaxId.Length (); i;) - iFrame.Append (iFaxServerSessionSettings->iFaxId[--i]); - if (SendframeL (iFrame) != 1) - return (KFaxErrCSIorCIG); - - // we follow that with our DIS frame - - iModem->iOurMessage.Format (_L8 ("sending %S"), &capabilityTxt); - iModem->iProgress.iPhase = ESessionNegotiation; - iModem->ProgressUpdateL (); - iDisFrame.byte[1] &= 0xc3; - switch (iActualFaxSpeed) - { - case 48: - iDisFrame.byte[1] |= 0x08; - break; /* V.27 4800+2400 */ - case 96: - iDisFrame.byte[1] |= 0x0c; - break; /* & V.29 9600+7200 */ - case 145: - iDisFrame.byte[1] |= 0x2c; - break; /* & V.17 14400+1200+9600+7200 */ - default: - iDisFrame.byte[1] |= 0x00; /* V.27 fallback 2400 only */ - } - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (capabilityFcf); - for (i = 0; i < iDisBytes; i++) - iFrame.Append (iDisFrame.byte[i]); - if (SendframeL (iFrame) != 1) - return (KFaxErrDISorDTC); - - // and now we await the negotiation from the caller - // note that we'll resend the last frame (DIS or DTC) if we get no reply - // until we get a TSI or a DCS (which show the DIS or DTC was received) - - return (RxPrePageL ()); -} - -/********************************************************************/ - -// here we prepare for receiving via a poll - // we have received a DIS in iResults, so check the polling bit - // iResults[0] is the address - // iResults[1] is the control - // iResults[2] is the FCF - // iResults[3] has bits 1-8 of the FIF - // iResults[4] has bits 9-16 of the FIF - // the polling bit is bit 9 - -TInt CFaxClass1::RxPrePollL () -{ - TInt pollDocsAvailable = 0; - TInt i; - iResults.Copy (_L8 ("CALL JUST ANSWERED")); - for (;;) - { - if (GetframeL (iResults) == 0) - return (KFaxErrFrameFail); - iModem->ProgressUpdateL (); - - // the third byte in the frame is the FCF (fax control field) - - switch ((TUint8) iResults[2]) - { - case 0x20: // this marks a non-standard frame, which we ignore - iModem->iOurMessage.Format (_L8 ("NSF nonstandard facilities Frame")); - iModem->ProgressUpdateL (); - break; - - case 0x40: // this marks the receiver ID - iModem->iOurMessage.Format (_L8 ("CSI identity Frame")); - iModem->ProgressUpdateL (); - iModem->iProgress.iAnswerback.Zero (); - for (i = 22; i > 2; i--) - iModem->iProgress.iAnswerback.Append (iResults[i]); - iModem->iOurMessage.Format (_L8 ("Remote fax ID is %S"), &iModem->iProgress.iAnswerback); - iModem->ProgressUpdateL (); - break; // the capability frame should follows - - case 0x80: // this marks the receiver capability frame - iModem->iOurMessage.Format (_L8 ("DIS capability Frame")); - iModem->ProgressUpdateL (); - iFcfXbit = 1; // we've received a DIS, so set the X bit - pollDocsAvailable = iResults[4] & 0x01; // and record the polling bit too - break; - - case 0xfa: // this means we were asked to disconnect - RxDCNL (); - return (KFaxErrRemoteDCN); - - default:; - } - - // if a final frame we return - // else we just issue AT+FRH=3 and continue - - if (iResults[1] & 0x10) - break; - iModem->ExportL (_L8 ("AT+FRH=3\r")); - } - - if (pollDocsAvailable) - { - iModem->iOurMessage.Format (_L8 ("Polling bit set")); - iModem->ProgressUpdateL (); - return (KErrNone); - } - return (KFaxNothingToPoll); // if the other machine isn't pollable we exit -} -/********************************************************************/ - -// here we negotiate a fax reception - Phase B - // this function is always called after we have connected. However, - // it can be called at other times if we have requested a renegotiation - // or if the sender want to change the fax parameters - -TInt CFaxClass1::RxPrePageL () -{ - TInt x, z, i, nullCounter; - TUint8 thisChar, lastChar; - TInt ticks; - - for (;;) - { - iModem->ExportL (_L8 ("AT+FRH=3\r")); - if (GetframeL (iResults) == 0) - return (KFaxErrFrameFail); - iModem->iOurMessage.Format (_L8 ("Response received")); - iModem->ProgressUpdateL (); - - // analyse the possible responses - - switch ((TUint8) iResults[2]) - { - case 0x42: // this is the sender ID - their capability should follow - - iModem->iOurMessage.Format (_L8 ("TSI identity Frame")); - iModem->ProgressUpdateL (); - iModem->iProgress.iAnswerback.Zero (); - for (i = 22; i > 2; i--) - iModem->iProgress.iAnswerback.Append (iResults[i]); - iModem->iOurMessage.Format (_L8 ("Remote fax ID is %S"), &iModem->iProgress.iAnswerback); - iModem->ProgressUpdateL (); - break; - - case 0x82: // here's the sender capability frame - the most complex case - - iModem->iOurMessage.Format (_L8 ("DCS capability Frame")); - iModem->ProgressUpdateL (); - for (i = 0; i < 5; i++) - iDcsFrame.byte[i] = (TUint8) iResults[i + 3]; - - // we have the DCS saved - we analyse it for speed and resolution and compression - - if (iDcsFrame.bit.b24 == 0) - iDcsFrame.byte[3] = 0; - - iModem->iProgress.iResolution = TFaxResolution (iDcsFrame.bit.b15); - iModem->iProgress.iCompression = TFaxCompression (iDcsFrame.bit.b16); - - switch (iDcsFrame.byte[1] & 0x3c) - { - case 0x08: - iActualFaxSpeed = 48; - break; /* 4800 V.27 */ - case 0x04: - iActualFaxSpeed = 96; - break; /* 9600 V.29 */ - case 0x0c: - iActualFaxSpeed = 72; - break; /* 7200 V.29 */ - case 0x24: - iActualFaxSpeed = 97; - break; /* 9600 V.17 */ - case 0x2c: - iActualFaxSpeed = 73; - break; /* 7200 V.17 */ - case 0x20: - iActualFaxSpeed = 145; - break; /* 14400 V.17 */ - case 0x28: - iActualFaxSpeed = 121; - break; /* 12000 V.17 */ - default: - iActualFaxSpeed = 24; /* 2400 V.27 */ - } - - i = (iActualFaxSpeed & (~1)); - - // now we prepare to recieve the training frame that follows the DCS - // we try to get the carrier at this speed three times before giving up - - for (x = 0; x < 3; x++) - { - iModem->iOurMessage.Format (_L8 ("setting %d00"), i); - iModem->iProgress.iSpeed = (i * 100); - iModem->ProgressUpdateL (); - - iResults.Copy (_L8 ("AT+FRM=")); - iResults.AppendNum (iActualFaxSpeed); - iResults.Append (_L8 ("\r")); - iModem->ExportL (iResults); - z = FramestatL (); - if (z == 1) - break; - if (z != 0) - { - iModem->TxcharL (Kcan); - if (FramestatL () < 0) - iModem->TxcharL (Kreturn); - ReceiveSilenceL (); - iModem->iOurMessage.Format (_L8 ("sending FTT")); - iModem->ProgressUpdateL (); - iFrame.Append (KT30_FTT); - if (SendframeL (iFrame) == 0) - return (KFaxErrTrainFail); - break; - } - } - if (x == 3) - return (KFaxErrAtNegotiatedSpeed); - - // once we have a carrier, we start receiving the training frame - // we look for a clear 750 milliseconds of zeros ending in - // this is determined by calculating the number of number of null bytes - // taken at any given speed - - iModem->iOurMessage.Format (_L8 ("training .... ")); - iModem->ProgressUpdateL (); - - ticks = (CLK_TCK * 165) / 100; // bug fix - was originally "CLK_TICK * (165/100)" - // This failed because 165/100 is rounded to 1 because - // ticks is an integer and that made the fax server - // training for 1 second instead of 1.5 - for (lastChar = 0, nullCounter = 0;;) - { - if (iModem->RxcharWaitL (ticks) == 0) - { - break; - } - thisChar = iModem->iReadone[0]; - if (nullCounter != (i * 75 / 8)) - { - if (thisChar != 0) - nullCounter = 0; - else - ++nullCounter; - } - if ((thisChar == Ketx) && (lastChar == Kdle)) - break; - lastChar = thisChar; - } - if (FramestatL () < 0) - { - iModem->TxcharL (Kcan); - if (FramestatL () < 0) - iModem->TxcharL (Kreturn); - } - - // now we check the count of null bytes and either send FTT - // (in which case the sender will send a new DCS and try again) - // or else send CFR confirmation and wait for the first page - - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - if (nullCounter == (i * 75 / 8)) - { - iModem->iOurMessage.Format (_L8 ("training OK")); - iModem->ProgressUpdateL (); - } - else - { - ReceiveSilenceL (); - iModem->iOurMessage.Format (_L8 ("sending FTT")); - iModem->ProgressUpdateL (); - iFrame.Append (KT30_FTT); - if (SendframeL (iFrame) == 0) - return (KFaxErrTrainFail); - break; - } - - iModem->iOurMessage.Format (_L8 ("sending CFR")); - iModem->ProgressUpdateL (); - - iFrame.Append (KT30_CFR); - if (SendframeL (iFrame) == 0) - return (KFaxErrCFR); - - // after we send a CFR, we interpret a failure to - // establish a high-speed carrier as an indication - // that the sender didn't get our CFR, and will - // act as if they received an FTT - - if (RxSetHighSpeedL () != KErrNone) - break; - return (KErrNone); - - // lastly, we cater for the sender disconnecting us, - // either because we couldn't train or because our - // capabilities were wrong, or because they were only trying - // to hack our fax machine - - case 0xfa: - RxDCNL (); - return (KFaxErrRemoteDCN); - - default:; - } - } -} -/********************************************************************/ - -// this is a small function to set a class 1 fax modem to phase C - // reception speed (found in iActualFaxSpeed) in preparation for - // receiving data. This is called before the first page and also - // between pages. If the modem can't find a high speed carrier, we - // leave the caller to decide what action to take - if we'd just sent a - // page confirmation we should try resending our last negotiating frame - // in case it was lost, but if we have just sent a CFR, we wait for the - // sender to retrain. - -// If the protocol is out of sync and we get a low speed carrier - // then we'll get a +FCERROR response (same as ERROR) - -TInt CFaxClass1::RxSetHighSpeedL () -{ - TInt x, portSpeed; - switch (iActualFaxSpeed) - { - case 145: - x = 144; - portSpeed = 146; - break; - case 121: - x = 120; - portSpeed = 122; - break; - case 97: - x = 96; - portSpeed = 98; - break; - case 73: - x = 72; - portSpeed = 74; - break; - default: - x = portSpeed = iActualFaxSpeed; - } - - iModem->iOurMessage.Format (_L8 ("setting %d00"), x); - iModem->iProgress.iSpeed = (x * 100); - iModem->ProgressUpdateL (); - - iResults.Copy (_L8 ("AT+FRM=")); - iResults.AppendNum (portSpeed); - iResults.Append (_L8 ("\r")); - iModem->ExportL (iResults); - - x = FramestatL (KT30_T2); // always wait 6 seconds before a timeout - if (x == 1) - { - return (RxStartPageL ()); - } - if (x != 0) - { - iModem->TxcharL (Kcan); - if (FramestatL () < 0) - iModem->TxcharL (Kreturn); - } - return (KFaxErrAtNegotiatedSpeed); -} -/********************************************************************/ - -// after page data has been received, we go back to 300 bps negotiation -// for the post-page message which the transmitter sends 75ms after the -// end of the data - -TInt CFaxClass1::RxPostPageL () -{ - TInt i, x = 0; - iOldFrame.Zero (); - iModem->iProgress.iPhase = EPostPageStatus; - iModem->ProgressUpdateL (); - - // wait for the modem to react to the end of fax data before proceeding - - if ((iModem->GetMatchL (_L8 ("NO CARRIER"), 5)) == 0) - return (KFaxErrCannotEndData); - - for (;;) - { - - // we start by requesting a frame - - iModem->ExportL (_L8 ("AT+FRH=3\r")); - if (GetframeL (iResults) == 0) - { - if (x++ == 3) - return (KFaxErrFrameFail); - continue; - } - - iModem->iOurMessage.Format (_L8 ("Response received")); - iModem->ProgressUpdateL (); - - // now we work out what it is - - switch ((TUint8) iResults[2]) - { - - // the first case is where the last page was the end of the fax - - case 0x3e: // we recognize PRI-Q frames but treat them like non-PRI-Q variants - iModem->iOurMessage.Format (_L8 ("PRI-Q bit set")); - iModem->ProgressUpdateL (); - // fallthrough - case 0x2e: - iModem->iOurMessage.Format (_L8 ("EOP end of page %u and transmission"), iModem->iProgress.iPage); - iModem->ProgressUpdateL (); - iModem->iOurMessage.Format (_L8 ("sending MCF")); - iModem->ProgressUpdateL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (KT30_MCF); - if (SendframeL (iFrame) == 0) - return (KFaxErrMCF); - - // now it isn't an error if get a DCN and hang up - // so, loop and wait for it - - iModem->iProgress.iPhase = EDisconnection; - continue; - - // the second case is where the sender demands a renegotiation - - case 0x9e: // we recognize PRI-Q frames but treat them like non-PRI-Q variants - iModem->iOurMessage.Format (_L8 ("PRI-Q bit set")); - iModem->ProgressUpdateL (); - // fallthrough - case 0x8e: - iModem->iOurMessage.Format (_L8 ("EOM end of page %u and document"), iModem->iProgress.iPage); - iModem->ProgressUpdateL (); - iModem->iOurMessage.Format (_L8 ("sending MCF")); - iModem->ProgressUpdateL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (KT30_MCF); - if (SendframeL (iFrame) == 0) - return (KFaxErrMCF); - iModem->iProgress.iPhase = ESessionNegotiation; - iOldFrame.Zero (); - iOldFrame.Append (KT30_CTLLST); - iOldFrame.Append (KT30_DIS); - for (i = 0; i < iDisBytes; i++) - iOldFrame.Append (iDisFrame.byte[i]); - return (RxPrePageL ()); - - // the third case is where another page is going to follow - - case 0x5e: // we recognize PRI-Q frames but treat them like non-PRI-Q variants - - iModem->iOurMessage.Format (_L8 ("PRI-Q bit set")); - iModem->ProgressUpdateL (); - // fallthrough - case 0x4e: - iModem->iOurMessage.Format (_L8 ("MPS end of page %u"), iModem->iProgress.iPage); - iModem->ProgressUpdateL (); - - iModem->iOurMessage.Format (_L8 ("sending MCF")); - iModem->ProgressUpdateL (); - - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (KT30_MCF); - if (SendframeL (iFrame) == 0) - return (KFaxErrMCF); - - for (x = 0; x < 3; x++) - { - if (RxSetHighSpeedL () == KErrNone) - return (KErrNone); - iModem->iOurMessage.Format (_L8 ("Resending last response .... ")); - iModem->ProgressUpdateL (); - if (SendframeL (iOldFrame) == 0) - return (KFaxErrMCF); - } - return (KFaxErrMCF); - - // the fourth case is where we are told to disconnect - // it's an error if we hadn't been expecting it - - case 0xfa: - if (iModem->iProgress.iPhase == EDisconnection) - { - RxDCNL (); - return (KErrNone); - } - - RxDCNL (); - return (KFaxErrRemoteDCN); - - // the fifth case is where we see a negotiation frame - // the sixth case is where we see a negotiation frame - // our supposed page may have been a mistake - // just go back to phase B and try to recover that way - - case 0x42: // TSI frame - case 0x82: // DCS frame - if ((TUint8) iResults[2] == 0x42) - iModem->iOurMessage.Format (_L8 ("TSI identity")); - else - iModem->iOurMessage.Format (_L8 ("DCS capability")); - iModem->iOurMessage.Append (_L8 (" Frame - renegotiating session parameters")); - iModem->ProgressUpdateL (); - iModem->iProgress.iPhase = ESessionNegotiation; - return (RxPrePageL ()); - - // the last case is where we see an unsupported frame - // if it is a final frame we ask for a repeat via CRP - - default: - if (SendCRPL () != KErrNone) - return (KFaxErrCRP); - } - } -} -/********************************************************************/ - -// here we have detected a disconnection frame so we hang up the modem - -void CFaxClass1::RxDCNL () -{ - iModem->iOurMessage.Format (_L8 ("DCN disconnect Frame")); - iModem->iProgress.iPhase = EDisconnection; - iModem->ProgressUpdateL (); -} -/********************************************************************/ - -// here we send a DCN disconnect frame and then hang up the modem - -TInt CFaxClass1::TxDCNL () -{ - iModem->iOurMessage.Format (_L8 ("sending DCN")); - iModem->iProgress.iPhase = EDisconnection; - iModem->ProgressUpdateL (); - ReceiveSilenceL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (KT30_DCN); - if (SendframeL (iFrame) == 0) - return (KFaxErrDCN); - return (KErrNone); -} -/********************************************************************/ - -// here we set up a fax transmit - Phase A - // there's no HDLC stuff here - -TInt CFaxClass1::TxConnectL () -{ - - // we query the modem to find out what its speed capabilities are - iModem->ExportL (_L8 ("AT+FTM=?\r")); - // coverity[check_return] - iModem->ImportL (iResults, 2); - iModem->iOurMessage.Format (_L8 ("%S"), &iResults); - iModem->ProgressUpdateL (); - iModem->GetMatchL (_L8 ("OK"), 1); - - // the available speeds are stored in iResults - // we set our proposed speed to the highest compatible with faxini settings - - if ((iResults.FindF (_L8 ("24"))) >= 0) - iActualFaxSpeed = 24; - else - return (KFaxErrModemNotWorking); - if ((iFaxServerSessionSettings->iMaxSpeed) > 2400) - if ((iResults.FindF (_L8 ("48"))) >= 0) - iActualFaxSpeed = 48; - if ((iFaxServerSessionSettings->iMaxSpeed) > 4800) - if ((iResults.FindF (_L8 ("96"))) >= 0) - iActualFaxSpeed = 96; - if ((iFaxServerSessionSettings->iMaxSpeed) > 9600) - if ((iResults.FindF (_L8 ("145"))) >= 0) - iActualFaxSpeed = 145; - - // we now issue our ATD command, and if we aren't in immediate - // transmit mode (already off hook) then we dial a number - - iModem->ExportL (_L8 ("ATD")); - if ((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) - iModem->ExportL (iFaxServerSessionSettings->iPhoneNumber); - iModem->TxcharL (Kreturn); - iModem->iOurMessage.Format (_L8 ("Call has been dialled")); - iModem->iProgress.iPhase = ECallEstablishment; - iModem->ProgressUpdateL (); - - // now we wait up to KDialTimeout seconds for the modem to connect - - for (;;) - { - if (!(iModem->ImportL (iResults, KDialTimeout))) - return (KFaxErrNoDial); - iModem->iOurMessage.Format (_L8 ("%S"), &iResults); - iModem->ProgressUpdateL (); - if ((iResults.FindF (_L8 ("NO DIALTONE"))) >= 0 || - iResults.FindF (_L8 ("NO DIAL TONE")) >= 0) - return (KFaxErrNoDialTone); - if ((iResults.FindF (_L8 ("BUSY"))) >= 0) - return (KFaxErrBusy); - if ((iResults.FindF (_L8 ("NO ANSWER"))) >= 0) - return (KFaxErrNoAnswer); - if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0) - return (KFaxErrNoCarrier); - if ((iResults.FindF (_L8 ("CONNECT"))) >= 0) - break; - } - - // we can now go on to phase B - - iResults.Copy (_L8 ("CALL JUST ANSWERED")); - return (TxPrePageL ()); -} -/********************************************************************/ - -// here we negotiate a fax transmission, or a polled reception - Phase B -// this function is always called after we have connected. However, -// it can be called at other times if the receiver has requested a -// renegotiation or if we want to change the fax parameters, in which -// case we would enter with iModem->iProgress.iPhase == RFax::EPostPageStatus - -TInt CFaxClass1::TxPrePageL () -{ - TInt i; - //TInt x; - TInt successiveErrors = 0; - TInt trainingAttempts = 0; - iDcsBytes = 3; - iOldFrame.Zero (); - TInt ticks; - TInt trainbytes; - - // this routine is one big frame waiting loop - note that on first entry - // here we have set the length of the last frame stored in iOldFrame to - // zero, so we don't resend any last frame on first entry here. - // Subsequent iterations of our receive loop will resend the iOldFrame - // if nothing is received, in an attempt at error recovery, unless of - // course we have deliberately reset iOldFrame to zero again - - //x = 0; - for (;;) - { - if (iModem->iProgress.iPhase != EPostPageStatus) - { - if (GetframeL (iResults) == 0) - { - if (successiveErrors++ > 3) - return (KFaxErrFrameFail); - - if (iModem->iProgress.iPhase == ECallEstablishment) - // no point in carrying on without any capability frame - { - iModem->ExportL (_L8 ("AT+FRH=3\r")); - continue; - } - // if (iModem->iProgress.iPhase == ECallEstablishment) - // { - // if (x++ == 3) - // return (KFaxErrFrameFail); - // - // iModem->ExportL (_L8 ("AT+FRH=3\r")); - // continue; - // } - - // no point in carrying on without any capability frame - // else - - iResults[1] = 0x10; - iResults[2] = 0xff; - - // this is a nonexistent response - // the effect of this is to force a retransmission of the TSI and DCS - // with (hopefully) a subsequent retrain in an attempt to resync - } - else - successiveErrors = 0; - - - - if (iResults[2] != 0xff) - { - - iModem->iOurMessage.Format (_L8 ("Response received")); - iModem->ProgressUpdateL (); - - // the third byte in the frame is the FCF (fax control field) - - switch ((TUint8) iResults[2]) - { - case 0xff: // this is our dummy octet to force a restart - break; - - case 0x40: // this marks the receiver ID - iModem->iOurMessage.Format (_L8 ("CSI identity Frame")); - iModem->ProgressUpdateL (); - iModem->iProgress.iAnswerback.Zero (); - for (i = 22; i > 2; i--) - iModem->iProgress.iAnswerback.Append (iResults[i]); - iModem->iOurMessage.Format (_L8 ("Remote fax ID is %S"), &iModem->iProgress.iAnswerback); - iModem->ProgressUpdateL (); - break; // the capability frame should follows - - case 0x80: // this marks the receiver capability frame - iFcfXbit = 1; // we've received a DIS, so set the X bit - iModem->iOurMessage.Format (_L8 ("DIS capability Frame")); - iModem->ProgressUpdateL (); - AnalyseDISL (); // analyse the DIS and compose a DCS - if (iDisFrame.bit.b10 != 1) - return (KFaxErrRemoteCannotReceive); // if the other machine can't receive we exit - break; - - case 0x84: // this marks a good train and is the normal exit from this loop - iModem->iOurMessage.Format (_L8 ("CFR confirmation Frame")); - iModem->ProgressUpdateL (); - return (TxSetHighSpeedL ()); - - case 0x44: // this marks a failed train so we drop the speed - iModem->iOurMessage.Format (_L8 ("FTT failure to train Frame")); - iModem->ProgressUpdateL (); - if (++trainingAttempts & 1) // train down on failures 2 4 6 8 - break; - if (iActualFaxSpeed == 73) - iActualFaxSpeed = 96; - else - iActualFaxSpeed -= 24; - if (iActualFaxSpeed < (iFaxServerSessionSettings->iMinSpeed / 100)) - { - TxDCNL (); - return (KFaxBelowMinSpeed); - } - break; - - case 0xfa: // this means we were asked to disconnect - RxDCNL (); - return (KFaxErrRemoteDCN); - - case 0x20: // this marks a non-standard frame, which we ignore - iModem->iOurMessage.Format (_L8 ("NSF nonstandard facilities Frame")); - iModem->ProgressUpdateL (); - break; - - // the last case is where we see an unsupported frame - // if it is a final frame we ask for a repeat via CRP - - default: - if (SendCRPL () != KErrNone) - return (KFaxErrCRP); - } - - // if not a final frame we just issue AT+FRH=3 and continue - - if (!(iResults[1] & 0x10)) - { - iModem->ExportL (_L8 ("AT+FRH=3\r")); - continue; - } - // otherwise we send our proposals, starting with our own ID - - iModem->iOurMessage.Format (_L8 ("Final frame received")); - iModem->ProgressUpdateL (); - } - }// if (iResults[2] !=0) statement - if (iModem->iProgress.iPhase == ECallEstablishment) - { - iModem->iOurMessage.Format (_L8 ("sending TSI")); - iModem->ProgressUpdateL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLNXT); - iFrame.Append (KT30_TSI); - for (i = 20; i > iFaxServerSessionSettings->iFaxId.Length (); i--) - iFrame.Append (0x20); - for (i = iFaxServerSessionSettings->iFaxId.Length (); i;) - iFrame.Append (iFaxServerSessionSettings->iFaxId[--i]); - if (SendframeL (iFrame) != 1) - return (KFaxErrHDLC); - } - else - { - iModem->ExportL (_L8 ("AT+FTH=3\r")); - if (FramestatL () != 1) - return (KFaxErrHDLC); - } - - iModem->iProgress.iPhase = ESessionNegotiation; - - // before sending our DCS frame we ensure the speeds bits match what we want - - iDcsFrame.byte[1] &= 0xc3; - switch (iActualFaxSpeed) - { - case 48: - iDcsFrame.byte[1] |= 0x08; - break; /* 4800 */ - case 96: - iDcsFrame.byte[1] |= 0x04; - break; /* 9600 V.29 */ - case 97: - iDcsFrame.byte[1] |= 0x24; - break; /* 9600 V.17 */ - case 72: - iDcsFrame.byte[1] |= 0x0c; - break; /* 7200 V.29 */ - case 73: - iDcsFrame.byte[1] |= 0x2c; - break; /* 7200 V.17 */ - case 145: - iDcsFrame.byte[1] |= 0x20; - break; /* 14400 */ - case 121: - iDcsFrame.byte[1] |= 0x28; - break; /* 12000 */ - default: - iDcsFrame.byte[1] |= 0x00; /* 2400 */ - } - iModem->iOurMessage.Format (_L8 ("sending DCS ")); - iModem->ProgressUpdateL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (KT30_DCS); - //x = 3; - for (i = 0; i < iDcsBytes; i++) - iFrame.Append (iDcsFrame.byte[i]); - if (SendframeL (iFrame) != 1) - return (KFaxErrHDLC); - - // after sending our DCS frame we wait fot 75 ms before training - // - // Note on the 75 millisecond delays - // ================================= - // At this point we need to introduce a 75 ms delay (+-20%). - // this is usually done with the AT+FTS=8 command and the code - // would normally run as follows : - // - // iModem->ExportL (_L8 ("AT+FTS=8\r")); - // if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) - // return (KFaxErrStopAndWait); - // - // or, alternatively, we could use our own routines to delay - // for this amount of time using - // - // iModem->Silence (75000); - // - // However, the innards of the comms driver in EPOC32 introduces - // 2-tick delays on timed reads and writes - in other words, there - // was a 2-tick delay before the OK from our last frame was received - // and there will also be a 2-tick delay before the next command - // reaches the modem. Note that a 2-tick delay could be from 15 - // to 30 ms - we want a delay from 60ms to 90 ms (75 ms +- 20%) - - // which must be between 4 and 6 ticks. All the delays we use - // here are empirically arrived at via Faxlab testing rather - // than being worked out in advance. - - // NOTE : these delays are really applicable ONLY to Protea/ARM7100 - // the machine dependency is unavoidable under the - // circumstances. Protea ticks @ 64 Hz, which gives - // us 15.625 ms per tick. WINS ticks @ 10 Hz, - // which gives us 100 microseconds per tick - clearly a - // significant difference - the delta timers in the comms - // kernel are therefore also very different - - iModem->iOurMessage.Format (_L8 ("delaying for 75 ms")); - iModem->ProgressUpdateL (); - - // iModem->Silence ((iModem->iGranularity - 125) * 4); // 4 ticks pre-TCF - below iModem->iGranularity x 1 - - TInt delay=iModem->iCalls*37; //iCalls for 2ms *37 to get an approximatelly 75ms delay - TInt k=0; - - for (k=0;kclock(); - - i = (iActualFaxSpeed & 0xfe); - iModem->iOurMessage.Format (_L8 ("setting %d00"), i); - iModem->iProgress.iSpeed = (i * 100); - iModem->ProgressUpdateL (); - iResults.Copy (_L8 ("AT+FTM=")); - iResults.AppendNum (iActualFaxSpeed); - iResults.Append (_L8 ("\r")); - iModem->ExportL (iResults); - - // say how many bytes in the 1.5 second TCF - // prepare a null filled transmit buffer length and get length to maxnulls - // calculate minimum scan line times - // wait for the modem CONNECT - - trainbytes = (i * 150 / 8); - iModem->iOurMessage.Format (_L8 ("training sequence for %d bytes"), trainbytes); - - iModem->iTransmitBuffer.SetMax (); - iModem->iTransmitBuffer.FillZ (); - TInt maxnulls = iModem->iTransmitBuffer.Length (); - iModem->ProgressUpdateL (); - if (iMinscan == 0) - iMinlinelength = 0; - else - iMinlinelength = ((iModem->iProgress.iSpeed / (1000 / iMinscan)) / 8) + 1; - if ((iModem->GetMatchL (_L8 ("CONNECT"), 5)) == 0) - return (KFaxErrAtNegotiatedSpeed); - - // now we send our TCF with flow control - - iModem->Xonon (); - - iModem->iOurMessage.Format (_L8 ("Entering training loop")); - iModem->ProgressUpdateL (); - - while (trainbytes != 0) - { - if (maxnulls > trainbytes) - { - iModem->iTransmitBuffer.SetLength (trainbytes); - trainbytes = 0; - } - else - { - iModem->iTransmitBuffer.SetMax (); - trainbytes -= maxnulls; - } - iModem->CommitTransmitBufferL (); - } - - iModem->iTransmitBuffer.Append (Kdle); - iModem->iTransmitBuffer.Append (Ketx); - iModem->CommitTransmitBufferL (); - - - iModem->iOurMessage.Format (_L8 ("Train complete")); - iModem->ProgressUpdateL (); - - // now wait for the modem to return to command mode - - while (iModem->Rxstat () != 0) - { - ticks = CLK_TCK; - iModem->RxcharWaitL (ticks); - } - if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0) - return (KFaxErrTrainStop); - - iModem->Xonoff (); - // there's no frame to resend, so we prepare a CRP in case of - // any errors before looping for the response - - iOldFrame.Zero (); - iModem->ExportL (_L8 ("AT+FRH=3\r")); - } -} -/********************************************************************/ - -// this is a small function to set a class 1 fax modem to phase C - // transmission speed (found in iActualFaxSpeed) in preparation for - // sending data. This function is called before the first page - // and also between pages. Class 1 modems require that we delay for - // 75 ms before going to phase C transmission - see the note - // earlier on method of achieving a 75 ms delay here - -TInt CFaxClass1::TxSetHighSpeedL () -{ - TInt x, portSpeed; - iFrame.SetMax (); - iModem->iOurMessage.Format (_L8 ("delaying for 75 ms")); - iModem->ProgressUpdateL (); -// iModem->Silence ((iModem->iGranularity - 125) * 4); // 4 ticks pre-T4 - below iModem->iGranularity x 3 - - TInt delay=iModem->iCalls*37; //iCalls for 2ms *37 to get an approximatelly 75ms delay - TInt k=0; - - for (k=0;kclock(); - - switch (iActualFaxSpeed) - { - case 145: - x = 144; - portSpeed = 146; - break; - case 121: - x = 120; - portSpeed = 122; - break; - case 97: - x = 96; - portSpeed = 98; - break; - case 73: - x = 72; - portSpeed = 74; - break; - default: - x = portSpeed = iActualFaxSpeed; - } - iModem->iOurMessage.Format (_L8 ("setting %d00"), x); - iModem->iProgress.iSpeed = (x * 100); - iModem->ProgressUpdateL (); - iResults.Copy (_L8 ("AT+FTM=")); - iResults.AppendNum (portSpeed); - iResults.Append (_L8 ("\r")); - iModem->ExportL (iResults); - if (FramestatL () != 1) - return (KFaxErrAtNegotiatedSpeed); - return (TxStartPageL ()); -} -/********************************************************************/ - -// here's where we wait after sending a page and the postpage -// message to see what the receiver thought - there are five responses -// MCF RTP PIP = good page RTN PIN = bad page -// -// TxPostPage should return either with -// -// a) an error code and iPhase set to RFax::EPostPageStatus, in which case the send returns with the error -// b) KErrNone and iPhase set to RFax::EDataTransfer, in which case we send the next page -// c) KErrNone and iPhase set to RFax::EDisconnection, in which case the send returns with KErrNone -// - -TInt CFaxClass1::TxPostPageL () -{ - if (iModem->iProgress.iCompression == EModifiedRead) - { - iModem->iTransmitBuffer.Append (0x00); - iModem->iTransmitBuffer.Append (0x60); - iModem->iTransmitBuffer.Append (0x00); - iModem->iTransmitBuffer.Append (0x0C); - iModem->iTransmitBuffer.Append (0x80); - iModem->iTransmitBuffer.Append (0x01); - iModem->iTransmitBuffer.Append (0x30); - iModem->iTransmitBuffer.Append (0x00); - iModem->iTransmitBuffer.Append (0x06); - iModem->iTransmitBuffer.Append (0xC0); - } - else - { - for (TInt x = 3; x; x--) - { - iModem->iTransmitBuffer.Append (0x0); - iModem->iTransmitBuffer.Append (0x08); - iModem->iTransmitBuffer.Append (0x80); - } - } - iModem->iTransmitBuffer.Append (Kdle); - iModem->iTransmitBuffer.Append (Ketx); - iModem->CommitTransmitBufferL (); - - iModem->iOurMessage.Format (_L8 (" transmitted after %d lines"), iModem->iProgress.iLines); - iModem->iProgress.iPhase = EPostPageStatus; - iModem->ProgressUpdateL (); - while (iModem->Txstat () != 0) - ; - - // we've just ended phase C data, so we need to wait for the modem to respond with OK - - if (iModem->GetMatchL (_L8 ("OK"), (32 * 1024) / (iModem->iProgress.iSpeed / 10)) == 0) - return (KFaxErrCannotEndData); - - iModem->Xonoff (); - - iModem->iOurMessage.Format (_L8 ("delaying for 75 ms")); - iModem->ProgressUpdateL (); - - -/************************************* NOTE ******************************************************* -// see the note earlier on reason for the lack of an explicit 75 ms delay here - - -// iModem->Silence ((iModem->iGranularity - 125) * 4); 4 ticks post-T4 - below iModem->iGranularity x 1 -// The above line of code was removed because the Silence function calls User::After which is fairly inaccurate -// Faxlab revealed that we were actually waiting for 432 ms !!! instead of the recomended 75ms +- 20% -// The delay is now generated using the timing callibration loop -// This is more CPU intensive than the User::After call because essentially is a aoftware delay loop but -// will enhance the reliability of fax class 1 especially over GSM -*****************************************************************************************************************/ - TInt delay=iModem->iCalls*30; //iCalls for 2ms *37 to get an approximatelly 75ms delay - TInt k=0; - - for (k=0;kclock(); - - iOldFrame.Zero (); - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - - - if ((iFaxServerSessionSettings->iTxPages) == iModem->iProgress.iPage) - { - iModem->iOurMessage.Format (_L8 ("sending EOP")); - iModem->ProgressUpdateL (); - - iFrame.Append ((KT30_EOP)); - if (SendframeL (iFrame) == 0) - return (KFaxErrEOP); - - iModem->iOurMessage.Format (_L8 ("End of document transmitted")); - iModem->ProgressUpdateL (); - } - else - { - iModem->iOurMessage.Format (_L8 ("sending MPS")); - iModem->ProgressUpdateL (); - - iFrame.Append ((KT30_MPS)); - if (SendframeL (iFrame) == 0) - return (KFaxErrMPS); - - iModem->iOurMessage.Format (_L8 ("End of page %u transmitted"), iModem->iProgress.iPage); - iModem->ProgressUpdateL (); - } - - // now we await the post-page response from the receiver - // we loop here because we need a final frame - - for (;;) - { - iModem->ExportL (_L8 ("AT+FRH=3\r")); - if (GetframeL (iResults) == 0) - return (KFaxErrFrameFail); - iModem->iOurMessage.Format (_L8 ("Response received")); - iModem->ProgressUpdateL (); - - // the third byte in the frame is the FCF (fax control field) - // for those we recognize straight off, we say so - // for any others, we either loop immediately or after a CRP request - - switch ((TUint8) iResults[2]) - { - case 0x8c: - iModem->iOurMessage.Format (_L8 ("MCF")); - break; - case 0xcc: - iModem->iOurMessage.Format (_L8 ("RTP")); - break; - case 0xac: - iModem->iOurMessage.Format (_L8 ("PIP")); - break; - case 0x4c: - iModem->iOurMessage.Format (_L8 ("RTN")); - break; - case 0x2c: - iModem->iOurMessage.Format (_L8 ("PIN")); - break; - - // the last case is where we see an unsupported frame - // if it is a final frame we ask for a repeat via CRP - - default: - if (SendCRPL () != KErrNone) - return (KFaxErrCRP); - continue; - } - - // now back to look at the FCF some more - switch ((TUint8) iResults[2]) - { - case 0x8c: - case 0xcc: // for good pages we say confirmed - case 0xac: - iModem->iOurMessage.Append (_L8 (" message confirmation")); - iModem->ProgressUpdateL (); - break; - - case 0x4c: // for bad pages we say no good - case 0x2c: // if we haven't done so, resent last page - iModem->iOurMessage.Append (_L8 (" : page not confirmed")); - iModem->ProgressUpdateL (); - if (iRepeatPage == 0) - { - iRepeatPage++; - iModem->iProgress.iPage--; - return (TxPrePageL ()); - } - - default:; - } - - // we aren't going to resend the last page now - - iRepeatPage = 0; - - // if we've reached the end, we just quit - - if ((iFaxServerSessionSettings->iTxPages) == iModem->iProgress.iPage) - { - return (TxDCNL ()); - } - - // if we've received an MCF we carry on with phase C - - if (iResults[2] == KT30_MCF) // carry on with phase C only if MCF - - { - return (TxSetHighSpeedL ()); - } - - // we renegotiate if PIP or RTP, or PIN or RTN with no resend - - iModem->iOurMessage.Format (_L8 ("Renegotiating session parameters")); - iModem->ProgressUpdateL (); - return (TxPrePageL ()); - } -} -/********************************************************************/ - -// the analysis of the DIS frame and composition of the DCS frame - // has been moved here for readability - -inline void CFaxClass1::AnalyseDISL () -{ - TInt i; - - // we copy iResults to our iDisFrame and compose our reply in iDcsFrame - - for (i = 0; i < 5; i++) - iDisFrame.byte[i] = (TUint8) iResults[i + 3]; - - for (i = 0; i < 5; i++) - iDcsFrame.byte[i] = 0; - - // we always set T.4 - - iDcsFrame.bit.b10 = 1; - - // we check the speed capability next and reset our iActualFaxSpeed - - switch (iDisFrame.byte[1] & 0x3c) - { - case 0x08: - i = 48; - break; /* V.27 ter 4800 2400 */ - case 0x0c: - i = 96; - break; /* V.29 9600 7200 + V.27 */ - case 0x2c: - i = 145; - break; /* V.17 14400 + V.29 + V.27 */ - default: - i = 24; /* V.27 fallback 2400 only */ - } - if (i < (iActualFaxSpeed)) - iActualFaxSpeed = i; - - // we set our resolution to that of the fax we want to send - // but if the receiver can only understand normal resolution - // then we send all our faxes as normal and resign ourselves - // to stretching them to double length - - iDcsFrame.bit.b15 = iFaxServerSessionSettings->iTxResolution; - if (iDisFrame.bit.b15 == 0) - iDcsFrame.bit.b15 = 0; - iModem->iProgress.iResolution = TFaxResolution (iDcsFrame.bit.b15); - - // we set our compression to that of the fax we want to send - // unless the receiver can only understand 1D compression - in - // which case the sender should be able to compensate from the - // progress settings - - iDcsFrame.bit.b16 = iFaxServerSessionSettings->iTxCompression; - if (iDisFrame.bit.b16 == 0) - { - iDcsFrame.bit.b16 = 0; - } - - if ((iDisFrame.bit.b16==1) && ((iFaxServerSessionSettings->iTxCompression==EModifiedRead))) - { - iDcsFrame.bit.b16 = 1; - } - - iModem->iProgress.iCompression = TFaxCompression (iDcsFrame.bit.b16); - - if (iModem->iProgress.iCompression==0) - { - iModem->iOurMessage.Format (_L8("DCS frame set to 1D")); - iModem->ProgressUpdateL(); - } - else - { - iModem->iOurMessage.Format (_L8("DCS frame set to 2D")); - iModem->ProgressUpdateL(); - } - - - // we set the minumum scan line time to that of the receiver - - iDcsFrame.byte[2] &= 0x8f; - switch (iDisFrame.byte[2] & 0x70) - { - case 0x70: - iMinscan = 0; - iDcsFrame.byte[2] |= 0x70; - break; /* b21=1 b22=1 b23=1 */ - case 0x50: - if (iDcsFrame.bit.b15 == 0) - { - iMinscan = 40; - iDcsFrame.byte[2] |= 0x40; - } - else - { - iMinscan = 20; - } - break; /* b21=1 b22=0 b23=1 - for fine res, /by 2 */ - case 0x30: - if (iDcsFrame.bit.b15 == 0) - { - iMinscan = 20; - } - else - { - iMinscan = 10; - iDcsFrame.byte[2] |= 0x20; - } - break; /* b21=1 b22=1 b23=0 - for fine res, /by 2 */ - case 0x60: - if (iDcsFrame.bit.b15 == 0) - { - iMinscan = 10; - iDcsFrame.byte[2] |= 0x20; - } - else - { - iMinscan = 5; - iDcsFrame.byte[2] |= 0x10; - } - break; /* b21=0 b22=1 b23=1 - for fine res, /by 2 */ - case 0x10: - iMinscan = 5; - iDcsFrame.byte[2] |= 0x10; - break; /* b21=1 b22=0 b23=0 */ - case 0x20: - iMinscan = 10; - iDcsFrame.byte[2] |= 0x20; - break; /* b21=0 b22=1 b23=0 */ - case 0x40: - iMinscan = 40; - iDcsFrame.byte[2] |= 0x40; - break; /* b21=0 b22=0 b23=1 */ - default: - iMinscan = 20; /* b21=0 b22=0 b23=0 */ - } - - // lastly, we always match our page length to the receiver page length - - iDcsFrame.bit.b19 = iDisFrame.bit.b19; - iDcsFrame.bit.b20 = iDisFrame.bit.b20; -} -/********************************************************************/ - -// this is where we wait for modem responses - - // this function can be called either with a timeout in seconds - // or with nothing, in which case we use a default as follows : - - // when we wait for the frame data we use a 6 second timeout - // as specified in T.30 as timer T2 if we are waiting for - // a command or a 3 second timer as specified in timer T4 - // if we are waiting for a response, with the presence of - // a resendable frame in iOldFrame being the test - - // notice that importL() takes a timeout specified in seconds - - // normally OK and CONNECT are good with ERROR or NO CARRIER being bad - // we save the actual result for inspection as ERROR codes after - // frame reception with AT+FRH needs special handling via GETFRAMESTAT - -TInt CFaxClass1::FramestatL () -{ - TInt ticks; - if (iOldFrame.Length () == 0) - ticks = KT30_T2; - else - ticks = KT30_T4; - return (FramestatL (ticks)); -} -/********************************************************************/ - -TInt CFaxClass1::FramestatL (TInt aTicks) -{ - for (;;) - { - iModemString.SetMax (); - if (iModem->ImportL (iModemString, aTicks) == 0) - return (-1);; - - iModem->iOurMessage.Format (_L8 ("%S"), &iModemString); - iModem->ProgressUpdateL (); - - if ((iModemString.FindF (_L8 ("OK"))) >= 0) - return (1); - if ((iModemString.FindF (_L8 ("CONNECT"))) >= 0) - return (1); - if ((iModemString.FindF (_L8 ("ERROR"))) >= 0) - return (0); - if ((iModemString.FindF (_L8 ("NO CARRIER"))) >= 0) - return (0); - } -} -/********************************************************************/ - -// if we have an ERROR result on receiving a frame it means that - // the CRC was incorrect - the action is to wait until 200 ms of - // silence have elapsed before resending the last frame - we use - // the ReceiveSilenceL function for this - -TInt CFaxClass1::GetFramestatL () -{ - TInt code = FramestatL (); - if ((iModemString.FindF (_L8 ("ERROR"))) >= 0) - ReceiveSilenceL (); - return (code); -} -/********************************************************************/ - -// this is the HDLC frame reception handler after AT+FRH commands - -TInt CFaxClass1::GetframeL (TDes8 & aResult) -{ - TInt i, retries = 0, frameStatus = 1; - TInt ticks; - TUint8 thisChar, lastChar; - TBuf8 < 4 > iHexchar; - - iModem->iOurMessage.Format (_L8 ("Waiting for Frame")); - iModem->ProgressUpdateL (); - - // framestat is set to 1 for no error before entry to the loop - - for (;;) - { - - // we only try three times before giving up - - retries++; - if (retries > 3) - return (0); - - // if we timed out, cancel the frame before proceeding - - if (frameStatus < 0) - { - iModem->TxcharL (Kcan); - iModem->iOurMessage.Format (_L8 ("Frame timed out")); - iModem->ProgressUpdateL (); - GetFramestatL (); - } - - // on any error, we resend the last frame if possible before - // waiting for another go - - if (frameStatus != 1) - { - if (SendframeL (iOldFrame) == 0) - { - iModem->iOurMessage.Format (_L8 ("Cannot resend Frame")); - iModem->ProgressUpdateL (); - return (0); - } - iModem->iOurMessage.Format (_L8 ("Frame has been resent")); - iModem->ProgressUpdateL (); - iModem->ExportL (_L8 ("AT+FRH=3\r")); - } - - // if we've just answered the phone, we don't wait for a result - // otherwise we must have an OK or CONNECT before proceeding - - if ((aResult.Compare (_L8 ("CALL JUST ANSWERED"))) == 0) - { - frameStatus = 1; - } - else - { - frameStatus = GetFramestatL (); - } - - aResult.FillZ (); - aResult.SetMax (); - - // if we got NO CARRIER or ERROR then we have to try again - - if (frameStatus != 1) - continue; - - // when we wait for the frame data we use a 6 second timeout - // as specified in T.30 as timer T2 if we are waiting for - // a command or a 3 second timer as specified in timer T4 - // if we are waiting for a response, with the presence of - // a resendable frame in iOldFrame being the test - - // note that RxcharWaitL () takes a timeout in microseconds - - if (iOldFrame.Length () == 0) - ticks = CLK_TCK * KT30_T2; - else - ticks = CLK_TCK * KT30_T4; - - // we expect data with dle shielding, ending with dle etx, - // and with a hex dump for our session log - - // there is a 3 second maximum length to a frame but - // the modem will detect bad HDLC frames for us and - // flag with ERROR - - for (i = 0, lastChar = 0; i < 64;) - { - if ((iModem->RxcharWaitL (ticks)) == 0) - { - frameStatus = (-1); - break; - } - thisChar = iModem->iReadone[0]; - if (lastChar == Kdle) - { - if (thisChar == Ketx) - break; - lastChar = 0; - if (thisChar != Kdle) - continue; - } - else if (thisChar == Kdle) - { - lastChar = Kdle; - continue; - } - aResult[i++] = thisChar; - - iHexchar.Format (_L8 ("%x "), thisChar); - if ((iModem->iOurMessage.Length () + iHexchar.Length ()) + 18 < iModem->iOurMessage.MaxLength ()) - iModem->iOurMessage.Append (iHexchar); - } - - iModem->ProgressUpdateL (); - - // if we timed out during the wait, then go round again and handle it - - if (frameStatus != 1) - continue; - - // otherwise we wait for the result code following the dle etx - // and handle any errors from that - - frameStatus = GetFramestatL (); - if (frameStatus != 1) - continue; - - // the third byte in the frame is the FCF (fax control field) - // we don't care whether we originated or answered the call - // so we always knock off the T.30 X bit (LSB) - - aResult[2] &= 0xfe; - - // if we have been asked for a frame repeat we do that in here - - if (aResult[2] == 0x1a) - { - iModem->iOurMessage.Format (_L8 ("CRP command repeat Frame")); - iModem->ProgressUpdateL (); - ReceiveSilenceL (); - frameStatus = 0; // treat as a timeout and resend - continue; - } - - // otherwise we can now return with success - - return (1); - } -} -/********************************************************************/ - -// this is the send HDLC frame handler following AT+FTH commands - -TInt CFaxClass1::SendframeL (TDes8 & newframe) -{ - TUint8 i; - TInt frameSize; - TBuf8 < 4 > iHexchar; - - // we take a copy of the frame we've been passed in case we want - // to resend for error recovery during GetFrame - it's the copy - // we work with - - if (&newframe != &iOldFrame) - iOldFrame.Copy (newframe); - frameSize = iOldFrame.Length (); - if (frameSize < 2) - return (0); - - // all frames must be at least three characters - // note that calling SendframeL with an empty frame disables - // resends - iOldFrame.Zero() is rather quicker though - - // we don't need to tell the modem that we're going to send a frame - // if we're sending DCS or CSI or DIS/DTC for the first time after a CONNECT response - // (not a resend) - in all other cases we need to send AT+FTH - - iOldFrame[1] |= iFcfXbit; // combine the FCF with the X bit - i = iOldFrame[1]; - - if (!((&newframe != &iOldFrame) && (i == (KT30_DCS|iFcfXbit)) || (i == KT30_CSI) || (i == (KT30_DIS|iFcfXbit)))) - { - iModem->ExportL (_L8 ("AT+FTH=3\r")); - if (FramestatL () != 1) - return (0); - } - - // we have a short delay before sending data here after any modem response - - iModem->ExportL (_L8 ("")); - - // we now send the frame, starting with the fixed address followed - // by the data we have been passed. We use dle shielding and end - // with dle etx and a hex dump before returning with the modem - // response code - - iModem->TxcharL (KT30_ADDR); - iModem->iOurMessage.Format (_L8 ("%x "), KT30_ADDR); - for (i = 0; i < frameSize; i++) - { - iModem->TxcharL (iOldFrame[i]); - iHexchar.Format (_L8 ("%x "), iOldFrame[i]); - if ((iModem->iOurMessage.Length () + iHexchar.Length ()) + 18 < iModem->iOurMessage.MaxLength ()) - iModem->iOurMessage.Append (iHexchar); - if (iOldFrame[i] == Kdle) - iModem->TxcharL (Kdle); - } - iModem->TxcharL (Kdle); - iModem->TxcharL (Ketx); - iModem->ProgressUpdateL (); - return (FramestatL ()); -} -/********************************************************************/ - -// this is short routine to request a resend of a frame - -TInt CFaxClass1::SendCRPL () -{ - iModem->iOurMessage.Format (_L8 ("Inappropriate frame %x"), (TUint8) iResults[2]); - iModem->ProgressUpdateL (); - if (iResults[1] & 0x10) - { - iModem->iOurMessage.Format (_L8 ("sending CRP")); - iModem->ProgressUpdateL (); - ReceiveSilenceL (); - iFrame.Zero (); - iFrame.Append (KT30_CTLLST); - iFrame.Append (KT30_CRP); - if (SendframeL (iFrame) == 0) - return (KFaxErrCRP); - iResults[1] = 0x0; - } - return (KErrNone); -} -/********************************************************************/ - -// this utility waits for 200 ms of silence before proceeding. We allow -// a three second timeout here in case we are waiting for a train to -// finish. we used the modem AT+FRS command - if it fails we'll have -// waited for three seconds in any case, so why bother with an error ? - -// this code is used mostly for error recovery purposes but note that -// not all modems support the +FRS command properly for example the -// Megahertz PCMCIA sportster - -void CFaxClass1::ReceiveSilenceL () -{ - iModem->ExportL (_L8 ("AT+FRS=20\r")); - if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) - { - iModem->iOurMessage.Format (_L8 ("Timeout waiting for silence")); - iModem->ProgressUpdateL (); - iModem->TxcharL (Kcan); - if (iModem->GetMatchL (_L8 ("OK"), 1) == 0) - iModem->TxcharL (Kreturn); - } -} -/********************************************************************/ -