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