]> git.mxchange.org Git - simgear.git/blob - simgear/serial/serial.cxx
8c31a602fc779bd468017f585ce9833f2d4a8844
[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 #include STL_IOSTREAM
28
29 #ifdef SG_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 <simgear/debug/logstream.hxx>
46
47 #include "serial.hxx"
48
49 FGSerialPort::FGSerialPort()
50     : dev_open(false)
51 {
52     // empty
53 }
54
55 FGSerialPort::FGSerialPort(const string& device, int baud) {
56     open_port(device);
57     
58     if ( dev_open ) {
59         set_baud(baud);
60     }
61 }
62
63 FGSerialPort::~FGSerialPort() {
64     // closing the port here screws us up because if we would even so
65     // much as make a copy of an FGSerialPort object and then delete it,
66     // the file descriptor gets closed.  Doh!!!
67 }
68
69 bool FGSerialPort::open_port(const string& device) {
70
71 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
72
73     fd = CreateFile( device.c_str(),
74         GENERIC_READ | GENERIC_WRITE,
75         0, // dwShareMode
76         NULL, // lpSecurityAttributes
77         OPEN_EXISTING,
78         FILE_FLAG_OVERLAPPED,
79         NULL );
80     if ( fd == INVALID_HANDLE_VALUE )
81     {
82         LPVOID lpMsgBuf;
83         FormatMessage(
84             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
85             FORMAT_MESSAGE_FROM_SYSTEM | 
86             FORMAT_MESSAGE_IGNORE_INSERTS,
87             NULL,
88             GetLastError(),
89             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
90             (LPTSTR) &lpMsgBuf,
91             0,
92             NULL );
93
94         SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \"" 
95             << device << "\" " << (const char*) lpMsgBuf );
96         LocalFree( lpMsgBuf );
97         return false;
98     }
99
100     dev_open = true;
101     return true;
102
103 #else
104
105     struct termios config;
106
107     fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
108     SG_LOG( SG_EVENT, SG_DEBUG, "Serial fd created = " << fd);
109
110     if ( fd  == -1 ) {
111         SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
112                 << " for serial I/O" );
113         return false;
114     } else {
115         dev_open = true;
116     }
117
118     // set required port parameters 
119     if ( tcgetattr( fd, &config ) != 0 ) {
120         SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
121         return false;
122     }
123
124     // cfmakeraw( &config );
125
126     // cout << "config.c_iflag = " << config.c_iflag << endl;
127
128     // software flow control on
129     config.c_iflag |= IXON;
130     // config.c_iflag |= IXOFF;
131
132     // config.c_cflag |= CLOCAL;
133
134 #if ! defined( sgi )    
135     // disable hardware flow control
136     config.c_cflag &= ~(CRTSCTS);
137 #endif
138
139     // cout << "config.c_iflag = " << config.c_iflag << endl;
140
141     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
142         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
143         return false;
144     }
145
146     return true;
147 #endif
148 }
149
150
151 bool FGSerialPort::close_port() {
152 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
153     CloseHandle( fd );
154 #else
155     close(fd);
156 #endif
157
158     dev_open = false;
159
160     return true;
161 }
162
163
164 bool FGSerialPort::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         SG_LOG( SG_IO, SG_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         SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
204         return false;
205     }
206
207     if ( cfsetispeed( &config, speed ) != 0 ) {
208         SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
209         return false;
210     }
211
212     if ( cfsetospeed( &config, speed ) != 0 ) {
213         SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
214         return false;
215     }
216
217     if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
218         SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
219         return false;
220     }
221
222     return true;
223
224 #endif
225
226 }
227
228 string FGSerialPort::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             SG_LOG( SG_IO, SG_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 FGSerialPort::read_port(char *buf, int len) {
265
266 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
267
268     buf[0] = '\0';
269     return 0;
270
271 #else
272
273     string result;
274
275     int count = read(fd, buf, len);
276     // cout << "read " << count << " bytes" << endl;
277
278     if ( count < 0 ) {
279         // error condition
280         if ( errno != EAGAIN ) {
281             SG_LOG( SG_IO, SG_ALERT, 
282                     "Serial I/O on read, error number = " << errno );
283         }
284
285         buf[0] = '\0';
286         return 0;
287     } else {
288         buf[count] = '\0';
289
290         return count;
291     }
292
293 #endif
294
295 }
296
297
298 int FGSerialPort::write_port(const string& value) {
299
300 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
301
302     LPCVOID lpBuffer = value.c_str();
303     DWORD nNumberOfBytesToWrite = value.length();
304     DWORD lpNumberOfBytesWritten;
305     OVERLAPPED lpOverlapped;
306
307     if ( WriteFile( fd,
308         lpBuffer,
309         nNumberOfBytesToWrite,
310         &lpNumberOfBytesWritten,
311         &lpOverlapped ) == 0 )
312     {
313         LPVOID lpMsgBuf;
314         FormatMessage(
315             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
316             FORMAT_MESSAGE_FROM_SYSTEM | 
317             FORMAT_MESSAGE_IGNORE_INSERTS,
318             NULL,
319             GetLastError(),
320             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
321             (LPTSTR) &lpMsgBuf,
322             0,
323             NULL );
324
325         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
326              << (const char*) lpMsgBuf );
327         LocalFree( lpMsgBuf );
328         return int(lpNumberOfBytesWritten);
329     }
330
331     return int(lpNumberOfBytesWritten);
332
333 #else
334
335     static bool error = false;
336     int count;
337
338     if ( error ) {
339         SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
340         // attempt some sort of error recovery
341         count = write(fd, "\n", 1);
342         if ( count == 1 ) {
343             // cout << "Serial error recover successful!\n";
344             error = false;
345         } else {
346             return 0;
347         }
348     }
349
350     count = write(fd, value.c_str(), value.length());
351     // cout << "write '" << value << "'  " << count << " bytes" << endl;
352
353     if ( (int)count == (int)value.length() ) {
354         error = false;
355     } else {
356         if ( errno == EAGAIN ) {
357             // ok ... in our context we don't really care if we can't
358             // write a string, we'll just get it the next time around
359             error = false;
360         } else {
361             error = true;
362             SG_LOG( SG_IO, SG_ALERT,
363                     "Serial I/O on write, error number = " << errno );
364         }
365     }
366
367     return count;
368
369 #endif
370
371 }
372
373
374 int FGSerialPort::write_port(const char* buf, int len) {
375 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
376
377     LPCVOID lpBuffer = buf;
378     DWORD nNumberOfBytesToWrite = len;
379     DWORD lpNumberOfBytesWritten;
380     OVERLAPPED lpOverlapped;
381
382     if ( WriteFile( fd,
383         lpBuffer,
384         nNumberOfBytesToWrite,
385         &lpNumberOfBytesWritten,
386         &lpOverlapped ) == 0 )
387     {
388         LPVOID lpMsgBuf;
389         FormatMessage(
390             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
391             FORMAT_MESSAGE_FROM_SYSTEM | 
392             FORMAT_MESSAGE_IGNORE_INSERTS,
393             NULL,
394             GetLastError(),
395             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
396             (LPTSTR) &lpMsgBuf,
397             0,
398             NULL );
399
400         SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: " 
401              << (const char*) lpMsgBuf );
402         LocalFree( lpMsgBuf );
403         return int(lpNumberOfBytesWritten);
404     }
405
406     return int(lpNumberOfBytesWritten);
407
408 #else
409
410     static bool error = false;
411     int count;
412
413     if ( error ) {
414         // attempt some sort of error recovery
415         count = write(fd, "\n", 1);
416         if ( count == 1 ) {
417             // cout << "Serial error recover successful!\n";
418             error = false;
419         } else {
420             return 0;
421         }
422     }
423
424     count = write(fd, buf, len);
425     // cout << "write '" << buf << "'  " << count << " bytes" << endl;
426
427     if ( (int)count == len ) {
428         error = false;
429     } else {
430         error = true;
431         if ( errno == EAGAIN ) {
432             // ok ... in our context we don't really care if we can't
433             // write a string, we'll just get it the next time around
434         } else {
435             SG_LOG( SG_IO, SG_ALERT,
436                     "Serial I/O on write, error number = " << errno );
437         }
438     }
439
440     return count;
441
442 #endif
443
444 }