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