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