00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "wvmodem.h"
00013 #include <sys/ioctl.h>
00014
00015 #if HAVE_LINUX_SERIAL_H
00016 # include <linux/serial.h>
00017 #endif
00018
00019 #if ! HAVE_CFMAKERAW
00020 static inline void cfmakeraw(struct termios *termios_p)
00021 {
00022 termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
00023 termios_p->c_oflag &= ~OPOST;
00024 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
00025 termios_p->c_cflag &= ~(CSIZE|PARENB);
00026 termios_p->c_cflag |= CS8;
00027 }
00028 #endif
00029
00030 struct SpeedLookup {
00031 int baud;
00032 speed_t speedt;
00033 };
00034
00035
00036 static SpeedLookup speeds[] = {
00037 #ifdef B460800
00038 {460800, B460800},
00039 #endif
00040 #ifdef B230400
00041 {230400, B230400},
00042 #endif
00043 {115200, B115200},
00044 { 57600, B57600},
00045 { 38400, B38400},
00046 { 19200, B19200},
00047 { 9600, B9600},
00048 { 4800, B4800},
00049 { 2400, B2400},
00050 { 1200, B1200},
00051 { 300, B300}
00052 };
00053
00054
00055 WvModemBase::WvModemBase(int _fd) : WvFile(_fd)
00056 {
00057 get_real_speed();
00058 }
00059
00060
00061 WvModemBase::~WvModemBase()
00062 {
00063
00064 }
00065
00066
00067 int WvModemBase::get_real_speed()
00068 {
00069 speed_t s;
00070
00071 if (!isok()) return 0;
00072
00073 tcgetattr( getrfd(), &t );
00074 s = cfgetospeed( &t );
00075 for (unsigned int i = 0; i < sizeof(speeds) / sizeof(*speeds); i++)
00076 {
00077 if (speeds[i].speedt == s)
00078 {
00079 baud = speeds[i].baud;
00080 break;
00081 }
00082 }
00083
00084 return baud;
00085 }
00086
00087
00088 void WvModemBase::close()
00089 {
00090
00091 }
00092
00093
00094 bool WvModemBase::carrier()
00095 {
00096 return true;
00097 }
00098
00099
00100 int WvModemBase::speed(int)
00101 {
00102 return baud;
00103 }
00104
00105
00106 void WvModemBase::hangup()
00107 {
00108 int i, oldbaud = baud;
00109
00110 if (die_fast || !isok()) return;
00111
00112
00113
00114
00115 drain();
00116 write( "\r", 1 );
00117
00118
00119 for (i = 0; !select(200, false, true) && i < 10; i++)
00120 write( "\r", 1 );
00121 drain();
00122
00123
00124 if (carrier())
00125 {
00126 cfsetospeed( &t, B0 );
00127 tcsetattr( getrfd(), TCSANOW, &t );
00128 for (i = 0; carrier() && i < 10; i++)
00129 usleep( 100 * 1000 );
00130
00131
00132 speed(oldbaud);
00133 }
00134
00135 if (carrier())
00136 {
00137
00138 write( "+++", 3 );
00139 usleep( 1500 * 1000 );
00140 write( "ATH\r", 4 );
00141
00142 for (i = 0; carrier() && i < 5; i++)
00143 usleep( 100 * 1000 );
00144 }
00145 }
00146
00147
00148
00149 WvModem::WvModem(WvStringParm filename, int _baud, bool rtscts, bool _no_reset)
00150 : WvModemBase(), lock(filename), log("WvModem", WvLog::Debug1)
00151 {
00152 closing = false;
00153 baud = _baud;
00154 die_fast = false;
00155 no_reset = _no_reset;
00156 have_old_t = false;
00157
00158 if (!lock.lock())
00159 {
00160 seterr(EBUSY);
00161 return;
00162 }
00163
00164
00165
00166
00167
00168
00169 open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY);
00170
00171 if (isok())
00172 setup_modem(rtscts);
00173 }
00174
00175
00176 WvModem::~WvModem()
00177 {
00178 close();
00179 }
00180
00181
00182 void WvModem::setup_modem(bool rtscts)
00183 {
00184 if (!isok()) return;
00185
00186 if (tcgetattr(getrfd(), &t) || tcgetattr(getrfd(), &old_t))
00187 {
00188 closing = true;
00189 seterr(errno);
00190 return;
00191 }
00192 have_old_t = true;
00193
00194 drain();
00195
00196 #if 0
00197 struct serial_struct old_sinfo, sinfo;
00198 sinfo.reserved_char[0] = 0;
00199 if (ioctl(getrfd(), TIOCGSERIAL, &old_sinfo) < 0)
00200 log("Cannot get information for serial port.");
00201 else
00202 {
00203 sinfo = old_sinfo;
00204
00205
00206
00207 sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
00208 sinfo.closing_wait2 = ASYNC_CLOSING_WAIT_NONE;
00209
00210 if (ioctl(getrfd(), TIOCSSERIAL, &sinfo) < 0)
00211 log("Cannot set information for serial port.");
00212 }
00213 #endif
00214
00215
00216
00217 t.c_iflag &= ~(BRKINT | ISTRIP | IUCLC | IXON | IXANY | IXOFF | IMAXBEL);
00218 t.c_iflag |= (IGNBRK | IGNPAR);
00219 t.c_oflag &= ~(OLCUC);
00220 t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
00221 t.c_cflag |= (CS8 | CREAD | HUPCL | CLOCAL);
00222 if(rtscts)
00223 t.c_cflag |= CRTSCTS;
00224 t.c_lflag &= ~(ISIG | XCASE | ECHO);
00225 tcsetattr(getrfd(), TCSANOW, &t);
00226
00227
00228
00229 old_t.c_cflag |= CLOCAL;
00230
00231
00232 if (cfgetospeed(&t) != B0 && !no_reset)
00233 {
00234 for(int i=0; i<5; i++)
00235 {
00236 write("\r", 1);
00237 usleep(10 * 1000);
00238 }
00239 }
00240
00241
00242 cfsetispeed(&t, B0);
00243 cfsetospeed(&t, B0);
00244 cfmakeraw(&t);
00245 tcsetattr(getrfd(), TCSANOW, &t);
00246 if (carrier())
00247 usleep(500 * 1000);
00248
00249 speed(baud);
00250 usleep(10 * 1000);
00251
00252 drain();
00253 }
00254
00255
00256 void WvModem::close()
00257 {
00258 if (!closed)
00259 {
00260 if (!closing)
00261 {
00262 closing = true;
00263 if (!no_reset)
00264 hangup();
00265 else
00266 {
00267 drain();
00268 cfsetospeed(&t, B0);
00269
00270 write("\r");
00271 }
00272 }
00273
00274 closing = true;
00275 if (getrfd() >= 0)
00276 {
00277 tcflush(getrfd(), TCIOFLUSH);
00278 if (have_old_t)
00279 tcsetattr(getrfd(), TCSANOW, &old_t);
00280 tcflush(getrfd(), TCIOFLUSH);
00281 }
00282 WvFile::close();
00283 closing = false;
00284 }
00285 }
00286
00287
00288 int WvModem::speed(int _baud)
00289 {
00290 speed_t s = B0;
00291 baud = 0;
00292 for (unsigned int i = 0; i < sizeof(speeds) / sizeof(*speeds); i++)
00293 {
00294 if (speeds[i].baud <= _baud)
00295 {
00296 s = speeds[i].speedt;
00297 break;
00298 }
00299 }
00300
00301 cfsetispeed(&t, B0);
00302 cfsetospeed(&t, s);
00303 tcsetattr(getrfd(), TCSANOW, &t);
00304
00305 return get_real_speed();
00306 }
00307
00308
00309 int WvModem::getstatus()
00310 {
00311 if (!isok()) return 0;
00312 int status = 0;
00313 ioctl(getrfd(), TIOCMGET, &status);
00314 return status;
00315 }
00316
00317
00318 bool WvModem::carrier()
00319 {
00320 return (getstatus() & TIOCM_CD) ? 1 : 0;
00321 }