]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
Class 2.0: Implement Phase C debugging and +FDB=1 support for Multitech
authorAidan Van Dyk <aidan@ifax.com>
Wed, 26 Sep 2007 12:54:46 +0000 (12:54 +0000)
committerAidan Van Dyk <aidan@ifax.com>
Wed, 26 Sep 2007 12:54:46 +0000 (12:54 +0000)
From Lee:
| commit cec8c45c447d6b25b3d5c2320e39c69e152958e1
| Author: Lee Howard <faxguy@howardsilvan.com>
| Date:   Fri Jul 6 01:33:43 2007 +0000
|
|   This implements support for +FDB=1 Phase C receive debugging for MultiTechs.
|
|   There is more to come... send support needs to be done, for example.

and
| commit ab579cecee024ef0ca50e6bc47ed789d9b177848
| Author: Lee Howard <faxguy@howardsilvan.com>
| Date:   Wed Jul 11 00:27:25 2007 +0000
|
|   This is the send-portion of the earlier +FDB=1 debugging support work.
|
|   This implements ModemDoPhaseCDebug config option which will make HylaFAX
|   query the modem during Phase C transmit to check for modem responses.  This
|   is done at that time so that they can be displayed at roughly the correct
|   time in the log, rather than being buffered up for the end.
|
|   This is left off by default, although in theory it should be harmless enabled
|   all of the time.  There is some potential risk if something goes wrong... like,
|   say the modem shows NO CARRIER before the DTE signals <DLE><ETX> (i.e. I can
|   envision a modem like iaxmodem doing this if there is a premature hangup).  And,
|   in that case the NO CARRIER response will get taken from the buffer and simply
|   logged rather than interpreted... which means that we have some work to do
|   in order to make this better... but this should be good for now.

and
| commit bedb9087bb28ce6c58cd77b216b6e89c6b7910ca
| Author: Lee Howard <faxguy@howardsilvan.com>
| Date:   Fri Jul 20 01:44:41 2007 +0000
|
|   Final mod to support MultiTech +FDB DCE debugging.

faxd/Class1.c++
faxd/Class20.c++
faxd/Class2Recv.c++
faxd/Class2Send.c++
faxd/ClassModem.c++
faxd/ClassModem.h
faxd/ModemConfig.c++
faxd/ModemConfig.h
faxd/ModemServer.c++
faxd/ModemServer.h
man/hylafax-config.4f

index 2ac8282bc3d52a6cc2b774eb77745bbacff1ee66..868675235c381771be887157f4863da763ad4b17 100644 (file)
@@ -530,7 +530,7 @@ bool
 Class1Modem::sendClass1Data(const u_char* data, u_int cc,
     const u_char* bitrev, bool eod, long ms)
 {
-    bool ok = putModemDLEData(data, cc, bitrev, ms);
+    bool ok = putModemDLEData(data, cc, bitrev, ms, conf.doPhaseCDebug);
     if (eod || abortRequested()) {
        u_char buf[2];
        buf[0] = DLE;
index 8d9df28974fc4e2bf789b279401512cae481bd02..e4c7d0e03d25dee30f9359e662bcdb4df129d362 100644 (file)
@@ -273,6 +273,27 @@ Class20Modem::nextByte()
     }
     if (b == DLE) {
        switch (b = getModemDataChar()) {
+           case 0x01:                  // +FDB=1 support
+               {
+                   fxStr dbdata;
+                   bool notdone = true;
+                   do {
+                       b = getModemDataChar();
+                       if (b == DLE) {
+                           b = getModemDataChar();
+                           if (b == 0x04) {
+                               notdone = false;
+                               protoTrace("DCE DEBUG: %s", (const char*) dbdata);
+                           } else {
+                               dbdata.append(DLE);
+                           }
+                       }
+                       if (b != '\0' && b != '\r' && b != '\n')
+                           dbdata.append(b);
+                   } while (notdone);
+                   b = nextByte();
+               }
+           break;
        case EOF: raiseEOF();
        case ETX: raiseRTC();           // RTC
        case DLE: break;                // <DLE><DLE> -> <DLE>
index 9762480fe3448ec570004e853cf18cf5977db82f..c80a75a989ac3b12002c25819adb4f3b343dc972 100644 (file)
@@ -281,8 +281,9 @@ Class2Modem::abortPageRecv()
 bool
 Class2Modem::recvPageData(TIFF* tif, Status& eresult)
 {
+    // be careful about flushing here -- otherwise we can lose +FDB messages
     if (flowControl == FLOW_XONXOFF)
-       (void) setXONXOFF(FLOW_NONE, FLOW_XONXOFF, ACT_FLUSH);
+       (void) setXONXOFF(FLOW_NONE, FLOW_XONXOFF, ACT_DRAIN);
     protoTrace("RECV: send trigger 0%o", recvDataTrigger&0377);
     (void) putModem(&recvDataTrigger, 1);      // initiate data transfer
 
index 4b21e8f1ca171321d5aa642b881611133dc91cf3..fe8b1f704028125f07b730ee75f7db102b6100a1 100644 (file)
@@ -503,7 +503,7 @@ Class2Modem::sendPageData(TIFF* tif, u_int pageChop)
        }
 
        beginTimedTransfer();
-       rc = putModemDLEData(dp, (u_int) totdata, bitrev, getDataTimeout());
+       rc = putModemDLEData(dp, (u_int) totdata, bitrev, getDataTimeout(), conf.doPhaseCDebug);
        endTimedTransfer();
        protoTrace("SENT %u bytes of data", totdata);
     }
index 7c6f3f8c59c465630d0d57555d5c277759ce2b1a..b68874aa5c49200f6af8cc30aa439f0a88975094 100644 (file)
@@ -155,6 +155,7 @@ ClassModem::isNoise(const char* s)
        "RINGING",      // ZyXEL
        "+FHR:",        // Intel 144e
        "+F34:",        // Class 1.0 V.34 report
+       "+FDB:",        // DCE debugging
        "MESSAGE-WAITING",      // voice-mail waiting, Conexant
     };
 #define        NNOISE  (sizeof (noiseMsgs) / sizeof (noiseMsgs[0]))
@@ -461,14 +462,14 @@ ClassModem::getModemLine(char buf[], u_int bufSize, long ms)
     return (n);
 }
 int ClassModem::getModemBit(long ms)  { return server.getModemBit(ms); }
