]> git.mxchange.org Git - flightgear.git/blob - src/Network/ATC-Main.cxx
Create TimeManager subsystem, and collect the time related code out of main.cxx and...
[flightgear.git] / src / Network / ATC-Main.cxx
1 // ATC-Main.cxx -- FGFS interface to ATC hardware
2 //
3 // Written by Curtis Olson, started January 2002
4 //
5 // Copyright (C) 2002  Curtis L. Olson - http://www.flightgear.org/~curt
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29
30 #include <stdlib.h>             // atoi() atof() abs()
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <stdio.h>              //snprintf
35 #ifdef _WIN32
36 #  include <io.h>                 //lseek, read, write
37 #endif
38
39 #include <string>
40
41 #include <plib/ul.h>
42
43 #include <simgear/debug/logstream.hxx>
44 #include <simgear/props/props_io.hxx>
45 #include <simgear/io/iochannel.hxx>
46 #include <simgear/math/sg_types.hxx>
47 #include <simgear/misc/sg_path.hxx>
48 #include <simgear/props/props.hxx>
49
50 #include <Scripting/NasalSys.hxx>
51 #include <Main/fg_props.hxx>
52 #include <Main/globals.hxx>
53
54 #include "ATC-Main.hxx"
55
56 using std::string;
57
58
59 // Lock the ATC hardware
60 static int fgATCMainLock( int fd ) {
61     // rewind
62     lseek( fd, 0, SEEK_SET );
63
64     char tmp[2];
65     int result = read( fd, tmp, 1 );
66     if ( result != 1 ) {
67         SG_LOG( SG_IO, SG_DEBUG, "Lock failed" );
68     }
69
70     return result;
71 }
72
73
74 // Write a radios command
75 static int fgATCMainRelease( int fd ) {
76     // rewind
77     lseek( fd, 0, SEEK_SET );
78
79     char tmp[2];
80     tmp[0] = tmp[1] = 0;
81     int result = write( fd, tmp, 1 );
82
83     if ( result != 1 ) {
84         SG_LOG( SG_IO, SG_DEBUG, "Release failed" );
85     }
86
87     return result;
88 }
89
90
91 void FGATCMain::init_config() {
92 #if defined( unix ) || defined( __CYGWIN__ )
93     // Next check home directory for .fgfsrc.hostname file
94     char *envp = ::getenv( "HOME" );
95     if ( envp != NULL ) {
96         SGPath atcsim_config( envp );
97         atcsim_config.append( ".fgfs-atc610x.xml" );
98         try {
99           SG_LOG(SG_GENERAL, SG_ALERT,
100                  "Warning: loading deprecated config file: " <<
101                  atcsim_config.str() );
102           readProperties( atcsim_config.str(), globals->get_props() );
103         } catch (const sg_exception &e) {
104           // fail silently, this is an old style config file I want to continue
105           // to support if it exists.
106         }
107     }
108 #endif
109 }
110
111
112 // Open and initialize ATC hardware
113 bool FGATCMain::open() {
114     if ( is_enabled() ) {
115         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " 
116                 << "is already in use, ignoring" );
117         return false;
118     }
119
120     SG_LOG( SG_IO, SG_ALERT,
121             "Initializing ATC hardware, please wait ..." );
122
123     // This loads the config parameters generated by "simcal"
124     init_config();
125
126     /////////////////////////////////////////////////////////////////////
127     // Open the /proc files
128     /////////////////////////////////////////////////////////////////////
129
130     string lock0_file = "/proc/atcflightsim/board0/lock";
131     string lock1_file = "/proc/atcflightsim/board1/lock";
132
133     lock0_fd = ::open( lock0_file.c_str(), O_RDWR );
134     if ( lock0_fd == -1 ) {
135         SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
136         char msg[256];
137         snprintf( msg, 256, "Error opening %s", lock0_file.c_str() );
138         perror( msg );
139         exit( -1 );
140     }
141
142     lock1_fd = ::open( lock1_file.c_str(), O_RDWR );
143     if ( lock1_fd == -1 ) {
144         SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
145         char msg[256];
146         snprintf( msg, 256, "Error opening %s", lock1_file.c_str() );
147         perror( msg );
148         exit( -1 );
149     }
150
151     if ( input0_path.str().length() ) {
152         input0 = new FGATCInput( 0, input0_path );
153         input0->open();
154     }
155     if ( input1_path.str().length() ) {
156         input1 = new FGATCInput( 1, input1_path );
157         input1->open();
158     }
159     if ( output0_path.str().length() ) {
160         output0 = new FGATCOutput( 0, output0_path );
161         output0->open( lock0_fd );
162     }
163     if ( output1_path.str().length() ) {
164         output1 = new FGATCOutput( 1, output1_path );
165         output1->open( lock1_fd );
166     }
167
168     set_hz( 30 );               // default to processing requests @ 30Hz
169     set_enabled( true );
170
171     /////////////////////////////////////////////////////////////////////
172     // Finished initing hardware
173     /////////////////////////////////////////////////////////////////////
174
175     SG_LOG( SG_IO, SG_ALERT,
176             "Done initializing ATC hardware." );
177
178     return true;
179 }
180
181
182 bool FGATCMain::process() {
183     // cout << "Main::process()\n";
184
185     bool board0_locked = false;
186     bool board1_locked = false;
187
188     if ( input0 != NULL || output0 != NULL ) {
189         // Lock board0 if we have a configuration for it
190         if ( fgATCMainLock( lock0_fd ) > 0 ) {
191             board0_locked = true;
192         }
193     }
194
195     if ( input1 != NULL || output1 != NULL ) {
196         // Lock board1 if we have a configuration for it
197         if ( fgATCMainLock( lock1_fd ) > 0 ) {
198             board1_locked = true;
199         }
200     }
201
202     // cout << "  locks: ";
203     // if ( board0_locked ) { cout << "board0 "; }
204     // if ( board1_locked ) { cout << "board1 "; }
205     // cout << endl;
206
207     // process the ATC inputs
208     if ( input0 != NULL && board0_locked ) {
209         input0->process();
210     }
211     if ( input1 != NULL && board1_locked ) {
212         input1->process();
213     }
214
215     // run our custom nasal script.  This is a layer above the raw
216     // hardware inputs.  It handles situations where there isn't a
217     // direct 1-1 linear mapping between ATC functionality and FG
218     // functionality, and handles situations where FG expects more
219     // functionality from the interface than the ATC hardware can
220     // directly provide.
221
222     FGNasalSys *n = (FGNasalSys*)globals->get_subsystem("nasal");
223     bool result = n->parseAndRun( "atcsim.update()" );
224     if ( !result ) {
225         SG_LOG( SG_GENERAL, SG_ALERT, "Nasal: atcsim.update() failed!" );
226     }
227
228     // process the ATC outputs
229     if ( output0 != NULL && board0_locked ) {
230         output0->process();
231     }
232     if ( output1 != NULL && board1_locked ) {
233         output1->process();
234     }
235
236     if ( board0_locked ) {
237         fgATCMainRelease( lock0_fd );
238     }
239     if ( board1_locked ) {
240         fgATCMainRelease( lock1_fd );
241     }
242
243     return true;
244 }
245
246
247 bool FGATCMain::close() {
248     cout << "FGATCMain::close()" << endl;
249
250     int result;
251
252     if ( input0 != NULL ) {
253         input0->close();
254     }
255     if ( input1 != NULL ) {
256         input1->close();
257     }
258     if ( output0 != NULL ) {
259         output0->close();
260     }
261     if ( output1 != NULL ) {
262         output1->close();
263     }
264
265     result = ::close( lock0_fd );
266     if ( result == -1 ) {
267         SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
268         char msg[256];
269         snprintf( msg, 256, "Error closing lock0_fd" );
270         perror( msg );
271         exit( -1 );
272     }
273
274     result = ::close( lock1_fd );
275     if ( result == -1 ) {
276         SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
277         char msg[256];
278         snprintf( msg, 256, "Error closing lock1_fd" );
279         perror( msg );
280         exit( -1 );
281     }
282
283     return true;
284 }