Gammu internals  1.38.0
ser_unx.c
Go to the documentation of this file.
1 /* (c) 2002-2005 by Marcin Wiacek */
2 /* locking device and settings all speeds by Michal Cihar */
3 /* based on some work from Gnokii (www.gnokii.org)
4  * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
5  * GNU GPL version 2 or later
6  */
7 /* Due to a problem in the source code management, the names of some of
8  * the authors have unfortunately been lost. We do not mean to belittle
9  * their efforts and hope they will contact us to see their names
10  * properly added to the Copyright notice above.
11  * Having published their contributions under the terms of the GNU
12  * General Public License (GPL) [version 2], the Copyright of these
13  * authors will remain respected by adhering to the license they chose
14  * to publish their code under.
15  */
16 
17 #include "../../gsmstate.h"
18 
19 #ifdef GSM_ENABLE_SERIALDEVICE
20 #ifndef WIN32
21 #ifndef DJGPP
22 
23 #include <sys/file.h>
24 #include <sys/time.h>
25 #include <string.h>
26 #include <termios.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #ifdef HAVE_I_SETSIG
32 #include <stropts.h>
33 #endif
34 
35 #include "../../gsmcomon.h"
36 #include "ser_unx.h"
37 
38 #ifndef O_NONBLOCK
39 # define O_NONBLOCK 0
40 #endif
41 
42 #ifdef __NetBSD__
43 #ifndef B57600
44 # define B57600 0010001
45 #endif
46 #ifndef B115200
47 # define B115200 0010002
48 #endif
49 #ifndef B230400
50 # define B230400 0010003
51 #endif
52 #endif
53 
54 typedef struct {
55  speed_t code;
56  int value;
57 } baud_record;
58 
59 #ifdef B115200
60 # define SERIAL_DEFAULT_SPEED 115200
61 #elif defined(B19200)
62 # define SERIAL_DEFAULT_SPEED 19200
63 #else
64 # define SERIAL_DEFAULT_SPEED 9600
65 #endif
66 
67 static baud_record baud_table[] = {
68  { B50, 50 },
69  { B75, 75 },
70  { B110, 110 },
71  { B134, 134 },
72  { B150, 150 },
73  { B200, 200 },
74  { B300, 300 },
75  { B600, 600 },
76  { B1200, 1200 },
77  { B1800, 1800 },
78  { B2400, 2400 },
79  { B4800, 4800 },
80  { B9600, 9600 },
81 #ifdef B19200
82  { B19200, 19200 },
83 #else /* ! defined (B19200) */
84 #ifdef EXTA
85  { EXTA, 19200 },
86 #endif /* EXTA */
87 #endif /* ! defined (B19200) */
88 #ifdef B38400
89  { B38400, 38400 },
90 #else /* ! defined (B38400) */
91 #ifdef EXTB
92  { EXTB, 38400 },
93 #endif /* EXTB */
94 #endif /* ! defined (B38400) */
95 #ifdef B57600
96  { B57600, 57600 },
97 #endif
98 #ifdef B76800
99  { B76800, 76800 },
100 #endif
101 #ifdef B115200
102  { B115200, 115200 },
103 #endif
104 #ifdef B230400
105  { B230400, 230400 },
106 #else
107 #ifdef _B230400
108  { _B230400, 230400 },
109 #endif /* _B230400 */
110 #endif /* ! defined (B230400) */
111 #ifdef B460800
112  { B460800, 460800 },
113 #else
114 #ifdef _B460800
115  { _B460800, 460800 },
116 #endif /* _B460800 */
117 #endif /* ! defined (B460800) */
118 #ifdef B500000
119  { B500000, 500000 },
120 #endif
121 #ifdef B576000
122  { B576000, 576000 },
123 #endif
124 #ifdef B921600
125  { B921600, 921600 },
126 #endif
127 #ifdef B1000000
128  { B1000000, 1000000 },
129 #endif
130 #ifdef B1152000
131  { B1152000, 1152000 },
132 #endif
133 #ifdef B1500000
134  { B1500000, 1500000 },
135 #endif
136 #ifdef B2000000
137  { B2000000, 2000000 },
138 #endif
139 #ifdef B2500000
140  { B2500000, 2500000 },
141 #endif
142 #ifdef B3000000
143  { B3000000, 3000000 },
144 #endif
145 #ifdef B3500000
146  { B3500000, 3500000 },
147 #endif
148 #ifdef B4000000
149  { B4000000, 4000000 },
150 #endif
151  { B0, 0 },
152 };
153 
154 static GSM_Error serial_close(GSM_StateMachine *s)
155 {
156  GSM_Device_SerialData *d = &s->Device.Data.Serial;
157 
158  if (d->hPhone < 0) return ERR_NONE;
159 
160  /* Restores old settings */
161  tcsetattr(d->hPhone, TCSANOW, &d->old_settings);
162 
163  /* Remove advisory lock */
164  flock(d->hPhone, LOCK_UN);
165 
166  /* Closes device */
167  close(d->hPhone);
168 
169  d->hPhone = -1;
170 
171  return ERR_NONE;
172 }
173 
174 static GSM_Error serial_open (GSM_StateMachine *s)
175 {
176  GSM_Device_SerialData *d = &s->Device.Data.Serial;
177  struct termios t;
178  int orig_errno;
179 
180  /* O_NONBLOCK MUST is required to avoid waiting for DCD */
181  d->hPhone = open(s->CurrentConfig->Device, O_RDWR | O_NOCTTY | O_NONBLOCK);
182  if (d->hPhone < 0) {
183  orig_errno = errno;
184  GSM_OSErrorInfo(s,"open in serial_open");
185  if (orig_errno == ENOENT) {
186  return ERR_DEVICENOTEXIST; /* no such file or directory */
187  }
188  if (orig_errno == EACCES) {
189  return ERR_DEVICENOPERMISSION; /* permission denied */
190  }
191  return ERR_DEVICEOPENERROR;
192  }
193 
194 #ifdef TIOCEXCL
195  /* open() calls from other applications shall fail now */
196  /* this works only with CAP_SYS_ADMIN on Linux though */
197  ioctl(d->hPhone, TIOCEXCL, (char *) 0);
198 #endif
199 #ifdef HAVE_I_SETSIG
200  /* Disable any signals from this file */
201  ioctl(d->hPhone, I_SETSIG, (char *) 0);
202 #endif
203 
204  /* Try advisory locks */
205  if (flock(d->hPhone, LOCK_EX | LOCK_NB) != 0) {
206  if (errno == EWOULDBLOCK) {
207  GSM_OSErrorInfo(s, "failed to lock device, probably opened by other process");
208  return ERR_DEVICEOPENERROR;
209  }
210  }
211 
212  if (tcgetattr(d->hPhone, &d->old_settings) == -1) {
213  close(d->hPhone);
214  GSM_OSErrorInfo(s,"tcgetattr in serial_open");
215  return ERR_DEVICEOPENERROR;
216  }
217 
218  if (tcflush(d->hPhone, TCIOFLUSH) == -1) {
219  serial_close(s);
220  GSM_OSErrorInfo(s,"tcflush in serial_open");
221  return ERR_DEVICEOPENERROR;
222  }
223 
224  /* Use previous settings as start */
225  t = d->old_settings;
226 
227  /* Opening without parity */
228  t.c_iflag = IGNPAR;
229  t.c_oflag = 0;
230  /* disconnect line, 8 bits, enable receiver,
231  * ignore modem lines,lower modem line after disconnect
232  */
233  t.c_cflag = B0 | CS8 | CREAD | CLOCAL | HUPCL;
234  /* enable hardware (RTS/CTS) flow control (NON POSIX) */
235  /* t.c_cflag |= CRTSCTS; */
236  t.c_lflag = 0;
237  t.c_cc[VMIN] = 1;
238  t.c_cc[VTIME] = 0;
239 
240  if (tcsetattr(d->hPhone, TCSANOW, &t) == -1) {
241  serial_close(s);
242  GSM_OSErrorInfo(s,"tcsetattr in serial_open");
243  return ERR_DEVICEOPENERROR;
244  }
245 
246  return ERR_NONE;
247 }
248 
249 static GSM_Error serial_setparity(GSM_StateMachine *s, gboolean parity)
250 {
251  GSM_Device_SerialData *d = &s->Device.Data.Serial;
252  struct termios t;
253 
254  assert(d->hPhone >= 0);
255 
256  if (tcgetattr(d->hPhone, &t)) {
257  GSM_OSErrorInfo(s,"tcgetattr in serial_setparity");
258  return ERR_DEVICEPARITYERROR;
259  }
260 
261  if (parity) {
262  t.c_cflag |= (PARENB | PARODD);
263  t.c_iflag = 0;
264  } else {
265  t.c_iflag = IGNPAR;
266  }
267 
268  if (tcsetattr(d->hPhone, TCSANOW, &t) == -1){
269  serial_close(s);
270  GSM_OSErrorInfo(s,"tcsetattr in serial_setparity");
271  return ERR_DEVICEPARITYERROR;
272  }
273 
274  return ERR_NONE;
275 }
276 
277 static GSM_Error serial_setdtrrts(GSM_StateMachine *s, gboolean dtr, gboolean rts)
278 {
279  GSM_Device_SerialData *d = &s->Device.Data.Serial;
280  struct termios t;
281  unsigned int flags;
282 
283  if (s->SkipDtrRts) return ERR_NONE;
284 
285  assert(d->hPhone >= 0);
286 
287  if (tcgetattr(d->hPhone, &t)) {
288  GSM_OSErrorInfo(s,"tcgetattr in serial_setdtrrts");
289  return ERR_DEVICEDTRRTSERROR;
290  }
291 
292 #ifdef CRTSCTS
293  /* Disabling hardware flow control */
294  t.c_cflag &= ~CRTSCTS;
295 #endif
296 
297  if (tcsetattr(d->hPhone, TCSANOW, &t) == -1) {
298  serial_close(s);
299  GSM_OSErrorInfo(s,"tcsetattr in serial_setdtrrts");
300  return ERR_DEVICEDTRRTSERROR;
301  }
302 
303  flags = TIOCM_DTR;
304  if (dtr) {
305  ioctl(d->hPhone, TIOCMBIS, &flags);
306  } else {
307  ioctl(d->hPhone, TIOCMBIC, &flags);
308  }
309 
310  flags = TIOCM_RTS;
311  if (rts) {
312  ioctl(d->hPhone, TIOCMBIS, &flags);
313  } else {
314  ioctl(d->hPhone, TIOCMBIC, &flags);
315  }
316 
317  flags = 0;
318  ioctl(d->hPhone, TIOCMGET, &flags);
319 
320  smprintf(s, "Serial device:");
321  smprintf(s, " DTR is %s", flags & TIOCM_DTR ? "up" : "down");
322  smprintf(s, ", RTS is %s", flags & TIOCM_RTS ? "up" : "down");
323  smprintf(s, ", CAR is %s", flags & TIOCM_CAR ? "up" : "down");
324  smprintf(s, ", CTS is %s\n", flags & TIOCM_CTS ? "up" : "down");
325 
326  if (((flags & TIOCM_DTR) == TIOCM_DTR) != dtr) {
327  smprintf(s, "Setting DTR failed, disabling setting of DTR/RTS signals.\n");
328  s->SkipDtrRts = TRUE;
329  }
330 
331  if (((flags & TIOCM_RTS) == TIOCM_RTS) != rts) {
332  smprintf(s, "Setting RTS failed, disabling setting of DTR/RTS signals.\n");
333  s->SkipDtrRts = TRUE;
334  }
335 
336  return ERR_NONE;
337 }
338 
339 static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed)
340 {
341  GSM_Device_SerialData *d = &s->Device.Data.Serial;
342  struct termios t;
343  baud_record *curr = baud_table;
344 
345  if (s->SkipDtrRts) return ERR_NONE;
346 
347  assert(d->hPhone >= 0);
348 
349  if (tcgetattr(d->hPhone, &t)) {
350  GSM_OSErrorInfo(s,"tcgetattr in serial_setspeed");
351  return ERR_DEVICEREADERROR;
352  }
353 
354  while (curr->value != speed) {
355  curr++;
356  /* This is how we make default fallback */
357  if (curr->value == 0) {
358  if (speed == SERIAL_DEFAULT_SPEED) {
359  return ERR_NOTSUPPORTED;
360  }
361  curr = baud_table;
362  speed = SERIAL_DEFAULT_SPEED;
363  }
364  }
365 
366  smprintf(s, "Setting speed to %d\n", curr->value);
367 
368  cfsetispeed(&t, curr->code);
369  cfsetospeed(&t, curr->code);
370 
371  if (tcsetattr(d->hPhone, TCSADRAIN, &t) == -1) {
372  serial_close(s);
373  GSM_OSErrorInfo(s,"tcsetattr in serial_setspeed");
375  }
376 
377  return ERR_NONE;
378 }
379 
380 static int serial_read(GSM_StateMachine *s, void *buf, size_t nbytes)
381 {
382  GSM_Device_SerialData *d = &s->Device.Data.Serial;
383  struct timeval timeout2;
384  fd_set readfds;
385  int actual = 0;
386 
387  assert(d->hPhone >= 0);
388 
389  FD_ZERO(&readfds);
390  FD_SET(d->hPhone, &readfds);
391 
392  timeout2.tv_sec = 0;
393  timeout2.tv_usec = 50000;
394 
395  if (select(d->hPhone+1, &readfds, NULL, NULL, &timeout2)) {
396  actual = read(d->hPhone, buf, nbytes);
397  if (actual == -1) GSM_OSErrorInfo(s,"serial_read");
398  }
399  return actual;
400 }
401 
402 static int serial_write(GSM_StateMachine *s, const void *buf, size_t nbytes)
403 {
404  GSM_Device_SerialData *d = &s->Device.Data.Serial;
405  int ret;
406  size_t actual = 0;
407  const unsigned char *buffer = (const unsigned char *)buf; /* Just to have correct type */
408 
409  assert(d->hPhone >= 0);
410 
411  do {
412  ret = write(d->hPhone, buffer, nbytes - actual);
413  if (ret < 0) {
414  if (errno == EAGAIN) {
415  usleep(1000);
416  continue;
417  }
418  if (actual != nbytes) {
419  GSM_OSErrorInfo(s, "serial_write");
420  smprintf(s, "Wanted to write %ld bytes, but %ld were written\n",
421  (long)nbytes, (long)actual);
422  }
423  return actual;
424  }
425  actual += ret;
426  buffer += ret;
427  if (s->ConnectionType == GCT_FBUS2PL2303) usleep(1000);
428  } while (actual < nbytes);
429  return actual;
430 }
431 
432 GSM_Device_Functions SerialDevice = {
433  serial_open,
434  serial_close,
435  serial_setparity,
436  serial_setdtrrts,
437  serial_setspeed,
438  serial_read,
439  serial_write
440 };
441 
442 #endif
443 #endif
444 #endif
445 
446 /* How should editor hadle tabs in this file? Add editor commands here.
447  * vim: noexpandtab sw=8 ts=8 sts=8:
448  */
GSM_Config * CurrentConfig
Definition: gsmstate.h:1415
union GSM_Device::@0 Data
GSM_ConnectionType ConnectionType
Definition: gsmstate.h:1402
GSM_Error
Definition: gammu-error.h:23
int gboolean
Definition: gammu-types.h:23
void GSM_OSErrorInfo(GSM_StateMachine *s, const char *description)
Definition: gsmstate.c:1593
gboolean SkipDtrRts
Definition: gsmstate.h:1406
struct termios old_settings
Definition: ser_unx.h:13
#define TRUE
Definition: gammu-types.h:28
GSM_Device Device
Definition: gsmstate.h:1429
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261