{ 0x00,0x18,0x00,0xC0,0x06,0x00,0x30,0x01,0x80,0x0C };
protoTrace("SEND %s RTC", is2D ? "2D" : "1D");
if (is2D)
- return sendClass1Data(RTC2D, sizeof (RTC2D), frameRev, true);
+ return sendClass1Data(RTC2D, sizeof (RTC2D), rtcRev, true);
else
- return sendClass1Data(RTC1D, sizeof (RTC1D), frameRev, true);
+ return sendClass1Data(RTC1D, sizeof (RTC1D), rtcRev, true);
}
#define EOLcheck(w,mask,code) \
uint16 fillorder;
TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
const u_char* bitrev =
- TIFFGetBitRevTable(conf.sendFillOrder != FILLORDER_LSB2MSB);
+ TIFFGetBitRevTable(sendFillOrder != FILLORDER_LSB2MSB);
/*
* Setup tag line processing.
*/
{
hangupCode[0] = '\0';
serviceType = 0; // must be set in derived class
- rtcRev = TIFFGetBitRevTable(conf.sendFillOrder == FILLORDER_LSB2MSB);
}
Class2Modem::~Class2Modem()
{
}
-void
-Class2Modem::setupDefault(fxStr& s, const fxStr& configured, const char* def)
-{
- if (configured == "")
- s = def;
- else
- s = configured;
-}
-
/*
* Check if the modem is a Class 2 modem and, if so,
* configure it for use. We try to confine a lot of
else
xmitWaitForXON = conf.class2XmitWaitForXON;
+ /*
+ * Most Class2 modems require recvFillOrder == MSB2LSB
+ * (Rockwell bug, which has become "standard" now).
+ *
+ * The only known exception is early Multitech modems,
+ * that follow original Class2 specs (LSB2MSB). They report the
+ * manufacturer as "Multi-Tech Sys" or "Multi-Tech Systems".
+ *
+ * Other Class2 modems that requires recvFillOrder == LSB2MSB
+ * (if any) are expected to set the appropriate value in the
+ * config file.
+ */
+ if( conf.recvFillOrder == 0 && serviceType == SERVICE_CLASS2 ){
+ if ( modemMfr.find(0, "MULTI-TECH") >= modemMfr.length() ){
+ // Not a Multitech
+ recvFillOrder = FILLORDER_MSB2LSB;
+ }
+ }
+
setupClass2Parameters(); // send parameters to the modem
return (true);
}
char recvDataTrigger; // char to send to start recv'ing data
char hangupCode[4]; // hangup reason (from modem)
bool hadHangup; // true if +FHNG:/+FHS: received
- const u_char* rtcRev; // bit reversal table for RTC
fxStr lid; // prepared local identifier string
// modem setup stuff
- void setupDefault(fxStr&, const fxStr&, const char*);
virtual bool setupModem();
virtual bool setupModel(fxStr& model);
virtual bool setupRevision(fxStr& rev);
uint16 fillorder;
TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
const u_char* bitrev =
- TIFFGetBitRevTable(fillorder != conf.sendFillOrder);
+ TIFFGetBitRevTable(fillorder != sendFillOrder);
/*
* Setup tag line processing.
*/
flowControl = conf.flowControl;
iFlow = FLOW_NONE;
oFlow = FLOW_NONE;
+ setupDefault(mfrQueryCmd, conf.mfrQueryCmd, "ATI3");
+ setupDefault(modelQueryCmd, conf.modelQueryCmd, "ATI0");
+ setupDefault(revQueryCmd, conf.revQueryCmd, ""); // No "standard" way? -- dbely
}
ClassModem::~ClassModem()
(void) select(0, 0, 0, 0, &tv);
}
+static void
+ClassModem::setupDefault(fxStr& s, const fxStr& configured, const char* def)
+{
+ if (configured == "")
+ s = def;
+ else
+ s = configured;
+}
+
/*
* Reset the modem and set the DTE-DCE rate.
*/
ClassModem(ModemServer&, const ModemConfig&);
// setup and configuration
+ static void setupDefault(fxStr&, const fxStr&, const char*);
virtual bool selectBaudRate(BaudRate max, FlowControl i, FlowControl o);
virtual bool setupManufacturer(fxStr& mfr);
virtual bool setupModel(fxStr& model);
const fxStr& getManufacturer() const;
const fxStr& getRevision() const;
fxStr getCapabilities() const;
+ u_int getModemServices() const;
// data transfer timeout controls
void setDataTimeout(long secs, u_int br);
long getDataTimeout() const;
inline const fxStr& ClassModem::getModel() const { return modemModel; }
inline const fxStr& ClassModem::getManufacturer() const { return modemMfr; }
inline const fxStr& ClassModem::getRevision() const { return modemRevision; }
+inline u_int ClassModem::getModemServices() const { return modemServices; }
inline FlowControl ClassModem::getInputFlow() { return iFlow; }
inline FlowControl ClassModem::getOutputFlow() { return oFlow; }
#endif /* _ClassModem_ */
FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality,
const Class2Params& params, fxStr& emsg)
{
- setupDecoder(conf.recvFillOrder, params.is2D());
+ setupDecoder(recvFillOrder, params.is2D());
u_int rowpixels = params.pageWidth(); // NB: assume rowpixels <= 2432
tiff_runlen_t runs[2*2432]; // run arrays for cur+ref rows
minsp = BR_2400;
curreq = NULL;
group3opts = 0;
+ // fill order settings may be overwritten in derived class
+ recvFillOrder = (conf.recvFillOrder != 0)? conf.recvFillOrder : FILLORDER_LSB2MSB;
+ sendFillOrder = (conf.sendFillOrder != 0)? conf.sendFillOrder : FILLORDER_LSB2MSB;
+ rtcRev = TIFFGetBitRevTable(sendFillOrder == FILLORDER_LSB2MSB);
}
FaxModem::~FaxModem()
fxStackBuffer* recvBuf; // raw recv data for when copy quality disabled
uint32 group3opts; // for writing received TIFF
Class2Params params; // current session params
+ u_int recvFillOrder; // bit order of recvd data (ModemConfig & autodetected)
+ u_int sendFillOrder; // bit order of sent data (ModemConfig & autodetected)
+ const u_char* rtcRev; // bit reversal table for RTC
FaxModem(FaxServer&, const ModemConfig&);
#include "Sys.h"
#include "FaxServer.h"
+#include "Class0.h"
#include "Class1.h"
#include "Class2Ersatz.h"
#include "Class20.h"
* Probe for modem using type, if specified; otherwise
* try Class 2.0, Class 2, Class 1, and then Class 0 types.
*/
+ u_int modemServices = 0; // fax classes to try (bitmask)
ClassModem* modem;
- if (h == "CLASS2.0" || h == "UNKNOWN") {
+ if (h == "UNKNOWN"){
+ modem = new Class0Modem(*this, *this);
+ if (modem) {
+ if (modem->setupModem()){
+ modemServices = modem->getModemServices();
+ fxStr mfr = modem->getManufacturer();
+ mfr.raisecase();
+ if( mfr.find(0,"ROBOTICS") < mfr.length() ||
+ mfr.find(0,"3COM") < mfr.length() ){
+ /*
+ * Don't use Class2.0 with USR modems if not explicitly
+ * specified in the config file (it doesn't work reliably) -- dbely
+ */
+ modem->serverTrace("USR/3COM modem: disable Class 2.0");
+ modemServices &= ~SERVICE_CLASS20;
+ }
+ }
+ delete modem;
+ }
+ }
+ else if (h == "CLASS2.0")
+ modemServices |= SERVICE_CLASS20;
+ else if (h == "CLASS2")
+ modemServices |= SERVICE_CLASS2;
+ else if (h == "CLASS1")
+ modemServices |= SERVICE_CLASS1;
+
+ if (modemServices & SERVICE_CLASS20) {
modem = new Class20Modem(*this, *this);
if (modem) {
if (modem->setupModem())
delete modem;
}
}
- if (h == "CLASS2" || h == "UNKNOWN") {
+ if (modemServices & SERVICE_CLASS2) {
modem = new Class2ErsatzModem(*this, *this);
if (modem) {
if (modem->setupModem())
delete modem;
}
}
- if (h == "CLASS1" || h == "UNKNOWN") {
+ if (modemServices & SERVICE_CLASS1) {
modem = new Class1Modem(*this, *this);
if (modem) {
if (modem->setupModem())
u_int ModemConfig::* p;
u_int def;
} fillorders[] = {
-{ "modemrecvfillorder", &ModemConfig::recvFillOrder, FILLORDER_LSB2MSB },
-{ "modemsendfillorder", &ModemConfig::sendFillOrder, FILLORDER_LSB2MSB },
+{ "modemrecvfillorder", &ModemConfig::recvFillOrder, 0 }, // will be autodetected
+{ "modemsendfillorder", &ModemConfig::sendFillOrder, 0 }, // will be autodetected
{ "modemframefillorder", &ModemConfig::frameFillOrder, FILLORDER_LSB2MSB },
};
static const struct {
for (i = N(numbers)-1; i >= 0; i--)
(*this).*numbers[i].p = numbers[i].def;
- flowControl = ClassModem::FLOW_NONE;// no flow control
+ flowControl = ClassModem::FLOW_XONXOFF;// software flow control
maxRate = ClassModem::BR19200; // reasonable for most modems
minSpeed = BR_2400; // minimum transmit speed
waitForConnect = false; // unique modem answer response
.if n .po 0
.ds Fx \fIHyla\s-1FAX\s+1\fP
.ds Ps P\s-2OST\s+2S\s-2CRIPT\s+2
-.TH CONFIG 4F "August 28, 1996"
+.TH CONFIG 4F "$Date$"
.SH NAME
config \- \*(Fx configuration database
.SH DESCRIPTION
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)
ModemEchoOffCmd string \s-1ATE0\s+1 command for disabling command echo
-ModemFlowControl string \s-1None\s+1 \s-1DTE-DCE\s+1 flow control scheme
+ModemFlowControl string \s-1XONXOFF\s+1 \s-1DTE-DCE\s+1 flow control scheme
ModemFrameFillOrder string \s-1LSB2MSB\s+1 bit order for \s-1HDLC\s+1 frames
ModemHardFlowCmd string \- command for setting hardware flow control between \s-1DTE\s+1 and \s-1DCE\s+1
ModemMinSpeed string \s-12400\s+1 minimum acceptable transmit speed
ModemPageDoneTimeout integer \s-1180000\s+1 page send/receive timeout (ms)
ModemPageStartTimeout integer \s-1180000\s+1 page send/receive timeout (ms)
ModemRate integer \s-119200\s+1 baud rate to use for \s-1DCE-DTE\s+1 communication
-ModemRecvFillOrder string \s-1LSB2MSB\s+1 bit order for received facsimile data
+ModemRecvFillOrder string \s-1\fIsee below\fP\s+1 bit order for received facsimile data
ModemResetCmds string \- additional commands when resetting modem
ModemResetDelay integer \s-12600\s+1 delay (ms) after sending modem reset commands
ModemResultCodesCmd string \s-1ATQ0\s+1 command for enabling result codes
ModemSetupDTRCmd string \- command for setting up \s-1DTR\s+1 handling
ModemSoftFlowCmd string \- command for setting software flow control between \s-1DTE\s+1 and \s-1DCE\s+1
ModemSoftResetCmd string \s-1ATZ\s+1 command for doing a soft reset
-ModemType string \- modem type
+ModemType string \s-1\fIsee below\fP\s+1 modem type
ModemVerboseResultsCmd string \s-1ATV1\s+1 command for enabling verbose result codes
ModemWaitForConnect boolean \s-1No\s+1 force server to wait for ``\s-1CONNECT\s+1'' response on answer
ModemWaitTimeCmd string \s-1ATS7=60\s+1 command for setting time to wait for carrier when dialing
communication.
However, beware that many modems only support software
flow control when sending or receiving facsimile.
+.IP
+Note that modems usually support software flow control even
+if they have no explicit AT-command to activate it; in this case
+it is switched on when the modem enters fax mode, having
+AT+FCLASS=... from \s-1DTE\s+1.
.TP
.B ModemFrameFillOrder
The bit order to expect for received
identification string.
If this parameter is not set, then it is initialized
to ``\s-1AT+FMFR?\s+1'' for Class 2 modems, or
-to ``\s-1AT+FMI?\s+1'' for Class 2.0 modems.
+to ``\s-1AT+FMI?\s+1'' for Class 2.0 modems, or
+to ``\s-1ATI3\s+1'' for Class 1 modems.
If the parameter begins with a ``!'', then the remainder of the
string is taken to be the identification string and no command
is issued to the modem.
.B ModemModelQueryCmd
The command to send to the modem to get the model identification string.
If this parameter is not set, then it is initialized to
-to ``\s-1AT+FMDL?\s+1'' for Class 2 modems,
-or to ``\s-1AT+FMM?\s+1'' for Class 2.0 modems.
+to ``\s-1AT+FMDL?\s+1'' for Class 2 modems, or
+to ``\s-1AT+FMM?\s+1'' for Class 2.0 modems, or
+to ``\s-1ATI0\s+1'' for Class 1 modems.
If the parameter begins with a ``!'', then the remainder of the
string is taken to be the identification string and no command
is issued to the modem.
data in
.SM LSB2MSB
order.
-However many Class 2 modems use
+However most Class 2 modems (except maybe only Multitech) use
.SM MSB2LSB
for compatibility with modems that were built with
Rockwell hardware/firmware that included a bug
that was too widespread to correct.
+.IP
+If this parameter is not set, then it is autodetected and set to
+.SM LSB2MSB
+for Class 1 and Class 2.0 modems and
+.SM MSB2LSB
+for non-Multitech Class 2 modems. However this may be wrong for
+your modem, so you will have to specify this parameter explicitly.
.TP
.B ModemResetCmds
A string of commands to issue to the modem during initialization.
or ``Class1'';
to indicate that the modem is a Class 2-,
Class 2.0-, or Class 1-style modem, respectively.
+If this parameter is not set, then it is autodetected and
+the highest supported fax class is used.
.TP
.B ModemVerboseResultsCmd
The command to enable verbose, as opposed to numeric, result codes.