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