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