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