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