-int ClassModem::getModemChar(long ms) { return server.getModemChar(ms); }
+int ClassModem::getModemChar(long ms, bool doquery) { return server.getModemChar(ms, doquery); }
 int ClassModem::getModemDataChar()    { return server.getModemChar(dataTimeout); }
 int ClassModem::getLastByte()         { return server.getLastByte(); }
 bool ClassModem::didBlockEnd()        { return server.didBlockEnd(); }
 void ClassModem::resetBlock()         { server.resetBlock(); }
 
 bool
-ClassModem::putModemDLEData(const u_char* data, u_int cc, const u_char* bitrev, long ms)
+ClassModem::putModemDLEData(const u_char* data, u_int cc, const u_char* bitrev, long ms, bool doquery)
 {
     u_char dlebuf[2*1024];
     while (cc > 0) {
@@ -488,6 +489,32 @@ ClassModem::putModemDLEData(const u_char* data, u_int cc, const u_char* bitrev,
            return (false);
        data += n;
        cc -= n;
+       /*
+        * Fax is half-duplex.  Thus, we shouldn't typically need to read
+        * data from the modem while we are transmitting.  However, Phase C
+        * can be long, and things can go wrong, and it will be nice to
+        * see the timing of any messages that will come from the modem,
+        * instead of letting them buffer.  Furthermore, advanced Class 2
+        * debugging will send us messages during Phase C.  So in those
+        * cases when it will be useful, we query the modem during transmits.
+        *
+        * In the cases where things do go wrong, we'll need to begin
+        * building-in the intelligence to handle that here.  But we have
+        * to wait and see what turns up in order to do that.
+        */
+       if (doquery) {
+           int c;
+           fxStr dbdata;
+           do {
+               c = getModemChar(0, true);
+               if (c != EOF && c != '\0' && c != '\r' && c != '\n')
+                   dbdata.append(c);
+               else if (dbdata.length()) {
+                   protoTrace("DCE DEBUG: %s", (const char*) dbdata);
+                   dbdata = "";
+               }
+           } while (c != EOF);
+       }
     }
     return (true);
 }
index 7a5e8b87031e1a22bef046d1e5eab6b96d050471..361953869b823bf4499b04314dc6ec9adc94246a 100644 (file)
@@ -267,10 +267,10 @@ public:
     bool       putModem(void* data, int n, long ms = 0);
     bool       putModemData(void* data, int n);
     bool       putModemDLEData(const u_char* data, u_int,
-                   const u_char* brev, long ms);
+                   const u_char* brev, long ms, bool doquery = false);
     bool       putModemLine(const char* cp, long ms = 0);
     int                getModemBit(long ms = 0);
-    int                getModemChar(long ms = 0);
+    int                getModemChar(long ms = 0, bool doquery = false);
     int                getModemDataChar();
     int                getLastByte();
     bool       didBlockEnd();
index d0b6b63650be064dc4f50b9e1f620905cc3c292f..3634f783a0b9335f14a1d05489bc251ef34664cc 100644 (file)
@@ -285,6 +285,7 @@ ModemConfig::setupConfig()
     badPageHandling    = FaxModem::BADPAGE_RTNSAVE; // send RTN but save the page
     saveUnconfirmedPages = true;               // keep unconfirmed pages
     softRTFCC          = true;                 // real-time fax comp. conv. (software)
+    doPhaseCDebug      = false;                // query modem for responses in Phase C transmit
     noAnswerVoice      = false;                // answer voice calls
 
     idConfig.resize(0);
@@ -797,6 +798,8 @@ ModemConfig::setConfigItem(const char* tag, const char* value)
        noAnswerVoice = getBoolean(value);
     else if (streq(tag, "modemsoftrtfcc"))
        softRTFCC = getBoolean(value);
