~ubuntu-branches/debian/jessie/gsmlib/jessie

« back to all changes in this revision

Viewing changes to gsmlib/gsm_unix_serial.cc

  • Committer: Package Import Robot
  • Author(s): Andrew Shadura
  • Date: 2013-10-15 13:29:27 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20131015132927-1i5iwvj21wue3uvu
Tags: 1.10+20120414.gita5e5ae9a-0.1
* Non-maintainer upload.
* Update to the latest Git version by Vianney Bouchaud.
* Use 3.0 (quilt) source package format.
* Own the run subdirectory (Closes: #689891).
* Don't remove the system user on package remove.
* Fix init script (LP: #30228).

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include <termios.h>
20
20
#include <fcntl.h>
21
21
#include <iostream>
22
 
#include <strstream>
 
22
#include <sstream>
23
23
#include <cassert>
24
24
#include <errno.h>
25
25
#include <stdio.h>
29
29
#include <pthread.h>
30
30
#include <cstring>
31
31
 
32
 
using namespace std;
33
32
using namespace gsmlib;
34
33
 
35
34
static const int holdoff[] = {2000000, 1000000, 400000};
36
 
static const int holdoffArraySize = sizeof(holdoff)/sizeof(int);
 
35
static const int holdoffArraySize = sizeof(holdoff) / sizeof(int);
37
36
  
38
37
// alarm handling for socket read/write
39
38
// the timerMtx is necessary since several threads cannot use the
84
83
 
85
84
// UnixSerialPort members
86
85
 
87
 
void UnixSerialPort::throwModemException(string message) throw(GsmException)
 
86
void UnixSerialPort::throwModemException(std::string message) throw(GsmException)
88
87
{
89
 
  ostrstream os;
 
88
  std::ostringstream os;
90
89
  os << message << " (errno: " << errno << "/" << strerror(errno) << ")"
91
 
     << ends;
92
 
  char *ss = os.str();
93
 
  string s(ss);
94
 
  delete[] ss;
95
 
  throw GsmException(s, OSError, errno);
 
90
     << std::ends;
 
91
  throw GsmException(os.str(), OSError, errno);
96
92
}
97
93
 
98
94
void UnixSerialPort::putBack(unsigned char c)
115
111
  struct timeval oneSecond;
116
112
  bool readDone = false;
117
113
 
118
 
  while (! readDone && timeElapsed < _timeoutVal)
 
114
  while (!readDone && timeElapsed < _timeoutVal)
119
115
  {
120
116
    if (interrupted())
121
117
      throwModemException(_("interrupted when reading from TA"));
130
126
    switch (select(FD_SETSIZE, &fdSet, NULL, NULL, &oneSecond))
131
127
    {
132
128
    case 1:
133
 
    {
134
 
      int res = read(_fd, &c, 1);
135
 
      if (res != 1)
136
 
        throwModemException(_("end of file when reading from TA"));
137
 
      else
138
 
        readDone = true;
139
 
      break;
140
 
    }
 
129
      {
 
130
        int res = read(_fd, &c, 1);
 
131
        if (res != 1)
 
132
          throwModemException(_("end of file when reading from TA"));
 
133
        else
 
134
          readDone = true;
 
135
        break;
 
136
      }
141
137
    case 0:
142
138
      ++timeElapsed;
143
139
      break;
147
143
      break;
148
144
    }
149
145
  }
150
 
  if (! readDone)
 
146
  if (!readDone)
151
147
    throwModemException(_("timeout when reading from TA"));
152
148
 
153
149
#ifndef NDEBUG
155
151
  {
156
152
    // some useful debugging code
157
153
    if (c == LF)
158
 
      cerr << "<LF>";
 
154
      std::cerr << "<LF>";
159
155
    else if (c == CR)
160
 
      cerr << "<CR>";
161
 
    else cerr << "<'" << (char) c << "'>";
162
 
    cerr.flush();
 
156
      std::cerr << "<CR>";
 
157
    else
 
158
      std::cerr << "<'" << (char) c << "'>";
 
159
    std::cerr.flush();
163
160
  }
164
161
#endif
165
162
  return c;
166
163
}
167
164
 
168
 
UnixSerialPort::UnixSerialPort(string device, speed_t lineSpeed,
169
 
                               string initString, bool swHandshake)
 
165
UnixSerialPort::UnixSerialPort(std::string device, speed_t lineSpeed,
 
166
                                       std::string initString, bool swHandshake)
170
167
  throw(GsmException) :
171
168
  _oldChar(-1), _timeoutVal(TIMEOUT_SECS)
172
169
{
180
177
 
181
178
  // switch off non-blocking mode
182
179
  int fdFlags;
183
 
  if ((fdFlags = fcntl(_fd, F_GETFL)) == -1) {
184
 
    close(_fd);
185
 
    throwModemException(_("getting file status flags failed"));
186
 
  }
 
180
  if ((fdFlags = fcntl(_fd, F_GETFL)) == -1)
 
181
    {
 
182
      close(_fd);
 
183
      throwModemException(_("getting file status flags failed"));
 
184
    }
187
185
  fdFlags &= ~O_NONBLOCK;
188
 
  if (fcntl(_fd, F_SETFL, fdFlags) == -1) {
189
 
    close(_fd);
190
 
    throwModemException(_("switching of non-blocking mode failed"));
191
 
  }
 
186
  if (fcntl(_fd, F_SETFL, fdFlags) == -1)
 
187
    {
 
188
      close(_fd);
 
189
      throwModemException(_("switching of non-blocking mode failed"));
 
190
    }
192
191
 
193
192
  long int saveTimeoutVal = _timeoutVal;
194
193
  _timeoutVal = 3;
195
194
  int initTries = holdoffArraySize;
196
195
  while (initTries-- > 0)
197
 
  {
198
 
    // flush all pending output
199
 
    tcflush(_fd, TCOFLUSH);
200
 
 
201
 
    // toggle DTR to reset modem
202
 
    int mctl = TIOCM_DTR;
203
 
    if (ioctl(_fd, TIOCMBIC, &mctl) < 0) {
204
 
      close(_fd);
205
 
      throwModemException(_("clearing DTR failed"));
206
 
    }
207
 
    // the waiting time for DTR toggling is increased with each loop
208
 
    usleep(holdoff[initTries]);
209
 
    if (ioctl(_fd, TIOCMBIS, &mctl) < 0) {
210
 
      close(_fd);
211
 
      throwModemException(_("setting DTR failed"));
212
 
    }
213
 
    // get line modes
214
 
    if (tcgetattr(_fd, &t) < 0) {
215
 
      close(_fd);
216
 
      throwModemException(stringPrintf(_("tcgetattr device '%s'"),
217
 
                                       device.c_str()));
218
 
    }
219
 
 
220
 
    // set line speed
221
 
    cfsetispeed(&t, lineSpeed);
222
 
    cfsetospeed(&t, lineSpeed);
223
 
 
224
 
    // set the device to a sane state
225
 
    t.c_iflag |= IGNPAR | (swHandshake ? IXON | IXOFF : 0);
226
 
    t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL |
227
 
                   (swHandshake ? 0 : IXON |  IXOFF)
228
 
                   | IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK);
229
 
    t.c_oflag &= ~(OPOST);
230
 
    // be careful, only touch "known" flags
231
 
    t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD |
232
 
                  (swHandshake ? CRTSCTS : 0 ));
233
 
    t.c_cflag |= CS8 | CREAD | HUPCL | (swHandshake ? 0 : CRTSCTS) | CLOCAL;
234
 
    t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL |
235
 
                   ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON);
