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