+    else if (streq(tag, "modemdophasecdebug"))
+       doPhaseCDebug = getBoolean(value);
     else if (streq(tag, "saveunconfirmedpages"))
        saveUnconfirmedPages = getBoolean(value);
     else if (streq(tag, "distinctiverings"))
index 63ff0e11e76b22e0354720593cc49fe2329d6727..17284ff55394e02cd5f34c608652b79e72aed7b6 100644 (file)
@@ -236,6 +236,7 @@ public:
     fxStr      tagLineFontFile;        // font file for imaging tag lines
     u_int      recvDataFormat;         // received facsimile data format
     bool       useJobTagLine;          // Use Job tagline or use conf taglineformat
+    bool       doPhaseCDebug;          // Query modem during Phase C for debugging info.
 
     RTNHandling rtnHandling;            // RTN signal handling method
     BadPageHandling badPageHandling;   // bad page (received) handling method
index 73f8b16a7bf773c3122635d6910ca11620c60a9b..e27213e8e106b8e5503ec4f608c6c7b5ff18dee0 100644 (file)
@@ -1430,20 +1430,32 @@ ModemServer::getModemLine(char rbuf[], u_int bufSize, long ms)
 }
 
 int
-ModemServer::getModemChar(long ms)
+ModemServer::getModemChar(long ms, bool isquery)
 {
     if (rcvNext >= rcvCC) {
        int n = 0;
+       if (isquery) {
+           if (fcntl(modemFd, F_SETFL, fcntl(modemFd, F_GETFL, 0) | O_NONBLOCK)) {
+               traceStatus(FAXTRACE_MODEMCOM, "Can not set O_NONBLOCK: errno %u", errno);
+               return (EOF);
+           }
+           n = 5;              // only read once
+       }
        if (ms) startTimeout(ms);
        do
            rcvCC = Sys::read(modemFd, (char*) rcvBuf, sizeof (rcvBuf));
        while (n++ < 5 && rcvCC == 0);
        if (ms) stopTimeout("reading from modem");
+       if (isquery) {
+           if (fcntl(modemFd, F_SETFL, fcntl(modemFd, F_GETFL, 0) &~ O_NONBLOCK))
+               traceStatus(FAXTRACE_MODEMCOM, "Can not reset O_NONBLOCK: errno %u", errno);
+       }
        if (rcvCC <= 0) {
            if (rcvCC < 0) {
                if (errno != EINTR)
-                   traceStatus(FAXTRACE_MODEMCOM,
-                       "MODEM READ ERROR: errno %u", errno);
+                   if (!isquery || errno != EAGAIN)
+                       traceStatus(FAXTRACE_MODEMCOM,
+                           "MODEM READ ERROR: errno %u", errno);
            }
            return (EOF);
        } else
index 8223f89a7ac3020904a61891c99ffe02b1d98b08..34d7a86113b0f08686fa3dc37280920323827f69 100644 (file)
@@ -139,7 +139,7 @@ protected:
     void       timerExpired(long, long);
     void       sendDLEETX();
     int                getModemLine(char buf[], u_int bufSize, long ms = 0);
-    int                getModemChar(long ms = 0);
+    int                getModemChar(long ms = 0, bool isquery = false);
     int                getModemBit(long ms = 0);
     int                getLastByte();
     bool       didBlockEnd();
index aecdf84b0e6042122dbebfcc8fd3775c3a25d9b0..99038608974c2c45a912d18224081641c6b796e9 100644 (file)
@@ -241,6 +241,7 @@ ModemClassQueryCmd  string  \s-1AT+FCLASS=?\s+1     command for querying modem service
 ModemCommaPauseTimeCmd string  \s-1ATS8=2\s+1  command for setting time to pause for ``,'' in dialing string
 ModemDialCmd   string  \s-1ATDT%s\s+1  command for dialing (%s for number to dial)
 ModemDialResponseTimeout       integer \s-1180000\s+1  dialing command timeout (ms)
+ModemDoPhaseCDebug     boolean \s-1No\s+1      query modem responses during Phase C transmit
 ModemDTRDropDelay      integer \s-175\s+1      delay (ms) between DTR OFF and DTR ON
 ModemEchoOffCmd        string  \s-1ATE0\s+1    command for disabling command echo
 ModemFlowControl       string  \s-1XONXOFF\s+1 \s-1DTE-DCE\s+1 flow control scheme
@@ -2006,6 +2007,14 @@ parameter.
 This additional server-based timeout is provided to guard against
 modems that can ``lock up'' when dialing the telephone.
 .TP
+.B ModemDoPhaseCDebug
+Whether or not to query the modem for responses during image data
+transmission.  Normally the modem should not produce any responses
+during Phase C data transmission.  However, in some debugging
+scenarios (i.e. some Class 2.1 modems may show debugging information)
+it may be appropriate to query the modem for responses during
+the data transmission.
+.TP
 .B ModemDTRDropDelay
 The time, in milliseconds, to pause between placing
 .SM DTR