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