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