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