?? gsm_unix_serial.c
字號:
// *************************************************************************
// * GSM TA/ME library
// *
// * File: gsm_unix_port.cc
// *
// * Purpose: UNIX serial port implementation
// *
// * Author: Peter Hofmann (software@pxh.de)
// *
// * Created: 10.5.1999
// *************************************************************************
#ifdef HAVE_CONFIG_H
#include <gsm_config.h>
#endif
#include <gsmlib/gsm_nls.h>
#include <gsmlib/gsm_unix_serial.h>
#include <gsmlib/gsm_util.h>
#include <termios.h>
#include <fcntl.h>
#include <iostream>
#include <strstream>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pthread.h>
using namespace std;
using namespace gsmlib;
static const int holdoff[] = {2000000, 1000000, 400000};
static const int holdoffArraySize = sizeof(holdoff)/sizeof(int);
// alarm handling for socket read/write
// the timerMtx is necessary since several threads cannot use the
// timer indepently of each other
static pthread_mutex_t timerMtx = PTHREAD_MUTEX_INITIALIZER;
// for non-GNU systems, define alarm()
#ifndef HAVE_ALARM
unsigned int alarm(unsigned int seconds)
{
struct itimerval old, newt;
newt.it_interval.tv_usec = 0;
newt.it_interval.tv_sec = 0;
newt.it_value.tv_usec = 0;
newt.it_value.tv_sec = (long int)seconds;
if (setitimer(ITIMER_REAL, &newt, &old) < 0)
return 0;
else
return old.it_value.tv_sec;
}
#endif
// this routine is called in case of a timeout
static void catchAlarm(int)
{
// do nothing
}
// start timer
static void startTimer()
{
pthread_mutex_lock(&timerMtx);
struct sigaction newAction;
newAction.sa_handler = catchAlarm;
newAction.sa_flags = 0;
sigaction(SIGALRM, &newAction, NULL);
alarm(1);
}
// reset timer
static void stopTimer()
{
alarm(0);
sigaction(SIGALRM, NULL, NULL);
pthread_mutex_unlock(&timerMtx);
}
// UnixSerialPort members
void UnixSerialPort::throwModemException(string message) throw(GsmException)
{
ostrstream os;
os << message << " (errno: " << errno << "/" << strerror(errno) << ")"
<< ends;
char *ss = os.str();
string s(ss);
delete[] ss;
throw GsmException(s, OSError, errno);
}
void UnixSerialPort::putBack(char c)
{
assert(_oldChar == -1);
_oldChar = c;
}
int UnixSerialPort::readByte() throw(GsmException)
{
if (_oldChar != -1)
{
int result = _oldChar;
_oldChar = -1;
return result;
}
unsigned char c;
int timeElapsed = 0;
struct timeval oneSecond;
bool readDone = false;
while (! readDone && timeElapsed < _timeoutVal)
{
if (interrupted())
throwModemException(_("interrupted when reading from TA"));
// setup fd_set data structure for select()
fd_set fdSet;
oneSecond.tv_sec = 1;
oneSecond.tv_usec = 0;
FD_ZERO(&fdSet);
FD_SET(_fd, &fdSet);
switch (select(FD_SETSIZE, &fdSet, NULL, NULL, &oneSecond))
{
case 1:
{
int res = read(_fd, &c, 1);
if (res != 1)
return -1;
else
readDone = true;
break;
}
case 0:
++timeElapsed;
break;
default:
if (errno != EINTR)
throwModemException(_("reading from TA"));
break;
}
}
if (! readDone)
throwModemException(_("timeout when reading from TA"));
#ifndef NDEBUG
if (debugLevel() >= 2)
{
// some useful debugging code
if (c == LF)
cerr << "<LF>";
else if (c == CR)
cerr << "<CR>";
else cerr << "<'" << (char) c << "'>";
cerr.flush();
}
#endif
return c;
}
UnixSerialPort::UnixSerialPort(string device, speed_t lineSpeed,
string initString, bool swHandshake)
throw(GsmException) :
_oldChar(-1), _timeoutVal(TIMEOUT_SECS)
{
struct termios t;
// open device
_fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (_fd == -1)
throwModemException(stringPrintf(_("opening device '%s'"),
device.c_str()));
// switch off non-blocking mode
int fdFlags;
if ((fdFlags = fcntl(_fd, F_GETFL)) == -1)
throwModemException(_("getting file status flags failed"));
fdFlags &= ~O_NONBLOCK;
if (fcntl(_fd, F_SETFL, fdFlags) == -1)
throwModemException(_("switching of non-blocking mode failed"));
long int saveTimeoutVal = _timeoutVal;
_timeoutVal = 3;
int initTries = holdoffArraySize;
while (initTries-- > 0)
{
// flush all pending output
tcflush(_fd, TCOFLUSH);
// toggle DTR to reset modem
int mctl = TIOCM_DTR;
if (ioctl(_fd, TIOCMBIC, &mctl) < 0)
throwModemException(_("clearing DTR failed"));
// the waiting time for DTR toggling is increased with each loop
usleep(holdoff[initTries]);
if (ioctl(_fd, TIOCMBIS, &mctl) < 0)
throwModemException(_("setting DTR failed"));
// get line modes
if (tcgetattr(_fd, &t) < 0)
throwModemException(stringPrintf(_("tcgetattr device '%s'"),
device.c_str()));
// set line speed
cfsetispeed(&t, lineSpeed);
cfsetospeed(&t, lineSpeed);
// set the device to a sane state
t.c_iflag |= IGNPAR | (swHandshake ? IXON | IXOFF : 0);
t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL |
(swHandshake ? 0 : IXON | IXOFF)
| IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK);
t.c_oflag &= ~(OPOST);
// be careful, only touch "known" flags
t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD |
(swHandshake ? CRTSCTS : 0 ));
t.c_cflag |= CS8 | CREAD | HUPCL | (swHandshake ? 0 : CRTSCTS) | CLOCAL;
t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL |
ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON);
t.c_lflag |= NOFLSH;
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 0;
t.c_cc[VSUSP] = 0;
// write back
if(tcsetattr (_fd, TCSANOW, &t) < 0)
throwModemException(stringPrintf(_("tcsetattr device '%s'"),
device.c_str()));
// the waiting time for writing to the ME/TA is increased with each loop
usleep(holdoff[initTries]);
// flush all pending input
tcflush(_fd, TCIFLUSH);
try
{
// reset modem
putLine("ATZ");
bool foundOK = false;
int readTries = 5;
while (readTries-- > 0)
{
// for the first call getLine() waits only 3 seconds
// because of _timeoutVal = 3
string s = getLine();
if (s.find("OK") != string::npos ||
s.find("CABLE: GSM") != string::npos)
{
foundOK = true;
readTries = 0; // found OK, exit loop
}
}
// set getLine/putLine timeout back to old value
_timeoutVal = saveTimeoutVal;
if (foundOK)
{
// init modem
readTries = 5;
putLine("AT" + initString);
while (readTries-- > 0)
{
string s = getLine();
if (s.find("OK") != string::npos ||
s.find("CABLE: GSM") != string::npos)
return; // found OK, return
}
}
}
catch (GsmException &e)
{
_timeoutVal = saveTimeoutVal;
if (initTries == 0)
throw e;
}
}
// no response after 3 tries
throw GsmException(stringPrintf(_("reset modem failed '%s'"),
device.c_str()), OtherError);
}
string UnixSerialPort::getLine() throw(GsmException)
{
string result;
int c;
while ((c = readByte()) >= 0)
{
while (c == CR)
{
c = readByte();
}
if (c == LF)
break;
result += c;
}
#ifndef NDEBUG
if (debugLevel() >= 1)
cerr << "<-- " << result << endl;
#endif
return result;
}
void UnixSerialPort::putLine(string line,
bool carriageReturn) throw(GsmException)
{
#ifndef NDEBUG
if (debugLevel() >= 1)
cerr << "--> " << line << endl;
#endif
if (carriageReturn) line += CR;
const char *l = line.c_str();
int timeElapsed = 0;
struct timeval oneSecond;
ssize_t bytesWritten = 0;
while (bytesWritten < (ssize_t)line.length() && timeElapsed < _timeoutVal)
{
if (interrupted())
throwModemException(_("interrupted when writing to TA"));
// setup fd_set data structure for select()
fd_set fdSet;
oneSecond.tv_sec = 1;
oneSecond.tv_usec = 0;
FD_ZERO(&fdSet);
FD_SET(_fd, &fdSet);
switch (select(FD_SETSIZE, NULL, &fdSet, NULL, &oneSecond))
{
case 1:
{
ssize_t bw = write(_fd, l + bytesWritten, line.length() - bytesWritten);
if (bw < 0)
throwModemException(_("writing to TA"));
bytesWritten += bw;
break;
}
case 0:
++timeElapsed;
break;
default:
if (errno != EINTR)
throwModemException(_("writing to TA"));
break;
}
}
while (timeElapsed < _timeoutVal)
{
if (interrupted())
throwModemException(_("interrupted when writing to TA"));
startTimer();
int res = tcdrain(_fd); // wait for output to be read by TA
stopTimer();
if (res == 0)
break;
else
{
assert(errno == EINTR);
++timeElapsed;
}
}
if (timeElapsed >= _timeoutVal)
throwModemException(_("timeout when writing to TA"));
// echo CR LF must be removed by higher layer functions in gsm_at because
// in order to properly handle unsolicited result codes from the ME/TA
}
bool UnixSerialPort::wait(GsmTime timeout) throw(GsmException)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(_fd, &fds);
return select(FD_SETSIZE, &fds, NULL, NULL, timeout) != 0;
}
// set timeout for read or write in seconds.
void UnixSerialPort::setTimeOut(unsigned int timeout)
{
_timeoutVal = timeout;
}
UnixSerialPort::~UnixSerialPort()
{
if (_fd != -1)
close(_fd);
}
speed_t gsmlib::baudRateStrToSpeed(string baudrate) throw(GsmException)
{
if (baudrate == "300")
return B300;
else if (baudrate == "600")
return B600;
else if (baudrate == "1200")
return B1200;
else if (baudrate == "2400")
return B2400;
else if (baudrate == "4800")
return B4800;
else if (baudrate == "9600")
return B9600;
else if (baudrate == "19200")
return B19200;
else if (baudrate == "38400")
return B38400;
#ifdef B57600
else if (baudrate == "57600")
return B57600;
#endif
#ifdef B115200
else if (baudrate == "115200")
return B115200;
#endif
#ifdef B230400
else if (baudrate == "230400")
return B230400;
#endif
#ifdef B460800
else if (baudrate == "460800")
return B460800;
#endif
else
throw GsmException(stringPrintf(_("unknown baudrate '%s'"),
baudrate.c_str()), ParameterError);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -