]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_io.cxx
Changes to better support arbitrary external flight models.
[flightgear.git] / src / Main / fg_io.cxx
1 // fg_io.cxx -- higher level I/O channel management routines
2 //
3 // Written by Curtis Olson, started November 1999.
4 //
5 // Copyright (C) 1999  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 #include <simgear/compiler.h>
25
26 #include <stdlib.h>             // atoi()
27
28 #include STL_STRING
29
30 #include <simgear/debug/logstream.hxx>
31 #include <simgear/io/iochannel.hxx>
32 #include <simgear/io/sg_file.hxx>
33 #include <simgear/io/sg_serial.hxx>
34 #include <simgear/io/sg_socket.hxx>
35 #include <simgear/math/sg_types.hxx>
36 #include <simgear/timing/timestamp.hxx>
37
38 #include <Network/protocol.hxx>
39 #include <Network/atlas.hxx>
40 #include <Network/garmin.hxx>
41 #include <Network/httpd.hxx>
42 #include <Network/joyclient.hxx>
43 #include <Network/native.hxx>
44 #include <Network/native_ctrls.hxx>
45 #include <Network/native_fdm.hxx>
46 #include <Network/nmea.hxx>
47 #include <Network/props.hxx>
48 #include <Network/pve.hxx>
49 #include <Network/ray.hxx>
50 #include <Network/rul.hxx>
51
52 #include "globals.hxx"
53
54 SG_USING_STD(string);
55
56
57 // define the global I/O channel list
58 io_container global_io_list;
59
60
61 // configure a port based on the config string
62 static FGProtocol *parse_port_config( const string& config )
63 {
64     bool short_circuit = false;
65
66     string::size_type begin, end;
67
68     begin = 0;
69
70     SG_LOG( SG_IO, SG_INFO, "Parse I/O channel request: " << config );
71
72     // determine protocol
73     end = config.find(",", begin);
74     if ( end == string::npos ) {
75         return NULL;            // dummy
76     }
77     
78     string protocol = config.substr(begin, end - begin);
79     begin = end + 1;
80     SG_LOG( SG_IO, SG_INFO, "  protocol = " << protocol );
81
82     FGProtocol *io;
83     if ( protocol == "atlas" ) {
84         FGAtlas *atlas = new FGAtlas;
85         io = atlas;
86     } else if ( protocol == "garmin" ) {
87         FGGarmin *garmin = new FGGarmin;
88         io = garmin;
89     } else if ( protocol == "httpd" ) {
90         // determine port
91         string port = config.substr(begin);
92         FGHttpd *httpd = new FGHttpd( atoi(port.c_str()) );
93         io = httpd;
94         short_circuit = true;
95     } else if ( protocol == "joyclient" ) {
96         FGJoyClient *joyclient = new FGJoyClient;
97         io = joyclient;
98     } else if ( protocol == "native" ) {
99         FGNative *native = new FGNative;
100         io = native;
101     } else if ( protocol == "native_ctrls" ) {
102         FGNativeCtrls *native_ctrls = new FGNativeCtrls;
103         io = native_ctrls;
104     } else if ( protocol == "native_fdm" ) {
105         FGNativeFDM *native_fdm = new FGNativeFDM;
106         io = native_fdm;
107     } else if ( protocol == "nmea" ) {
108         FGNMEA *nmea = new FGNMEA;
109         io = nmea;
110     } else if ( protocol == "props" ) {
111         FGProps *props = new FGProps;
112         io = props;
113     } else if ( protocol == "pve" ) {
114         FGPVE *pve = new FGPVE;
115         io = pve;
116     } else if ( protocol == "ray" ) {
117         FGRAY *ray = new FGRAY;
118         io = ray;
119     } else if ( protocol == "rul" ) {
120         FGRUL *rul = new FGRUL;
121         io = rul;
122     } else {
123         return NULL;
124     }
125
126     if ( ! short_circuit ) {
127         // determine medium
128         end = config.find(",", begin);
129         if ( end == string::npos ) {
130             return NULL;                // dummy
131         }
132     
133         string medium = config.substr(begin, end - begin);
134         begin = end + 1;
135         SG_LOG( SG_IO, SG_INFO, "  medium = " << medium );
136
137         // determine direction
138         end = config.find(",", begin);
139         if ( end == string::npos ) {
140             return NULL;                // dummy
141         }
142     
143         string direction = config.substr(begin, end - begin);
144         begin = end + 1;
145         io->set_direction( direction );
146         SG_LOG( SG_IO, SG_INFO, "  direction = " << direction );
147
148         // determine hertz
149         end = config.find(",", begin);
150         if ( end == string::npos ) {
151             return NULL;                // dummy
152         }
153     
154         string hertz_str = config.substr(begin, end - begin);
155         begin = end + 1;
156         double hertz = atof( hertz_str.c_str() );
157         io->set_hz( hertz );
158         SG_LOG( SG_IO, SG_INFO, "  hertz = " << hertz );
159
160         if ( medium == "serial" ) {
161             // device name
162             end = config.find(",", begin);
163             if ( end == string::npos ) {
164                 return NULL;
165             }
166     
167             string device = config.substr(begin, end - begin);
168             begin = end + 1;
169             SG_LOG( SG_IO, SG_INFO, "  device = " << device );
170
171             // baud
172             string baud = config.substr(begin);
173             SG_LOG( SG_IO, SG_INFO, "  baud = " << baud );
174
175             SGSerial *ch = new SGSerial( device, baud );
176             io->set_io_channel( ch );
177         } else if ( medium == "file" ) {
178             // file name
179             string file = config.substr(begin);
180             SG_LOG( SG_IO, SG_INFO, "  file name = " << file );
181
182             SGFile *ch = new SGFile( file );
183             io->set_io_channel( ch );
184         } else if ( medium == "socket" ) {
185             // hostname
186             end = config.find(",", begin);
187             if ( end == string::npos ) {
188                 return NULL;
189             }
190     
191             string hostname = config.substr(begin, end - begin);
192             begin = end + 1;
193             SG_LOG( SG_IO, SG_INFO, "  hostname = " << hostname );
194
195             // port string
196             end = config.find(",", begin);
197             if ( end == string::npos ) {
198                 return NULL;
199             }
200     
201             string port = config.substr(begin, end - begin);
202             begin = end + 1;
203             SG_LOG( SG_IO, SG_INFO, "  port string = " << port );
204
205             // socket style
206             string style_str = config.substr(begin);
207             SG_LOG( SG_IO, SG_INFO, "  style string = " << style_str );
208             
209             SGSocket *ch = new SGSocket( hostname, port, style_str );
210             io->set_io_channel( ch );
211         }
212     }
213
214     return io;
215 }
216
217
218 // step through the port config streams (from fgOPTIONS) and setup
219 // serial port channels for each
220 void fgIOInit() {
221     // SG_LOG( SG_IO, SG_INFO, "I/O Channel initialization, " << 
222     //         globals->get_channel_options_list()->size() << " requests." );
223
224     FGProtocol *p;
225     string_list *channel_options_list = globals->get_channel_options_list();
226
227     // we could almost do this in a single step except pushing a valid
228     // port onto the port list copies the structure and destroys the
229     // original, which closes the port and frees up the fd ... doh!!!
230
231     // parse the configuration strings and store the results in the
232     // appropriate FGIOChannel structures
233     for ( int i = 0; i < (int)channel_options_list->size(); ++i ) {
234         p = parse_port_config( (*channel_options_list)[i] );
235         if ( p != NULL ) {
236             p->open();
237             global_io_list.push_back( p );
238             if ( !p->is_enabled() ) {
239                 SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." );
240                 exit(-1);
241             }
242         } else {
243             SG_LOG( SG_IO, SG_INFO, "I/O Channel parse failed." );
244         }
245     }
246 }
247
248
249 // process any serial port work
250 void fgIOProcess() {
251     FGProtocol *p;
252
253     // cout << "processing I/O channels" << endl;
254
255     static int inited = 0;
256     int interval;
257     static SGTimeStamp last;
258     SGTimeStamp current;
259
260     if ( ! inited ) {
261         inited = 1;
262         last.stamp();
263         interval = 0;
264     } else {
265         current.stamp();
266         interval = current - last;
267         last = current;
268     }
269
270     for ( int i = 0; i < (int)global_io_list.size(); ++i ) {
271         // cout << "  channel = " << i << endl;
272         p = global_io_list[i];
273
274         if ( p->is_enabled() ) {
275             p->dec_count_down( interval );
276             while ( p->get_count_down() < 0 ) {
277                 p->process();
278                 p->dec_count_down( -1000000.0 / p->get_hz() );
279             }
280         }
281     }
282 }
283
284
285 // shutdown all I/O connections
286 void fgIOShutdownAll() {
287     FGProtocol *p;
288
289     // cout << "processing I/O channels" << endl;
290
291     for ( int i = 0; i < (int)global_io_list.size(); ++i ) {
292         // cout << "  channel = " << i << endl;
293         p = global_io_list[i];
294
295         if ( p->is_enabled() ) {
296             p->close();
297         }
298     }
299 }