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