236
 
    t.c_lflag |= NOFLSH;
237
 
    t.c_cc[VMIN] = 1;
238
 
    t.c_cc[VTIME] = 0;
239
 
 
240
 
    t.c_cc[VSUSP] = 0;
241
 
 
242
 
    // write back
243
 
    if(tcsetattr (_fd, TCSANOW, &t) < 0) {
244
 
      close(_fd);
245
 
      throwModemException(stringPrintf(_("tcsetattr device '%s'"),
246
 
                                       device.c_str()));
247
 
    }
248
 
    // the waiting time for writing to the ME/TA is increased with each loop
249
 
    usleep(holdoff[initTries]);
250
 
 
251
 
    // flush all pending input
252
 
    tcflush(_fd, TCIFLUSH);
253
 
 
254
 
    try
255
 
    {
256
 
      // reset modem
257
 
      putLine("ATZ");
258
 
      bool foundOK = false;
259
 
      int readTries = 5;
260
 
      while (readTries-- > 0)
261
 
      {
262
 
        // for the first call getLine() waits only 3 seconds
263
 
        // because of _timeoutVal = 3
264
 
        string s = getLine();
265
 
        if (s.find("OK") != string::npos ||
266
 
            s.find("CABLE: GSM") != string::npos)
267
 
        {
268
 
          foundOK = true;
269
 
          readTries = 0;        // found OK, exit loop
270
 
        }
271
 
        else if (s.find("ERROR") != string::npos)
272
 
          readTries = 0;        // error, exit loop
273
 
      }
274
 
 
275
 
      // set getLine/putLine timeout back to old value
276
 
      _timeoutVal = saveTimeoutVal;
277
 
 
278
 
      if (foundOK)
279
 
      {
280
 
        // init modem
281
 
        readTries = 5;
282
 
        putLine("AT" + initString);
283
 
        while (readTries-- > 0)
284
 
        {
285
 
          string s = getLine();
286
 
          if (s.find("OK") != string::npos ||
287
 
              s.find("CABLE: GSM") != string::npos)
288
 
            return;                 // found OK, return
289
 
        }
290
 
      }
291
 
    }
