]> git.mxchange.org Git - simgear.git/blob - simgear/serial/serial.cxx
Cygwin fixes.
[simgear.git] / simgear / serial / serial.cxx
1 // serial.cxx -- Unix serial I/O support
2 //
3 // Written by Curtis Olson, started November 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson - http://www.flightgear.org/~curt
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public
18 // License along with this library; if not, write to the
19 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 // Boston, MA  02111-1307, USA.
21 //
22 // $Id$
23
24
25 #include <simgear/compiler.h>
26
27 #include STL_IOSTREAM
28
29 #ifdef SG_HAVE_STD_INCLUDE
30 #  include <cerrno>
31 #else
32 #  include <errno.h>
33 #endif
34
35 #if !defined( WIN32 ) || defined( __CYGWIN__) || defined( __CYGWIN32__ )
36 #  include <termios.h>
37 #  include <sys/types.h>
38 #  include <sys/stat.h>
39 #  include <fcntl.h>
40 #  include <unistd.h>
41 #endif
42
43 #include <simgear/debug/logstream.hxx>
44
45 #include "serial.hxx"
46
47 SGSerialPort::SGSerialPort()
48     : dev_open(false)
49 {
50     // empty
51 }
52
53 SGSerialPort::SGSerialPort(const string& device, int baud) {
54     open_port(device);
55     
56     if ( dev_open ) {
57         set_baud(baud);
58     }
59 }
60
61 SGSerialPort::~SGSerialPort() {
62     // closing the port here screws us up because if we would even so
63     // much as make a copy of an SGSerialPort object and then delete it,
64     // the file descriptor gets closed.  Doh!!!
65 }
66
67 bool SGSerialPort::open_port(const string& device) {
68
69 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
70
71     fd = CreateFile( device.c_str(),
72         GENERIC_READ | GENERIC_WRITE,
73         0, // dwShareMode
74         NULL, // lpSecurityAttributes
75         OPEN_EXISTING,
76         0,
77         NULL );
78     if ( fd == INVALID_HANDLE_VALUE )
79     {
80         LPVOID lpMsgBuf;
81         FormatMessage(
82             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
83             FORMAT_MESSAGE_FROM_SYSTEM | 
84             FORMAT_MESSAGE_IGNORE_INSERTS,
85             NULL,
86             GetLastError(),
87             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
88             (LPTSTR) &lpMsgBuf,
89             0,
90             NULL );
91
92         SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \"" 
93             << device << "\" " << (const char*) lpMsgBuf );
94         LocalFree( lpMsgBuf );
95         return false;
96     }
97
98     dev_open = true;
99     return true;
100
101 #else
102
103     struct termios config;
104
105     fd = open(device.c_str(), O_RDWR | O_NOCTTY| O_NDELAY);
106     SG_LOG( SG_EVENT, SG_DEBUG, "Serial fd created = " << fd);
107
108     if ( fd  == -1 ) {
109         SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
110                 << " for serial I/O" );
111         return false;
112     } else {
113         dev_open = true;
114     }
115
116     // set required port parameters 
117     if ( tcgetattr( fd, &config ) != 0 ) {
118         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
119         return false;
120     }
121
122     // cfmakeraw( &config );
123
124     // cout << "config.c_iflag = " << config.c_iflag << endl;
125
126     // disable software flow control
127     config.c_iflag &= ~(IXON | IXOFF | IXANY);
128
129     // enable the receiver and set local mode
130     config.c_cflag |= (CLOCAL | CREAD);
131
132 #if !defined( sgi ) && !defined(_AIX)
133     // disable hardware flow control
134     config.c_cflag &= ~(CRTSCTS);
135 #endif
136
137     // cout << "config.c_iflag = " << config.c_iflag << endl;
138     
139     // Raw (not cooked/canonical) input mode
140     config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
141
142     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
143         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
144         return false;
145     }
146
147     return true;
148 #endif
149 }
150
151
152 bool SGSerialPort::close_port() {
153 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
154     CloseHandle( fd );
155 #else
156     close(fd);
157 #endif
158
159     dev_open = false;
160
161     return true;
162 }
163
164
165 bool SGSerialPort::set_baud(int baud) {
166
167 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
168
169     DCB dcb;
170     if ( GetCommState( fd, &dcb ) ) {
171         dcb.BaudRate = baud;
172         dcb.fOutxCtsFlow = FALSE;
173         dcb.fOutxDsrFlow = FALSE;
174         dcb.fOutX = TRUE;
175         dcb.fInX = TRUE;
176
177         if ( !SetCommState( fd, &dcb ) ) {
178             LPVOID lpMsgBuf;
179             FormatMessage(
180                 FORMAT_MESSAGE_ALLOCATE_BUFFER | 
181                 FORMAT_MESSAGE_FROM_SYSTEM | 
182                 FORMAT_MESSAGE_IGNORE_INSERTS,
183                 NULL,
184                 GetLastError(),
185                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
186                 (LPTSTR) &lpMsgBuf,
187                 0,
188                 NULL );
189
190             SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings: " 
191                 << (const char*) lpMsgBuf );
192             LocalFree( lpMsgBuf );
193             return false;
194         }
195     } else {
196         LPVOID lpMsgBuf;
197         FormatMessage(
198             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
199             FORMAT_MESSAGE_FROM_SYSTEM | 
200             FORMAT_MESSAGE_IGNORE_INSERTS,
201             NULL,
202             GetLastError(),
203             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
204             (LPTSTR) &lpMsgBuf,
205             0,
206             NULL );
207
208         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings: " 
209              << (const char*) lpMsgBuf );
210         LocalFree( lpMsgBuf );
211         return false;
212     }
213
214     return true;
215
216 #else
217
218     struct termios config;
219     speed_t speed = B9600;
220
221     if ( tcgetattr( fd, &config ) != 0 ) {
222         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
223         return false;
224     }
225
226     if ( baud == 300 ) {
227         speed = B300;
228     } else if ( baud == 1200 ) {
229         speed = B1200;
230     } else if ( baud == 2400 ) {
231         speed = B2400;
232     } else if ( baud == 4800 ) {
233         speed = B4800;
234     } else if ( baud == 9600 ) {
235         speed = B9600;
236     } else if ( baud == 19200 ) {
237         speed = B19200;
238     } else if ( baud == 38400 ) {
239         speed = B38400;
240 #if defined( linux ) || defined( __FreeBSD__ )
241     } else if ( baud == 57600 ) {
242         speed = B57600;
243     } else if ( baud == 115200 ) {
244         speed = B115200;
245     } else if ( baud == 230400 ) {
246         speed = B230400;
247 #endif
248     } else {
249         SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
250         return false;
251     }
252
253     if ( cfsetispeed( &config, speed ) != 0 ) {
254         SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
255         return false;
256     }
257
258     if ( cfsetospeed( &config, speed ) != 0 ) {
259         SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
260         return false;
261     }
262
263     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
264         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
265         return false;
266     }
267
268     return true;
269
270 #endif
271
272 }
273
274 string SGSerialPort::read_port() {
275
276     const int max_count = 1024;
277     char buffer[max_count+1];
278     string result;
279
280 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
281
282     DWORD count;
283     if ( ReadFile( fd, buffer, max_count, &count, 0 ) ) {
284         buffer[count] = '\0';
285         result = buffer;
286     } else {
287         LPVOID lpMsgBuf;
288         FormatMessage(
289             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
290             FORMAT_MESSAGE_FROM_SYSTEM | 
291             FORMAT_MESSAGE_IGNORE_INSERTS,
292             NULL,
293             GetLastError(),
294             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
295             (LPTSTR) &lpMsgBuf,
296             0,
297             NULL );
298
299         SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: " 
300              << (const char*) lpMsgBuf );
301         LocalFree( lpMsgBuf );
302     }
303
304     return result;
305
306 #else
307
308     int count = read(fd, buffer, max_count);
309     // cout << "read " << count << " bytes" << endl;
310
311     if ( count < 0 ) {
312         // error condition
313         if ( errno != EAGAIN ) {
314             SG_LOG( SG_IO, SG_ALERT, 
315                     "Serial I/O on read, error number = " << errno );
316         }
317
318         return "";
319     } else {
320         buffer[count] = '\0';
321         result = buffer;
322
323         return result;
324     }
325
326 #endif
327
328 }
329
330 int SGSerialPort::read_port(char *buf, int len) {
331
332 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
333
334     DWORD count;
335     if ( ReadFile( fd, buf, len, &count, 0 ) ) {
336         buf[count] = '\0';
337
338         return count;
339     } else {
340         LPVOID lpMsgBuf;
341         FormatMessage(
342             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
343             FORMAT_MESSAGE_FROM_SYSTEM | 
344             FORMAT_MESSAGE_IGNORE_INSERTS,
345             NULL,
346             GetLastError(),
347             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
348             (LPTSTR) &lpMsgBuf,
349             0,
350             NULL );
351
352         SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: " 
353              << (const char*) lpMsgBuf );
354         LocalFree( lpMsgBuf );
355
356         buf[0] = '\0';
357         return 0;
358     }
359
360 #else
361
362     string result;
363
364     int count = read(fd, buf, len);
365     // cout << "read " << count << " bytes" << endl;
366
367     if ( count < 0 ) {
368         // error condition
369         if ( errno != EAGAIN ) {
370             SG_LOG( SG_IO, SG_ALERT, 
371                     "Serial I/O on read, error number = " << errno );
372         }
373
374         buf[0] = '\0';
375         return 0;
376     } else {
377         buf[count] = '\0';
378
379         return count;
380     }
381
382 #endif
383
384 }
385
386
387 int SGSerialPort::write_port(const string& value) {
388
389 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
390
391     LPCVOID lpBuffer = value.data();
392     DWORD nNumberOfBytesToWrite = value.length();
393     DWORD lpNumberOfBytesWritten;
394
395     if ( WriteFile( fd,
396         lpBuffer,
397         nNumberOfBytesToWrite,
398         &lpNumberOfBytesWritten,
399         0 ) == 0 )
400     {
401         LPVOID lpMsgBuf;
402         FormatMessage(
403             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
404             FORMAT_MESSAGE_FROM_SYSTEM | 
405             FORMAT_MESSAGE_IGNORE_INSERTS,
406             NULL,
407             GetLastError(),
408             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
409             (LPTSTR) &lpMsgBuf,
410             0,
411             NULL );
412
413         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
414              << (const char*) lpMsgBuf );
415         LocalFree( lpMsgBuf );
416         return int(lpNumberOfBytesWritten);
417     }
418
419     return int(lpNumberOfBytesWritten);
420
421 #else
422
423     static bool error = false;
424     int count;
425
426     if ( error ) {
427         SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
428         // attempt some sort of error recovery
429         count = write(fd, "\n", 1);
430         if ( count == 1 ) {
431             // cout << "Serial error recover successful!\n";
432             error = false;
433         } else {
434             return 0;
435         }
436     }
437
438     count = write(fd, value.c_str(), value.length());
439     // cout << "write '" << value << "'  " << count << " bytes" << endl;
440
441     if ( (int)count == (int)value.length() ) {
442         error = false;
443     } else {
444         if ( errno == EAGAIN ) {
445             // ok ... in our context we don't really care if we can't
446             // write a string, we'll just get it the next time around
447             error = false;
448         } else {
449             error = true;
450             SG_LOG( SG_IO, SG_ALERT,
451                     "Serial I/O on write, error number = " << errno );
452         }
453     }
454
455     return count;
456
457 #endif
458
459 }
460
461
462 int SGSerialPort::write_port(const char* buf, int len) {
463 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
464
465     LPCVOID lpBuffer = buf;
466     DWORD nNumberOfBytesToWrite = len;
467     DWORD lpNumberOfBytesWritten;
468
469     if ( WriteFile( fd,
470         lpBuffer,
471         nNumberOfBytesToWrite,
472         &lpNumberOfBytesWritten,
473         0 ) == 0 )
474     {
475         LPVOID lpMsgBuf;
476         FormatMessage(
477             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
478             FORMAT_MESSAGE_FROM_SYSTEM | 
479             FORMAT_MESSAGE_IGNORE_INSERTS,
480             NULL,
481             GetLastError(),
482             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
483             (LPTSTR) &lpMsgBuf,
484             0,
485             NULL );
486
487         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
488              << (const char*) lpMsgBuf );
489         LocalFree( lpMsgBuf );
490         return int(lpNumberOfBytesWritten);
491     }
492
493     return int(lpNumberOfBytesWritten);
494
495 #else
496
497     static bool error = false;
498     int count;
499
500     if ( error ) {
501         // attempt some sort of error recovery
502         count = write(fd, "\n", 1);
503         if ( count == 1 ) {
504             // cout << "Serial error recover successful!\n";
505             error = false;
506         } else {
507             return 0;
508         }
509     }
510
511     count = write(fd, buf, len);
512     // cout << "write '" << buf << "'  " << count << " bytes" << endl;
513
514     if ( (int)count == len ) {
515         error = false;
516     } else {
517         error = true;
518         if ( errno == EAGAIN ) {
519             // ok ... in our context we don't really care if we can't
520             // write a string, we'll just get it the next time around
521         } else {
522             SG_LOG( SG_IO, SG_ALERT,
523                     "Serial I/O on write, error number = " << errno );
524         }
525     }
526
527     return count;
528
529 #endif
530
531 }