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