292
 
    catch (GsmException &e)
293
 
    {
294
 
      _timeoutVal = saveTimeoutVal;
295
 
      if (initTries == 0) {
296
 
        close(_fd);
297
 
        throw e;
298
 
      }
299
 
    }
300
 
  }
 
196
    {
 
197
      // flush all pending output
 
198
      tcflush(_fd, TCOFLUSH);
 
199
      
 
200
      // toggle DTR to reset modem
 
201
      int mctl = TIOCM_DTR;
 
202
      if (ioctl(_fd, TIOCMBIC, &mctl) < 0) {
 
203
        close(_fd);
 
204
        throwModemException(_("clearing DTR failed"));
 
205
      }
 
206
      // the waiting time for DTR toggling is increased with each loop
 
207
      usleep(holdoff[initTries]);
 
208
      if (ioctl(_fd, TIOCMBIS, &mctl) < 0) {
 
209
        close(_fd);
 
210
        throwModemException(_("setting DTR failed"));
 
211
      }
 
212
      // get line modes
 
213
      if (tcgetattr(_fd, &t) < 0) {
 
214
        close(_fd);
 
215
        throwModemException(stringPrintf(_("tcgetattr device '%s'"),
 
216
                                         device.c_str()));
 
217
      }
 
218
      
 
219
      // set line speed
 
220
      cfsetispeed(&t, lineSpeed);
 
221
      cfsetospeed(&t, lineSpeed);
 
222
      
 
223
      // set the device to a sane state
 
224
      t.c_iflag |= IGNPAR | (swHandshake ? IXON | IXOFF : 0);
 
225
      t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL |
 
226
                     (swHandshake ? 0 : IXON |  IXOFF)
 
227
                     | IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK);
 
228
      t.c_oflag &= ~(OPOST);
 
229
      // be careful, only touch "known" flags
 
230
      t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD |
 
231
                     (swHandshake ? CRTSCTS : 0 ));
 
232
      t.c_cflag |= CS8 | CREAD | HUPCL | (swHandshake ? 0 : CRTSCTS) | CLOCAL;
 
233
      t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL |
 
234
                     ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON);
 
235
      t.c_lflag |= NOFLSH;
 
236
      t.c_cc[VMIN] = 1;
 
237
      t.c_cc[VTIME] = 0;
 
238
      
 
239
      t.c_cc[VSUSP] = 0;
 
240
      
 
241
      // write back
 
242
      if(tcsetattr (_fd, TCSANOW, &t) < 0)
 
243
        {
 
244
          close(_fd);
 
245
          throwModemException(stringPrintf(_("tcsetattr device '%s'"),
 
246
                                           device.c_str()));
 
247
        }
 
248
      // the waiting time for writing to the ME/TA is increased with each loop
 
249
      usleep(holdoff[initTries]);
 
250
      
 
251
      // flush all pending input
 
252
      tcflush(_fd, TCIFLUSH);
 
253
      
 
254
      try
 
