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