From 88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22 Mon Sep 17 00:00:00 2001 From: zautrix Date: Sat, 07 Aug 2004 17:24:40 +0000 Subject: Initial revision --- (limited to 'gammu/emb/common/device/serial/ser_unx.c') diff --git a/gammu/emb/common/device/serial/ser_unx.c b/gammu/emb/common/device/serial/ser_unx.c new file mode 100644 index 0000000..2a87b11 --- a/dev/null +++ b/gammu/emb/common/device/serial/ser_unx.c @@ -0,0 +1,291 @@ +/* (c) 2002-2004 by Marcin Wiacek */ +/* locking device and settings all speeds by Michal Cihar */ + +#include "../../gsmstate.h" + +#ifdef GSM_ENABLE_SERIALDEVICE +#ifndef WIN32 +#ifndef DJGPP + +#include +#include +#include +#include +#include + +#include "../../gsmcomon.h" +#include "ser_unx.h" + +static GSM_Error serial_close(GSM_StateMachine *s) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + + /* Restores old settings */ + tcsetattr(d->hPhone, TCSANOW, &d->old_settings); + + /* Closes device */ + close(d->hPhone); + + return ERR_NONE; +} + +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + +static GSM_Error serial_open (GSM_StateMachine *s) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + struct termios t; + int i; + + /* O_NONBLOCK MUST is required to avoid waiting for DCD */ + d->hPhone = open(s->CurrentConfig->Device, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (d->hPhone < 0) { + i = errno; + GSM_OSErrorInfo(s,"open in serial_open"); + if (i == 2) return ERR_DEVICENOTEXIST; //no such file or directory + if (i == 13) return ERR_DEVICENOPERMISSION; //permission denied + return ERR_DEVICEOPENERROR; + } + +#ifdef TIOCEXCL + /* open() calls from other applications shall fail now */ + ioctl(d->hPhone, TIOCEXCL, (char *) 0); +#endif + + if (tcgetattr(d->hPhone, &d->old_settings) == -1) { + close(d->hPhone); + GSM_OSErrorInfo(s,"tcgetattr in serial_open"); + return ERR_DEVICEREADERROR; + } + + if (tcflush(d->hPhone, TCIOFLUSH) == -1) { + serial_close(s); + GSM_OSErrorInfo(s,"tcflush in serial_open"); + return ERR_DEVICEOPENERROR; + } + + memcpy(&t, &d->old_settings, sizeof(struct termios)); + + /* Opening without parity */ + t.c_iflag = IGNPAR; + t.c_oflag = 0; + /* disconnect line, 8 bits, enable receiver, + * ignore modem lines,lower modem line after disconnect + */ + t.c_cflag = B0 | CS8 | CREAD | CLOCAL | HUPCL; + /* enable hardware (RTS/CTS) flow control (NON POSIX) */ + /* t.c_cflag |= CRTSCTS; */ + t.c_lflag = 0; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + + if (tcsetattr(d->hPhone, TCSANOW, &t) == -1) { + serial_close(s); + GSM_OSErrorInfo(s,"tcsetattr in serial_open"); + return ERR_DEVICEOPENERROR; + } + + /* Making file descriptor asynchronous. */ + if (fcntl(d->hPhone, F_SETFL, FASYNC | FNONBLOCK) == -1) { + serial_close(s); + GSM_OSErrorInfo(s,"fcntl in serial_open"); + return ERR_DEVICEOPENERROR; + } + + return ERR_NONE; +} + +static GSM_Error serial_setparity(GSM_StateMachine *s, bool parity) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + struct termios t; + + if (tcgetattr(d->hPhone, &t)) { + GSM_OSErrorInfo(s,"tcgetattr in serial_setparity"); + return ERR_DEVICEREADERROR; + } + + if (parity) { + t.c_cflag |= (PARENB | PARODD); + t.c_iflag = 0; + } else { + t.c_iflag = IGNPAR; + } + + if (tcsetattr(d->hPhone, TCSANOW, &t) == -1){ + serial_close(s); + GSM_OSErrorInfo(s,"tcsetattr in serial_setparity"); + return ERR_DEVICEPARITYERROR; + } + + return ERR_NONE; +} + +static GSM_Error serial_setdtrrts(GSM_StateMachine *s, bool dtr, bool rts) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + struct termios t; + unsigned int flags; + + if (tcgetattr(d->hPhone, &t)) { + GSM_OSErrorInfo(s,"tcgetattr in serial_setdtrrts"); + return ERR_DEVICEREADERROR; + } + +#ifdef CRTSCTS + /* Disabling hardware flow control */ + t.c_cflag &= ~CRTSCTS; +#endif + + if (tcsetattr(d->hPhone, TCSANOW, &t) == -1) { + serial_close(s); + GSM_OSErrorInfo(s,"tcsetattr in serial_setdtrrts"); + return ERR_DEVICEDTRRTSERROR; + } + + flags = TIOCM_DTR; + if (dtr) { + ioctl(d->hPhone, TIOCMBIS, &flags); + } else { + ioctl(d->hPhone, TIOCMBIC, &flags); + } + + flags = TIOCM_RTS; + if (rts) { + ioctl(d->hPhone, TIOCMBIS, &flags); + } else { + ioctl(d->hPhone, TIOCMBIC, &flags); + } + + flags = 0; + ioctl(d->hPhone, TIOCMGET, &flags); + + dbgprintf("Serial device:"); + dbgprintf(" DTR is %s", flags&TIOCM_DTR?"up":"down"); + dbgprintf(", RTS is %s", flags&TIOCM_RTS?"up":"down"); + dbgprintf(", CAR is %s", flags&TIOCM_CAR?"up":"down"); + dbgprintf(", CTS is %s\n", flags&TIOCM_CTS?"up":"down"); + if (((flags&TIOCM_DTR)==TIOCM_DTR) != dtr) return ERR_DEVICEDTRRTSERROR; + if (((flags&TIOCM_RTS)==TIOCM_RTS) != rts) return ERR_DEVICEDTRRTSERROR; + + return ERR_NONE; +} + +static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + struct termios t; + int speed2 = B19200; + + if (tcgetattr(d->hPhone, &t)) { + GSM_OSErrorInfo(s,"tcgetattr in serial_setspeed"); + return ERR_DEVICEREADERROR; + } + + smprintf(s, "Setting speed to %d\n", speed); + + switch (speed) { + case 50: speed2 = B50; break; + case 75: speed2 = B75; break; + case 110: speed2 = B110; break; + case 134: speed2 = B134; break; + case 150: speed2 = B150; break; + case 200: speed2 = B200; break; + case 300: speed2 = B300; break; + case 600: speed2 = B600; break; + case 1200: speed2 = B1200; break; + case 1800: speed2 = B1800; break; + case 2400: speed2 = B2400; break; + case 4800: speed2 = B4800; break; + case 9600: speed2 = B9600; break; + case 19200: speed2 = B19200; break; + case 38400: speed2 = B38400; break; + case 57600: speed2 = B57600; break; + case 115200: speed2 = B115200; break; + case 230400: speed2 = B230400; break; + case 460800: speed2 = B460800; break; + case 500000: speed2 = B500000; break; + case 576000: speed2 = B576000; break; + case 921600: speed2 = B921600; break; + case 1000000: speed2 = B1000000; break; + case 1152000: speed2 = B1152000; break; + case 1500000: speed2 = B1500000; break; + case 2000000: speed2 = B2000000; break; + case 2500000: speed2 = B2500000; break; + case 3000000: speed2 = B3000000; break; + case 3500000: speed2 = B3500000; break; + case 4000000: speed2 = B4000000; break; + } + + /* This should work on all systems because it is done according to POSIX */ + cfsetispeed(&t, speed2); + cfsetospeed(&t, speed2); + + if (tcsetattr(d->hPhone, TCSADRAIN, &t) == -1) { + serial_close(s); + GSM_OSErrorInfo(s,"tcsetattr in serial_setspeed"); + return ERR_DEVICECHANGESPEEDERROR; + } + + return ERR_NONE; +} + +static int serial_read(GSM_StateMachine *s, void *buf, size_t nbytes) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + struct timeval timeout2; + fd_set readfds; + int actual = 0; + + FD_ZERO(&readfds); + FD_SET(d->hPhone, &readfds); + + timeout2.tv_sec = 0; + timeout2.tv_usec = 1; + + if (select(d->hPhone+1, &readfds, NULL, NULL, &timeout2)) { + actual = read(d->hPhone, buf, nbytes); + if (actual == -1) GSM_OSErrorInfo(s,"serial_read"); + } + return actual; +} + +static int serial_write(GSM_StateMachine *s, void *buf, size_t nbytes) +{ + GSM_Device_SerialData *d = &s->Device.Data.Serial; + int ret; + size_t actual = 0; + + do { + ret = write(d->hPhone, (unsigned char *)buf, nbytes - actual); + if (ret < 0 && errno == EAGAIN) continue; + if (ret < 0) { + if (actual != nbytes) GSM_OSErrorInfo(s,"serial_write"); + return actual; + } + actual += ret; + buf += ret; + if (s->ConnectionType == GCT_FBUS2PL2303) my_sleep(1); + } while (actual < nbytes); + return actual; +} + +GSM_Device_Functions SerialDevice = { + serial_open, + serial_close, + serial_setparity, + serial_setdtrrts, + serial_setspeed, + serial_read, + serial_write +}; + +#endif +#endif +#endif + +/* How should editor hadle tabs in this file? Add editor commands here. + * vim: noexpandtab sw=8 ts=8 sts=8: + */ -- cgit v0.9.0.2