]> git.mxchange.org Git - flightgear.git/blob - src/Main/bfi.cxx
1c0be117489796421c763e898d807a1176df4bc8
[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/fg_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
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.tieBool("/sim/hud/visibility",
99                              getHUDVisible, setHUDVisible);
100   current_properties.tieBool("/sim/panel/visibility",
101                              getPanelVisible, setPanelVisible);
102
103                                 // Position
104   current_properties.tieDouble("/position/latitude",
105                                 getLatitude, setLatitude);
106   current_properties.tieDouble("/position/longitude",
107                                getLongitude, setLongitude);
108   current_properties.tieDouble("/position/altitude",
109                                getAltitude, setAltitude);
110   current_properties.tieDouble("/position/altitude-agl",
111                                getAGL, 0);
112
113                                 // Orientation
114   current_properties.tieDouble("/orientation/heading",
115                                getHeading, setHeading);
116   current_properties.tieDouble("/orientation/heading-magnetic",
117                                getHeadingMag, 0);
118   current_properties.tieDouble("/orientation/pitch",
119                                getPitch, setPitch);
120   current_properties.tieDouble("/orientation/roll",
121                                getRoll, setRoll);
122
123                                 // Velocities
124   current_properties.tieDouble("/velocities/airspeed",
125                                getAirspeed, 0);
126   current_properties.tieDouble("/velocities/side-slip",
127                                getSideSlip, 0);
128   current_properties.tieDouble("/velocities/vertical-speed",
129                                getVerticalSpeed, 0);
130   current_properties.tieDouble("/velocities/speed-north",
131                                getSpeedNorth, setSpeedNorth);
132   current_properties.tieDouble("/velocities/speed-east",
133                                getSpeedEast, setSpeedEast);
134   current_properties.tieDouble("/velocities/speed-down",
135                                getSpeedDown, setSpeedDown);
136
137                                 // Controls
138   current_properties.tieDouble("/controls/throttle",
139                                getThrottle, setThrottle);
140   current_properties.tieDouble("/controls/flaps",
141                                getFlaps, setFlaps);
142   current_properties.tieDouble("/controls/aileron",
143                                getAileron, setAileron);
144   current_properties.tieDouble("/controls/rudder",
145                                getRudder, setRudder);
146   current_properties.tieDouble("/controls/elevator",
147                                getElevator, setElevator);
148   current_properties.tieDouble("/controls/elevator-trim",
149                                getElevatorTrim, setElevatorTrim);
150   current_properties.tieDouble("/controls/brake",
151                                getBrake, setBrake);
152
153                                 // Autopilot
154   current_properties.tieBool("/autopilot/locks/altitude",
155                              getAPAltitudeLock, setAPAltitudeLock);
156   current_properties.tieDouble("/autopilot/settings/altitude",
157                                getAPAltitude, setAPAltitude);
158   current_properties.tieBool("/autopilot/locks/heading",
159                              getAPHeadingLock, setAPHeadingLock);
160   current_properties.tieDouble("/autopilot/settings/heading-magnetic",
161                                getAPHeadingMag, setAPHeadingMag);
162   current_properties.tieBool("/autopilot/locks/nav1",
163                              getAPNAV1Lock, setAPNAV1Lock);
164
165                                 // Radio navigation
166   current_properties.tieDouble("/radios/nav1/frequencies/selected",
167                                getNAV1Freq, setNAV1Freq);
168   current_properties.tieDouble("/radios/nav1/frequencies/standby",
169                                getNAV1AltFreq, setNAV1AltFreq);
170   current_properties.tieDouble("/radios/nav1/radials/actual",
171                                getNAV1Radial, 0);
172   current_properties.tieDouble("/radios/nav1/radials/selected",
173                                getNAV1SelRadial, setNAV1SelRadial);
174   current_properties.tieDouble("/radios/nav1/dme/distance",
175                                getNAV1DistDME, 0);
176   current_properties.tieBool("/radios/nav1/in-range",
177                              getNAV1InRange, 0);
178   current_properties.tieBool("/radios/nav1/dme/in-range",
179                              getNAV1DMEInRange, 0);
180                                
181   current_properties.tieDouble("/radios/nav2/frequencies/selected",
182                                getNAV2Freq, setNAV2Freq);
183   current_properties.tieDouble("/radios/nav2/frequencies/standby",
184                                getNAV2AltFreq, setNAV2AltFreq);
185   current_properties.tieDouble("/radios/nav2/radials/actual",
186                                getNAV2Radial, 0);
187   current_properties.tieDouble("/radios/nav2/radials/selected",
188                                getNAV2SelRadial, setNAV2SelRadial);
189   current_properties.tieDouble("/radios/nav2/dme/distance",
190                                getNAV2DistDME, 0);
191   current_properties.tieBool("/radios/nav2/in-range",
192                              getNAV2InRange, 0);
193   current_properties.tieBool("/radios/nav2/dme/in-range",
194                              getNAV2DMEInRange, 0);
195
196   current_properties.tieDouble("/radios/adf/frequencies/selected",
197                                getADFFreq, setADFFreq);
198   current_properties.tieDouble("/radios/adf/frequencies/standby",
199                                getADFAltFreq, setADFAltFreq);
200   current_properties.tieDouble("/radios/adf/rotation",
201                                getADFRotation, setADFRotation);
202
203   FG_LOG(FG_GENERAL, FG_INFO, "Ending BFI init");
204 }
205
206
207 /**
208  * Reinitialize FGFS if required.
209  *
210  * Some changes (especially those in aircraft position) require that
211  * FGFS be reinitialized afterwards.  Rather than reinitialize after
212  * every change, the setter methods simply set a flag so that there
213  * can be a single reinit at the end of the frame.
214  */
215 void
216 FGBFI::update ()
217 {
218   if (_needReinit) {
219     reinit();
220   }
221 }
222
223
224 /**
225  * Reinitialize FGFS to use the new BFI settings.
226  */
227 void
228 FGBFI::reinit ()
229 {
230                                 // Save the state of everything
231                                 // that's going to get clobbered
232                                 // when we reinit the subsystems.
233
234   cout << "BFI: start reinit\n";
235
236   setHeading(getHeading());
237   setPitch(getPitch());
238   setRoll(getRoll());
239   setSpeedNorth(getSpeedNorth());
240   setSpeedEast(getSpeedEast());
241   setSpeedDown(getSpeedDown());
242   setLatitude(getLatitude());
243   setLongitude(getLongitude());
244   setAltitude(getAltitude());
245
246                                 // TODO: add more AP stuff
247   double elevator = getElevator();
248   double aileron = getAileron();
249   double rudder = getRudder();
250   double throttle = getThrottle();
251   double elevator_trim = getElevatorTrim();
252   double flaps = getFlaps();
253   double brake = getBrake();
254   bool apHeadingLock = getAPHeadingLock();
255   double apHeadingMag = getAPHeadingMag();
256   bool apAltitudeLock = getAPAltitudeLock();
257   double apAltitude = getAPAltitude();
258   const string &targetAirport = getTargetAirport();
259   bool gpsLock = getGPSLock();
260   double gpsLatitude = getGPSTargetLatitude();
261   double gpsLongitude = getGPSTargetLongitude();
262
263   setTargetAirport("");
264   cout << "Target airport is " << current_options.get_airport_id() << endl;
265
266   fgReInitSubsystems();
267
268                                 // FIXME: this is wrong.
269                                 // All of these are scheduled events,
270                                 // and it should be possible to force
271                                 // them all to run once.
272   fgUpdateSunPos();
273   fgUpdateMoonPos();
274   cur_light_params.Update();
275   fgUpdateLocalTime();
276   fgUpdateWeatherDatabase();
277   fgRadioSearch();
278
279                                 // Restore all of the old states.
280   setElevator(elevator);
281   setAileron(aileron);
282   setRudder(rudder);
283   setThrottle(throttle);
284   setElevatorTrim(elevator_trim);
285   setFlaps(flaps);
286   setBrake(brake);
287   setAPHeadingLock(apHeadingLock);
288   setAPHeadingMag(apHeadingMag);
289   setAPAltitudeLock(apAltitudeLock);
290   setAPAltitude(apAltitude);
291   setTargetAirport(targetAirport);
292   setGPSLock(gpsLock);
293   setGPSTargetLatitude(gpsLatitude);
294   setGPSTargetLongitude(gpsLongitude);
295
296   _needReinit = false;
297
298   cout << "BFI: end reinit\n";
299 }
300
301
302 \f
303 ////////////////////////////////////////////////////////////////////////
304 // Simulation.
305 ////////////////////////////////////////////////////////////////////////
306
307
308 /**
309  * Return the flight model as an integer.
310  *
311  * TODO: use a string instead.
312  */
313 int
314 FGBFI::getFlightModel ()
315 {
316   return current_options.get_flight_model();
317 }
318
319
320 /**
321  * Return the current aircraft as a string.
322  */
323 const string
324 FGBFI::getAircraft ()
325 {
326   return current_options.get_aircraft();
327 }
328
329
330 /**
331  * Return the current aircraft directory (UIUC) as a string.
332  */
333 const string
334 FGBFI::getAircraftDir ()
335 {
336   return aircraft_dir;
337 }
338
339
340 /**
341  * Set the flight model as an integer.
342  *
343  * TODO: use a string instead.
344  */
345 void
346 FGBFI::setFlightModel (int model)
347 {
348   current_options.set_flight_model(model);
349   needReinit();
350 }
351
352
353 /**
354  * Set the current aircraft.
355  */
356 void
357 FGBFI::setAircraft (const string &aircraft)
358 {
359   current_options.set_aircraft(aircraft);
360   needReinit();
361 }
362
363
364 /**
365  * Set the current aircraft directory (UIUC).
366  */
367 void
368 FGBFI::setAircraftDir (const string &dir)
369 {
370   aircraft_dir = dir;
371   needReinit();
372 }
373
374
375 /**
376  * Return the current Zulu time.
377  */
378 time_t
379 FGBFI::getTimeGMT ()
380 {
381   return globals->get_time_params()->get_cur_time();
382 }
383
384
385 /**
386  * Set the current Zulu time.
387  */
388 void
389 FGBFI::setTimeGMT (time_t time)
390 {
391                                 // FIXME: need to update lighting
392                                 // and solar system
393   current_options.set_time_offset(time);
394   current_options.set_time_offset_type(fgOPTIONS::FG_TIME_GMT_ABSOLUTE);
395   globals->get_time_params()->init( cur_fdm_state->get_Longitude(),
396                                     cur_fdm_state->get_Latitude(),
397                                     current_options.get_fg_root() );
398   globals->get_time_params()->update( cur_fdm_state->get_Longitude(),
399                                       cur_fdm_state->get_Latitude(),
400                                       globals->get_warp() );
401   needReinit();
402 }
403
404
405 /**
406  * Return true if the HUD is visible.
407  */
408 bool
409 FGBFI::getHUDVisible ()
410 {
411   return current_options.get_hud_status();
412 }
413
414
415 /**
416  * Ensure that the HUD is visible or hidden.
417  */
418 void
419 FGBFI::setHUDVisible (bool visible)
420 {
421   current_options.set_hud_status(visible);
422 }
423
424
425 /**
426  * Return true if the 2D panel is visible.
427  */
428 bool
429 FGBFI::getPanelVisible ()
430 {
431   return current_options.get_panel_status();
432 }
433
434
435 /**
436  * Ensure that the 2D panel is visible or hidden.
437  */
438 void
439 FGBFI::setPanelVisible (bool visible)
440 {
441   if (current_options.get_panel_status() != visible) {
442     current_options.toggle_panel();
443   }
444 }
445
446
447 \f
448 ////////////////////////////////////////////////////////////////////////
449 // Position
450 ////////////////////////////////////////////////////////////////////////
451
452
453 /**
454  * Return the current latitude in degrees (negative for south).
455  */
456 double
457 FGBFI::getLatitude ()
458 {
459   return current_aircraft.fdm_state->get_Latitude() * RAD_TO_DEG;
460 }
461
462
463 /**
464  * Set the current latitude in degrees (negative for south).
465  */
466 void
467 FGBFI::setLatitude (double latitude)
468 {
469   current_options.set_lat(latitude);
470   current_aircraft.fdm_state->set_Latitude(latitude * DEG_TO_RAD);
471   needReinit();
472 }
473
474
475 /**
476  * Return the current longitude in degrees (negative for west).
477  */
478 double
479 FGBFI::getLongitude ()
480 {
481   return current_aircraft.fdm_state->get_Longitude() * RAD_TO_DEG;
482 }
483
484
485 /**
486  * Set the current longitude in degrees (negative for west).
487  */
488 void
489 FGBFI::setLongitude (double longitude)
490 {
491   current_options.set_lon(longitude);
492   current_aircraft.fdm_state->set_Longitude(longitude * DEG_TO_RAD);
493   needReinit();
494 }
495
496
497 /**
498  * Return the current altitude in feet.
499  */
500 double
501 FGBFI::getAltitude ()
502 {
503   return current_aircraft.fdm_state->get_Altitude();
504 }
505
506
507
508 /**
509  * Return the current altitude in above the terrain.
510  */
511 double
512 FGBFI::getAGL ()
513 {
514   return current_aircraft.fdm_state->get_Altitude()
515          - scenery.cur_elev * METER_TO_FEET;
516 }
517
518
519 /**
520  * Set the current altitude in feet.
521  */
522 void
523 FGBFI::setAltitude (double altitude)
524 {
525   fgFDMForceAltitude(getFlightModel(), altitude * FEET_TO_METER);
526 //   current_options.set_altitude(altitude * FEET_TO_METER);
527 //   current_aircraft.fdm_state->set_Altitude(altitude);
528 //   needReinit();
529 }
530
531
532 \f
533 ////////////////////////////////////////////////////////////////////////
534 // Attitude
535 ////////////////////////////////////////////////////////////////////////
536
537
538 /**
539  * Return the current heading in degrees.
540  */
541 double
542 FGBFI::getHeading ()
543 {
544   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG;
545 }
546
547
548 /**
549  * Return the current heading in degrees.
550  */
551 double
552 FGBFI::getHeadingMag ()
553 {
554   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG - getMagVar();
555 }
556
557
558 /**
559  * Set the current heading in degrees.
560  */
561 void
562 FGBFI::setHeading (double heading)
563 {
564   current_options.set_heading(heading);
565   current_aircraft.fdm_state->set_Euler_Angles(getRoll() * DEG_TO_RAD,
566                                                getPitch() * DEG_TO_RAD,
567                                                heading * DEG_TO_RAD);
568   needReinit();
569 }
570
571
572 /**
573  * Return the current pitch in degrees.
574  */
575 double
576 FGBFI::getPitch ()
577 {
578   return current_aircraft.fdm_state->get_Theta() * RAD_TO_DEG;
579 }
580
581
582 /**
583  * Set the current pitch in degrees.
584  */
585 void
586 FGBFI::setPitch (double pitch)
587 {
588
589   current_options.set_pitch(pitch);
590   current_aircraft.fdm_state->set_Euler_Angles(getRoll() * DEG_TO_RAD,
591                                                pitch * DEG_TO_RAD,
592                                                getHeading() * DEG_TO_RAD);
593   needReinit();
594 }
595
596
597 /**
598  * Return the current roll in degrees.
599  */
600 double
601 FGBFI::getRoll ()
602 {
603   return current_aircraft.fdm_state->get_Phi() * RAD_TO_DEG;
604 }
605
606
607 /**
608  * Set the current roll in degrees.
609  */
610 void
611 FGBFI::setRoll (double roll)
612 {
613   current_options.set_roll(roll);
614   current_aircraft.fdm_state->set_Euler_Angles(roll * DEG_TO_RAD,
615                                                getPitch() * DEG_TO_RAD,
616                                                getHeading() * DEG_TO_RAD);
617   needReinit();
618 }
619
620
621 \f
622 ////////////////////////////////////////////////////////////////////////
623 // Velocities
624 ////////////////////////////////////////////////////////////////////////
625
626
627 /**
628  * Return the current airspeed in knots.
629  */
630 double
631 FGBFI::getAirspeed ()
632 {
633                                 // FIXME: should we add speed-up?
634   return current_aircraft.fdm_state->get_V_calibrated_kts();
635 }
636
637
638 /**
639  * Return the current sideslip (FIXME: units unknown).
640  */
641 double
642 FGBFI::getSideSlip ()
643 {
644   return current_aircraft.fdm_state->get_Beta();
645 }
646
647
648 /**
649  * Return the current climb rate in feet/minute
650  */
651 double
652 FGBFI::getVerticalSpeed ()
653 {
654                                 // What about meters?
655   return current_aircraft.fdm_state->get_Climb_Rate() * 60.0;
656 }
657
658
659 /**
660  * Get the current north velocity (units??).
661  */
662 double
663 FGBFI::getSpeedNorth ()
664 {
665   return current_aircraft.fdm_state->get_V_north();
666 }
667
668
669 /**
670  * Set the current north velocity (units??).
671  */
672 void
673 FGBFI::setSpeedNorth (double speed)
674 {
675   current_options.set_uBody(speed);
676   current_aircraft.fdm_state->set_Velocities_Local(speed,
677                                                    getSpeedEast(),
678                                                    getSpeedDown());
679   needReinit();
680 }
681
682
683 /**
684  * Get the current east velocity (units??).
685  */
686 double
687 FGBFI::getSpeedEast ()
688 {
689   return current_aircraft.fdm_state->get_V_east();
690 }
691
692
693 /**
694  * Set the current east velocity (units??).
695  */
696 void
697 FGBFI::setSpeedEast (double speed)
698 {
699   current_options.set_vBody(speed);
700   current_aircraft.fdm_state->set_Velocities_Local(getSpeedNorth(),
701                                                    speed,
702                                                    getSpeedDown());
703   needReinit();
704 }
705
706
707 /**
708  * Get the current down velocity (units??).
709  */
710 double
711 FGBFI::getSpeedDown ()
712 {
713   return current_aircraft.fdm_state->get_V_down();
714 }
715
716
717 /**
718  * Set the current down velocity (units??).
719  */
720 void
721 FGBFI::setSpeedDown (double speed)
722 {
723   current_options.set_wBody(speed);
724   current_aircraft.fdm_state->set_Velocities_Local(getSpeedNorth(),
725                                                    getSpeedEast(),
726                                                    speed);
727   needReinit();
728 }
729
730
731 \f
732 ////////////////////////////////////////////////////////////////////////
733 // Controls
734 ////////////////////////////////////////////////////////////////////////
735
736
737 /**
738  * Get the throttle setting, from 0.0 (none) to 1.0 (full).
739  */
740 double
741 FGBFI::getThrottle ()
742 {
743                                 // FIXME: add throttle selector
744   return controls.get_throttle(0);
745 }
746
747
748 /**
749  * Set the throttle, from 0.0 (none) to 1.0 (full).
750  */
751 void
752 FGBFI::setThrottle (double throttle)
753 {
754                                 // FIXME: allow throttle selection
755                                 // FIXME: clamp?
756   controls.set_throttle(0, throttle);
757 }
758
759
760 /**
761  * Get the flaps setting, from 0.0 (none) to 1.0 (full).
762  */
763 double
764 FGBFI::getFlaps ()
765 {
766   return controls.get_flaps();
767 }
768
769
770 /**
771  * Set the flaps, from 0.0 (none) to 1.0 (full).
772  */
773 void
774 FGBFI::setFlaps (double flaps)
775 {
776                                 // FIXME: clamp?
777   controls.set_flaps(flaps);
778 }
779
780
781 /**
782  * Get the aileron, from -1.0 (left) to 1.0 (right).
783  */
784 double
785 FGBFI::getAileron ()
786 {
787   return controls.get_aileron();
788 }
789
790
791 /**
792  * Set the aileron, from -1.0 (left) to 1.0 (right).
793  */
794 void
795 FGBFI::setAileron (double aileron)
796 {
797                                 // FIXME: clamp?
798   controls.set_aileron(aileron);
799 }
800
801
802 /**
803  * Get the rudder setting, from -1.0 (left) to 1.0 (right).
804  */
805 double
806 FGBFI::getRudder ()
807 {
808   return controls.get_rudder();
809 }
810
811
812 /**
813  * Set the rudder, from -1.0 (left) to 1.0 (right).
814  */
815 void
816 FGBFI::setRudder (double rudder)
817 {
818                                 // FIXME: clamp?
819   controls.set_rudder(rudder);
820 }
821
822
823 /**
824  * Get the elevator setting, from -1.0 (down) to 1.0 (up).
825  */
826 double
827 FGBFI::getElevator ()
828 {
829   return controls.get_elevator();
830 }
831
832
833 /**
834  * Set the elevator, from -1.0 (down) to 1.0 (up).
835  */
836 void
837 FGBFI::setElevator (double elevator)
838 {
839                                 // FIXME: clamp?
840   controls.set_elevator(elevator);
841 }
842
843
844 /**
845  * Get the elevator trim, from -1.0 (down) to 1.0 (up).
846  */
847 double
848 FGBFI::getElevatorTrim ()
849 {
850   return controls.get_elevator_trim();
851 }
852
853
854 /**
855  * Set the elevator trim, from -1.0 (down) to 1.0 (up).
856  */
857 void
858 FGBFI::setElevatorTrim (double trim)
859 {
860                                 // FIXME: clamp?
861   controls.set_elevator_trim(trim);
862 }
863
864
865 /**
866  * Get the brake setting, from 0.0 (none) to 1.0 (full).
867  */
868 double
869 FGBFI::getBrake ()
870 {
871                                 // FIXME: add brake selector
872   return controls.get_brake(0);
873 }
874
875
876 /**
877  * Set the brake, from 0.0 (none) to 1.0 (full).
878  */
879 void
880 FGBFI::setBrake (double brake)
881 {
882                                 // FIXME: clamp?
883                                 // FIXME: allow brake selection
884   controls.set_brake(0, brake);
885 }
886
887
888 \f
889 ////////////////////////////////////////////////////////////////////////
890 // Autopilot
891 ////////////////////////////////////////////////////////////////////////
892
893
894 /**
895  * Get the autopilot altitude lock (true=on).
896  */
897 bool
898 FGBFI::getAPAltitudeLock ()
899 {
900     return current_autopilot->get_AltitudeEnabled();
901 }
902
903
904 /**
905  * Set the autopilot altitude lock (true=on).
906  */
907 void
908 FGBFI::setAPAltitudeLock (bool lock)
909 {
910   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
911   current_autopilot->set_AltitudeEnabled(lock);
912 }
913
914
915 /**
916  * Get the autopilot target altitude in feet.
917  */
918 double
919 FGBFI::getAPAltitude ()
920 {
921   return current_autopilot->get_TargetAltitude() * METER_TO_FEET;
922 }
923
924
925 /**
926  * Set the autopilot target altitude in feet.
927  */
928 void
929 FGBFI::setAPAltitude (double altitude)
930 {
931     current_autopilot->set_TargetAltitude( altitude );
932 }
933
934
935 /**
936  * Get the autopilot heading lock (true=on).
937  */
938 bool
939 FGBFI::getAPHeadingLock ()
940 {
941     return
942       (current_autopilot->get_HeadingEnabled() &&
943        current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_LOCK);
944 }
945
946
947 /**
948  * Set the autopilot heading lock (true=on).
949  */
950 void
951 FGBFI::setAPHeadingLock (bool lock)
952 {
953   if (lock) {
954                                 // We need to do this so that
955                                 // it's possible to lock onto a
956                                 // heading other than the current
957                                 // heading.
958     double heading = getAPHeadingMag();
959     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_LOCK);
960     current_autopilot->set_HeadingEnabled(true);
961     setAPHeadingMag(heading);
962   } else if (current_autopilot->get_HeadingMode() ==
963              FGAutopilot::FG_HEADING_LOCK) {
964     current_autopilot->set_HeadingEnabled(false);
965   }
966 }
967
968
969 /**
970  * Get the autopilot target heading in degrees.
971  */
972 double
973 FGBFI::getAPHeadingMag ()
974 {
975   return current_autopilot->get_TargetHeading() - getMagVar();
976 }
977
978
979 /**
980  * Set the autopilot target heading in degrees.
981  */
982 void
983 FGBFI::setAPHeadingMag (double heading)
984 {
985   current_autopilot->set_TargetHeading( heading + getMagVar() );
986 }
987
988
989 /**
990  * Return true if the autopilot is locked to NAV1.
991  */
992 bool
993 FGBFI::getAPNAV1Lock ()
994 {
995   return
996     (current_autopilot->get_HeadingEnabled() &&
997      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
998 }
999
1000
1001 /**
1002  * Set the autopilot NAV1 lock.
1003  */
1004 void
1005 FGBFI::setAPNAV1Lock (bool lock)
1006 {
1007   if (lock) {
1008     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
1009     current_autopilot->set_HeadingEnabled(true);
1010   } else if (current_autopilot->get_HeadingMode() ==
1011              FGAutopilot::FG_HEADING_NAV1) {
1012     current_autopilot->set_HeadingEnabled(false);
1013   }
1014 }
1015
1016
1017 \f
1018 ////////////////////////////////////////////////////////////////////////
1019 // Radio navigation.
1020 ////////////////////////////////////////////////////////////////////////
1021
1022 double
1023 FGBFI::getNAV1Freq ()
1024 {
1025   return current_radiostack->get_nav1_freq();
1026 }
1027
1028 double
1029 FGBFI::getNAV1AltFreq ()
1030 {
1031   return current_radiostack->get_nav1_alt_freq();
1032 }
1033
1034 double
1035 FGBFI::getNAV1Radial ()
1036 {
1037   return current_radiostack->get_nav1_radial();
1038 }
1039
1040 double
1041 FGBFI::getNAV1SelRadial ()
1042 {
1043   return current_radiostack->get_nav1_sel_radial();
1044 }
1045
1046 double
1047 FGBFI::getNAV1DistDME ()
1048 {
1049   return current_radiostack->get_nav1_dme_dist();
1050 }
1051
1052 bool
1053 FGBFI::getNAV1InRange ()
1054 {
1055   return current_radiostack->get_nav1_inrange();
1056 }
1057
1058 bool
1059 FGBFI::getNAV1DMEInRange ()
1060 {
1061   return (current_radiostack->get_nav1_inrange() &&
1062           current_radiostack->get_nav1_has_dme());
1063 }
1064
1065 double
1066 FGBFI::getNAV2Freq ()
1067 {
1068   return current_radiostack->get_nav2_freq();
1069 }
1070
1071 double
1072 FGBFI::getNAV2AltFreq ()
1073 {
1074   return current_radiostack->get_nav2_alt_freq();
1075 }
1076
1077 double
1078 FGBFI::getNAV2Radial ()
1079 {
1080   return current_radiostack->get_nav2_radial();
1081 }
1082
1083 double
1084 FGBFI::getNAV2SelRadial ()
1085 {
1086   return current_radiostack->get_nav2_sel_radial();
1087 }
1088
1089 double
1090 FGBFI::getNAV2DistDME ()
1091 {
1092   return current_radiostack->get_nav2_dme_dist();
1093 }
1094
1095 bool
1096 FGBFI::getNAV2InRange ()
1097 {
1098   return current_radiostack->get_nav2_inrange();
1099 }
1100
1101 bool
1102 FGBFI::getNAV2DMEInRange ()
1103 {
1104   return (current_radiostack->get_nav2_inrange() &&
1105           current_radiostack->get_nav2_has_dme());
1106 }
1107
1108 double
1109 FGBFI::getADFFreq ()
1110 {
1111   return current_radiostack->get_adf_freq();
1112 }
1113
1114 double
1115 FGBFI::getADFAltFreq ()
1116 {
1117   return current_radiostack->get_adf_alt_freq();
1118 }
1119
1120 double
1121 FGBFI::getADFRotation ()
1122 {
1123   return current_radiostack->get_adf_rotation();
1124 }
1125
1126 void
1127 FGBFI::setNAV1Freq (double freq)
1128 {
1129   current_radiostack->set_nav1_freq(freq);
1130 }
1131
1132 void
1133 FGBFI::setNAV1AltFreq (double freq)
1134 {
1135   current_radiostack->set_nav1_alt_freq(freq);
1136 }
1137
1138 void
1139 FGBFI::setNAV1SelRadial (double radial)
1140 {
1141   current_radiostack->set_nav1_sel_radial(radial);
1142 }
1143
1144 void
1145 FGBFI::setNAV2Freq (double freq)
1146 {
1147   current_radiostack->set_nav2_freq(freq);
1148 }
1149
1150 void
1151 FGBFI::setNAV2AltFreq (double freq)
1152 {
1153   current_radiostack->set_nav2_alt_freq(freq);
1154 }
1155
1156 void
1157 FGBFI::setNAV2SelRadial (double radial)
1158 {
1159   current_radiostack->set_nav2_sel_radial(radial);
1160 }
1161
1162 void
1163 FGBFI::setADFFreq (double freq)
1164 {
1165   current_radiostack->set_adf_freq(freq);
1166 }
1167
1168 void
1169 FGBFI::setADFAltFreq (double freq)
1170 {
1171   current_radiostack->set_adf_alt_freq(freq);
1172 }
1173
1174 void
1175 FGBFI::setADFRotation (double rot)
1176 {
1177   current_radiostack->set_adf_rotation(rot);
1178 }
1179
1180
1181 \f
1182 ////////////////////////////////////////////////////////////////////////
1183 // GPS
1184 ////////////////////////////////////////////////////////////////////////
1185
1186
1187 /**
1188  * Get the autopilot GPS lock (true=on).
1189  */
1190 bool
1191 FGBFI::getGPSLock ()
1192 {
1193   return (current_autopilot->get_HeadingEnabled() &&
1194           (current_autopilot->get_HeadingMode() ==
1195            FGAutopilot::FG_HEADING_WAYPOINT ));
1196 }
1197
1198
1199 /**
1200  * Set the autopilot GPS lock (true=on).
1201  */
1202 void
1203 FGBFI::setGPSLock (bool lock)
1204 {
1205   if (lock) {
1206     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_WAYPOINT);
1207     current_autopilot->set_HeadingEnabled(true);
1208   } else if (current_autopilot->get_HeadingMode() ==
1209              FGAutopilot::FG_HEADING_WAYPOINT) {
1210     current_autopilot->set_HeadingEnabled(false);
1211   }
1212 }
1213
1214
1215 /**
1216  * Get the GPS target airport code.
1217  */
1218 const string
1219 FGBFI::getTargetAirport ()
1220 {
1221   return current_options.get_airport_id();
1222 }
1223
1224
1225 /**
1226  * Set the GPS target airport code.
1227  */
1228 void
1229 FGBFI::setTargetAirport (const string &airportId)
1230 {
1231   current_options.set_airport_id(airportId);
1232 }
1233
1234
1235 /**
1236  * Get the GPS target latitude in degrees (negative for south).
1237  */
1238 double
1239 FGBFI::getGPSTargetLatitude ()
1240 {
1241     return current_autopilot->get_TargetLatitude();
1242 }
1243
1244
1245 /**
1246  * Set the GPS target latitude in degrees (negative for south).
1247  */
1248 void
1249 FGBFI::setGPSTargetLatitude (double latitude)
1250 {
1251   current_autopilot->set_TargetLatitude( latitude );
1252 }
1253
1254
1255 /**
1256  * Get the GPS target longitude in degrees (negative for west).
1257  */
1258 double
1259 FGBFI::getGPSTargetLongitude ()
1260 {
1261   return current_autopilot->get_TargetLongitude();
1262 }
1263
1264
1265 /**
1266  * Set the GPS target longitude in degrees (negative for west).
1267  */
1268 void
1269 FGBFI::setGPSTargetLongitude (double longitude)
1270 {
1271   current_autopilot->set_TargetLongitude( longitude );
1272 }
1273
1274
1275 \f
1276 ////////////////////////////////////////////////////////////////////////
1277 // Weather
1278 ////////////////////////////////////////////////////////////////////////
1279
1280
1281 /**
1282  * Get the current visible (units??).
1283  */
1284 double
1285 FGBFI::getVisibility ()
1286 {
1287 #ifndef FG_OLD_WEATHER
1288   return WeatherDatabase->getWeatherVisibility();
1289 #else
1290   return current_weather.get_visibility();
1291 #endif
1292 }
1293
1294
1295 /**
1296  * Check whether clouds are enabled.
1297  */
1298 bool
1299 FGBFI::getClouds ()
1300 {
1301   return current_options.get_clouds();
1302 }
1303
1304
1305 /**
1306  * Check the height of the clouds ASL (units?).
1307  */
1308 double
1309 FGBFI::getCloudsASL ()
1310 {
1311   return current_options.get_clouds_asl();
1312 }
1313
1314
1315 /**
1316  * Set the current visibility (units??).
1317  */
1318 void
1319 FGBFI::setVisibility (double visibility)
1320 {
1321 #ifndef FG_OLD_WEATHER
1322   WeatherDatabase->setWeatherVisibility(visibility);
1323 #else
1324   current_weather.set_visibility(visibility);
1325 #endif
1326 }
1327
1328
1329 /**
1330  * Switch clouds on or off.
1331  */
1332 void
1333 FGBFI::setClouds (bool clouds)
1334 {
1335   cout << "Set clouds to " << clouds << endl;
1336   current_options.set_clouds(clouds);
1337   needReinit();
1338 }
1339
1340
1341 /**
1342  * Set the cloud height.
1343  */
1344 void
1345 FGBFI::setCloudsASL (double cloudsASL)
1346 {
1347   current_options.set_clouds_asl(cloudsASL);
1348   needReinit();
1349 }
1350
1351
1352 \f
1353 ////////////////////////////////////////////////////////////////////////
1354 // Time
1355 ////////////////////////////////////////////////////////////////////////
1356
1357 /**
1358  * Return the magnetic variation
1359  */
1360 double
1361 FGBFI::getMagVar ()
1362 {
1363   return cur_magvar.get_magvar() * RAD_TO_DEG;
1364 }
1365
1366
1367 /**
1368  * Return the magnetic variation
1369  */
1370 double
1371 FGBFI::getMagDip ()
1372 {
1373   return cur_magvar.get_magdip() * RAD_TO_DEG;
1374 }
1375
1376
1377 // end of bfi.cxx
1378