]> git.mxchange.org Git - flightgear.git/blob - src/Main/bfi.cxx
2b9945057d24ab4c08e41d7bada28e06c912e533
[flightgear.git] / src / Main / bfi.cxx
1 // bfi.cxx - Big Friendly Interface implementation
2 //
3 // Written by David Megginson, started February, 2000.
4 //
5 // Copyright (C) 2000  David Megginson - david@megginson.com
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 #if defined( FG_HAVE_NATIVE_SGI_COMPILERS )
29 #  include <iostream.h>
30 #else
31 #  include <iostream>
32 #endif
33
34 #include <simgear/constants.h>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/ephemeris/ephemeris.hxx>
37 #include <simgear/math/sg_types.hxx>
38 #include <simgear/misc/props.hxx>
39 #include <simgear/timing/sg_time.hxx>
40
41 #include <Aircraft/aircraft.hxx>
42 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
43 #include <Controls/controls.hxx>
44 #include <Autopilot/newauto.hxx>
45 #include <Scenery/scenery.hxx>
46 #include <Time/light.hxx>
47 #include <Time/event.hxx>
48 #include <Time/sunpos.hxx>
49 #include <Time/tmp.hxx>
50 #include <Cockpit/radiostack.hxx>
51 #ifndef FG_OLD_WEATHER
52 #  include <WeatherCM/FGLocalWeatherDatabase.h>
53 #else
54 #  include <Weather/weather.hxx>
55 #endif
56
57 #include "globals.hxx"
58 #include "options.hxx"
59 #include "save.hxx"
60 #include "fg_init.hxx"
61 #include <simgear/misc/props.hxx>
62
63 FG_USING_NAMESPACE(std);
64
65
66 #include "bfi.hxx"
67
68
69 \f
70 ////////////////////////////////////////////////////////////////////////
71 // Static variables.
72 ////////////////////////////////////////////////////////////////////////
73
74 bool FGBFI::_needReinit = false;
75
76
77 \f
78 ////////////////////////////////////////////////////////////////////////
79 // Local functions
80 ////////////////////////////////////////////////////////////////////////
81
82
83 /**
84  * Initialize the BFI by binding its functions to properties.
85  *
86  * TODO: perhaps these should migrate into the individual modules
87  * (i.e. they should register themselves).
88  */
89 void
90 FGBFI::init ()
91 {
92   FG_LOG(FG_GENERAL, FG_INFO, "Starting BFI init");
93                                 // Simulation
94   current_properties.tieInt("/sim/flight-model",
95                             getFlightModel, setFlightModel);
96 //   current_properties.tieString("/sim/aircraft",
97 //                             getAircraft, setAircraft);
98   // TODO: timeGMT
99   current_properties.tieString("/sim/time/gmt-string",
100                                getGMTString, 0);
101   current_properties.tieBool("/sim/hud/visibility",
102                              getHUDVisible, setHUDVisible);
103   current_properties.tieBool("/sim/panel/visibility",
104                              getPanelVisible, setPanelVisible);
105
106                                 // Position
107   current_properties.tieDouble("/position/latitude",
108                                 getLatitude, setLatitude);
109   current_properties.tieDouble("/position/longitude",
110                                getLongitude, setLongitude);
111   current_properties.tieDouble("/position/altitude",
112                                getAltitude, setAltitude);
113   current_properties.tieDouble("/position/altitude-agl",
114                                getAGL, 0);
115
116                                 // Orientation
117   current_properties.tieDouble("/orientation/heading",
118                                getHeading, setHeading);
119   current_properties.tieDouble("/orientation/heading-magnetic",
120                                getHeadingMag, 0);
121   current_properties.tieDouble("/orientation/pitch",
122                                getPitch, setPitch);
123   current_properties.tieDouble("/orientation/roll",
124                                getRoll, setRoll);
125
126                                 // Engine
127   current_properties.tieDouble("/engines/engine0/rpm",
128                                getRPM, 0);
129   current_properties.tieDouble("/engines/engine0/egt",
130                                getEGT, 0);
131
132                                 // Velocities
133   current_properties.tieDouble("/velocities/airspeed",
134                                getAirspeed, 0);
135   current_properties.tieDouble("/velocities/side-slip",
136                                getSideSlip, 0);
137   current_properties.tieDouble("/velocities/vertical-speed",
138                                getVerticalSpeed, 0);
139   current_properties.tieDouble("/velocities/speed-north",
140                                getSpeedNorth, setSpeedNorth);
141   current_properties.tieDouble("/velocities/speed-east",
142                                getSpeedEast, setSpeedEast);
143   current_properties.tieDouble("/velocities/speed-down",
144                                getSpeedDown, setSpeedDown);
145
146                                 // Controls
147   current_properties.tieDouble("/controls/throttle",
148                                getThrottle, setThrottle);
149   current_properties.tieDouble("/controls/mixture",
150                                getMixture, setMixture);
151   current_properties.tieDouble("/controls/propellor-pitch",
152                                getPropAdvance, setPropAdvance);
153   current_properties.tieDouble("/controls/flaps",
154                                getFlaps, setFlaps);
155   current_properties.tieDouble("/controls/aileron",
156                                getAileron, setAileron);
157   current_properties.tieDouble("/controls/rudder",
158                                getRudder, setRudder);
159   current_properties.tieDouble("/controls/elevator",
160                                getElevator, setElevator);
161   current_properties.tieDouble("/controls/elevator-trim",
162                                getElevatorTrim, setElevatorTrim);
163   current_properties.tieDouble("/controls/brakes/all",
164                                getBrakes, setBrakes);
165   current_properties.tieDouble("/controls/brakes/left",
166                                getLeftBrake, setLeftBrake);
167   current_properties.tieDouble("/controls/brakes/right",
168                                getRightBrake, setRightBrake);
169   current_properties.tieDouble("/controls/brakes/center",
170                                getRightBrake, setCenterBrake);
171
172                                 // Autopilot
173   current_properties.tieBool("/autopilot/locks/altitude",
174                              getAPAltitudeLock, setAPAltitudeLock);
175   current_properties.tieDouble("/autopilot/settings/altitude",
176                                getAPAltitude, setAPAltitude);
177   current_properties.tieBool("/autopilot/locks/heading",
178                              getAPHeadingLock, setAPHeadingLock);
179   current_properties.tieDouble("/autopilot/settings/heading",
180                                getAPHeading, setAPHeading);
181   current_properties.tieDouble("/autopilot/settings/heading-magnetic",
182                                getAPHeadingMag, setAPHeadingMag);
183   current_properties.tieBool("/autopilot/locks/nav1",
184                              getAPNAV1Lock, setAPNAV1Lock);
185
186                                 // Radio navigation
187   current_properties.tieDouble("/radios/nav1/frequencies/selected",
188                                getNAV1Freq, setNAV1Freq);
189   current_properties.tieDouble("/radios/nav1/frequencies/standby",
190                                getNAV1AltFreq, setNAV1AltFreq);
191   current_properties.tieDouble("/radios/nav1/radials/actual",
192                                getNAV1Radial, 0);
193   current_properties.tieDouble("/radios/nav1/radials/selected",
194                                getNAV1SelRadial, setNAV1SelRadial);
195   current_properties.tieDouble("/radios/nav1/dme/distance",
196                                getNAV1DistDME, 0);
197   current_properties.tieBool("/radios/nav1/to-flag",
198                              getNAV1TO, 0);
199   current_properties.tieBool("/radios/nav1/from-flag",
200                              getNAV1FROM, 0);
201   current_properties.tieBool("/radios/nav1/in-range",
202                              getNAV1InRange, 0);
203   current_properties.tieBool("/radios/nav1/dme/in-range",
204                              getNAV1DMEInRange, 0);
205                                
206   current_properties.tieDouble("/radios/nav2/frequencies/selected",
207                                getNAV2Freq, setNAV2Freq);
208   current_properties.tieDouble("/radios/nav2/frequencies/standby",
209                                getNAV2AltFreq, setNAV2AltFreq);
210   current_properties.tieDouble("/radios/nav2/radials/actual",
211                                getNAV2Radial, 0);
212   current_properties.tieDouble("/radios/nav2/radials/selected",
213                                getNAV2SelRadial, setNAV2SelRadial);
214   current_properties.tieDouble("/radios/nav2/dme/distance",
215                                getNAV2DistDME, 0);
216   current_properties.tieBool("/radios/nav2/to-flag",
217                              getNAV2TO, 0);
218   current_properties.tieBool("/radios/nav2/from-flag",
219                              getNAV2FROM, 0);
220   current_properties.tieBool("/radios/nav2/in-range",
221                              getNAV2InRange, 0);
222   current_properties.tieBool("/radios/nav2/dme/in-range",
223                              getNAV2DMEInRange, 0);
224
225   current_properties.tieDouble("/radios/adf/frequencies/selected",
226                                getADFFreq, setADFFreq);
227   current_properties.tieDouble("/radios/adf/frequencies/standby",
228                                getADFAltFreq, setADFAltFreq);
229   current_properties.tieDouble("/radios/adf/rotation",
230                                getADFRotation, setADFRotation);
231
232   current_properties.tieDouble("/environment/visibility",
233                                getVisibility, setVisibility);
234
235   FG_LOG(FG_GENERAL, FG_INFO, "Ending BFI init");
236 }
237
238
239 /**
240  * Reinitialize FGFS if required.
241  *
242  * Some changes (especially those in aircraft position) require that
243  * FGFS be reinitialized afterwards.  Rather than reinitialize after
244  * every change, the setter methods simply set a flag so that there
245  * can be a single reinit at the end of the frame.
246  */
247 void
248 FGBFI::update ()
249 {
250   if (_needReinit) {
251     reinit();
252   }
253 }
254
255
256 /**
257  * Reinitialize FGFS to use the new BFI settings.
258  */
259 void
260 FGBFI::reinit ()
261 {
262                                 // Save the state of everything
263                                 // that's going to get clobbered
264                                 // when we reinit the subsystems.
265
266   cout << "BFI: start reinit\n";
267
268                                 // TODO: add more AP stuff
269   double elevator = getElevator();
270   double aileron = getAileron();
271   double rudder = getRudder();
272   double throttle = getThrottle();
273   double elevator_trim = getElevatorTrim();
274   double flaps = getFlaps();
275   double brake = getBrakes();
276   bool apHeadingLock = getAPHeadingLock();
277   double apHeadingMag = getAPHeadingMag();
278   bool apAltitudeLock = getAPAltitudeLock();
279   double apAltitude = getAPAltitude();
280   const string &targetAirport = getTargetAirport();
281   bool gpsLock = getGPSLock();
282   double gpsLatitude = getGPSTargetLatitude();
283   double gpsLongitude = getGPSTargetLongitude();
284
285   setTargetAirport("");
286   cout << "Target airport is " << current_options.get_airport_id() << endl;
287
288   fgReInitSubsystems();
289
290                                 // FIXME: this is wrong.
291                                 // All of these are scheduled events,
292                                 // and it should be possible to force
293                                 // them all to run once.
294   fgUpdateSunPos();
295   fgUpdateMoonPos();
296   cur_light_params.Update();
297   fgUpdateLocalTime();
298   fgUpdateWeatherDatabase();
299   fgRadioSearch();
300
301                                 // Restore all of the old states.
302   setElevator(elevator);
303   setAileron(aileron);
304   setRudder(rudder);
305   setThrottle(throttle);
306   setElevatorTrim(elevator_trim);
307   setFlaps(flaps);
308   setBrakes(brake);
309   setAPHeadingLock(apHeadingLock);
310   setAPHeadingMag(apHeadingMag);
311   setAPAltitudeLock(apAltitudeLock);
312   setAPAltitude(apAltitude);
313   setTargetAirport(targetAirport);
314   setGPSLock(gpsLock);
315   setGPSTargetLatitude(gpsLatitude);
316   setGPSTargetLongitude(gpsLongitude);
317
318   _needReinit = false;
319
320   cout << "BFI: end reinit\n";
321 }
322
323
324 \f
325 ////////////////////////////////////////////////////////////////////////
326 // Simulation.
327 ////////////////////////////////////////////////////////////////////////
328
329
330 /**
331  * Return the flight model as an integer.
332  *
333  * TODO: use a string instead.
334  */
335 int
336 FGBFI::getFlightModel ()
337 {
338   return current_options.get_flight_model();
339 }
340
341
342 /**
343  * Return the current aircraft as a string.
344  */
345 const string
346 FGBFI::getAircraft ()
347 {
348   return current_options.get_aircraft();
349 }
350
351
352 /**
353  * Return the current aircraft directory (UIUC) as a string.
354  */
355 const string
356 FGBFI::getAircraftDir ()
357 {
358   return aircraft_dir;
359 }
360
361
362 /**
363  * Set the flight model as an integer.
364  *
365  * TODO: use a string instead.
366  */
367 void
368 FGBFI::setFlightModel (int model)
369 {
370   if (getFlightModel() != model) {
371     current_options.set_flight_model(model);
372     needReinit();
373   }
374 }
375
376
377 /**
378  * Set the current aircraft.
379  */
380 void
381 FGBFI::setAircraft (const string &aircraft)
382 {
383   if (getAircraft() != aircraft) {
384     current_options.set_aircraft(aircraft);
385     needReinit();
386   }
387 }
388
389
390 /**
391  * Set the current aircraft directory (UIUC).
392  */
393 void
394 FGBFI::setAircraftDir (const string &dir)
395 {
396   if (getAircraftDir() != dir) {
397     aircraft_dir = dir;
398     needReinit();
399   }
400 }
401
402
403 /**
404  * Return the current Zulu time.
405  */
406 time_t
407 FGBFI::getTimeGMT ()
408 {
409   return globals->get_time_params()->get_cur_time();
410 }
411
412
413 /**
414  * Set the current Zulu time.
415  */
416 void
417 FGBFI::setTimeGMT (time_t time)
418 {
419   if (getTimeGMT() != time) {
420                                 // FIXME: need to update lighting
421                                 // and solar system
422     current_options.set_time_offset(time);
423     current_options.set_time_offset_type(fgOPTIONS::FG_TIME_GMT_ABSOLUTE);
424     globals->get_time_params()->update( cur_fdm_state->get_Longitude(),
425                                         cur_fdm_state->get_Latitude(),
426                                         globals->get_warp() );
427     needReinit();
428   }
429 }
430
431
432 /**
433  * Return the GMT as a string.
434  */
435 const string &
436 FGBFI::getGMTString ()
437 {
438   static string out;            // FIXME: not thread-safe
439   char buf[16];
440   struct tm * t = globals->get_time_params()->getGmt();
441   sprintf(buf, " %.2d:%.2d:%.2d",
442           t->tm_hour, t->tm_min, t->tm_sec);
443   out = buf;
444   return out;
445 }
446
447
448 /**
449  * Return true if the HUD is visible.
450  */
451 bool
452 FGBFI::getHUDVisible ()
453 {
454   return current_options.get_hud_status();
455 }
456
457
458 /**
459  * Ensure that the HUD is visible or hidden.
460  */
461 void
462 FGBFI::setHUDVisible (bool visible)
463 {
464   current_options.set_hud_status(visible);
465 }
466
467
468 /**
469  * Return true if the 2D panel is visible.
470  */
471 bool
472 FGBFI::getPanelVisible ()
473 {
474   return current_options.get_panel_status();
475 }
476
477
478 /**
479  * Ensure that the 2D panel is visible or hidden.
480  */
481 void
482 FGBFI::setPanelVisible (bool visible)
483 {
484   if (current_options.get_panel_status() != visible) {
485     current_options.toggle_panel();
486   }
487 }
488
489
490 \f
491 ////////////////////////////////////////////////////////////////////////
492 // Position
493 ////////////////////////////////////////////////////////////////////////
494
495
496 /**
497  * Return the current latitude in degrees (negative for south).
498  */
499 double
500 FGBFI::getLatitude ()
501 {
502   return current_aircraft.fdm_state->get_Latitude() * RAD_TO_DEG;
503 }
504
505
506 /**
507  * Set the current latitude in degrees (negative for south).
508  */
509 void
510 FGBFI::setLatitude (double latitude)
511 {
512   if (getLatitude() != latitude) {
513     current_options.set_lat(latitude);
514     current_aircraft.fdm_state->set_Latitude(latitude * DEG_TO_RAD);
515     needReinit();
516   }
517 }
518
519
520 /**
521  * Return the current longitude in degrees (negative for west).
522  */
523 double
524 FGBFI::getLongitude ()
525 {
526   return current_aircraft.fdm_state->get_Longitude() * RAD_TO_DEG;
527 }
528
529
530 /**
531  * Set the current longitude in degrees (negative for west).
532  */
533 void
534 FGBFI::setLongitude (double longitude)
535 {
536   if (getLongitude() != longitude) {
537     current_options.set_lon(longitude);
538     current_aircraft.fdm_state->set_Longitude(longitude * DEG_TO_RAD);
539     needReinit();
540   }
541 }
542
543
544 /**
545  * Return the current altitude in feet.
546  */
547 double
548 FGBFI::getAltitude ()
549 {
550   return current_aircraft.fdm_state->get_Altitude();
551 }
552
553
554
555 /**
556  * Return the current altitude in above the terrain.
557  */
558 double
559 FGBFI::getAGL ()
560 {
561   return current_aircraft.fdm_state->get_Altitude()
562          - (scenery.cur_elev * METER_TO_FEET);
563 }
564
565
566 /**
567  * Set the current altitude in feet.
568  */
569 void
570 FGBFI::setAltitude (double altitude)
571 {
572   if (getAltitude() != altitude) {
573     fgFDMForceAltitude(getFlightModel(), altitude);
574     current_options.set_altitude(altitude);
575     current_aircraft.fdm_state->set_Altitude(altitude);
576   }
577 }
578
579
580 \f
581 ////////////////////////////////////////////////////////////////////////
582 // Attitude
583 ////////////////////////////////////////////////////////////////////////
584
585
586 /**
587  * Return the current heading in degrees.
588  */
589 double
590 FGBFI::getHeading ()
591 {
592   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG;
593 }
594
595
596 /**
597  * Return the current heading in degrees.
598  */
599 double
600 FGBFI::getHeadingMag ()
601 {
602   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG - getMagVar();
603 }
604
605
606 /**
607  * Set the current heading in degrees.
608  */
609 void
610 FGBFI::setHeading (double heading)
611 {
612   if (getHeading() != heading) {
613     current_options.set_heading(heading);
614     current_aircraft.fdm_state->set_Euler_Angles(getRoll() * DEG_TO_RAD,
615                                                  getPitch() * DEG_TO_RAD,
616                                                  heading * DEG_TO_RAD);
617     needReinit();
618   }
619 }
620
621
622 /**
623  * Return the current pitch in degrees.
624  */
625 double
626 FGBFI::getPitch ()
627 {
628   return current_aircraft.fdm_state->get_Theta() * RAD_TO_DEG;
629 }
630
631
632 /**
633  * Set the current pitch in degrees.
634  */
635 void
636 FGBFI::setPitch (double pitch)
637 {
638   if (getPitch() != pitch) {
639     current_options.set_pitch(pitch);
640     current_aircraft.fdm_state->set_Euler_Angles(getRoll() * DEG_TO_RAD,
641                                                  pitch * DEG_TO_RAD,
642                                                  getHeading() * DEG_TO_RAD);
643     needReinit();
644   }
645 }
646
647
648 /**
649  * Return the current roll in degrees.
650  */
651 double
652 FGBFI::getRoll ()
653 {
654   return current_aircraft.fdm_state->get_Phi() * RAD_TO_DEG;
655 }
656
657
658 /**
659  * Set the current roll in degrees.
660  */
661 void
662 FGBFI::setRoll (double roll)
663 {
664   if (getRoll() != roll) {
665     current_options.set_roll(roll);
666     current_aircraft.fdm_state->set_Euler_Angles(roll * DEG_TO_RAD,
667                                                  getPitch() * DEG_TO_RAD,
668                                                  getHeading() * DEG_TO_RAD);
669     needReinit();
670   }
671 }
672
673
674 /**
675  * Return the current engine0 rpm
676  */
677 double
678 FGBFI::getRPM ()
679 {
680   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
681       return current_aircraft.fdm_state->get_engine(0)->get_RPM();
682   } else {
683       return 0.0;
684   }
685 }
686
687
688 /**
689  * Set the current engine0 rpm
690  */
691 void
692 FGBFI::setRPM (double rpm)
693 {
694     if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
695         if (getRPM() != rpm) {
696             current_aircraft.fdm_state->get_engine(0)->set_RPM( rpm );
697         }
698     }
699 }
700
701
702 /**
703  * Return the current engine0 EGT.
704  */
705 double
706 FGBFI::getEGT ()
707 {
708   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
709       return current_aircraft.fdm_state->get_engine(0)->get_EGT();
710   }
711 }
712
713
714 \f
715 ////////////////////////////////////////////////////////////////////////
716 // Velocities
717 ////////////////////////////////////////////////////////////////////////
718
719
720 /**
721  * Return the current airspeed in knots.
722  */
723 double
724 FGBFI::getAirspeed ()
725 {
726                                 // FIXME: should we add speed-up?
727   return current_aircraft.fdm_state->get_V_calibrated_kts();
728 }
729
730
731 /**
732  * Return the current sideslip (FIXME: units unknown).
733  */
734 double
735 FGBFI::getSideSlip ()
736 {
737   return current_aircraft.fdm_state->get_Beta();
738 }
739
740
741 /**
742  * Return the current climb rate in feet/minute
743  */
744 double
745 FGBFI::getVerticalSpeed ()
746 {
747                                 // What about meters?
748   return current_aircraft.fdm_state->get_Climb_Rate() * 60.0;
749 }
750
751
752 /**
753  * Get the current north velocity (units??).
754  */
755 double
756 FGBFI::getSpeedNorth ()
757 {
758   return current_aircraft.fdm_state->get_V_north();
759 }
760
761
762 /**
763  * Set the current north velocity (units??).
764  */
765 void
766 FGBFI::setSpeedNorth (double speed)
767 {
768   if (getSpeedNorth() != speed) {
769     current_options.set_uBody(speed);
770     current_aircraft.fdm_state->set_Velocities_Local(speed,
771                                                      getSpeedEast(),
772                                                      getSpeedDown());
773     needReinit();
774   }
775 }
776
777
778 /**
779  * Get the current east velocity (units??).
780  */
781 double
782 FGBFI::getSpeedEast ()
783 {
784   return current_aircraft.fdm_state->get_V_east();
785 }
786
787
788 /**
789  * Set the current east velocity (units??).
790  */
791 void
792 FGBFI::setSpeedEast (double speed)
793 {
794   if (getSpeedEast() != speed) {
795     current_options.set_vBody(speed);
796     current_aircraft.fdm_state->set_Velocities_Local(getSpeedNorth(),
797                                                      speed,
798                                                      getSpeedDown());
799     needReinit();
800   }
801 }
802
803
804 /**
805  * Get the current down velocity (units??).
806  */
807 double
808 FGBFI::getSpeedDown ()
809 {
810   return current_aircraft.fdm_state->get_V_down();
811 }
812
813
814 /**
815  * Set the current down velocity (units??).
816  */
817 void
818 FGBFI::setSpeedDown (double speed)
819 {
820   if (getSpeedDown() != speed) {
821     current_options.set_wBody(speed);
822     current_aircraft.fdm_state->set_Velocities_Local(getSpeedNorth(),
823                                                      getSpeedEast(),
824                                                      speed);
825     needReinit();
826   }
827 }
828
829
830 \f
831 ////////////////////////////////////////////////////////////////////////
832 // Controls
833 ////////////////////////////////////////////////////////////////////////
834
835
836 /**
837  * Get the throttle setting, from 0.0 (none) to 1.0 (full).
838  */
839 double
840 FGBFI::getThrottle ()
841 {
842                                 // FIXME: add engine selector
843   return controls.get_throttle(0);
844 }
845
846
847 /**
848  * Set the throttle, from 0.0 (none) to 1.0 (full).
849  */
850 void
851 FGBFI::setThrottle (double throttle)
852 {
853                                 // FIXME: allow engine selection
854   controls.set_throttle(0, throttle);
855 }
856
857
858 /**
859  * Get the fuel mixture setting, from 0.0 (none) to 1.0 (full).
860  */
861 double
862 FGBFI::getMixture ()
863 {
864                                 // FIXME: add engine selector
865   return controls.get_mixture(0);
866 }
867
868
869 /**
870  * Set the fuel mixture, from 0.0 (none) to 1.0 (full).
871  */
872 void
873 FGBFI::setMixture (double mixture)
874 {
875                                 // FIXME: allow engine selection
876   controls.set_mixture(0, mixture);
877 }
878
879
880 /**
881  * Get the propellor pitch setting, from 0.0 (none) to 1.0 (full).
882  */
883 double
884 FGBFI::getPropAdvance ()
885 {
886                                 // FIXME: add engine selector
887   return controls.get_prop_advance(0);
888 }
889
890
891 /**
892  * Set the propellor pitch, from 0.0 (none) to 1.0 (full).
893  */
894 void
895 FGBFI::setPropAdvance (double pitch)
896 {
897                                 // FIXME: allow engine selection
898   controls.set_prop_advance(0, pitch);
899 }
900
901
902 /**
903  * Get the flaps setting, from 0.0 (none) to 1.0 (full).
904  */
905 double
906 FGBFI::getFlaps ()
907 {
908   return controls.get_flaps();
909 }
910
911
912 /**
913  * Set the flaps, from 0.0 (none) to 1.0 (full).
914  */
915 void
916 FGBFI::setFlaps (double flaps)
917 {
918                                 // FIXME: clamp?
919   controls.set_flaps(flaps);
920 }
921
922
923 /**
924  * Get the aileron, from -1.0 (left) to 1.0 (right).
925  */
926 double
927 FGBFI::getAileron ()
928 {
929   return controls.get_aileron();
930 }
931
932
933 /**
934  * Set the aileron, from -1.0 (left) to 1.0 (right).
935  */
936 void
937 FGBFI::setAileron (double aileron)
938 {
939                                 // FIXME: clamp?
940   controls.set_aileron(aileron);
941 }
942
943
944 /**
945  * Get the rudder setting, from -1.0 (left) to 1.0 (right).
946  */
947 double
948 FGBFI::getRudder ()
949 {
950   return controls.get_rudder();
951 }
952
953
954 /**
955  * Set the rudder, from -1.0 (left) to 1.0 (right).
956  */
957 void
958 FGBFI::setRudder (double rudder)
959 {
960                                 // FIXME: clamp?
961   controls.set_rudder(rudder);
962 }
963
964
965 /**
966  * Get the elevator setting, from -1.0 (down) to 1.0 (up).
967  */
968 double
969 FGBFI::getElevator ()
970 {
971   return controls.get_elevator();
972 }
973
974
975 /**
976  * Set the elevator, from -1.0 (down) to 1.0 (up).
977  */
978 void
979 FGBFI::setElevator (double elevator)
980 {
981                                 // FIXME: clamp?
982   controls.set_elevator(elevator);
983 }
984
985
986 /**
987  * Get the elevator trim, from -1.0 (down) to 1.0 (up).
988  */
989 double
990 FGBFI::getElevatorTrim ()
991 {
992   return controls.get_elevator_trim();
993 }
994
995
996 /**
997  * Set the elevator trim, from -1.0 (down) to 1.0 (up).
998  */
999 void
1000 FGBFI::setElevatorTrim (double trim)
1001 {
1002                                 // FIXME: clamp?
1003   controls.set_elevator_trim(trim);
1004 }
1005
1006
1007 /**
1008  * Get the highest brake setting, from 0.0 (none) to 1.0 (full).
1009  */
1010 double
1011 FGBFI::getBrakes ()
1012 {
1013   double b1 = getCenterBrake();
1014   double b2 = getLeftBrake();
1015   double b3 = getRightBrake();
1016   return (b1 > b2 ? (b1 > b3 ? b1 : b3) : (b2 > b3 ? b2 : b3));
1017 }
1018
1019
1020 /**
1021  * Set all brakes, from 0.0 (none) to 1.0 (full).
1022  */
1023 void
1024 FGBFI::setBrakes (double brake)
1025 {
1026   setCenterBrake(brake);
1027   setLeftBrake(brake);
1028   setRightBrake(brake);
1029 }
1030
1031
1032 /**
1033  * Get the center brake, from 0.0 (none) to 1.0 (full).
1034  */
1035 double
1036 FGBFI::getCenterBrake ()
1037 {
1038   return controls.get_brake(2);
1039 }
1040
1041
1042 /**
1043  * Set the center brake, from 0.0 (none) to 1.0 (full).
1044  */
1045 void
1046 FGBFI::setCenterBrake (double brake)
1047 {
1048   controls.set_brake(2, brake);
1049 }
1050
1051
1052 /**
1053  * Get the left brake, from 0.0 (none) to 1.0 (full).
1054  */
1055 double
1056 FGBFI::getLeftBrake ()
1057 {
1058   return controls.get_brake(0);
1059 }
1060
1061
1062 /**
1063  * Set the left brake, from 0.0 (none) to 1.0 (full).
1064  */
1065 void
1066 FGBFI::setLeftBrake (double brake)
1067 {
1068   controls.set_brake(0, brake);
1069 }
1070
1071
1072 /**
1073  * Get the right brake, from 0.0 (none) to 1.0 (full).
1074  */
1075 double
1076 FGBFI::getRightBrake ()
1077 {
1078   return controls.get_brake(1);
1079 }
1080
1081
1082 /**
1083  * Set the right brake, from 0.0 (none) to 1.0 (full).
1084  */
1085 void
1086 FGBFI::setRightBrake (double brake)
1087 {
1088   controls.set_brake(1, brake);
1089 }
1090
1091
1092
1093
1094 \f
1095 ////////////////////////////////////////////////////////////////////////
1096 // Autopilot
1097 ////////////////////////////////////////////////////////////////////////
1098
1099
1100 /**
1101  * Get the autopilot altitude lock (true=on).
1102  */
1103 bool
1104 FGBFI::getAPAltitudeLock ()
1105 {
1106     return current_autopilot->get_AltitudeEnabled();
1107 }
1108
1109
1110 /**
1111  * Set the autopilot altitude lock (true=on).
1112  */
1113 void
1114 FGBFI::setAPAltitudeLock (bool lock)
1115 {
1116   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
1117   current_autopilot->set_AltitudeEnabled(lock);
1118 }
1119
1120
1121 /**
1122  * Get the autopilot target altitude in feet.
1123  */
1124 double
1125 FGBFI::getAPAltitude ()
1126 {
1127   return current_autopilot->get_TargetAltitude() * METER_TO_FEET;
1128 }
1129
1130
1131 /**
1132  * Set the autopilot target altitude in feet.
1133  */
1134 void
1135 FGBFI::setAPAltitude (double altitude)
1136 {
1137     current_autopilot->set_TargetAltitude( altitude );
1138 }
1139
1140
1141 /**
1142  * Get the autopilot heading lock (true=on).
1143  */
1144 bool
1145 FGBFI::getAPHeadingLock ()
1146 {
1147     return
1148       (current_autopilot->get_HeadingEnabled() &&
1149        current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_LOCK);
1150 }
1151
1152
1153 /**
1154  * Set the autopilot heading lock (true=on).
1155  */
1156 void
1157 FGBFI::setAPHeadingLock (bool lock)
1158 {
1159   if (lock) {
1160                                 // We need to do this so that
1161                                 // it's possible to lock onto a
1162                                 // heading other than the current
1163                                 // heading.
1164     double heading = getAPHeadingMag();
1165     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_LOCK);
1166     current_autopilot->set_HeadingEnabled(true);
1167     setAPHeadingMag(heading);
1168   } else if (current_autopilot->get_HeadingMode() ==
1169              FGAutopilot::FG_HEADING_LOCK) {
1170     current_autopilot->set_HeadingEnabled(false);
1171   }
1172 }
1173
1174
1175 /**
1176  * Get the autopilot target heading in degrees.
1177  */
1178 double
1179 FGBFI::getAPHeading ()
1180 {
1181   return current_autopilot->get_TargetHeading();
1182 }
1183
1184
1185 /**
1186  * Set the autopilot target heading in degrees.
1187  */
1188 void
1189 FGBFI::setAPHeading (double heading)
1190 {
1191   current_autopilot->set_TargetHeading( heading );
1192 }
1193
1194
1195 /**
1196  * Get the autopilot target heading in degrees.
1197  */
1198 double
1199 FGBFI::getAPHeadingMag ()
1200 {
1201   return current_autopilot->get_TargetHeading() - getMagVar();
1202 }
1203
1204
1205 /**
1206  * Set the autopilot target heading in degrees.
1207  */
1208 void
1209 FGBFI::setAPHeadingMag (double heading)
1210 {
1211   current_autopilot->set_TargetHeading( heading + getMagVar() );
1212 }
1213
1214
1215 /**
1216  * Return true if the autopilot is locked to NAV1.
1217  */
1218 bool
1219 FGBFI::getAPNAV1Lock ()
1220 {
1221   return
1222     (current_autopilot->get_HeadingEnabled() &&
1223      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
1224 }
1225
1226
1227 /**
1228  * Set the autopilot NAV1 lock.
1229  */
1230 void
1231 FGBFI::setAPNAV1Lock (bool lock)
1232 {
1233   if (lock) {
1234     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
1235     current_autopilot->set_HeadingEnabled(true);
1236   } else if (current_autopilot->get_HeadingMode() ==
1237              FGAutopilot::FG_HEADING_NAV1) {
1238     current_autopilot->set_HeadingEnabled(false);
1239   }
1240 }
1241
1242
1243 \f
1244 ////////////////////////////////////////////////////////////////////////
1245 // Radio navigation.
1246 ////////////////////////////////////////////////////////////////////////
1247
1248 double
1249 FGBFI::getNAV1Freq ()
1250 {
1251   return current_radiostack->get_nav1_freq();
1252 }
1253
1254 double
1255 FGBFI::getNAV1AltFreq ()
1256 {
1257   return current_radiostack->get_nav1_alt_freq();
1258 }
1259
1260 double
1261 FGBFI::getNAV1Radial ()
1262 {
1263   return current_radiostack->get_nav1_radial();
1264 }
1265
1266 double
1267 FGBFI::getNAV1SelRadial ()
1268 {
1269   return current_radiostack->get_nav1_sel_radial();
1270 }
1271
1272 double
1273 FGBFI::getNAV1DistDME ()
1274 {
1275   return current_radiostack->get_nav1_dme_dist();
1276 }
1277
1278 bool 
1279 FGBFI::getNAV1TO ()
1280 {
1281   if (current_radiostack->get_nav1_inrange()) {
1282     double heading = current_radiostack->get_nav1_heading();
1283     double radial = current_radiostack->get_nav1_radial();
1284     double var = FGBFI::getMagVar();
1285     if (current_radiostack->get_nav1_loc()) {
1286       double offset = fabs(heading - radial);
1287       return (offset<= 8.0 || offset >= 352.0);
1288     } else {
1289       double offset =
1290         fabs(heading - var - radial);
1291       return (offset <= 20.0 || offset >= 340.0);
1292     }
1293   } else {
1294     return false;
1295   }
1296 }
1297
1298 bool
1299 FGBFI::getNAV1FROM ()
1300 {
1301   if (current_radiostack->get_nav1_inrange()) {
1302     double heading = current_radiostack->get_nav1_heading();
1303     double radial = current_radiostack->get_nav1_radial();
1304     double var = FGBFI::getMagVar();
1305     if (current_radiostack->get_nav1_loc()) {
1306       double offset = fabs(heading - radial);
1307       return (offset >= 172.0 && offset<= 188.0);
1308     } else {
1309       double offset =
1310         fabs(heading - var - radial);
1311       return (offset >= 160.0 && offset <= 200.0);
1312     }
1313   } else {
1314     return false;
1315   }
1316 }
1317
1318 bool
1319 FGBFI::getNAV1InRange ()
1320 {
1321   return current_radiostack->get_nav1_inrange();
1322 }
1323
1324 bool
1325 FGBFI::getNAV1DMEInRange ()
1326 {
1327   return (current_radiostack->get_nav1_inrange() &&
1328           current_radiostack->get_nav1_has_dme());
1329 }
1330
1331 double
1332 FGBFI::getNAV2Freq ()
1333 {
1334   return current_radiostack->get_nav2_freq();
1335 }
1336
1337 double
1338 FGBFI::getNAV2AltFreq ()
1339 {
1340   return current_radiostack->get_nav2_alt_freq();
1341 }
1342
1343 double
1344 FGBFI::getNAV2Radial ()
1345 {
1346   return current_radiostack->get_nav2_radial();
1347 }
1348
1349 double
1350 FGBFI::getNAV2SelRadial ()
1351 {
1352   return current_radiostack->get_nav2_sel_radial();
1353 }
1354
1355 double
1356 FGBFI::getNAV2DistDME ()
1357 {
1358   return current_radiostack->get_nav2_dme_dist();
1359 }
1360
1361 bool 
1362 FGBFI::getNAV2TO ()
1363 {
1364   if (current_radiostack->get_nav2_inrange()) {
1365     double heading = current_radiostack->get_nav2_heading();
1366     double radial = current_radiostack->get_nav2_radial();
1367     double var = FGBFI::getMagVar();
1368     if (current_radiostack->get_nav2_loc()) {
1369       double offset = fabs(heading - radial);
1370       return (offset<= 8.0 || offset >= 352.0);
1371     } else {
1372       double offset =
1373         fabs(heading - var - radial);
1374       return (offset <= 20.0 || offset >= 340.0);
1375     }
1376   } else {
1377     return false;
1378   }
1379 }
1380
1381 bool 
1382 FGBFI::getNAV2FROM ()
1383 {
1384   if (current_radiostack->get_nav2_inrange()) {
1385     double heading = current_radiostack->get_nav2_heading();
1386     double radial = current_radiostack->get_nav2_radial();
1387     double var = FGBFI::getMagVar();
1388     if (current_radiostack->get_nav2_loc()) {
1389       double offset = fabs(heading - radial);
1390       return (offset >= 172.0 && offset<= 188.0);
1391     } else {
1392       double offset =
1393         fabs(heading - var - radial);
1394       return (offset >= 160.0 && offset <= 200.0);
1395     }
1396   } else {
1397     return false;
1398   }
1399 }
1400
1401
1402 bool
1403 FGBFI::getNAV2InRange ()
1404 {
1405   return current_radiostack->get_nav2_inrange();
1406 }
1407
1408 bool
1409 FGBFI::getNAV2DMEInRange ()
1410 {
1411   return (current_radiostack->get_nav2_inrange() &&
1412           current_radiostack->get_nav2_has_dme());
1413 }
1414
1415 double
1416 FGBFI::getADFFreq ()
1417 {
1418   return current_radiostack->get_adf_freq();
1419 }
1420
1421 double
1422 FGBFI::getADFAltFreq ()
1423 {
1424   return current_radiostack->get_adf_alt_freq();
1425 }
1426
1427 double
1428 FGBFI::getADFRotation ()
1429 {
1430   return current_radiostack->get_adf_rotation();
1431 }
1432
1433 void
1434 FGBFI::setNAV1Freq (double freq)
1435 {
1436   current_radiostack->set_nav1_freq(freq);
1437 }
1438
1439 void
1440 FGBFI::setNAV1AltFreq (double freq)
1441 {
1442   current_radiostack->set_nav1_alt_freq(freq);
1443 }
1444
1445 void
1446 FGBFI::setNAV1SelRadial (double radial)
1447 {
1448   current_radiostack->set_nav1_sel_radial(radial);
1449 }
1450
1451 void
1452 FGBFI::setNAV2Freq (double freq)
1453 {
1454   current_radiostack->set_nav2_freq(freq);
1455 }
1456
1457 void
1458 FGBFI::setNAV2AltFreq (double freq)
1459 {
1460   current_radiostack->set_nav2_alt_freq(freq);
1461 }
1462
1463 void
1464 FGBFI::setNAV2SelRadial (double radial)
1465 {
1466   current_radiostack->set_nav2_sel_radial(radial);
1467 }
1468
1469 void
1470 FGBFI::setADFFreq (double freq)
1471 {
1472   current_radiostack->set_adf_freq(freq);
1473 }
1474
1475 void
1476 FGBFI::setADFAltFreq (double freq)
1477 {
1478   current_radiostack->set_adf_alt_freq(freq);
1479 }
1480
1481 void
1482 FGBFI::setADFRotation (double rot)
1483 {
1484   current_radiostack->set_adf_rotation(rot);
1485 }
1486
1487
1488 \f
1489 ////////////////////////////////////////////////////////////////////////
1490 // GPS
1491 ////////////////////////////////////////////////////////////////////////
1492
1493
1494 /**
1495  * Get the autopilot GPS lock (true=on).
1496  */
1497 bool
1498 FGBFI::getGPSLock ()
1499 {
1500   return (current_autopilot->get_HeadingEnabled() &&
1501           (current_autopilot->get_HeadingMode() ==
1502            FGAutopilot::FG_HEADING_WAYPOINT ));
1503 }
1504
1505
1506 /**
1507  * Set the autopilot GPS lock (true=on).
1508  */
1509 void
1510 FGBFI::setGPSLock (bool lock)
1511 {
1512   if (lock) {
1513     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_WAYPOINT);
1514     current_autopilot->set_HeadingEnabled(true);
1515   } else if (current_autopilot->get_HeadingMode() ==
1516              FGAutopilot::FG_HEADING_WAYPOINT) {
1517     current_autopilot->set_HeadingEnabled(false);
1518   }
1519 }
1520
1521
1522 /**
1523  * Get the GPS target airport code.
1524  */
1525 const string
1526 FGBFI::getTargetAirport ()
1527 {
1528   return current_options.get_airport_id();
1529 }
1530
1531
1532 /**
1533  * Set the GPS target airport code.
1534  */
1535 void
1536 FGBFI::setTargetAirport (const string &airportId)
1537 {
1538   current_options.set_airport_id(airportId);
1539 }
1540
1541
1542 /**
1543  * Get the GPS target latitude in degrees (negative for south).
1544  */
1545 double
1546 FGBFI::getGPSTargetLatitude ()
1547 {
1548     return current_autopilot->get_TargetLatitude();
1549 }
1550
1551
1552 /**
1553  * Set the GPS target latitude in degrees (negative for south).
1554  */
1555 void
1556 FGBFI::setGPSTargetLatitude (double latitude)
1557 {
1558   current_autopilot->set_TargetLatitude( latitude );
1559 }
1560
1561
1562 /**
1563  * Get the GPS target longitude in degrees (negative for west).
1564  */
1565 double
1566 FGBFI::getGPSTargetLongitude ()
1567 {
1568   return current_autopilot->get_TargetLongitude();
1569 }
1570
1571
1572 /**
1573  * Set the GPS target longitude in degrees (negative for west).
1574  */
1575 void
1576 FGBFI::setGPSTargetLongitude (double longitude)
1577 {
1578   current_autopilot->set_TargetLongitude( longitude );
1579 }
1580
1581
1582 \f
1583 ////////////////////////////////////////////////////////////////////////
1584 // Weather
1585 ////////////////////////////////////////////////////////////////////////
1586
1587
1588 /**
1589  * Get the current visible (units??).
1590  */
1591 double
1592 FGBFI::getVisibility ()
1593 {
1594 #ifndef FG_OLD_WEATHER
1595   return WeatherDatabase->getWeatherVisibility();
1596 #else
1597   return current_weather.get_visibility();
1598 #endif
1599 }
1600
1601
1602 /**
1603  * Check whether clouds are enabled.
1604  */
1605 bool
1606 FGBFI::getClouds ()
1607 {
1608   return current_options.get_clouds();
1609 }
1610
1611
1612 /**
1613  * Check the height of the clouds ASL (units?).
1614  */
1615 double
1616 FGBFI::getCloudsASL ()
1617 {
1618   return current_options.get_clouds_asl();
1619 }
1620
1621
1622 /**
1623  * Set the current visibility (units??).
1624  */
1625 void
1626 FGBFI::setVisibility (double visibility)
1627 {
1628 #ifndef FG_OLD_WEATHER
1629   WeatherDatabase->setWeatherVisibility(visibility);
1630 #else
1631   current_weather.set_visibility(visibility);
1632 #endif
1633 }
1634
1635
1636 /**
1637  * Switch clouds on or off.
1638  */
1639 void
1640 FGBFI::setClouds (bool clouds)
1641 {
1642   if (getClouds() != clouds) {
1643     cout << "Set clouds to " << clouds << endl;
1644     current_options.set_clouds(clouds);
1645     needReinit();
1646   }
1647 }
1648
1649
1650 /**
1651  * Set the cloud height.
1652  */
1653 void
1654 FGBFI::setCloudsASL (double cloudsASL)
1655 {
1656   if (getCloudsASL() != cloudsASL) {
1657     current_options.set_clouds_asl(cloudsASL);
1658     needReinit();
1659   }
1660 }
1661
1662
1663 \f
1664 ////////////////////////////////////////////////////////////////////////
1665 // Time
1666 ////////////////////////////////////////////////////////////////////////
1667
1668 /**
1669  * Return the magnetic variation
1670  */
1671 double
1672 FGBFI::getMagVar ()
1673 {
1674   return globals->get_mag()->get_magvar() * RAD_TO_DEG;
1675 }
1676
1677
1678 /**
1679  * Return the magnetic variation
1680  */
1681 double
1682 FGBFI::getMagDip ()
1683 {
1684   return globals->get_mag()->get_magdip() * RAD_TO_DEG;
1685 }
1686
1687
1688 // end of bfi.cxx
1689