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