]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/mk_viii.hxx
27cf023fabafd9999e18848562790952584a05bd
[flightgear.git] / src / Instrumentation / mk_viii.hxx
1 // mk_viii.cxx -- Honeywell MK VIII EGPWS emulation
2 //
3 // Written by Jean-Yves Lefort, started September 2005.
4 //
5 // Copyright (C) 2005, 2006  Jean-Yves Lefort - jylefort@FreeBSD.org
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
22 #ifndef __INSTRUMENTS_MK_VIII_HXX
23 #define __INSTRUMENTS_MK_VIII_HXX
24
25 #include <assert.h>
26
27 #include <vector>
28 #include <deque>
29 #include <map>
30
31 #include <simgear/props/props.hxx>
32 #include <simgear/sound/sample_openal.hxx>
33 #include <simgear/structure/subsystem_mgr.hxx>
34
35 using std::vector;
36 using std::deque;
37 using std::map;
38
39 class SGSampleGroup;
40
41 #include <Airports/runways.hxx>
42 #include <Airports/simple.hxx>
43 #include <Main/globals.hxx>
44
45 #ifdef _MSC_VER
46 #  pragma warning( push )
47 #  pragma warning( disable: 4355 )
48 #endif
49
50 ///////////////////////////////////////////////////////////////////////////////
51 // MK_VIII ////////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////////////////
53
54 class MK_VIII : public SGSubsystem
55 {
56   // keep in sync with Mode6Handler::altitude_callout_definitions[]
57   static const unsigned n_altitude_callouts = 11;
58
59   /////////////////////////////////////////////////////////////////////////////
60   // MK_VIII::RawValueMethodsData /////////////////////////////////////////////
61   /////////////////////////////////////////////////////////////////////////////
62
63   template <class C, class VT, class DT>
64   class RawValueMethodsData : public SGRawValue<VT>
65   {
66   public:
67     typedef VT (C::*getter_t) (DT) const;
68     typedef void (C::*setter_t) (DT, VT);
69
70     RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
71       : _obj(obj), _data(data), _getter(getter), _setter(setter) {}
72
73     virtual VT getValue () const
74     {
75       if (_getter)
76         return (_obj.*_getter)(_data);
77       else
78         return SGRawValue<VT>::DefaultValue();
79     }
80     virtual bool setValue (VT value)
81     {
82       if (_setter)
83         {
84           (_obj.*_setter)(_data, value);
85           return true;
86         }
87       else
88         return false;
89     }
90     virtual SGRawValue<VT> *clone () const 
91     {
92       return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
93     }
94
95   private:
96     C           &_obj;
97     DT          _data;
98     getter_t    _getter;
99     setter_t    _setter;
100   };
101
102   /////////////////////////////////////////////////////////////////////////////
103   // MK_VIII::Parameter ///////////////////////////////////////////////////////
104   /////////////////////////////////////////////////////////////////////////////
105
106   template <class T>
107   class Parameter
108   {
109     T _value;
110
111   public:
112     bool ncd;
113
114     inline Parameter ()
115       : _value(0), ncd(true) {}
116
117     inline T get () const { assert(! ncd); return _value; }
118     inline T *get_pointer () { return &_value; }
119     inline void set (T value) { ncd = false; _value = value; }
120     inline void unset () { ncd = true; }
121
122     inline void set (const Parameter<T> *parameter)
123     {
124       if (parameter->ncd)
125         unset();
126       else
127         set(parameter->get());
128     }
129
130     inline void set (const Parameter<double> *parameter, double factor)
131     {
132       if (parameter->ncd)
133         unset();
134       else
135         set(parameter->get() * factor);
136     }
137   };
138
139   /////////////////////////////////////////////////////////////////////////////
140   // MK_VIII::Sample //////////////////////////////////////////////////////////
141   /////////////////////////////////////////////////////////////////////////////
142
143   template <class T>
144   class Sample
145   {
146   public:
147     double      timestamp;
148     T           value;
149
150     inline Sample (T _value)
151       : timestamp(globals->get_sim_time_sec()), value(_value) {}
152   };
153
154   /////////////////////////////////////////////////////////////////////////////
155   // MK_VIII::Timer ///////////////////////////////////////////////////////////
156   /////////////////////////////////////////////////////////////////////////////
157
158   class Timer
159   {
160     double      start_time;
161
162   public:
163     bool        running;
164
165     inline Timer ()
166       : running(false) {}
167
168     inline void start () { running = true; start_time = globals->get_sim_time_sec(); }
169     inline void stop () { running = false; }
170     inline double elapsed () const { assert(running); return globals->get_sim_time_sec() - start_time; }
171     inline double start_or_elapsed ()
172     {
173       if (running)
174         return elapsed();
175       else
176         {
177           start();
178           return 0;
179         }
180     }
181   };
182
183   /////////////////////////////////////////////////////////////////////////////
184   // MK_VIII::PropertiesHandler ///////////////////////////////////////////////
185   /////////////////////////////////////////////////////////////////////////////
186
187   class PropertiesHandler
188   {
189     MK_VIII *mk;
190
191     vector<SGPropertyNode_ptr> tied_properties;
192
193   public:
194     struct
195     {
196       SGPropertyNode_ptr ai_caged;
197       SGPropertyNode_ptr ai_roll;
198       SGPropertyNode_ptr ai_serviceable;
199       SGPropertyNode_ptr altimeter_altitude;
200       SGPropertyNode_ptr altimeter_serviceable;
201       SGPropertyNode_ptr altitude;
202       SGPropertyNode_ptr altitude_agl;
203       SGPropertyNode_ptr asi_serviceable;
204       SGPropertyNode_ptr asi_speed;
205       SGPropertyNode_ptr autopilot_heading_lock;
206       SGPropertyNode_ptr flaps;
207       SGPropertyNode_ptr gear_down;
208       SGPropertyNode_ptr latitude;
209       SGPropertyNode_ptr longitude;
210       SGPropertyNode_ptr nav0_cdi_serviceable;
211       SGPropertyNode_ptr nav0_gs_distance;
212       SGPropertyNode_ptr nav0_gs_needle_deflection;
213       SGPropertyNode_ptr nav0_gs_serviceable;
214       SGPropertyNode_ptr nav0_has_gs;
215       SGPropertyNode_ptr nav0_heading_needle_deflection;
216       SGPropertyNode_ptr nav0_in_range;
217       SGPropertyNode_ptr nav0_nav_loc;
218       SGPropertyNode_ptr nav0_serviceable;
219       SGPropertyNode_ptr power;
220       SGPropertyNode_ptr replay_state;
221       SGPropertyNode_ptr vs;
222     } external_properties;
223
224     inline PropertiesHandler (MK_VIII *device)
225       : mk(device) {}
226
227     template <class T>
228     inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
229     {
230       node->tie(raw_value);
231       tied_properties.push_back(node);
232     }
233
234     template <class T>
235     inline void tie (SGPropertyNode *node,
236                      const char *relative_path,
237                      const SGRawValue<T> &raw_value)
238     {
239       tie(node->getNode(relative_path, true), raw_value);
240     }
241
242     PropertiesHandler() {};
243
244     void init ();
245     void unbind ();
246   };
247
248 public:
249   PropertiesHandler     properties_handler;
250
251 private:
252   /////////////////////////////////////////////////////////////////////////////
253   // MK_VIII::PowerHandler ////////////////////////////////////////////////////
254   /////////////////////////////////////////////////////////////////////////////
255
256   class PowerHandler
257   {
258     MK_VIII *mk;
259
260     bool serviceable;
261     bool powered;
262
263     Timer power_loss_timer;
264     Timer abnormal_timer;
265     Timer low_surge_timer;
266     Timer high_surge_timer;
267     Timer very_high_surge_timer;
268
269     bool handle_abnormal_voltage (bool abnormal,
270                                   Timer *timer,
271                                   double max_duration);
272
273     void power_on ();
274     void power_off ();
275
276   public:
277     inline PowerHandler (MK_VIII *device)
278       : mk(device), serviceable(false), powered(false) {}
279
280     void bind (SGPropertyNode *node);
281     void update ();
282   };
283
284   /////////////////////////////////////////////////////////////////////////////
285   // MK_VIII::SystemHandler ///////////////////////////////////////////////////
286   /////////////////////////////////////////////////////////////////////////////
287
288   class SystemHandler
289   {
290     MK_VIII *mk;
291
292     double      boot_delay;
293     Timer       boot_timer;
294
295     int         last_replay_state;
296     Timer       reposition_timer;
297
298   public:
299     typedef enum
300     {
301       STATE_OFF,
302       STATE_BOOTING,
303       STATE_ON,
304       STATE_REPOSITION
305     } State;
306
307     State state;
308
309     inline SystemHandler (MK_VIII *device)
310       : mk(device), state(STATE_OFF) {}
311
312     void power_on ();
313     void power_off ();
314     void update ();
315   };
316
317   /////////////////////////////////////////////////////////////////////////////
318   // MK_VIII::ConfigurationModule /////////////////////////////////////////////
319   /////////////////////////////////////////////////////////////////////////////
320
321   class ConfigurationModule
322   {
323   public:
324     // keep in sync with IOHandler::present_status()
325     typedef enum 
326     {
327       CATEGORY_AIRCRAFT_MODE_TYPE_SELECT,
328       CATEGORY_AIR_DATA_INPUT_SELECT,
329       CATEGORY_POSITION_INPUT_SELECT,
330       CATEGORY_ALTITUDE_CALLOUTS,
331       CATEGORY_AUDIO_MENU_SELECT,
332       CATEGORY_TERRAIN_DISPLAY_SELECT,
333       CATEGORY_OPTIONS_SELECT_GROUP_1,
334       CATEGORY_RADIO_ALTITUDE_INPUT_SELECT,
335       CATEGORY_NAVIGATION_INPUT_SELECT,
336       CATEGORY_ATTITUDE_INPUT_SELECT,
337       CATEGORY_HEADING_INPUT_SELECT,
338       CATEGORY_WINDSHEAR_INPUT_SELECT,
339       CATEGORY_INPUT_OUTPUT_DISCRETE_TYPE_SELECT,
340       CATEGORY_AUDIO_OUTPUT_LEVEL,
341       CATEGORY_UNDEFINED_INPUT_SELECT_1,
342       CATEGORY_UNDEFINED_INPUT_SELECT_2,
343       CATEGORY_UNDEFINED_INPUT_SELECT_3,
344       N_CATEGORIES
345     } Category;
346
347     typedef enum
348     {
349       STATE_OK,
350       STATE_INVALID_DATABASE,
351       STATE_INVALID_AIRCRAFT_TYPE
352     } State;
353     State state;
354
355     int effective_categories[N_CATEGORIES];
356
357     ConfigurationModule (MK_VIII *device);
358
359     void boot ();
360     void bind (SGPropertyNode *node);
361
362   private:
363     MK_VIII *mk;
364
365     int categories[N_CATEGORIES];
366
367     bool read_aircraft_mode_type_select (int value);
368     bool read_air_data_input_select (int value);
369     bool read_position_input_select (int value);
370     bool read_altitude_callouts (int value);
371     bool read_audio_menu_select (int value);
372     bool read_terrain_display_select (int value);
373     bool read_options_select_group_1 (int value);
374     bool read_radio_altitude_input_select (int value);
375     bool read_navigation_input_select (int value);
376     bool read_attitude_input_select (int value);
377     bool read_heading_input_select (int value);
378     bool read_windshear_input_select (int value);
379     bool read_input_output_discrete_type_select (int value);
380     bool read_audio_output_level (int value);
381     bool read_undefined_input_select (int value);
382
383     static bool m6_t2_is_bank_angle (Parameter<double> *agl,
384                                      double abs_roll_deg,
385                                      bool ap_engaged);
386     static bool m6_t4_is_bank_angle (Parameter<double> *agl,
387                                      double abs_roll_deg,
388                                      bool ap_engaged);
389   };
390
391   /////////////////////////////////////////////////////////////////////////////
392   // MK_VIII::FaultHandler ////////////////////////////////////////////////////
393   /////////////////////////////////////////////////////////////////////////////
394
395   class FaultHandler
396   {
397     enum
398     {
399       INOP_GPWS         = 1 << 0,
400       INOP_TAD          = 1 << 1
401     };
402
403     MK_VIII *mk;
404
405     static const unsigned int fault_inops[];
406
407     bool has_faults (unsigned int inop);
408
409   public:
410     // keep in sync with IOHandler::present_status()
411     typedef enum
412     {
413       FAULT_ALL_MODES_INHIBIT,
414       FAULT_GEAR_SWITCH,
415       FAULT_FLAPS_SWITCH,
416       FAULT_MOMENTARY_FLAP_OVERRIDE_INVALID,
417       FAULT_SELF_TEST_INVALID,
418       FAULT_GLIDESLOPE_CANCEL_INVALID,
419       FAULT_STEEP_APPROACH_INVALID,
420       FAULT_GPWS_INHIBIT,
421       FAULT_TA_TCF_INHIBIT,
422       FAULT_MODES14_INPUTS_INVALID,
423       FAULT_MODE5_INPUTS_INVALID,
424       FAULT_MODE6_INPUTS_INVALID,
425       FAULT_BANK_ANGLE_INPUTS_INVALID,
426       FAULT_TCF_INPUTS_INVALID,
427       N_FAULTS
428     } Fault;
429
430     bool faults[N_FAULTS];
431
432     inline FaultHandler (MK_VIII *device)
433       : mk(device) {}
434
435     void boot ();
436
437     void set_fault (Fault fault);
438     void unset_fault (Fault fault);
439
440     bool has_faults () const;
441   };
442
443   /////////////////////////////////////////////////////////////////////////////
444   // MK_VIII::IOHandler ///////////////////////////////////////////////////////
445   /////////////////////////////////////////////////////////////////////////////
446
447 public:
448   class IOHandler
449   {
450   public:
451     enum Lamp
452     {
453       LAMP_NONE,
454       LAMP_GLIDESLOPE,
455       LAMP_CAUTION,
456       LAMP_WARNING
457     };
458
459     struct LampConfiguration
460     {
461       bool format2;
462       bool flashing;
463     };
464
465     struct FaultsConfiguration
466     {
467       double max_flaps_down_airspeed;
468       double max_gear_down_airspeed;
469     };
470
471     struct _s_Conf
472     {
473       const LampConfiguration   *lamp;
474       const FaultsConfiguration *faults;
475       bool                      flap_reversal;
476       bool                      steep_approach_enabled;
477       bool                      gpws_inhibit_enabled;
478       bool                      momentary_flap_override_enabled;
479       bool                      alternate_steep_approach;
480       bool                      use_internal_gps;
481       bool                      localizer_enabled;
482     } conf;
483
484     struct _s_input_feeders
485     {
486       struct _s_discretes
487       {
488         bool landing_gear;
489         bool landing_flaps;
490         bool glideslope_inhibit;
491         bool decision_height;
492         bool autopilot_engaged;
493       } discretes;
494
495       struct _s_arinc429
496       {
497         bool uncorrected_barometric_altitude;
498         bool barometric_altitude_rate;
499         bool radio_altitude;
500         bool glideslope_deviation;
501         bool roll_angle;
502         bool localizer_deviation;
503         bool computed_airspeed;
504         bool decision_height;
505       } arinc429;
506     } input_feeders;
507
508     struct _s_inputs
509     {
510       struct _s_discretes
511       {
512         bool landing_gear;              // appendix E 6.6.2, 3.15.1.4
513         bool landing_flaps;             // appendix E 6.6.4, 3.15.1.2
514         bool momentary_flap_override;   // appendix E 6.6.6, 3.15.1.6
515         bool self_test;                 // appendix E 6.6.7, 3.15.1.10
516         bool glideslope_inhibit;        // appendix E 6.6.11, 3.15.1.1
517         bool glideslope_cancel;         // appendix E 6.6.13, 3.15.1.5
518         bool decision_height;           // appendix E 6.6.14, 3.10.2
519         bool mode6_low_volume;          // appendix E 6.6.15, 3.15.1.7
520         bool audio_inhibit;             // appendix E 6.6.16, 3.15.1.3
521         bool ta_tcf_inhibit;            // appendix E 6.6.20, 3.15.1.9
522         bool autopilot_engaged;         // appendix E 6.6.21, 3.15.1.8
523         bool steep_approach;            // appendix E 6.6.25, 3.15.1.11
524         bool gpws_inhibit;              // appendix E 6.6.27, 3.15.1.12
525       } discretes;
526
527       struct _s_arinc429
528       {
529         Parameter<double> uncorrected_barometric_altitude;      // appendix E 6.2.1
530         Parameter<double> barometric_altitude_rate;             // appendix E 6.2.2
531         Parameter<double> gps_altitude;                         // appendix E 6.2.4
532         Parameter<double> gps_latitude;                         // appendix E 6.2.7
533         Parameter<double> gps_longitude;                        // appendix E 6.2.8
534         Parameter<double> gps_vertical_figure_of_merit;         // appendix E 6.2.13
535         Parameter<double> radio_altitude;                       // appendix E 6.2.29
536         Parameter<double> glideslope_deviation;                 // appendix E 6.2.30
537         Parameter<double> roll_angle;                           // appendix E 6.2.31
538         Parameter<double> localizer_deviation;                  // appendix E 6.2.33
539         Parameter<double> computed_airspeed;                    // appendix E 6.2.39
540         Parameter<double> decision_height;                      // appendix E 6.2.41
541       } arinc429;
542     } inputs;
543
544     struct Outputs
545     {
546       struct _s_discretes
547       {
548         bool gpws_warning;              // appendix E 7.4.1, 3.15.2.5
549         bool gpws_alert;                // appendix E 7.4.1, 3.15.2.6
550         bool audio_on;                  // appendix E 7.4.2, 3.15.2.10
551         bool gpws_inop;                 // appendix E 7.4.3, 3.15.2.3
552         bool tad_inop;                  // appendix E 7.4.3, 3.15.2.4
553         bool flap_override;             // appendix E 7.4.5, 3.15.2.8
554         bool glideslope_cancel;         // appendix E 7.4.6, 3.15.2.7
555         bool steep_approach;            // appendix E 7.4.12, 3.15.2.9
556       } discretes;
557
558       struct _s_arinc429
559       {
560         int egpws_alert_discrete_1;     // appendix E 7.1.1.1
561         int egpwc_logic_discretes;      // appendix E 7.1.1.2
562         int mode6_callouts_discrete_1;  // appendix E 7.1.1.3
563         int mode6_callouts_discrete_2;  // appendix E 7.1.1.4
564         int egpws_alert_discrete_2;     // appendix E 7.1.1.5
565         int egpwc_alert_discrete_3;     // appendix E 7.1.1.6
566       } arinc429;
567     };
568
569     Outputs outputs;
570
571     struct _s_data
572     {
573       Parameter<double> barometric_altitude_rate;
574       Parameter<double> decision_height;
575       Parameter<double> geometric_altitude;
576       Parameter<double> glideslope_deviation_dots;
577       Parameter<double> gps_altitude;
578       Parameter<double> gps_latitude;
579       Parameter<double> gps_longitude;
580       Parameter<double> gps_vertical_figure_of_merit;
581       Parameter<double> localizer_deviation_dots;
582       Parameter<double> radio_altitude;
583       Parameter<double> roll_angle;
584       Parameter<double> terrain_clearance;
585     } data;
586
587     IOHandler (MK_VIII *device);
588
589     void boot ();
590     void post_boot ();
591     void power_off ();
592
593     void enter_ground ();
594     void enter_takeoff ();
595
596     void update_inputs ();
597     void update_input_faults ();
598     void update_alternate_discrete_input (bool *ptr);
599     void update_internal_latches ();
600
601     void update_egpws_alert_discrete_1 ();
602     void update_egpwc_logic_discretes ();
603     void update_mode6_callouts_discrete_1 ();
604     void update_mode6_callouts_discrete_2 ();
605     void update_egpws_alert_discrete_2 ();
606     void update_egpwc_alert_discrete_3 ();
607     void update_outputs ();
608
609     void update_lamps ();
610     void set_lamp (Lamp lamp);
611
612     bool gpws_inhibit () const;
613     bool real_flaps_down () const;
614     bool flaps_down () const;
615     bool flap_override () const;
616     bool steep_approach () const;
617     bool momentary_steep_approach_enabled () const;
618
619     void bind (SGPropertyNode *node);
620
621     MK_VIII *mk;
622
623   private:
624
625     ///////////////////////////////////////////////////////////////////////////
626     // MK_VIII::IOHandler::TerrainClearanceFilter /////////////////////////////
627     ///////////////////////////////////////////////////////////////////////////
628
629     class TerrainClearanceFilter
630     {
631       typedef deque< Sample<double> > samples_type;
632       samples_type              samples;
633       double                    value;
634
635     public:
636       inline TerrainClearanceFilter ()
637         : value(0) {}
638
639       double update (double agl);
640       void reset ();
641     };
642
643     ///////////////////////////////////////////////////////////////////////////
644     // MK_VIII::IOHandler (continued) /////////////////////////////////////////
645     ///////////////////////////////////////////////////////////////////////////
646
647     TerrainClearanceFilter terrain_clearance_filter;
648
649     Lamp        _lamp;
650     Timer       lamp_timer;
651
652     Timer audio_inhibit_fault_timer;
653     Timer landing_gear_fault_timer;
654     Timer flaps_down_fault_timer;
655     Timer momentary_flap_override_fault_timer;
656     Timer self_test_fault_timer;
657     Timer glideslope_cancel_fault_timer;
658     Timer steep_approach_fault_timer;
659     Timer gpws_inhibit_fault_timer;
660     Timer ta_tcf_inhibit_fault_timer;
661
662     bool last_landing_gear;
663     bool last_real_flaps_down;
664
665     typedef deque< Sample< Parameter<double> > > altitude_samples_type;
666     altitude_samples_type altitude_samples;
667
668     struct
669     {
670       bool glideslope_cancel;
671     } power_saved;
672
673     void update_terrain_clearance ();
674     void reset_terrain_clearance ();
675
676     void handle_input_fault (bool test, FaultHandler::Fault fault);
677     void handle_input_fault (bool test,
678                              Timer *timer,
679                              double max_duration,
680                              FaultHandler::Fault fault);
681
682     void tie_input (SGPropertyNode *node,
683                     const char *name,
684                     bool *input,
685                     bool *feed = NULL);
686     void tie_input (SGPropertyNode *node,
687                     const char *name,
688                     Parameter<double> *input,
689                     bool *feed = NULL);
690     void tie_output (SGPropertyNode *node,
691                      const char *name,
692                      bool *output);
693     void tie_output (SGPropertyNode *node,
694                      const char *name,
695                      int *output);
696
697   public:
698
699     bool get_discrete_input (bool *ptr) const;
700     void set_discrete_input (bool *ptr, bool value);
701
702     void present_status ();
703     void present_status_section (const char *name);
704     void present_status_item (const char *name, const char *value = NULL);
705     void present_status_subitem (const char *name);
706
707     bool get_present_status () const;
708     void set_present_status (bool value);
709
710     bool *get_lamp_output (Lamp lamp);
711   };
712
713   /////////////////////////////////////////////////////////////////////////////
714   // MK_VIII::VoicePlayer /////////////////////////////////////////////////////
715   /////////////////////////////////////////////////////////////////////////////
716
717   class VoicePlayer
718   {
719   public:
720
721     ///////////////////////////////////////////////////////////////////////////
722     // MK_VIII::VoicePlayer::Voice ////////////////////////////////////////////
723     ///////////////////////////////////////////////////////////////////////////
724
725     class Voice
726     {
727     public:
728
729       /////////////////////////////////////////////////////////////////////////
730       // MK_VIII::VoicePlayer::Voice::Element ////////////////////////////////////////
731       /////////////////////////////////////////////////////////////////////////
732
733       class Element
734       {
735       public:
736         bool silence;
737
738         virtual inline void play (float volume) {}
739         virtual inline void stop () {}
740         virtual bool is_playing () = 0;
741         virtual inline void set_volume (float volume) {}
742       };
743
744       /////////////////////////////////////////////////////////////////////////
745       // MK_VIII::VoicePlayer::Voice::SampleElement ///////////////////////////
746       /////////////////////////////////////////////////////////////////////////
747
748       class SampleElement : public Element
749       {
750         SGSoundSample   *_sample;
751         float           _volume;
752
753       public:
754         inline SampleElement (SGSoundSample *sample, float volume = 1.0)
755           : _sample(sample), _volume(volume) { silence = false; }
756
757         virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
758         virtual inline void stop () { if (_sample) _sample->stop(); }
759         virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
760         virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
761       };
762
763       /////////////////////////////////////////////////////////////////////////
764       // MK_VIII::VoicePlayer::Voice::SilenceElement //////////////////////////
765       /////////////////////////////////////////////////////////////////////////
766
767       class SilenceElement : public Element
768       {
769         double _duration;
770         double start_time;
771
772       public:
773         inline SilenceElement (double duration)
774           : _duration(duration) { silence = true; }
775
776         virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
777         virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
778       };
779
780       /////////////////////////////////////////////////////////////////////////
781       // MK_VIII::VoicePlayer::Voice (continued) //////////////////////////////
782       /////////////////////////////////////////////////////////////////////////
783
784       Element *element;
785
786       inline Voice (VoicePlayer *_player)
787         : element(NULL), player(_player), volume(1.0) {}
788
789       ~Voice ();
790
791       inline void append (Element *_element) { elements.push_back(_element); }
792
793       void play ();
794       void stop (bool now);
795       void set_volume (float _volume);
796       void volume_changed ();
797       void update ();
798
799     private:
800       VoicePlayer *player;
801
802       float volume;
803
804       vector<Element *>                 elements;
805       vector<Element *>::iterator       iter;
806
807       inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
808     };
809
810     ///////////////////////////////////////////////////////////////////////////
811     // MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
812     ///////////////////////////////////////////////////////////////////////////
813
814     struct
815     {
816       float volume;
817     } conf;
818
819     float volume;
820
821     Voice *voice;
822     Voice *next_voice;
823
824     struct
825     {
826       Voice *application_data_base_failed;
827       Voice *bank_angle;
828       Voice *bank_angle_bank_angle;
829       Voice *bank_angle_bank_angle_3;
830       Voice *bank_angle_inop;
831       Voice *bank_angle_pause_bank_angle;
832       Voice *bank_angle_pause_bank_angle_3;
833       Voice *callouts_inop;
834       Voice *configuration_type_invalid;
835       Voice *dont_sink;
836       Voice *dont_sink_pause_dont_sink;
837       Voice *five_hundred_above;
838       Voice *glideslope;
839       Voice *glideslope_inop;
840       Voice *gpws_inop;
841       Voice *hard_glideslope;
842       Voice *minimums;
843       Voice *minimums_minimums;
844       Voice *pull_up;
845       Voice *sink_rate;
846       Voice *sink_rate_pause_sink_rate;
847       Voice *soft_glideslope;
848       Voice *terrain;
849       Voice *terrain_pause_terrain;
850       Voice *too_low_flaps;
851       Voice *too_low_gear;
852       Voice *too_low_terrain;
853       Voice *altitude_callouts[n_altitude_callouts];
854     } voices;
855
856     inline VoicePlayer (MK_VIII *device)
857       : voice(NULL), next_voice(NULL),  mk(device), speaker(this) {}
858
859     ~VoicePlayer ();
860
861     void init ();
862
863     enum
864     {
865       PLAY_NOW          = 1 << 0,
866       PLAY_LOOPED       = 1 << 1
867     };
868     void play (Voice *_voice, unsigned int flags = 0);
869
870     enum
871     {
872       STOP_NOW          = 1 << 0
873     };
874     void stop (unsigned int flags = 0);
875
876     void set_volume (float _volume);
877     void update ();
878
879     inline void bind (SGPropertyNode *node) { speaker.bind(node); }
880
881   public:
882
883     ///////////////////////////////////////////////////////////////////////////
884     // MK_VIII::VoicePlayer::Speaker //////////////////////////////////////////
885     ///////////////////////////////////////////////////////////////////////////
886
887     class Speaker
888     {
889       VoicePlayer *player;
890
891       double    pitch;
892       SGVec3d   position;
893       SGVec3f   orientation;
894       float     inner_cone;
895       float     outer_cone;
896       float     outer_gain;
897       float     reference_dist;
898       float     max_dist;
899
900       template <class T>
901       inline void tie (SGPropertyNode *node, const char *name, T *ptr)
902       {
903         player->mk->properties_handler.tie
904           (node, (string("speaker/") + name).c_str(),
905            RawValueMethodsData<MK_VIII::VoicePlayer::Speaker,T,T*>
906            (*this, ptr,
907             &MK_VIII::VoicePlayer::Speaker::get_property,
908             &MK_VIII::VoicePlayer::Speaker::set_property));
909       }
910
911     public:
912       template <class T>
913       inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
914
915       template <class T>
916       inline T get_property (T *ptr) const { return *ptr; }
917
918       float volume;
919
920       inline Speaker (VoicePlayer *_player)
921         : player(_player),
922           pitch(1),
923           inner_cone(360),
924           outer_cone(360),
925           outer_gain(0),
926           reference_dist(3),
927           max_dist(10),
928           volume(1)
929       {
930         position[0] = 0; position[1] = 0; position[2] = 0;
931         orientation[0] = 0; orientation[1] = 0; orientation[2] = 0;
932       }
933
934       void bind (SGPropertyNode *node);
935       void update_configuration ();
936     };
937
938   private:
939     ///////////////////////////////////////////////////////////////////////////
940     // MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
941     ///////////////////////////////////////////////////////////////////////////
942
943     MK_VIII *mk;
944
945     SGSampleGroup *_sgr;
946     Speaker speaker;
947
948     map<string, SGSoundSample *>        samples;
949     vector<Voice *>                     _voices;
950
951     bool looped;
952     bool next_looped;
953
954     SGSoundSample *get_sample (const char *name);
955
956     inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
957     inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
958     inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
959
960     inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
961
962     template <class T1>
963     inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
964     template <class T1, class T2>
965     inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
966     template <class T1, class T2, class T3>
967     inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
968     template <class T1, class T2, class T3, class T4>
969     inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
970   };
971
972 private:
973   /////////////////////////////////////////////////////////////////////////////
974   // MK_VIII::SelfTestHandler /////////////////////////////////////////////////
975   /////////////////////////////////////////////////////////////////////////////
976
977   class SelfTestHandler
978   {
979     MK_VIII *mk;
980
981     typedef enum
982     {
983       CANCEL_NONE,
984       CANCEL_SHORT,
985       CANCEL_LONG
986     } Cancel;
987
988     enum
989     {
990       ACTION_SLEEP              = 1 << 0,
991       ACTION_VOICE              = 1 << 1,
992       ACTION_DISCRETE_ON_OFF    = 1 << 2,
993       ACTION_DONE               = 1 << 3
994     };
995
996     typedef struct
997     {
998       unsigned int      flags;
999       double            sleep_duration;
1000       bool              *discrete;
1001     } Action;
1002
1003     Cancel              cancel;
1004     Action              action;
1005     int                 current;
1006     bool                button_pressed;
1007     double              button_press_timestamp;
1008     IOHandler::Outputs  saved_outputs;
1009     double              sleep_start;
1010
1011     bool _was_here (int position);
1012
1013     Action sleep (double duration);
1014     Action play (VoicePlayer::Voice *voice);
1015     Action discrete_on (bool *discrete, double duration);
1016     Action discrete_on_off (bool *discrete, double duration);
1017     Action discrete_on_off (bool *discrete, VoicePlayer::Voice *voice);
1018     Action done ();
1019
1020     Action run ();
1021
1022     void start ();
1023     void stop ();
1024     void shutdown ();
1025
1026   public:
1027     typedef enum
1028     {
1029       STATE_NONE,
1030       STATE_START,
1031       STATE_RUNNING
1032     } State;
1033
1034     State state;
1035
1036     inline SelfTestHandler (MK_VIII *device)
1037       : mk(device), button_pressed(false), state(STATE_NONE) {}
1038
1039     inline void power_off () { stop(); }
1040     inline void set_inop () { stop(); }
1041     void handle_button_event (bool value);
1042     bool update ();
1043   };
1044
1045   /////////////////////////////////////////////////////////////////////////////
1046   // MK_VIII::AlertHandler ////////////////////////////////////////////////////
1047   /////////////////////////////////////////////////////////////////////////////
1048
1049   class AlertHandler
1050   {
1051     MK_VIII *mk;
1052
1053     unsigned int old_alerts;
1054     unsigned int voice_alerts;
1055     unsigned int repeated_alerts;
1056     VoicePlayer::Voice *altitude_callout_voice;
1057
1058     void reset ();
1059     inline bool has_alerts (unsigned int test) const { return (alerts & test) != 0; }
1060     inline bool has_old_alerts (unsigned int test) const { return (old_alerts & test) != 0; }
1061     inline bool must_play_voice (unsigned int test) const { return ! has_old_alerts(test) || (repeated_alerts & test) != 0; }
1062     bool select_voice_alerts (unsigned int test);
1063
1064   public:
1065     enum
1066     {
1067       ALERT_MODE1_PULL_UP                               = 1 << 0,
1068       ALERT_MODE1_SINK_RATE                             = 1 << 1,
1069
1070       ALERT_MODE2A_PREFACE                              = 1 << 2,
1071       ALERT_MODE2B_PREFACE                              = 1 << 3,
1072       ALERT_MODE2A                                      = 1 << 4,
1073       ALERT_MODE2B                                      = 1 << 5,
1074       ALERT_MODE2B_LANDING_MODE                         = 1 << 6,
1075       ALERT_MODE2A_ALTITUDE_GAIN                        = 1 << 7,
1076       ALERT_MODE2A_ALTITUDE_GAIN_TERRAIN_CLOSING        = 1 << 8,
1077
1078       ALERT_MODE3                                       = 1 << 9,
1079
1080       ALERT_MODE4_TOO_LOW_FLAPS                         = 1 << 10,
1081       ALERT_MODE4_TOO_LOW_GEAR                          = 1 << 11,
1082       ALERT_MODE4AB_TOO_LOW_TERRAIN                     = 1 << 12,
1083       ALERT_MODE4C_TOO_LOW_TERRAIN                      = 1 << 13,
1084
1085       ALERT_MODE5_SOFT                                  = 1 << 14,
1086       ALERT_MODE5_HARD                                  = 1 << 15,
1087
1088       ALERT_MODE6_MINIMUMS                              = 1 << 16,
1089       ALERT_MODE6_ALTITUDE_CALLOUT                      = 1 << 17,
1090       ALERT_MODE6_LOW_BANK_ANGLE_1                      = 1 << 18,
1091       ALERT_MODE6_HIGH_BANK_ANGLE_1                     = 1 << 19,
1092       ALERT_MODE6_LOW_BANK_ANGLE_2                      = 1 << 20,
1093       ALERT_MODE6_HIGH_BANK_ANGLE_2                     = 1 << 21,
1094       ALERT_MODE6_LOW_BANK_ANGLE_3                      = 1 << 22,
1095       ALERT_MODE6_HIGH_BANK_ANGLE_3                     = 1 << 23,
1096
1097       ALERT_TCF_TOO_LOW_TERRAIN                         = 1 << 24
1098     };
1099
1100     enum
1101     {
1102       ALERT_FLAG_REPEAT = 1 << 0
1103     };
1104
1105     unsigned int alerts;
1106
1107     inline AlertHandler (MK_VIII *device)
1108       : mk(device) {}
1109
1110     void boot ();
1111     void reposition ();
1112     void update ();
1113
1114     void set_alerts (unsigned int _alerts,
1115                      unsigned int flags = 0,
1116                      VoicePlayer::Voice *_altitude_callout_voice = NULL);
1117     void unset_alerts (unsigned int _alerts);
1118
1119     inline void repeat_alert (unsigned int alert) { set_alerts(alert, ALERT_FLAG_REPEAT); }
1120     inline void set_altitude_callout_alert (VoicePlayer::Voice *voice) { set_alerts(ALERT_MODE6_ALTITUDE_CALLOUT, 0, voice); }
1121   };
1122
1123   /////////////////////////////////////////////////////////////////////////////
1124   // MK_VIII::StateHandler ////////////////////////////////////////////////////
1125   /////////////////////////////////////////////////////////////////////////////
1126
1127   class StateHandler
1128   {
1129     MK_VIII *mk;
1130
1131     Timer potentially_airborne_timer;
1132
1133     void update_ground ();
1134     void enter_ground ();
1135     void leave_ground ();
1136
1137     void update_takeoff ();
1138     void enter_takeoff ();
1139     void leave_takeoff ();
1140
1141   public:
1142     bool ground;
1143     bool takeoff;
1144
1145     inline StateHandler (MK_VIII *device)
1146       : mk(device), ground(true), takeoff(true) {}
1147
1148     void post_reposition ();
1149     void update ();
1150   };
1151
1152   /////////////////////////////////////////////////////////////////////////////
1153   // MK_VIII::Mode1Handler ////////////////////////////////////////////////////
1154   /////////////////////////////////////////////////////////////////////////////
1155
1156   class Mode1Handler
1157   {
1158     MK_VIII *mk;
1159
1160     Timer pull_up_timer;
1161     Timer sink_rate_timer;
1162
1163     double sink_rate_tti;       // time-to-impact in minutes
1164
1165     double get_pull_up_bias ();
1166     bool is_pull_up ();
1167
1168     double get_sink_rate_bias ();
1169     bool is_sink_rate ();
1170     double get_sink_rate_tti ();
1171
1172     void update_pull_up ();
1173     void update_sink_rate ();
1174
1175   public:
1176     typedef struct
1177     {
1178       bool      flap_override_bias;
1179       int       min_agl;
1180       double    (*pull_up_min_agl1) (double vs);
1181       int       pull_up_max_agl1;
1182       double    (*pull_up_min_agl2) (double vs);
1183       int       pull_up_max_agl2;
1184     } EnvelopesConfiguration;
1185
1186     struct
1187     {
1188       const EnvelopesConfiguration *envelopes;
1189     } conf;
1190
1191     inline Mode1Handler (MK_VIII *device)
1192       : mk(device) {}
1193
1194     void update ();
1195   };
1196
1197   /////////////////////////////////////////////////////////////////////////////
1198   // MK_VIII::Mode2Handler ////////////////////////////////////////////////////
1199   /////////////////////////////////////////////////////////////////////////////
1200
1201   class Mode2Handler
1202   {
1203
1204     ///////////////////////////////////////////////////////////////////////////
1205     // MK_VIII::Mode2Handler::ClosureRateFilter ///////////////////////////////
1206     ///////////////////////////////////////////////////////////////////////////
1207
1208     class ClosureRateFilter
1209     {
1210       /////////////////////////////////////////////////////////////////////////
1211       // MK_VIII::Mode2Handler::ClosureRateFilter::PassFilter /////////////////
1212       /////////////////////////////////////////////////////////////////////////
1213
1214       class PassFilter
1215       {
1216         double a0;
1217         double a1;
1218         double b1;
1219
1220         double last_input;
1221         double last_output;
1222
1223       public:
1224         inline PassFilter (double _a0, double _a1, double _b1)
1225           : a0(_a0), a1(_a1), b1(_b1) {}
1226
1227         inline double filter (double input)
1228         {
1229           last_output = a0 * input + a1 * last_input + b1 * last_output;
1230           last_input = input;
1231
1232           return last_output;
1233         }
1234
1235         inline void reset ()
1236         {
1237           last_input = 0;
1238           last_output = 0;
1239         }
1240       };
1241
1242       /////////////////////////////////////////////////////////////////////////
1243       // MK_VIII::Mode2Handler::ClosureRateFilter (continued) /////////////////
1244       /////////////////////////////////////////////////////////////////////////
1245
1246       MK_VIII *mk;
1247
1248       Timer             timer;
1249       Parameter<double> last_ra;        // last radio altitude
1250       Parameter<double> last_ba;        // last barometric altitude
1251       PassFilter        ra_filter;      // radio altitude rate filter
1252       PassFilter        ba_filter;      // barometric altitude rate filter
1253
1254       double limit_radio_altitude_rate (double r);
1255
1256     public:
1257       Parameter<double> output;
1258
1259       inline ClosureRateFilter (MK_VIII *device)
1260         : mk(device),
1261           ra_filter(0.05, 0, 0.95),             // low-pass filter
1262           ba_filter(0.93, -0.93, 0.86) {}       // high-pass-filter
1263
1264       void init ();
1265       void update ();
1266     };
1267
1268     ///////////////////////////////////////////////////////////////////////////
1269     // MK_VIII::Mode2Handler (continued) //////////////////////////////////////
1270     ///////////////////////////////////////////////////////////////////////////
1271
1272     MK_VIII *mk;
1273
1274     ClosureRateFilter closure_rate_filter;
1275
1276     Timer takeoff_timer;
1277     Timer pull_up_timer;
1278
1279     double      a_start_time;
1280     Timer       a_altitude_gain_timer;
1281     double      a_altitude_gain_alt;
1282
1283     void check_pull_up (unsigned int preface_alert, unsigned int alert);
1284
1285     bool b_conditions ();
1286
1287     bool is_a ();
1288     bool is_b ();
1289
1290     void update_a ();
1291     void update_b ();
1292
1293   public:
1294     typedef struct
1295     {
1296       int airspeed1;
1297       int airspeed2;
1298     } Configuration;
1299
1300     const Configuration *conf;
1301
1302     inline Mode2Handler (MK_VIII *device)
1303       : mk(device), closure_rate_filter(device) {}
1304
1305     void boot ();
1306     void power_off ();
1307     void leave_ground ();
1308     void enter_takeoff ();
1309     void update ();
1310   };
1311
1312   /////////////////////////////////////////////////////////////////////////////
1313   // MK_VIII::Mode3Handler ////////////////////////////////////////////////////
1314   /////////////////////////////////////////////////////////////////////////////
1315
1316   class Mode3Handler
1317   {
1318     MK_VIII *mk;
1319
1320     bool        armed;
1321     bool        has_descent_alt;
1322     double      descent_alt;
1323     double      bias;
1324
1325     double max_alt_loss (double _bias);
1326     double get_bias (double initial_bias, double alt_loss);
1327     bool is (double *alt_loss);
1328
1329   public:
1330     typedef struct
1331     {
1332       int       min_agl;
1333       int       (*max_agl) (bool flap_override);
1334       double    (*max_alt_loss) (bool flap_override, double agl);
1335     } Configuration;
1336
1337     const Configuration *conf;
1338
1339     inline Mode3Handler (MK_VIII *device)
1340       : mk(device), armed(false), has_descent_alt(false) {}
1341
1342     void enter_takeoff ();
1343     void update ();
1344   };
1345
1346   /////////////////////////////////////////////////////////////////////////////
1347   // MK_VIII::Mode4Handler ////////////////////////////////////////////////////
1348   /////////////////////////////////////////////////////////////////////////////
1349
1350   class Mode4Handler
1351   {
1352   public:
1353     typedef struct
1354     {
1355       int       airspeed1;
1356       int       airspeed2;
1357       int       min_agl1;
1358       double    (*min_agl2) (double airspeed);
1359       int       min_agl3;
1360     } EnvelopesConfiguration;
1361
1362     typedef struct
1363     {
1364       const EnvelopesConfiguration *ac;
1365       const EnvelopesConfiguration *b;
1366     } ModesConfiguration;
1367
1368     struct
1369     {
1370       VoicePlayer::Voice        *voice_too_low_gear;
1371       const ModesConfiguration  *modes;
1372     } conf;
1373
1374     inline Mode4Handler (MK_VIII *device)
1375       : mk(device) {}
1376
1377     double get_upper_agl (const EnvelopesConfiguration *c);
1378     void update ();
1379
1380   private:
1381     MK_VIII *mk;
1382
1383     double ab_bias;
1384     double ab_expanded_bias;
1385     double c_bias;
1386
1387     const EnvelopesConfiguration *get_ab_envelope ();
1388     double get_bias (double initial_bias, double min_agl);
1389     void handle_alert (unsigned int alert, double min_agl, double *bias);
1390
1391     void update_ab ();
1392     void update_ab_expanded ();
1393     void update_c ();
1394   };
1395
1396   /////////////////////////////////////////////////////////////////////////////
1397   // MK_VIII::Mode5Handler ////////////////////////////////////////////////////
1398   /////////////////////////////////////////////////////////////////////////////
1399
1400   class Mode5Handler
1401   {
1402     MK_VIII *mk;
1403
1404     Timer hard_timer;
1405     Timer soft_timer;
1406
1407     double soft_bias;
1408
1409     bool is_hard ();
1410     bool is_soft (double bias);
1411
1412     double get_soft_bias (double initial_bias);
1413
1414     void update_hard (bool is);
1415     void update_soft (bool is);
1416
1417   public:
1418     inline Mode5Handler (MK_VIII *device)
1419       : mk(device) {}
1420
1421     void update ();
1422   };
1423
1424   /////////////////////////////////////////////////////////////////////////////
1425   // MK_VIII::Mode6Handler ////////////////////////////////////////////////////
1426   /////////////////////////////////////////////////////////////////////////////
1427
1428   class Mode6Handler
1429   {
1430   public:
1431     // keep in sync with altitude_callout_definitions[]
1432     typedef enum
1433     {
1434       ALTITUDE_CALLOUT_1000,
1435       ALTITUDE_CALLOUT_500,
1436       ALTITUDE_CALLOUT_400,
1437       ALTITUDE_CALLOUT_300,
1438       ALTITUDE_CALLOUT_200,
1439       ALTITUDE_CALLOUT_100,
1440       ALTITUDE_CALLOUT_50,
1441       ALTITUDE_CALLOUT_40,
1442       ALTITUDE_CALLOUT_30,
1443       ALTITUDE_CALLOUT_20,
1444       ALTITUDE_CALLOUT_10
1445     } AltitudeCallout;
1446
1447     typedef bool (*BankAnglePredicate) (Parameter<double> *agl,
1448                                         double abs_roll_deg,
1449                                         bool ap_engaged);
1450
1451     struct
1452     {
1453       bool                      minimums_enabled;
1454       bool                      smart_500_enabled;
1455       VoicePlayer::Voice        *above_field_voice;
1456
1457       bool                      altitude_callouts_enabled[n_altitude_callouts];
1458       bool                      bank_angle_enabled;
1459       BankAnglePredicate        is_bank_angle;
1460     } conf;
1461
1462     static const int altitude_callout_definitions[];
1463
1464     inline Mode6Handler (MK_VIII *device)
1465       : mk(device) {}
1466
1467     void boot ();
1468     void power_off ();
1469     void enter_takeoff ();
1470     void leave_takeoff ();
1471     void set_volume (float volume);
1472     bool altitude_callouts_enabled ();
1473     void update ();
1474
1475   private:
1476     MK_VIII *mk;
1477
1478     bool                last_decision_height;
1479     Parameter<double>   last_radio_altitude;
1480     Parameter<double>   last_altitude_above_field;
1481
1482     bool altitude_callouts_issued[n_altitude_callouts];
1483     bool minimums_issued;
1484     bool above_field_issued;
1485
1486     Timer               runway_timer;
1487     Parameter<bool>     has_runway;
1488
1489     struct
1490     {
1491       double elevation;         // elevation in feet
1492     } runway;
1493
1494     void reset_minimums ();
1495     void reset_altitude_callouts ();
1496     bool is_playing_altitude_callout ();
1497     bool is_near_minimums (double callout);
1498     bool is_outside_band (double elevation, double callout);
1499     bool inhibit_smart_500 ();
1500
1501     void update_minimums ();
1502     void update_altitude_callouts ();
1503
1504     bool test_runway (const FGRunway *_runway);
1505     bool test_airport (const FGAirport *airport);
1506     void update_runway ();
1507
1508     void get_altitude_above_field (Parameter<double> *parameter);
1509     void update_above_field_callout ();
1510
1511     bool is_bank_angle (double abs_roll_angle, double bias);
1512     bool is_high_bank_angle ();
1513     unsigned int get_bank_angle_alerts ();
1514     void update_bank_angle ();
1515     
1516     class AirportFilter : public FGAirport::AirportFilter
1517     {
1518     public: 
1519       AirportFilter(Mode6Handler *s)
1520         : self(s) {}
1521         
1522       virtual bool passAirport(FGAirport *a) const;
1523       
1524       virtual FGPositioned::Type maxType() const {
1525         return FGPositioned::AIRPORT;
1526       }
1527       
1528     private:
1529       Mode6Handler* self;
1530     };
1531   };
1532
1533   /////////////////////////////////////////////////////////////////////////////
1534   // MK_VIII::TCFHandler //////////////////////////////////////////////////////
1535   /////////////////////////////////////////////////////////////////////////////
1536
1537   class TCFHandler
1538   {
1539     typedef struct
1540     {
1541       double latitude;          // latitude in degrees
1542       double longitude;         // longitude in degrees
1543     } Position;
1544
1545     typedef struct
1546     {
1547       Position  position;       // position of threshold
1548       double    heading;        // runway heading
1549     } RunwayEdge;
1550
1551     MK_VIII *mk;
1552
1553     static const double k;
1554
1555     Timer       runway_timer;
1556     bool        has_runway;
1557
1558     struct
1559     {
1560       Position          center;         // center point
1561       double            elevation;      // elevation in feet
1562       double            half_length;    // runway half length, in nautical miles
1563       RunwayEdge        edges[2];       // runway threshold and end
1564       Position          bias_area[4];   // vertices of the bias area
1565     } runway;
1566
1567     double bias;
1568     double *reference;
1569     double initial_value;
1570
1571     double get_azimuth_difference (double from_lat,
1572                                    double from_lon,
1573                                    double to_lat,
1574                                    double to_lon,
1575                                    double to_heading);
1576     double get_azimuth_difference (const FGRunway *_runway);
1577
1578     FGRunway* select_runway (const FGAirport *airport);
1579     void update_runway ();
1580
1581     void get_bias_area_edges (Position *edge,
1582                               double reciprocal,
1583                               double half_width_m,
1584                               Position *bias_edge1,
1585                               Position *bias_edge2);
1586
1587     bool is_inside_edge_triangle (RunwayEdge *edge);
1588     bool is_inside_bias_area ();
1589
1590     bool is_tcf ();
1591     bool is_rfcf ();
1592
1593     class AirportFilter : public FGAirport::AirportFilter
1594     {
1595     public: 
1596       AirportFilter(MK_VIII *device)
1597         : mk(device) {}
1598         
1599       virtual bool passAirport(FGAirport *a) const;
1600       
1601       virtual FGPositioned::Type maxType() const {
1602         return FGPositioned::AIRPORT;
1603       }
1604     private:
1605       MK_VIII* mk;
1606     };
1607   public:
1608     struct
1609     {
1610       bool enabled;
1611     } conf;
1612
1613     inline TCFHandler (MK_VIII *device)
1614       : mk(device) {}
1615
1616     void update ();
1617   };
1618
1619   /////////////////////////////////////////////////////////////////////////////
1620   // MK_VIII (continued) //////////////////////////////////////////////////////
1621   /////////////////////////////////////////////////////////////////////////////
1622
1623   string        name;
1624   int           num;
1625
1626   PowerHandler          power_handler;
1627   SystemHandler         system_handler;
1628   ConfigurationModule   configuration_module;
1629   FaultHandler          fault_handler;
1630   IOHandler             io_handler;
1631   VoicePlayer           voice_player;
1632   SelfTestHandler       self_test_handler;
1633   AlertHandler          alert_handler;
1634   StateHandler          state_handler;
1635   Mode1Handler          mode1_handler;
1636   Mode2Handler          mode2_handler;
1637   Mode3Handler          mode3_handler;
1638   Mode4Handler          mode4_handler;
1639   Mode5Handler          mode5_handler;
1640   Mode6Handler          mode6_handler;
1641   TCFHandler            tcf_handler;
1642
1643   struct
1644   {
1645     int runway_database;
1646   } conf;
1647
1648 public:
1649   MK_VIII (SGPropertyNode *node);
1650
1651   virtual void init ();
1652   virtual void bind ();
1653   virtual void unbind ();
1654   virtual void update (double dt);
1655 };
1656
1657 #ifdef _MSC_VER
1658 #  pragma warning( pop )
1659 #endif
1660
1661 #endif // __INSTRUMENTS_MK_VIII_HXX