WvStreams
wvmodem.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 * Copyright (C) 1999 Red Hat, Inc.
5 *
6 * Implementation of the WvModem class. Inherits from WvFile, but
7 * handles various important details related to modems, like setting
8 * the baud rate, checking carrier detect, and dropping DTR.
9 *
10 */
11
12#include "wvmodem.h"
13#include <sys/ioctl.h>
14
15#if HAVE_LINUX_SERIAL_H
16# include <linux/serial.h>
17#endif
18
19#if ! HAVE_CFMAKERAW
20static inline void cfmakeraw(struct termios *termios_p)
21{
22 termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
23 termios_p->c_oflag &= ~OPOST;
24 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
25 termios_p->c_cflag &= ~(CSIZE|PARENB);
26 termios_p->c_cflag |= CS8;
27}
28#endif
29
31 int baud;
32 speed_t speedt;
33};
34
35
36static SpeedLookup speeds[] = {
37#ifdef B460800
38 {460800, B460800},
39#endif
40#ifdef B230400
41 {230400, B230400},
42#endif
43 {115200, B115200},
44 { 57600, B57600},
45 { 38400, B38400},
46 { 19200, B19200},
47 { 9600, B9600},
48 { 4800, B4800},
49 { 2400, B2400},
50 { 1200, B1200},
51 { 300, B300}
52};
53
54
55WvModemBase::WvModemBase(int _fd) : WvFile(_fd)
56{
57 get_real_speed();
58}
59
60
61WvModemBase::~WvModemBase()
62{
63 // nothing needed
64}
65
66
67int WvModemBase::get_real_speed()
68{
69 speed_t s;
70
71 if (!isok()) return 0;
72
73 tcgetattr( getrfd(), &t );
74 s = cfgetospeed( &t );
75 for (unsigned int i = 0; i < sizeof(speeds) / sizeof(*speeds); i++)
76 {
77 if (speeds[i].speedt == s)
78 {
79 baud = speeds[i].baud;
80 break;
81 }
82 }
83
84 return baud;
85}
86
87
89{
90 // no file open, no need to close it
91}
92
93
95{
96 return true;
97}
98
99
101{
102 return baud;
103}
104
105
107{
108 int i, oldbaud = baud;
109
110 if (die_fast || !isok()) return;
111
112 // politely abort any dial in progress, to avoid locking USR modems.
113 // we should only do this if we have received any response from the modem,
114 // so that WvModemScan can run faster.
115 drain();
116 write( "\r", 1 );
117 // FIXME: should be iswritable, but based on the numer of msec params
118 // tossed around I assume modems are very timing-sensitive
119 for (i = 0; !select(200, false, true) && i < 10; i++)
120 write( "\r", 1 );
121 drain();
122
123 // drop DTR for a while, if still online
124 if (carrier())
125 {
126 cfsetospeed( &t, B0 );
127 tcsetattr( getrfd(), TCSANOW, &t );
128 for (i = 0; carrier() && i < 10; i++)
129 usleep( 100 * 1000 );
130
131 // raise DTR again, restoring the old baud rate
132 speed(oldbaud);
133 }
134
135 if (carrier())
136 {
137 // need to do +++ manual-disconnect stuff
138 write( "+++", 3 );
139 usleep( 1500 * 1000 );
140 write( "ATH\r", 4 );
141
142 for (i = 0; carrier() && i < 5; i++)
143 usleep( 100 * 1000 );
144 }
145}
146
147
148
149WvModem::WvModem(WvStringParm filename, int _baud, bool rtscts, bool _no_reset)
150 : WvModemBase(), lock(filename), log("WvModem", WvLog::Debug1)
151{
152 closing = false;
153 baud = _baud;
154 die_fast = false;
155 no_reset = _no_reset;
156 have_old_t = false;
157
158 if (!lock.lock())
159 {
160 seterr(EBUSY);
161 return;
162 }
163
164 // note: if CLOCAL is not set on the modem, open will
165 // block until a carrier detect. Since we have to open the modem to
166 // generate a carrier detect, we have a problem. So we open the modem
167 // nonblocking. It would then be safe to switch to blocking mode,
168 // but that is no longer recommended for WvStream.
169 open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY);
170
171 if (isok())
172 setup_modem(rtscts);
173}
174
175
176WvModem::~WvModem()
177{
178 close();
179}
180
181
182void WvModem::setup_modem(bool rtscts)
183{
184 if (!isok()) return;
185
186 if (tcgetattr(getrfd(), &t) || tcgetattr(getrfd(), &old_t))
187 {
188 closing = true;
189 seterr(errno);
190 return;
191 }
192 have_old_t = true;
193
194 drain();
195
196#if HAVE_LINUX_SERIAL_H
197 struct serial_struct old_sinfo, sinfo;
198 sinfo.reserved_char[0] = 0;
199 if (ioctl(getrfd(), TIOCGSERIAL, &old_sinfo) < 0)
200 log("Cannot get information for serial port.");
201 else
202 {
203 sinfo = old_sinfo;
204 // Why there are two closing wait timeouts, is beyond me
205 // but there are... apparently the second one is deprecated
206 // but why take a chance...
207 sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
208 sinfo.closing_wait2 = ASYNC_CLOSING_WAIT_NONE;
209
210 if (ioctl(getrfd(), TIOCSSERIAL, &sinfo) < 0)
211 log("Cannot set information for serial port.");
212 }
213#endif
214
215 // set up the terminal characteristics.
216 // see "man tcsetattr" for more information about these options.
217 t.c_iflag &= ~(BRKINT | ISTRIP | IUCLC | IXON | IXANY | IXOFF | IMAXBEL);
218 t.c_iflag |= (IGNBRK | IGNPAR);
219 t.c_oflag &= ~(OLCUC);
220 t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
221 t.c_cflag |= (CS8 | CREAD | HUPCL | CLOCAL);
222 if(rtscts)
223 t.c_cflag |= CRTSCTS;
224 t.c_lflag &= ~(ISIG | XCASE | ECHO);
225 tcsetattr(getrfd(), TCSANOW, &t);
226
227 // make sure we leave the modem in CLOCAL when we exit, so normal user
228 // tasks can open the modem without using nonblocking.
229 old_t.c_cflag |= CLOCAL;
230
231 // Send a few returns to make sure the modem is "good and zonked".
232 if (cfgetospeed(&t) != B0 && !no_reset)
233 {
234 for(int i=0; i<5; i++)
235 {
236 write("\r", 1);
237 usleep(10 * 1000);
238 }
239 }
240
241 // Set the baud rate to 0 for half a second to drop DTR...
242 cfsetispeed(&t, B0);
243 cfsetospeed(&t, B0);
244 cfmakeraw(&t);
245 tcsetattr(getrfd(), TCSANOW, &t);
246 if (carrier())
247 usleep(500 * 1000);
248
249 speed(baud);
250 usleep(10 * 1000);
251
252 drain();
253}
254
255
257{
258 if (!closed)
259 {
260 if (!closing)
261 {
262 closing = true;
263 if (!no_reset)
264 hangup();
265 else
266 {
267 drain();
268 cfsetospeed(&t, B0);
269 // If this works??
270 write("\r");
271 }
272 }
273
274 closing = true;
275 if (getrfd() >= 0)
276 {
277 tcflush(getrfd(), TCIOFLUSH);
278 if (have_old_t)
279 tcsetattr(getrfd(), TCSANOW, &old_t);
280 tcflush(getrfd(), TCIOFLUSH);
281 }
283 closing = false;
284 }
285}
286
287
288int WvModem::speed(int _baud)
289{
290 speed_t s = B0;
291 baud = 0;
292 for (unsigned int i = 0; i < sizeof(speeds) / sizeof(*speeds); i++)
293 {
294 if (speeds[i].baud <= _baud)
295 {
296 s = speeds[i].speedt;
297 break;
298 }
299 }
300
301 cfsetispeed(&t, B0); // auto-match to output speed
302 cfsetospeed(&t, s);
303 tcsetattr(getrfd(), TCSANOW, &t);
304
305 return get_real_speed();
306}
307
308
309int WvModem::getstatus()
310{
311 if (!isok()) return 0;
312 int status = 0;
313 ioctl(getrfd(), TIOCMGET, &status);
314 return status;
315}
316
317
319{
320 return (getstatus() & TIOCM_CD) ? 1 : 0;
321}
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
int getrfd() const
Returns the Unix file descriptor for reading from this stream.
virtual bool isok() const
return true if the stream is actually usable right now
virtual void close()
Closes the file descriptors.
WvFile implements a stream connected to a file or Unix device.
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
WvModemBase provides the methods used to control a modem, but without real implementation for most of...
virtual int speed(int _baud)
do-nothing method that is not needed in WvModemBase
Definition wvmodem.cc:100
virtual void close()
do-nothing method that is not needed in WvModemBase
Definition wvmodem.cc:88
virtual bool carrier()
do-nothing method that is not needed in WvModemBase
Definition wvmodem.cc:94
virtual void hangup()
may need to hangup for redial reasons
Definition wvmodem.cc:106
virtual void close()
Close the connection to the modem.
Definition wvmodem.cc:256
virtual int speed(int _baud)
_baud is the desired speed, that you wish the modem to communicate with, and this method returns the ...
Definition wvmodem.cc:288
virtual bool carrier()
Is there a carrier present?
Definition wvmodem.cc:318
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
Definition wvstream.cc:532
bool select(time_t msec_timeout)
Return true if any of the requested features are true on the stream.
void drain()
drain the input buffer (read and discard data until select(0) returns false)
Definition wvstream.cc:699
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
Definition wvstream.cc:451