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