1
// *************************************************************************
4
// * File: gsm_win32_port.cc
6
// * Purpose: WIN32 serial port implementation
8
// * Author: Frediano Ziglio (freddy77@angelfire.com)
10
// * Created: 25.10.2000
11
// *************************************************************************
14
#include <gsm_config.h>
17
#include <gsmlib/gsm_nls.h>
18
#include <gsmlib/gsm_win32_serial.h>
19
#include <gsmlib/gsm_util.h>
29
using namespace gsmlib;
31
static long int timeoutVal = TIMEOUT_SECS;
33
struct ExceptionSafeOverlapped: public OVERLAPPED
35
ExceptionSafeOverlapped()
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());
42
~ExceptionSafeOverlapped()
43
{ CloseHandle(hEvent); }
46
typedef BOOL (WINAPI *TCancelIoProc)(HANDLE file);
47
TCancelIoProc CancelIoProc = NULL;
48
BOOL CancelIoHook(HANDLE file)
51
return CancelIoProc(file);
53
HMODULE hmodule = GetModuleHandle("KERNEL32");
56
CancelIoProc = (TCancelIoProc)GetProcAddress(hmodule,"CancelIo");
58
return CancelIoProc(file);
63
#define CancelIo CancelIoHook
65
// Win32SerialPort members
67
void Win32SerialPort::throwModemException(string message) throw(GsmException)
70
os << message << " (errno: " << errno << "/" << strerror(errno) << ")"
75
throw GsmException(s, OSError, errno);
78
void Win32SerialPort::putBack(char c)
80
assert(_oldChar == -1);
84
int Win32SerialPort::readByte() throw(GsmException)
88
int result = _oldChar;
96
ExceptionSafeOverlapped over;
98
DWORD initTime = GetTickCount();
100
if (!ReadFile(_file,&c,1,&dwReaded,&over))
103
if (GetLastError() != ERROR_IO_PENDING)
105
throwModemException(_("reading from TA"));
111
throwModemException(_("interrupted when reading from TA"));
113
// wait another second
114
switch(WaitForSingleObject(over.hEvent,1000))
120
// !!! do a infinite loop if (bytesWritten < lenght) ?
121
GetOverlappedResult(_file,&over,&dwReaded,TRUE);
125
throwModemException(_("reading from TA"));
128
timeElapsed = (GetTickCount() - initTime)/1000U;
131
if (timeElapsed >= timeoutVal)
141
throwModemException(_("timeout when reading from TA"));
144
if (debugLevel() >= 2)
146
// some useful debugging code
151
else cerr << "<'" << (char) c << "'>";
158
Win32SerialPort::Win32SerialPort(string device, int lineSpeed,
159
string initString, bool swHandshake)
160
throw(GsmException) :
163
int holdoff[] = {2000, 1000, 400};
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'"),
172
while (initTries-- > 0)
174
// flush all pending output
175
FlushFileBuffers(_file);
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"));
186
if (!GetCommState(_file,&dcb))
187
throwModemException(stringPrintf(_("GetCommState device '%s'"),
190
// if (tcgetattr(_fd, &t) < 0)
191
// throwModemException(stringPrintf(_("tcgetattr device '%s'"),
194
// set the device to a sane state
196
dcb.BaudRate = lineSpeed;
208
dcb.fOutxDsrFlow = FALSE;
209
dcb.fOutxCtsFlow = FALSE;
215
dcb.fOutxDsrFlow = FALSE;
216
dcb.fOutxCtsFlow = FALSE;
218
dcb.fDtrControl = DTR_CONTROL_ENABLE;
219
dcb.fRtsControl = RTS_CONTROL_ENABLE;
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) |
231
// t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL |
232
// ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON);
233
// t.c_lflag |= NOFLSH;
236
// t.c_cc[VTIME] = 0;
238
// t.c_cc[VSUSP] = 0;
241
if (!SetCommState(_file,&dcb))
242
throwModemException(stringPrintf(_("SetCommState device '%s'"),
245
Sleep(holdoff[initTries]);
247
if (!SetupComm(_file,1024,1024))
248
throwModemException(stringPrintf(_("SetupComm device '%s'"),
252
// flush all pending input
253
PurgeComm(_file,PURGE_RXABORT|PURGE_RXCLEAR);
259
bool foundOK = false;
261
while (readTries-- > 0)
263
string s = getLine();
264
if (s.find("OK") != string::npos ||
265
s.find("CABLE: GSM") != string::npos)
268
readTries = 0; // found OK, exit loop
276
// !!! no not declare this in loop, compiler error on Visual C++
277
// (without SP and with SP4)
279
putLine("AT" + initString);
283
if (s.find("OK") != string::npos ||
284
s.find("CABLE: GSM") != string::npos)
285
return; // found OK, return
286
} while(--readTries);
289
catch (GsmException &e)
295
// no response after 3 tries
296
throw GsmException(stringPrintf(_("reset modem failed '%s'"),
297
device.c_str()), OtherError);
300
string Win32SerialPort::getLine() throw(GsmException)
304
while ((c = readByte()) > 0)
316
if (debugLevel() >= 1)
317
cerr << "<-- " << result << endl;
323
void Win32SerialPort::putLine(string line,
324
bool carriageReturn) throw(GsmException)
327
if (debugLevel() >= 1)
328
cerr << "--> " << line << endl;
331
if (carriageReturn) line += CR;
332
// !!! BUG, mantain this pointer isn't corrent, use iterator !!!
333
const char *l = line.c_str();
335
FlushFileBuffers(_file); // flush all pending input and output
339
DWORD bytesWritten = 0;
341
ExceptionSafeOverlapped over;
343
DWORD initTime = GetTickCount();
344
if (!WriteFile(_file,l,line.length(),&bytesWritten,&over))
346
if (GetLastError() != ERROR_IO_PENDING)
348
throwModemException(_("writing to TA"));
351
while(bytesWritten < (DWORD)line.length())
354
throwModemException(_("interrupted when writing to TA"));
356
// wait another second
357
switch(WaitForSingleObject(over.hEvent,1000))
363
// !!! do a infinite loop if (bytesWritten < lenght) ?
364
GetOverlappedResult(_file,&over,&bytesWritten,TRUE);
367
throwModemException(_("writing to TA"));
370
timeElapsed = (GetTickCount() - initTime)/1000U;
373
if (timeElapsed >= timeoutVal)
376
throwModemException(_("timeout when writing to TA"));
385
SetCommMask(_file,EV_TXEMPTY);
387
ResetEvent(over.hEvent);
388
if( WaitCommEvent(_file,&dwEvent,&over) )
389
return; // already empty
392
if (GetLastError() != ERROR_IO_PENDING)
393
throwModemException(_("error comm waiting"));
395
while(timeElapsed < timeoutVal)
398
throwModemException(_("interrupted when flushing to TA"));
400
switch( WaitForSingleObject( over.hEvent, 1000 ) )
405
// successfully flushed
411
throwModemException(_("error waiting"));
413
timeElapsed = (GetTickCount() - initTime)/1000U;
417
throwModemException(_("timeout when writing to TA"));
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
424
bool Win32SerialPort::wait(GsmTime timeout) throw(GsmException)
426
// See differences from UNIX
427
// Why do I use Windows ?
428
ExceptionSafeOverlapped over;
430
SetCommMask(_file,EV_RXCHAR);
432
if( !WaitCommEvent(_file,&dwEvent,&over) )
435
if (GetLastError() != ERROR_IO_PENDING)
436
throwModemException(_("error comm waiting"));
438
switch( WaitForSingleObject( over.hEvent, timeout->tv_sec*1000U+timeout->tv_usec ) )
449
throwModemException(_("error waiting"));
456
void Win32SerialPort::setTimeOut(unsigned int timeout)
458
timeoutVal = timeout;
461
Win32SerialPort::~Win32SerialPort()
463
if ( _file != INVALID_HANDLE_VALUE)
467
int gsmlib::baudRateStrToSpeed(string baudrate) throw(GsmException)
469
if (baudrate == "300")
471
else if (baudrate == "600")
473
else if (baudrate == "1200")
475
else if (baudrate == "2400")
477
else if (baudrate == "4800")
479
else if (baudrate == "9600")
481
else if (baudrate == "19200")
483
else if (baudrate == "38400")
485
else if (baudrate == "57600")
487
else if (baudrate == "115200")
490
throw GsmException(stringPrintf(_("unknown baudrate '%s'"),
491
baudrate.c_str()), ParameterError);