]> git.mxchange.org Git - simgear.git/blob - simgear/serial/serial.cxx
Updates to remove unneeded and old version of zlib source.
[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 software flow control
126     config.c_iflag &= ~(IXON | IXOFF | IXANY);
127
128     // enable the receiver and set local mode
129     config.c_cflag |= (CLOCAL | CREAD);
130
131 #if !defined( sgi ) && !defined(_AIX)
132     // disable hardware flow control
133     config.c_cflag &= ~(CRTSCTS);
134 #endif
135
136     // cout << "config.c_iflag = " << config.c_iflag << endl;
137     
138     // Raw (not cooked/canonical) input mode
139     config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
140
141     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
142         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
143         return false;
144     }
145
146     return true;
147 #endif
148 }
149
150
151 bool SGSerialPort::close_port() {
152 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
153     CloseHandle( fd );
154 #else
155     close(fd);
156 #endif
157
158     dev_open = false;
159
160     return true;
161 }
162
163
164 bool SGSerialPort::set_baud(int baud) {
165
166 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
167
168     DCB dcb;
169     if ( GetCommState( fd, &dcb ) ) {
170         dcb.BaudRate = baud;
171         dcb.fOutxCtsFlow = FALSE;
172         dcb.fOutxDsrFlow = FALSE;
173         dcb.fOutX = TRUE;
174         dcb.fInX = TRUE;
175
176         if ( !SetCommState( fd, &dcb ) ) {
177             LPVOID lpMsgBuf;
178             FormatMessage(
179                 FORMAT_MESSAGE_ALLOCATE_BUFFER | 
180                 FORMAT_MESSAGE_FROM_SYSTEM | 
181                 FORMAT_MESSAGE_IGNORE_INSERTS,
182                 NULL,
183                 GetLastError(),
184                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
185                 (LPTSTR) &lpMsgBuf,
186                 0,
187                 NULL );
188
189             SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings: " 
190                 << (const char*) lpMsgBuf );
191             LocalFree( lpMsgBuf );
192             return false;
193         }
194     } else {
195         LPVOID lpMsgBuf;
196         FormatMessage(
197             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
198             FORMAT_MESSAGE_FROM_SYSTEM | 
199             FORMAT_MESSAGE_IGNORE_INSERTS,
200             NULL,
201             GetLastError(),
202             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
203             (LPTSTR) &lpMsgBuf,
204             0,
205             NULL );
206
207         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings: " 
208              << (const char*) lpMsgBuf );
209         LocalFree( lpMsgBuf );
210         return false;
211     }
212
213     return true;
214
215 #else
216
217     struct termios config;
218     speed_t speed = B9600;
219
220     if ( tcgetattr( fd, &config ) != 0 ) {
221         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
222         return false;
223     }
224
225     if ( baud == 300 ) {
226         speed = B300;
227     } else if ( baud == 1200 ) {
228         speed = B1200;
229     } else if ( baud == 2400 ) {
230         speed = B2400;
231     } else if ( baud == 4800 ) {
232         speed = B4800;
233     } else if ( baud == 9600 ) {
234         speed = B9600;
235     } else if ( baud == 19200 ) {
236         speed = B19200;
237     } else if ( baud == 38400 ) {
238         speed = B38400;
239 #if defined( linux ) || defined( __FreeBSD__ )
240     } else if ( baud == 57600 ) {
241         speed = B57600;
242     } else if ( baud == 115200 ) {
243         speed = B115200;
244     } else if ( baud == 230400 ) {
245         speed = B230400;
246 #endif
247     } else {
248         SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
249         return false;
250     }
251
252     if ( cfsetispeed( &config, speed ) != 0 ) {
253         SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
254         return false;
255     }
256
257     if ( cfsetospeed( &config, speed ) != 0 ) {
258         SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
259         return false;
260     }
261
262     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
263         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
264         return false;
265     }
266
267     return true;
268
269 #endif
270
271 }
272
273 string SGSerialPort::read_port() {
274
275     const int max_count = 1024;
276     char buffer[max_count+1];
277     string result;
278
279 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
280
281     DWORD count;
282     if ( ReadFile( fd, buffer, max_count, &count, 0 ) ) {
283         buffer[count] = '\0';
284         result = buffer;
285     } else {
286         LPVOID lpMsgBuf;
287         FormatMessage(
288             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
289             FORMAT_MESSAGE_FROM_SYSTEM | 
290             FORMAT_MESSAGE_IGNORE_INSERTS,
291             NULL,
292             GetLastError(),
293             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
294             (LPTSTR) &lpMsgBuf,
295             0,
296             NULL );
297
298         SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: " 
299              << (const char*) lpMsgBuf );
300         LocalFree( lpMsgBuf );
301     }
302
303     return result;
304
305 #else
306
307     int count = read(fd, buffer, max_count);
308     // cout << "read " << count << " bytes" << endl;
309
310     if ( count < 0 ) {
311         // error condition
312         if ( errno != EAGAIN ) {
313             SG_LOG( SG_IO, SG_ALERT, 
314                     "Serial I/O on read, error number = " << errno );
315         }
316
317         return "";
318     } else {
319         buffer[count] = '\0';
320         result = buffer;
321
322         return result;
323     }
324
325 #endif
326
327 }
328
329 int SGSerialPort::read_port(char *buf, int len) {
330
331 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
332
333     DWORD count;
334     if ( ReadFile( fd, buf, len, &count, 0 ) ) {
335         buf[count] = '\0';
336
337         return count;
338     } else {
339         LPVOID lpMsgBuf;
340         FormatMessage(
341             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
342             FORMAT_MESSAGE_FROM_SYSTEM | 
343             FORMAT_MESSAGE_IGNORE_INSERTS,
344             NULL,
345             GetLastError(),
346             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
347             (LPTSTR) &lpMsgBuf,
348             0,
349             NULL );
350
351         SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: " 
352              << (const char*) lpMsgBuf );
353         LocalFree( lpMsgBuf );
354
355         buf[0] = '\0';
356         return 0;
357     }
358
359 #else
360
361     string result;
362
363     int count = read(fd, buf, len);
364     // cout << "read " << count << " bytes" << endl;
365
366     if ( count < 0 ) {
367         // error condition
368         if ( errno != EAGAIN ) {
369             SG_LOG( SG_IO, SG_ALERT, 
370                     "Serial I/O on read, error number = " << errno );
371         }
372
373         buf[0] = '\0';
374         return 0;
375     } else {
376         buf[count] = '\0';
377
378         return count;
379     }
380
381 #endif
382
383 }
384
385
386 int SGSerialPort::write_port(const string& value) {
387
388 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
389
390     LPCVOID lpBuffer = value.data();
391     DWORD nNumberOfBytesToWrite = value.length();
392     DWORD lpNumberOfBytesWritten;
393
394     if ( WriteFile( fd,
395         lpBuffer,
396         nNumberOfBytesToWrite,
397         &lpNumberOfBytesWritten,
398         0 ) == 0 )
399     {
400         LPVOID lpMsgBuf;
401         FormatMessage(
402             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
403             FORMAT_MESSAGE_FROM_SYSTEM | 
404             FORMAT_MESSAGE_IGNORE_INSERTS,
405             NULL,
406             GetLastError(),
407             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
408             (LPTSTR) &lpMsgBuf,
409             0,
410             NULL );
411
412         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
413              << (const char*) lpMsgBuf );
414         LocalFree( lpMsgBuf );
415         return int(lpNumberOfBytesWritten);
416     }
417
418     return int(lpNumberOfBytesWritten);
419
420 #else
421
422     static bool error = false;
423     int count;
424
425     if ( error ) {
426         SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
427         // attempt some sort of error recovery
428         count = write(fd, "\n", 1);
429         if ( count == 1 ) {
430             // cout << "Serial error recover successful!\n";
431             error = false;
432         } else {
433             return 0;
434         }
435     }
436
437     count = write(fd, value.c_str(), value.length());
438     // cout << "write '" << value << "'  " << count << " bytes" << endl;
439
440     if ( (int)count == (int)value.length() ) {
441         error = false;
442     } else {
443         if ( errno == EAGAIN ) {
444             // ok ... in our context we don't really care if we can't
445             // write a string, we'll just get it the next time around
446             error = false;
447         } else {
448             error = true;
449             SG_LOG( SG_IO, SG_ALERT,
450                     "Serial I/O on write, error number = " << errno );
451         }
452     }
453
454     return count;
455
456 #endif
457
458 }
459
460
461 int SGSerialPort::write_port(const char* buf, int len) {
462 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
463
464     LPCVOID lpBuffer = buf;
465     DWORD nNumberOfBytesToWrite = len;
466     DWORD lpNumberOfBytesWritten;
467
468     if ( WriteFile( fd,
469         lpBuffer,
470         nNumberOfBytesToWrite,
471         &lpNumberOfBytesWritten,
472         0 ) == 0 )
473     {
474         LPVOID lpMsgBuf;
475         FormatMessage(
476             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
477             FORMAT_MESSAGE_FROM_SYSTEM | 
478             FORMAT_MESSAGE_IGNORE_INSERTS,
479             NULL,
480             GetLastError(),
481             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
482             (LPTSTR) &lpMsgBuf,
483             0,
484             NULL );
485
486         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
487              << (const char*) lpMsgBuf );
488         LocalFree( lpMsgBuf );
489         return int(lpNumberOfBytesWritten);
490     }
491
492     return int(lpNumberOfBytesWritten);
493
494 #else
495
496     static bool error = false;
497     int count;
498
499     if ( error ) {
500         // attempt some sort of error recovery
501         count = write(fd, "\n", 1);
502         if ( count == 1 ) {
503             // cout << "Serial error recover successful!\n";
504             error = false;
505         } else {
506             return 0;
507         }
508     }
509
510     count = write(fd, buf, len);
511     // cout << "write '" << buf << "'  " << count << " bytes" << endl;
512
513     if ( (int)count == len ) {
514         error = false;
515     } else {
516         error = true;
517         if ( errno == EAGAIN ) {
518             // ok ... in our context we don't really care if we can't
519             // write a string, we'll just get it the next time around
520         } else {
521             SG_LOG( SG_IO, SG_ALERT,
522                     "Serial I/O on write, error number = " << errno );
523         }
524     }
525
526     return count;
527
528 #endif
529
530 }