~ubuntu-branches/debian/sid/gsmlib/sid

« back to all changes in this revision

Viewing changes to gsmlib/gsm_win32_serial.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mikael Hedin
  • Date: 2002-01-24 12:59:07 UTC
  • Revision ID: james.westby@ubuntu.com-20020124125907-b7qkpokx5283jdpu
Tags: upstream-1.8
ImportĀ upstreamĀ versionĀ 1.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// *************************************************************************
 
2
// * GSM TA/ME library
 
3
// *
 
4
// * File:    gsm_win32_port.cc
 
5
// *
 
6
// * Purpose: WIN32 serial port implementation
 
7
// *
 
8
// * Author:  Frediano Ziglio (freddy77@angelfire.com)
 
9
// *
 
10
// * Created: 25.10.2000
 
11
// *************************************************************************
 
12
 
 
13
#ifdef HAVE_CONFIG_H
 
14
#include <gsm_config.h>
 
15
#endif
 
16
#include <winsock.h>
 
17
#include <gsmlib/gsm_nls.h>
 
18
#include <gsmlib/gsm_win32_serial.h>
 
19
#include <gsmlib/gsm_util.h>
 
20
#include <fcntl.h>
 
21
#include <iostream>
 
22
#include <strstream>
 
23
#include <errno.h>
 
24
#include <stdio.h>
 
25
#include <assert.h>
 
26
#include <signal.h>
 
27
 
 
28
using namespace std;
 
29
using namespace gsmlib;
 
30
 
 
31
static long int timeoutVal = TIMEOUT_SECS;
 
32
 
 
33
struct ExceptionSafeOverlapped: public OVERLAPPED
 
34
{
 
35
  ExceptionSafeOverlapped()
 
36
  {
 
37
    memset((OVERLAPPED*)this,0,sizeof(OVERLAPPED));
 
38
    hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 
 
39
    if (hEvent == INVALID_HANDLE_VALUE) 
 
40
      throw GsmException(_("error creating event"),OSError,GetLastError());
 
41
  }
 
42
  ~ExceptionSafeOverlapped()
 
43
  { CloseHandle(hEvent); }
 
44
};
 
45
 
 
46
typedef BOOL (WINAPI *TCancelIoProc)(HANDLE file);
 
47
TCancelIoProc CancelIoProc = NULL;
 
48
BOOL CancelIoHook(HANDLE file)
 
49
{
 
50
  if (CancelIoProc)
 
51
    return CancelIoProc(file);
 
52
 
 
53
  HMODULE hmodule = GetModuleHandle("KERNEL32");
 
54
  if (hmodule)
 
55
  {
 
56
    CancelIoProc = (TCancelIoProc)GetProcAddress(hmodule,"CancelIo");
 
57
    if (CancelIoProc)
 
58
      return CancelIoProc(file);
 
59
  }
 
60
                         
 
61
  return TRUE;
 
62
}
 
63
#define CancelIo CancelIoHook
 
64
 
 
65
// Win32SerialPort members
 
66
 
 
67
void Win32SerialPort::throwModemException(string message) throw(GsmException)
 
68
{
 
69
  ostrstream os;
 
70
  os << message << " (errno: " << errno << "/" << strerror(errno) << ")"
 
71
     << ends;
 
72
  char *ss = os.str();
 
73
  string s(ss);
 
74
  delete[] ss;
 
75
  throw GsmException(s, OSError, errno);
 
76
}
 
77
 
 
78
void Win32SerialPort::putBack(char c)
 
79
{
 
80
  assert(_oldChar == -1);
 
81
  _oldChar = c;
 
82
}
 
83
 
 
84
int Win32SerialPort::readByte() throw(GsmException)
 