255
        {
 
256
          // reset modem
 
257
          putLine("ATZ");
 
258
          bool foundOK = false;
 
259
          int readTries = 5;
 
260
          while (readTries-- > 0)
 
261
            {
 
262
              // for the first call getLine() waits only 3 seconds
 
263
              // because of _timeoutVal = 3
 
264
              std::string s = getLine();
 
265
              if (s.find("OK") != std::string::npos ||
 
266
                  s.find("CABLE: GSM") != std::string::npos)
 
267
                {
 
268
                  foundOK = true;
 
269
                  readTries = 0;        // found OK, exit loop
 
270
                }
 
271
              else if (s.find("ERROR") != std::string::npos)
 
272
                readTries = 0;        // error, exit loop
 
273
            }
 
274
          
 
275
          // set getLine/putLine timeout back to old value
 
276
          _timeoutVal = saveTimeoutVal;
 
277
          
 
278
          if (foundOK)
 
279
            {
 
280
              // init modem
 
281
              readTries = 5;
 
282
              putLine("AT" + initString);
 
283
              while (readTries-- > 0)
 
284
                {
 
285
                  std::string s = getLine();
 
286
                  if (s.find("OK") != std::string::npos ||
 
287
                      s.find("CABLE: GSM") != std::string::npos)
 
288
                    return;                 // found OK, return
 
289
                }
 
290
            }
 
291
        }
 
292
      catch (GsmException &e)
 
293
        {
 
294
          _timeoutVal = saveTimeoutVal;
 
295
          if (initTries == 0) {
 
296
            close(_fd);
 
297
            throw e;
 
298
          }
 
299
        }
 
300
    }
301
301
  // no response after 3 tries
302
302
  close(_fd);
303
303
  throw GsmException(stringPrintf(_("reset modem failed '%s'"),
304
304
                                  device.c_str()), OtherError);
305
305
}
306
306
 
307
 
string UnixSerialPort::getLine() throw(GsmException)
 
307
std::string UnixSerialPort::getLine() throw(GsmException)
308
308
{
309
 
  string result;
 
309
  std::string result;
310
310
  int c;
311
311
  while ((c = readByte()) >= 0)
312
312
  {
313
313
    while (c == CR)
314
 
    {
315
314
      c = readByte();
316
 
    }
317
315
    if (c == LF)
318
316
      break;
319
317
    result += c;
321
319
 
322
320
#ifndef NDEBUG
323
321
  if (debugLevel() >= 1)
324
 
    cerr << "<-- " << result << endl;
 
322
    std::cerr << "<-- " << result << std::endl;
325
323
#endif
326
324
 
327
325
  return result;
328
326
}
329
327
 
330
 
void UnixSerialPort::putLine(string line,
331
 
                             bool carriageReturn) throw(GsmException)
 
328
void UnixSerialPort::putLine(std::string line, bool carriageReturn)
 
329
  throw(GsmException)
332
330
{
333
331
#ifndef NDEBUG
334
332
  if (debugLevel() >= 1)
335
 
    cerr << "--> " << line << endl;
 
333
    std::cerr << "--> " << line << std::endl;
336
334
#endif
337
335
 
338
336
  if (carriageReturn) line += CR;
355
353
    FD_SET(_fd, &fdSet);
356
354
 
357
355
    switch (select(FD_SETSIZE, NULL, &fdSet, NULL, &oneSecond))
358
 
    {
359
 
    case 1:
360
 
    {
361
 
      ssize_t bw = write(_fd, l + bytesWritten, line.length() - bytesWritten);
362
 
      if (bw < 0)
363
 
        throwModemException(_("writing to TA"));
364
 
      bytesWritten += bw;
365
 
      break;
366
 
    }
367
 
    case 0:
368
 
      ++timeElapsed;
369
 
      break;
370
 
    default:
371
 
      if (errno != EINTR)
372
 
        throwModemException(_("writing to TA"));
373
 
      break;
374
 
    }
 
356
      {
 
357
      case 1:
 
358
        {
 
359
          ssize_t bw = write(_fd, l + bytesWritten, line.length() - bytesWritten);
 
360
          if (bw < 0)
 
361
            throwModemException(_("writing to TA"));
 
362
          bytesWritten += bw;
 
363
          break;
 
364
        }
 
365
      case 0:
 
366
        ++timeElapsed;
 
367
        break;
 
368
      default:
 
369
        if (errno != EINTR)
 
370
          throwModemException(_("writing to TA"));
 
371
        break;
 
372
      }
375
373
  }
376
374
  
377
375
  while (timeElapsed < _timeoutVal)
416
414
    close(_fd);
417
415
}
418
416
 
419
 
speed_t gsmlib::baudRateStrToSpeed(string baudrate) throw(GsmException)
 
417
speed_t gsmlib::baudRateStrToSpeed(std::string baudrate) throw(GsmException)
420
418
{
421
419
  if (baudrate == "300")
422
420
    return B300;