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