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
00157 if (!lock.lock())
00158 {
00159 seterr(EBUSY);
00160 return;
00161 }
00162
00163
00164
00165
00166
00167
00168 open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY);
00169
00170 if (isok())
00171 setup_modem(rtscts);
00172 }
00173
00174
00175 WvModem::~WvModem()
00176 {
00177 close();
00178 }
00179
00180
00181 void WvModem::setup_modem(bool rtscts)
00182 {
00183 if (!isok()) return;
00184
00185 if (tcgetattr(getrfd(), &t) || tcgetattr(getrfd(), &old_t))
00186 {
00187 closing = true;
00188 seterr(errno);
00189 return;
00190 }
00191
00192 drain();
00193
00194 #if HAVE_LINUX_SERIAL_H
00195 struct serial_struct old_sinfo, sinfo;
00196 sinfo.reserved_char[0] = 0;
00197 if (ioctl(getrfd(), TIOCGSERIAL, &old_sinfo) < 0)
00198 log("Cannot get information for serial port.");
00199 else
00200 {
00201 sinfo = old_sinfo;
00202
00203
00204
00205 sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
00206 sinfo.closing_wait2 = ASYNC_CLOSING_WAIT_NONE;
00207
00208 if (ioctl(getrfd(), TIOCSSERIAL, &sinfo) < 0)
00209 log("Cannot set information for serial port.");
00210 }
00211 #endif
00212
00213
00214
00215 t.c_iflag &= ~(BRKINT | ISTRIP | IUCLC | IXON | IXANY | IXOFF | IMAXBEL);
00216 t.c_iflag |= (IGNBRK | IGNPAR);
00217 t.c_oflag &= ~(OLCUC);
00218 t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
00219 t.c_cflag |= (CS8 | CREAD | HUPCL | CLOCAL);
00220 if(rtscts)
00221 t.c_cflag |= CRTSCTS;
00222 t.c_lflag &= ~(ISIG | XCASE | ECHO);
00223 tcsetattr(getrfd(), TCSANOW, &t);
00224
00225
00226
00227 old_t.c_cflag |= CLOCAL;
00228
00229
00230 if (cfgetospeed(&t) != B0 && !no_reset)
00231 {
00232 for(int i=0; i<5; i++)
00233 {
00234 write("\r", 1);
00235 usleep(10 * 1000);
00236 }
00237 }
00238
00239
00240 cfsetispeed(&t, B0);
00241 cfsetospeed(&t, B0);
00242 cfmakeraw(&t);
00243 tcsetattr(getrfd(), TCSANOW, &t);
00244 if (carrier())
00245 usleep(500 * 1000);
00246
00247 speed(baud);
00248 usleep(10 * 1000);
00249
00250 drain();
00251 }
00252
00253
00254 void WvModem::close()
00255 {
00256 if (!closed)
00257 {
00258 if (!closing)
00259 {
00260 closing = true;
00261 if (!no_reset)
00262 hangup();
00263 else
00264 {
00265 drain();
00266 cfsetospeed(&t, B0);
00267
00268 write("\r");
00269 }
00270 }
00271
00272 closing = true;
00273 if (getrfd() >= 0)
00274 {
00275 tcflush(getrfd(), TCIOFLUSH);
00276 tcsetattr(getrfd(), TCSANOW, &old_t);
00277 }
00278 WvFile::close();
00279 closing = false;
00280 }
00281 }
00282
00283
00284 int WvModem::speed(int _baud)
00285 {
00286 speed_t s = B0;
00287 baud = 0;
00288 for (unsigned int i = 0; i < sizeof(speeds) / sizeof(*speeds); i++)
00289 {
00290 if (speeds[i].baud <= _baud)
00291 {
00292 s = speeds[i].speedt;
00293 break;
00294 }
00295 }
00296
00297 cfsetispeed(&t, B0);
00298 cfsetospeed(&t, s);
00299 tcsetattr(getrfd(), TCSANOW, &t);
00300
00301 return get_real_speed();
00302 }
00303
00304
00305 int WvModem::getstatus()
00306 {
00307 if (!isok()) return 0;
00308 int status = 0;
00309 ioctl(getrfd(), TIOCMGET, &status);
00310 return status;
00311 }
00312
00313
00314 bool WvModem::carrier()
00315 {
00316 return (getstatus() & TIOCM_CD) ? 1 : 0;
00317 }