]> git.mxchange.org Git - simgear.git/blob - Lib/Serial/serial.cxx
Fixed an IRIX warning message where an inline function is referenced
[simgear.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
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include "Include/compiler.h"
29 #ifdef FG_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 <Debug/logstream.hxx>
46
47 #include "serial.hxx"
48
49
50 fgSERIAL::fgSERIAL()
51     : dev_open(false)
52 {
53     // empty
54 }
55
56 fgSERIAL::fgSERIAL(const string& device, int baud) {
57     open_port(device);
58     
59     if ( dev_open ) {
60         set_baud(baud);
61     }
62 }
63
64 fgSERIAL::~fgSERIAL() {
65     // closing the port here screws us up because if we would even so
66     // much as make a copy of an fgSERIAL object and then delete it,
67     // the file descriptor gets closed.  Doh!!!
68 }
69
70 bool fgSERIAL::open_port(const string& device) {
71
72 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
73
74     fd = CreateFile( device.c_str(),
75         GENERIC_READ | GENERIC_WRITE,
76         0, // dwShareMode
77         NULL, // lpSecurityAttributes
78         OPEN_EXISTING,
79         FILE_FLAG_OVERLAPPED,
80         NULL );
81     if ( fd == INVALID_HANDLE_VALUE )
82     {
83         LPVOID lpMsgBuf;
84         FormatMessage(
85             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
86             FORMAT_MESSAGE_FROM_SYSTEM | 
87             FORMAT_MESSAGE_IGNORE_INSERTS,
88             NULL,
89             GetLastError(),
90             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
91             (LPTSTR) &lpMsgBuf,
92             0,
93             NULL );
94
95         FG_LOG( FG_SERIAL, FG_ALERT, "Error opening serial device \"" 
96             << device << "\" " << (const char*) lpMsgBuf );
97         LocalFree( lpMsgBuf );
98         return false;
99     }
100
101     dev_open = true;
102     return true;
103
104 #else
105
106     struct termios config;
107
108     fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
109     cout << "Serial fd created = " << fd << endl;
110
111     if ( fd  == -1 ) {
112         FG_LOG( FG_SERIAL, FG_ALERT, "Cannot open " << device
113                 << " for serial I/O" );
114         return false;
115     } else {
116         dev_open = true;
117     }
118
119     // set required port parameters 
120     if ( tcgetattr( fd, &config ) != 0 ) {
121         FG_LOG( FG_SERIAL, FG_ALERT, "Unable to poll port settings" );
122         return false;
123     }
124
125     // cfmakeraw( &config );
126
127     // cout << "config.c_iflag = " << config.c_iflag << endl;
128
129     // software flow control on
130     config.c_iflag |= IXON;
131     // config.c_iflag |= IXOFF;
132
133     // config.c_cflag |= CLOCAL;
134
135 #if ! defined( sgi )    
136     // disable hardware flow control
137     config.c_cflag &= ~(CRTSCTS);
138 #endif
139
140     // cout << "config.c_iflag = " << config.c_iflag << endl;
141
142     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
143         FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
144         return false;
145     }
146
147     return true;
148 #endif
149 }
150
151
152 bool fgSERIAL::close_port() {
153 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
154     CloseHandle( fd );
155 #else
156     close(fd);
157 #endif
158
159     return true;
160 }
161
162
163 bool fgSERIAL::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         FG_LOG( FG_SERIAL, FG_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         FG_LOG( FG_SERIAL, FG_ALERT, "Unsupported baud rate " << baud );
203         return false;
204     }
205
206     if ( cfsetispeed( &config, speed ) != 0 ) {
207         FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting input baud rate" );
208         return false;
209     }
210
211     if ( cfsetospeed( &config, speed ) != 0 ) {
212         FG_LOG( FG_SERIAL, FG_ALERT, "Problem setting output baud rate" );
213         return false;
214     }
215
216     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
217         FG_LOG( FG_SERIAL, FG_ALERT, "Unable to update port settings" );
218         return false;
219     }
220
221     return true;
222
223 #endif
224
225 }
226
227 string fgSERIAL::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             FG_LOG( FG_SERIAL, FG_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 fgSERIAL::write_port(const string& value) {
264
265 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
266
267     LPCVOID lpBuffer = value.c_str();
268     DWORD nNumberOfBytesToWrite = value.length();
269     DWORD lpNumberOfBytesWritten;
270     OVERLAPPED lpOverlapped;
271
272     if ( WriteFile( fd,
273         lpBuffer,
274         nNumberOfBytesToWrite,
275         &lpNumberOfBytesWritten,
276         &lpOverlapped ) == 0 )
277     {
278         LPVOID lpMsgBuf;
279         FormatMessage(
280             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
281             FORMAT_MESSAGE_FROM_SYSTEM | 
282             FORMAT_MESSAGE_IGNORE_INSERTS,
283             NULL,
284             GetLastError(),
285             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
286             (LPTSTR) &lpMsgBuf,
287             0,
288             NULL );
289
290         FG_LOG( FG_SERIAL, FG_ALERT, "Serial I/O write error: " 
291              << (const char*) lpMsgBuf );
292         LocalFree( lpMsgBuf );
293         return int(lpNumberOfBytesWritten);
294     }
295
296     return int(lpNumberOfBytesWritten);
297
298 #else
299
300     static bool error = false;
301     int count;
302
303     if ( error ) {
304         // attempt some sort of error recovery
305         count = write(fd, "\n", 1);
306         if ( count == 1 ) {
307             // cout << "Serial error recover successful!\n";
308             error = false;
309         } else {
310             return 0;
311         }
312     }
313
314     count = write(fd, value.c_str(), value.length());
315     // cout << "write '" << value << "'  " << count << " bytes" << endl;
316
317     if ( (int)count == (int)value.length() ) {
318         error = false;
319     } else {
320         error = true;
321         if ( errno == EAGAIN ) {
322             // ok ... in our context we don't really care if we can't
323             // write a string, we'll just get it the next time around
324         } else {
325             FG_LOG( FG_SERIAL, FG_ALERT,
326                     "Serial I/O on write, error number = " << errno );
327         }
328     }
329
330     return count;
331
332 #endif
333
334 }
335
336