Changelog since HylaFAX 4.3.3
+* Simplify Class1SwitchingCmd code and prevent duplication of the
+ command in session (12 Mar 2007)
* Replace Class1TrainingRecovery with Class1SwitchingCmd
* Fix error of sending a block twice, empty the 2nd time (12 Mar 2007)
* Don't trigger hasV17Trouble for pages other than the first (12 Mar 2007)
fxAssert(ecmStuffedBlock != NULL, "ECM procedure error (stuffed block).");
gotCTRL = false;
repeatPhaseB = false;
+ silenceHeard = false;
}
Class1Modem::~Class1Modem()
free(ecmStuffedBlock);
}
+bool
+Class1Modem::atCmd(const fxStr& cmd, ATResponse r, long ms)
+{
+ silenceHeard = false;
+ return (ClassModem::atCmd(cmd, r, ms));
+}
+
/*
* Check if the modem is a Class 1 modem and,
* if so, configure it for use.
return decodeTSI(ascii, binary);
}
+bool
+Class1Modem::switchingPause(fxStr& emsg)
+{
+ if (!silenceHeard && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
+ emsg = "Failure to receive silence.";
+ protoTrace(emsg);
+ if (wasTimeout()) abortReceive();
+ return (false);
+ }
+ /*
+ * We necessarily use class1SwitchingCmd rather frequently...
+ * sometimes this is programmed to be immediately before our signalling,
+ * and sometimes this is programmed to be immediately after the remote
+ * signalling. That doesn't therefore give us very good control on
+ * ensuring that class1SwitchingCmd is not issued in duplicate in some
+ * kinds of program flow.
+ *
+ * Ideally we'd be able to standardize on issuing class1SwitchingCmd
+ * only in one case or another (but not both), but that's not particularly
+ * an easy ideal to realize given the number of exceptions to that rule
+ * that would neccesarily be required.
+ *
+ * So for now we just set this flag here, and we unset it in atCmd, and
+ * if the flag is set when we come back here, then we can avoid duplication.
+ */
+ silenceHeard = true;
+ return (true);
+}
+
/*
* Pass data to modem, filtering DLE's and
* optionally including the end-of-data
abortReceive();
return (false);
}
+ fxStr emsg;
do {
if (crpcnt) {
traceFCF(dir == FCF_SNDR ? "SEND send" : "RECV send", FCF_CRP);
frame.reset();
gotframe = recvRawFrame(frame);
} while (!gotframe && docrp && crpcnt++ < 3 && !wasTimeout() &&
- atCmd(conf.class1SwitchingCmd, AT_OK) && transmitFrame(dir|FCF_CRP));
+ switchingPause(emsg) && transmitFrame(dir|FCF_CRP));
return (gotframe);
} else if (lastResponse == AT_ERROR) gotEOT = true; // on hook
stopTimeout("waiting for v.21 carrier");
bool recvdDCN; // received DCN frame
bool messageReceived; // expect/don't expect message carrier
bool repeatPhaseB; // return to beginning of Phase B before next page
+ bool silenceHeard; // indicates whether the last command was +FRS
u_int lastPPM; // last PPM during receive
bool sendCFR; // received TCF was not confirmed
u_short ecmBitPos; // bit position to populate on ecmByte
};
virtual ATResponse atResponse(char* buf, long ms = 30*1000);
virtual bool waitFor(ATResponse wanted, long ms = 30*1000);
+ virtual bool atCmd(const fxStr& cmd, ATResponse = AT_OK, long ms = 30*1000);
+ bool switchingPause(fxStr& emsg);
void encodeTSI(fxStr& binary, const fxStr& ascii);
void encodeNSF(fxStr& binary, const fxStr& ascii);
const fxStr& decodeTSI(fxStr& ascii, const HDLCFrame& binary);
* The best way to do that is to make sure that there is
* silence on the line, and we do that with Class1SwitchingCmd.
*/
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!switchingPause(emsg)) {
return (false);
}
}
* Send training response; we follow the spec
* by delaying 75ms before switching carriers.
*/
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) return (false);
+ fxStr emsg;
+ if (!switchingPause(emsg)) return (false);
if (ok) {
/*
* Send CFR later so that we can cancel
* that we just received, write it to disk.
*/
if (messageReceived) {
- if (!useV34 && emsg == "" && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- }
+ if (!useV34 && emsg == "") (void) switchingPause(emsg);
/*
* On servers where disk access may be bottlenecked or stressed,
* the TIFFWriteDirectory call can lag. The strategy, then, is
} else if (params.ec != EC_DISABLE && rrframe.getFCF() != FCF_RR) {
protoTrace("Ignoring invalid response to RNR.");
}
- if (!useV34) atCmd(conf.class1SwitchingCmd, AT_OK);
+ if (!useV34) (void) switchingPause(emsg);
}
} while (!gotEOT && !recvdDCN && !gotresponse && ++rnrcnt < 2 && Sys::now()-rrstart < 60);
if (!gotresponse) emsg = "No response to RNR repeated 3 times.";
* to implement than using +FRH and more reliable than
* using +FTS
*/
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!switchingPause(emsg)) {
return (false);
}
u_int rtnfcf = conf.badPageHandling == FaxModem::BADPAGE_DCN ? FCF_DCN : FCF_RTN;
case FCF_PRI_EOM:
case FCF_PRI_MPS:
case FCF_PRI_EOP:
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!useV34 && !switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
if (signalRcvd) lastblock = true;
sendERR = true;
} else {
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!useV34 && !switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
dcs = rtncframe[3] | (rtncframe[4]<<8);
curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
// requisite pause before sending response (CTR)
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
}
case FCF_CRP:
// command repeat... just repeat whatever we last sent
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!useV34 && !switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
}
// requisite pause before sending response (PPR/MCF)
- if (!blockgood && !useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!blockgood && !useV34 && !switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
lastResponse = AT_NOTHING;
while (rtnframe.getFCF() == FCF_PPS && lastResponse != AT_NOCARRIER && recvFrameCount < 5 && gotrtnframe) {
// we sent PPR, but got PPS again...
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!useV34 && !switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
dcs = rtnframe[3] | (rtnframe[4]<<8);
curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
// requisite pause before sending response (CTR)
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!switchingPause(emsg)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
bool gotresponse = true;
u_short rnrcnt = 0;
do {
- if (!useV34) atCmd(conf.class1SwitchingCmd, AT_OK);
+ if (!useV34) (void) switchingPause(emsg);
if (emsg != "") break;
(void) transmitFrame(FCF_RNR|FCF_RCVR);
traceFCF("RECV send", FCF_RNR);
if (!lastblock) {
// confirm block received as good
- if (!useV34) atCmd(conf.class1SwitchingCmd, AT_OK);
+ if (!useV34) (void) switchingPause(emsg);
(void) transmitFrame((sendERR ? FCF_ERR : FCF_MCF)|FCF_RCVR);
traceFCF("RECV send", sendERR ? FCF_ERR : FCF_MCF);
}
* Complete a receive session.
*/
bool
-Class1Modem::recvEnd(fxStr&)
+Class1Modem::recvEnd(fxStr& emsg)
{
if (!recvdDCN && !gotEOT) {
u_int t1 = howmany(conf.t1Timer, 1000); // T1 timer in seconds
case FCF_PPS:
case FCF_EOP:
case FCF_CRP:
- if (!useV34) atCmd(conf.class1SwitchingCmd, AT_OK);
+ if (!useV34) (void) switchingPause(emsg);
(void) transmitFrame(FCF_MCF|FCF_RCVR);
traceFCF("RECV send", FCF_MCF);
break;
recvdDCN = true;
break;
default:
- if (!useV34) atCmd(conf.class1SwitchingCmd, AT_OK);
+ if (!useV34) (void) switchingPause(emsg);
transmitFrame(FCF_DCN|FCF_RCVR);
recvdDCN = true;
break;
* "before sending any signals using V.27 ter/V.29/V.33/V.17
* modulation system"
*/
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- protoTrace("Failure to receive silence.");
+ if (!switchingPause(emsg)) {
return (send_failed);
}
}
pph.remove(0,2+5+1);// discard page-chop+handling info
else
pph.remove(0,3); // discard page-handling info
- if (params.ec == EC_DISABLE) atCmd(conf.class1SwitchingCmd, AT_OK);
+ if (params.ec == EC_DISABLE) (void) switchingPause(emsg);
ntrys = 0;
if (morePages) { // meaning, more pages in this file, but there may be other files
if (!TIFFReadDirectory(tif)) {
protoTrace(emsg);
return (send_failed);
case FCF_CRP:
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (send_retry);
}
break;
bool frameSent;
if (useV34) frameSent = true;
else {
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- protoTrace("Failure to receive silence.");
+ fxStr emsg;
+ if (!switchingPause(emsg)) {
return (false);
}
frameSent = (atCmd(thCmd, AT_NOTHING) && atResponse(rbuf, 7550) == AT_CONNECT);
* The best way to do that is to make sure that there is
* silence on the line, and we do that with Class1SwitchingCmd.
*/
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
+ if (!switchingPause(emsg)) {
return (false);
}
}
setXONXOFF(FLOW_XONXOFF, FLOW_NONE, ACT_FLUSH);
if (!useV34) {
// T.30 5.3.2.4 (03/93) gives this to be a 75ms minimum
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- protoTrace("Failure to receive silence.");
+ if (!switchingPause(emsg)) {
return (false);
}
/*
gotppr = false;
crpcnt++;
ppscnt = 0;
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
}
}
} while (!gotppr && (++ppscnt < 3) && (crpcnt < 3) && !(useV34 && gotEOT));
if (gotppr) {
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
if (pprframe.getFCF() == FCF_RNR) {
gotmsg = false;
crpcnt++;
rrcnt = 0;
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
}
gotppr = true;
break;
case FCF_RNR:
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
break;
gotctr = false;
crpcnt++;
ctccnt = 0;
- if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!switchingPause(emsg)) {
return (false);
}
}
goterr = false;
crpcnt++;
eorcnt = 0;
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
}
gotmsg = false;
crpcnt++;
rrcnt = 0;
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
}
goterr = true;
break;
case FCF_RNR:
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
- emsg = "Failure to receive silence.";
- protoTrace(emsg);
+ if (!useV34 && !switchingPause(emsg)) {
return (false);
}
break;