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