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