85
{
 
86
  if (_oldChar != -1)
 
87
  {
 
88
    int result = _oldChar;
 
89
    _oldChar = -1;
 
90
    return result;
 
91
  }
 
92
 
 
93
  char c;
 
94
  int timeElapsed = 0;
 
95
  bool readDone = true;
 
96
  ExceptionSafeOverlapped  over;
 
97
 
 
98
  DWORD initTime = GetTickCount();
 
99
  DWORD dwReaded;
 
100
  if (!ReadFile(_file,&c,1,&dwReaded,&over))
 
101
  {
 
102
    readDone = false;
 
103
    if (GetLastError() != ERROR_IO_PENDING)
 
104
    {
 
105
      throwModemException(_("reading from TA"));
 
106
    }
 
107
 
 
108
    while(!readDone)
 
109
    {
 
110
      if (interrupted())
 
111
        throwModemException(_("interrupted when reading from TA"));
 
112
 
 
113
      // wait another second
 
114
      switch(WaitForSingleObject(over.hEvent,1000))
 
115
      {
 
116
      case WAIT_TIMEOUT:
 
117
        break;
 
118
      case WAIT_OBJECT_0:
 
119
      case WAIT_ABANDONED:
 
120
              // !!! do a infinite loop if (bytesWritten < lenght) ?
 
121
        GetOverlappedResult(_file,&over,&dwReaded,TRUE);
 
122
        readDone = true;
 
123
        break;
 
124
      case WAIT_FAILED:
 
125
        throwModemException(_("reading from TA"));
 
126
      }
 
127
 
 
128
      timeElapsed = (GetTickCount() - initTime)/1000U;
 
129
 
 
130
      // timeout elapsed ?
 
131
      if (timeElapsed >= timeoutVal)
 
132
      {
 
133
        CancelIo(_file);
 
134
        break;
 
135
      }
 
136
 
 
137
    }
 
138
  }
 
139
  
 
140
  if (! readDone)
 
141
    throwModemException(_("timeout when reading from TA"));
 
142
 
 
143
#ifndef NDEBUG
 
144
  if (debugLevel() >= 2)
 
145
  {
 
146
    // some useful debugging code
 
147
    if (c == LF)
 
148
      cerr << "<LF>";
 
149
    else if (c == CR)
 
150
      cerr << "<CR>";
 
151
    else cerr << "<'" << (char) c << "'>";
 
152
    cerr.flush();
 
153
  }
 
154
#endif
 
155
  return c;
 
156
}
 
157
 
 
158
Win32SerialPort::Win32SerialPort(string device, int lineSpeed,
 
159
                               string initString, bool swHandshake)
 
160
  throw(GsmException) :
 
161
  _oldChar(-1)
 
