]> git.mxchange.org Git - flightgear.git/blob - Lib/Serial/serial.cxx
Merge FG_Lib as subdirectory
[flightgear.git] / Lib / 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 // (Log is kept at end of this file)
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include "Include/compiler.h"
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 <Debug/logstream.hxx>
47
48 #include "serial.hxx"
49
50
51 fgSERIAL::fgSERIAL()
52     : dev_open(false)
53 {
54     // empty
55 }
56
57 fgSERIAL::fgSERIAL(const string& device, int baud) {
58     open_port(device);
59     
60     if ( dev_open ) {
61         set_baud(baud);
62     }
63 }
64
65 fgSERIAL::~fgSERIAL() {
66     // closing the port here screws us up because if we would even so
67     // much as make a copy of an fgSERIAL object and then delete it,
68     // the file descriptor gets closed.  Doh!!!
69 }
70
71 bool fgSERIAL::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_SERIAL, 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_SERIAL, 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_SERIAL, 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_SERIAL, FG_ALERT, "Unable to update port settings" );
145         return false;
146     }
147
148     return true;
149 #endif
150 }
151
152
153 bool fgSERIAL::close_port() {
154 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
155     CloseHandle( fd );
156 #else
157     close(fd);
158 #endif
159
160     return true;
161 }
162
163
164 bool fgSERIAL::set_baud(int baud) {
165
166 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
167
168     return true;
169
170 #else
171
172     struct termios config;
173     speed_t speed = B9600;
174
175     if ( tcgetattr( fd, &config ) != 0 ) {
176         FG_LOG( FG_SERIAL, FG_ALERT, "Unable to poll port settings" );
177         return false;
178     }
179
180     if ( baud == 300 ) {
181         speed = B300;
182     } else if ( baud == 1200 ) {
183         speed = B1200;
184     } else if ( baud == 2400 ) {
185         speed = B2400;
186     } else if ( baud == 4800 ) {
187         speed = B4800;
188     } else if ( baud == 9600 ) {
189         speed = B9600;
190     } else if ( baud == 19200 ) {
191         speed = B19200;
192     } else if ( baud == 38400 ) {
193         speed = B38400;
194     } else if ( baud == 57600 ) {
195         speed = B57600;
196     } else if ( baud == 115200 ) {
197         speed = B115200;
198 #if defined( linux ) || defined( __FreeBSD__ )
199     } else if ( baud == 230400 ) {
200         speed = B230400;
201 #endif
202     } else {
203         FG_LOG( FG_SERIAL, FG_ALERT, "Unsupported baud rate " << baud );
204         return false;
205     }
206
207     if ( cfsetispeed( &config, speed ) != 0 ) {
208         FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting input baud rate" );
209         return false;
210     }
211
212     if ( cfsetospeed( &config, speed ) != 0 ) {
213         FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting output baud rate" );
214         return false;
215     }
216
217     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
218         FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
219         return false;
220     }
221
222     return true;
223
224 #endif
225
226 }
227
228 string fgSERIAL::read_port() {
229
230 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
231
232     string result = "";
233     return result;
234
235 #else
236
237     const int max_count = 1024;
238     char buffer[max_count+1];
239     int count;
240     string result;
241
242     count = read(fd, buffer, max_count);
243     // cout << "read " << count << " bytes" << endl;
244
245     if ( count < 0 ) {
246         // error condition
247         if ( errno != EAGAIN ) {
248             FG_LOG( FG_SERIAL, FG_ALERT, 
249                     "Serial I/O on read, error number = " << errno );
250         }
251
252         return "";
253     } else {
254         buffer[count] = '\0';
255         result = buffer;
256
257         return result;
258     }
259
260 #endif
261
262 }
263
264 int fgSERIAL::write_port(const string& value) {
265
266 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
267
268     LPCVOID lpBuffer = value.c_str();
269     DWORD nNumberOfBytesToWrite = value.length();
270     DWORD lpNumberOfBytesWritten;
271     OVERLAPPED lpOverlapped;
272
273     if ( WriteFile( fd,
274         lpBuffer,
275         nNumberOfBytesToWrite,
276         &lpNumberOfBytesWritten,
277         &lpOverlapped ) == 0 )
278     {
279         LPVOID lpMsgBuf;
280         FormatMessage(
281             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
282             FORMAT_MESSAGE_FROM_SYSTEM | 
283             FORMAT_MESSAGE_IGNORE_INSERTS,
284             NULL,
285             GetLastError(),
286             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
287             (LPTSTR) &lpMsgBuf,
288             0,
289             NULL );
290
291         FG_LOG( FG_SERIAL, FG_ALERT, "Serial I/O write error: " 
292              << (const char*) lpMsgBuf );
293         LocalFree( lpMsgBuf );
294         return int(lpNumberOfBytesWritten);
295     }
296
297     return int(lpNumberOfBytesWritten);
298
299 #else
300
301     static bool error = false;
302     int count;
303
304     if ( error ) {
305         // attempt some sort of error recovery
306         count = write(fd, "\n", 1);
307         if ( count == 1 ) {
308             // cout << "Serial error recover successful!\n";
309             error = false;
310         } else {
311             return 0;
312         }
313     }
314
315     count = write(fd, value.c_str(), value.length());
316     // cout << "write '" << value << "'  " << count << " bytes" << endl;
317
318     if ( (int)count == (int)value.length() ) {
319         error = false;
320     } else {
321         error = true;
322         if ( errno == EAGAIN ) {
323             // ok ... in our context we don't really care if we can't
324             // write a string, we'll just get it the next time around
325         } else {
326             FG_LOG( FG_SERIAL, FG_ALERT,
327                     "Serial I/O on write, error number = " << errno );
328         }
329     }
330
331     return count;
332
333 #endif
334
335 }
336
337
338 // $Log$
339 // Revision 1.9  1999/02/02 20:13:23  curt
340 // MSVC++ portability changes by Bernie Bright:
341 //
342 // Lib/Serial/serial.[ch]xx: Initial Windows support - incomplete.
343 // Simulator/Astro/stars.cxx: typo? included <stdio> instead of <cstdio>
344 // Simulator/Cockpit/hud.cxx: Added Standard headers
345 // Simulator/Cockpit/panel.cxx: Redefinition of default parameter
346 // Simulator/Flight/flight.cxx: Replaced cout with FG_LOG.  Deleted <stdio.h>
347 // Simulator/Main/fg_init.cxx:
348 // Simulator/Main/GLUTmain.cxx:
349 // Simulator/Main/options.hxx: Shuffled <fg_serial.hxx> dependency
350 // Simulator/Objects/material.hxx:
351 // Simulator/Time/timestamp.hxx: VC++ friend kludge
352 // Simulator/Scenery/tile.[ch]xx: Fixed using std::X declarations
353 // Simulator/Main/views.hxx: Added a constant
354 //
355 // Revision 1.8  1999/01/20 13:42:21  curt
356 // Tweaked FDM interface.
357 // Testing check sum support for NMEA serial output.
358 //
359 // Revision 1.7  1998/12/04 01:24:35  curt
360 // Tweak for SGI portability.
361 //
362 // Revision 1.6  1998/11/30 17:15:29  curt
363 // Having the class destructor close the fd was a bad idea ... especially if you
364 // ever make a copy of the instance and then subsequently destroy either.
365 // close_port() is now a separate member function.
366 //
367 // Revision 1.5  1998/11/25 01:33:23  curt
368 // Remove call to cfmakeraw()
369 //
370 // Revision 1.4  1998/11/23 21:47:00  curt
371 // Cygnus tools compatibility tweaks.
372 //
373 // Revision 1.3  1998/11/19 13:52:54  curt
374 // port configuration tweaks & experiments.
375 //
376 // Revision 1.2  1998/11/19 03:35:43  curt
377 // Updates ...
378 //
379 // Revision 1.1  1998/11/16 13:53:02  curt
380 // Initial revision.
381 //