162
{
 
163
  int holdoff[] = {2000, 1000, 400};
 
164
 
 
165
  // open device
 
166
  _file = CreateFile(device.c_str(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
 
167
  if (_file == INVALID_HANDLE_VALUE)
 
168
    throwModemException(stringPrintf(_("opening device '%s'"),
 
169
                                     device.c_str()));
 
170
 
 
171
  int initTries = 3;
 
172
  while (initTries-- > 0)
 
173
  {
 
174
    // flush all pending output
 
175
    FlushFileBuffers(_file);
 
176
 
 
177
    // toggle DTR to reset modem
 
178
    if (!EscapeCommFunction(_file,CLRDTR))
 
179
      throwModemException(_("clearing DTR failed"));
 
180
    Sleep(holdoff[initTries]);
 
181
    if (!EscapeCommFunction(_file,SETDTR))
 
182
      throwModemException(_("setting DTR failed"));
 
183
 
 
184
    DCB dcb;
 
185
    // get line modes
 
186
    if (!GetCommState(_file,&dcb))
 
187
      throwModemException(stringPrintf(_("GetCommState device '%s'"),
 
188
                                       device.c_str()));
 
189
 
 
190
//    if (tcgetattr(_fd, &t) < 0)
 
191
//      throwModemException(stringPrintf(_("tcgetattr device '%s'"),
 
192
//                                       device.c_str()));
 
193
 
 
194
    // set the device to a sane state
 
195
    dcb.fBinary = TRUE;
 
196
    dcb.BaudRate = lineSpeed;
 
197
 
 
198
    // n,8,1
 
199
    dcb.fParity = FALSE;
 
200
    dcb.Parity = 0;
 
201
    dcb.ByteSize = 8;
 
202
    dcb.StopBits = 0;
 
203
 
 
204
    if (!swHandshake)
 
205
    {
 
206
      dcb.fInX = FALSE;
 
207
      dcb.fOutX = FALSE;
 
208
      dcb.fOutxDsrFlow = FALSE;
 
209
      dcb.fOutxCtsFlow = FALSE;
 
210
    }
 
211
    else
 
212
    {
 
213
      dcb.fInX  = TRUE;
 
214
      dcb.fOutX = TRUE;
 
215
      dcb.fOutxDsrFlow = FALSE;
 
216
      dcb.fOutxCtsFlow = FALSE;
 
217
    }
 
218
    dcb.fDtrControl = DTR_CONTROL_ENABLE;
 
219
    dcb.fRtsControl = RTS_CONTROL_ENABLE;
 
220
    
 
221
//    t.c_iflag |= IGNPAR;
 
222
//    t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL |
 
223
//                   (swHandshake ? CRTSCTS : IXON |  IXOFF)
 
224
//                   | IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK);
 
225
//    t.c_oflag &= ~(OPOST);
 
226
//    // be careful, only touch "known" flags
 
227
//    t.c_cflag&= ~(CSIZE | CSTOPB | PARENB | PARODD);
 
228
//    t.c_cflag|= CS8 | CREAD | HUPCL |
 
229
//      (swHandshake ? IXON |  IXOFF : CRTSCTS) |
 
230
//      CLOCAL;
 
231
//    t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL |
 
232
//                   ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON);
 
233
//    t.c_lflag |= NOFLSH;
 
234
//
 
235
//    t.c_cc[VMIN] = 1;
 
236
//    t.c_cc[VTIME] = 0;
 
237
//
 
238
//    t.c_cc[VSUSP] = 0;
 
239
 
 
240
    // write back
 
241
    if (!SetCommState(_file,&dcb))
 
242
      throwModemException(stringPrintf(_("SetCommState device '%s'"),
 
243
                                       device.c_str()));
 
244
 
 
245
    Sleep(holdoff[initTries]);
 
246
 
 
247
    if (!SetupComm(_file,1024,1024))
 
248
      throwModemException(stringPrintf(_("SetupComm device '%s'"),
 
249
                                       device.c_str()));
 
250
 
 
251
 
 
252
    // flush all pending input
 
253
    PurgeComm(_file,PURGE_RXABORT|PURGE_RXCLEAR);
 
254
 
 
255
    try
 
256
    {
 
257
      // reset modem
 
258
      putLine("ATZ");
 
259
      bool foundOK = false;
 
260
      int readTries = 5;
 
261
      while (readTries-- > 0)
 
262
      {
 
263
        string s = getLine();
 
264
        if (s.find("OK") != string::npos ||
 
265
            s.find("CABLE: GSM") != string::npos)
 
266
        {
 
267
          foundOK = true;
 
268
          readTries = 0;           // found OK, exit loop
 
269
        }
 
270
      }
 
271
 
 
272
      if (foundOK)
 
273
      {
 
274
        // init modem
 
275
        readTries = 5;
 
276
        // !!! no not declare this in loop, compiler error on Visual C++
 
277
        // (without SP and with SP4)
 
278
        string s; 
 
279
        putLine("AT" + initString);
 
280
        do
 
281
        {
 
282
          s = getLine();
 
283
          if (s.find("OK") != string::npos ||
 
284
              s.find("CABLE: GSM") != string::npos)
 
285
            return;                 // found OK, return
 
286
        } while(--readTries);
 
287
      }
 
288
    }
 
289
    catch (GsmException &e)
 
290
    {
 
291
      if (initTries == 0)
 
292
        throw e;
 
293
    }
 
294
  }
 
295
  // no response after 3 tries
 
296
  throw GsmException(stringPrintf(_("reset modem failed '%s'"),
 
297
                                  device.c_str()), OtherError);
 
298
}
 
299
 
 
300
string Win32SerialPort::getLine() throw(GsmException)
 
301
{
 
302
  string result;
 
303
  int c;
 
304
  while ((c = readByte()) > 0)
 
305
  {
 
306
    while (c == CR)
 
307
    {
 
308
      c = readByte();
 
309
    }
 
310
    if (c == LF)
 
311
      break;
 
312
    result += c;
 
313
  }
 
314
 
 
315
#ifndef NDEBUG
 
316
  if (debugLevel() >= 1)
 
317
    cerr << "<-- " << result << endl;
 
318
#endif
 
319
 
 
320
  return result;
 
321
}
 
322
 
 
323
void Win32SerialPort::putLine(string line,
 
324
                             bool carriageReturn) throw(GsmException)
 
325
{
 
326
#ifndef NDEBUG
 
327
  if (debugLevel() >= 1)
 
328
    cerr << "--> " << line << endl;
 
329
#endif
 
330
 
 
331
  if (carriageReturn) line += CR;
 
332
  // !!! BUG, mantain this pointer isn't corrent, use iterator !!!
 
333
  const char *l = line.c_str();
 
334
  
 
335
  FlushFileBuffers(_file);      // flush all pending input and output
 
336
 
 
337
  int timeElapsed = 0;
 
338
 
 
339
  DWORD bytesWritten = 0;
 
340
 
 
341
  ExceptionSafeOverlapped over;
 
342
 
 
343
  DWORD initTime = GetTickCount();
 
344
  if (!WriteFile(_file,l,line.length(),&bytesWritten,&over))
 
345
  {
 
346
    if (GetLastError() != ERROR_IO_PENDING)
 
347
    {
 
348
      throwModemException(_("writing to TA"));
 
349
    }
 
350
 
 
351
    while(bytesWritten < (DWORD)line.length())
 
352
    {
 
353
      if (interrupted())
 
354
        throwModemException(_("interrupted when writing to TA"));
 
355
 
 
356
      // wait another second
 
357
      switch(WaitForSingleObject(over.hEvent,1000))
 
358
      {
 
359
      case WAIT_TIMEOUT:
 
360
        break;
 
361
      case WAIT_OBJECT_0:
 
362
      case WAIT_ABANDONED:
 
363
        // !!! do a infinite loop if (bytesWritten < lenght) ?
 
364
        GetOverlappedResult(_file,&over,&bytesWritten,TRUE);
 
365
        break;
 
366
      case WAIT_FAILED:
 
367
        throwModemException(_("writing to TA"));
 
368
      }
 
369
 
 
370
      timeElapsed = (GetTickCount() - initTime)/1000U;
 
371
 
 
372
      // timeout elapsed ?
 
373
      if (timeElapsed >= timeoutVal)
 
374
      {
 
375
        CancelIo(_file);
 
376
        throwModemException(_("timeout when writing to TA"));
 
377
      }
 
378
 
 
379
    }
 
380
  }
 
381
 
 
382
  return;
 
383
/*
 
384
  // empty buffer
 
385
  SetCommMask(_file,EV_TXEMPTY);
 
386
  DWORD dwEvent;
 
387
  ResetEvent(over.hEvent);
 
388
  if( WaitCommEvent(_file,&dwEvent,&over) )
 
389
    return; // already empty
 
390
 
 
391
  // check true errors
 
392
  if (GetLastError() != ERROR_IO_PENDING)
 
393
    throwModemException(_("error comm waiting"));
 
394
 
 
395
  while(timeElapsed < timeoutVal)
 
396
  {
 
397
    if (interrupted())
 
398
      throwModemException(_("interrupted when flushing to TA"));
 
399
 
 
400
    switch( WaitForSingleObject( over.hEvent, 1000 ) ) 
 
401
    {
 
402
    case WAIT_TIMEOUT:
 
403
      break;
 
404
 
 
405
    // successfully flushed
 
406
    case WAIT_ABANDONED:
 
407
    case WAIT_OBJECT_0:
 
408
      return;
 
409
 
 
410
    default:
 
411
      throwModemException(_("error waiting"));
 
412
    }
 
413
    timeElapsed = (GetTickCount() - initTime)/1000U;
 
414
  }
 
415
 
 
416
  CancelIo(_file);
 
417
  throwModemException(_("timeout when writing to TA"));
 
418
*/
 
419
 
 
420
  // echo CR LF must be removed by higher layer functions in gsm_at because
 
421
  // in order to properly handle unsolicited result codes from the ME/TA
 
422
}
 
423
 
 
424
bool Win32SerialPort::wait(GsmTime timeout) throw(GsmException)
 
425
{
 
426
  // See differences from UNIX
 
427
  // Why do I use Windows ?
 
428
  ExceptionSafeOverlapped over;
 
429
 
 
430
  SetCommMask(_file,EV_RXCHAR);
 
431
  DWORD dwEvent;
 
432
  if( !WaitCommEvent(_file,&dwEvent,&over) )
 
433
  {
 
434
    // check true errors
 
435
    if (GetLastError() != ERROR_IO_PENDING)
 
436
      throwModemException(_("error comm waiting"));
 
437
 
 
438
    switch( WaitForSingleObject( over.hEvent, timeout->tv_sec*1000U+timeout->tv_usec ) ) 
 
439
    {
 
440
    case WAIT_TIMEOUT:
 
441
      CancelIo(_file);
 
442
      return false;
 
443
 
 
444
    case WAIT_ABANDONED:
 
445
    case WAIT_OBJECT_0:
 
446
      return true;
 
447
 
 
448
    default:
 
449
      throwModemException(_("error waiting"));
 
450
    }
 
451
  }
 
452
 
 
453
  return true;
 
454
}
 
455
 
 
456
void Win32SerialPort::setTimeOut(unsigned int timeout)
 
457
{
 
458
  timeoutVal = timeout;
 
459
}
 
460
 
 
461
Win32SerialPort::~Win32SerialPort()
 
462
{
 
463
  if ( _file != INVALID_HANDLE_VALUE)
 
464
    CloseHandle(_file);
 
465
}
 
466
 
 
467
int gsmlib::baudRateStrToSpeed(string baudrate) throw(GsmException)
 
468
{
 
469
  if (baudrate == "300")
 
470
    return 300;
 
471
  else if (baudrate == "600")
 
472
    return 600;
 
473
  else if (baudrate == "1200")
 
474
    return 1200;
 
475
  else if (baudrate == "2400")
 
476
    return 2400;
 
477
  else if (baudrate == "4800")
 
478
    return 4800;
 
479
  else if (baudrate == "9600")
 
480
    return 9600;
 
481
  else if (baudrate == "19200")
 
482
    return 19200;
 
483
  else if (baudrate == "38400")
 
484
    return 38400;
 
485
  else if (baudrate == "57600")
 
486
    return 57600;
 
487
  else if (baudrate == "115200")
 
488
    return 115200;
 
489
  else
 
490
    throw GsmException(stringPrintf(_("unknown baudrate '%s'"),
 
491
                                    baudrate.c_str()), ParameterError);
 
492
}