1 // mk_viii.cxx -- Honeywell MK VIII EGPWS emulation
3 // Written by Jean-Yves Lefort, started September 2005.
5 // Copyright (C) 2005, 2006 Jean-Yves Lefort - jylefort@FreeBSD.org
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.
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.
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.
22 #ifndef __INSTRUMENTS_MK_VIII_HXX
23 #define __INSTRUMENTS_MK_VIII_HXX
31 #include <simgear/props/props.hxx>
32 #include <simgear/sound/sample_openal.hxx>
33 #include <simgear/structure/subsystem_mgr.hxx>
41 #include <Airports/runways.hxx>
42 #include <Airports/simple.hxx>
43 #include <Main/globals.hxx>
46 # pragma warning( push )
47 # pragma warning( disable: 4355 )
50 ///////////////////////////////////////////////////////////////////////////////
51 // MK_VIII ////////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////////////////
54 class MK_VIII : public SGSubsystem
56 // keep in sync with Mode6Handler::altitude_callout_definitions[]
57 static const unsigned n_altitude_callouts = 11;
59 /////////////////////////////////////////////////////////////////////////////
60 // MK_VIII::RawValueMethodsData /////////////////////////////////////////////
61 /////////////////////////////////////////////////////////////////////////////
63 template <class C, class VT, class DT>
64 class RawValueMethodsData : public SGRawValue<VT>
67 typedef VT (C::*getter_t) (DT) const;
68 typedef void (C::*setter_t) (DT, VT);
70 RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
71 : _obj(obj), _data(data), _getter(getter), _setter(setter) {}
73 virtual VT getValue () const
76 return (_obj.*_getter)(_data);
78 return SGRawValue<VT>::DefaultValue();
80 virtual bool setValue (VT value)
84 (_obj.*_setter)(_data, value);
90 virtual SGRawValue<VT> *clone () const
92 return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
102 /////////////////////////////////////////////////////////////////////////////
103 // MK_VIII::Parameter ///////////////////////////////////////////////////////
104 /////////////////////////////////////////////////////////////////////////////
115 : _value(0), ncd(true) {}
117 inline T get () const { assert(! ncd); return _value; }
118 inline T *get_pointer () { return &_value; }
119 inline void set (T value) { ncd = false; _value = value; }
120 inline void unset () { ncd = true; }
122 inline void set (const Parameter<T> *parameter)
127 set(parameter->get());
130 inline void set (const Parameter<double> *parameter, double factor)
135 set(parameter->get() * factor);
139 /////////////////////////////////////////////////////////////////////////////
140 // MK_VIII::Sample //////////////////////////////////////////////////////////
141 /////////////////////////////////////////////////////////////////////////////
150 inline Sample (T _value)
151 : timestamp(globals->get_sim_time_sec()), value(_value) {}
154 /////////////////////////////////////////////////////////////////////////////
155 // MK_VIII::Timer ///////////////////////////////////////////////////////////
156 /////////////////////////////////////////////////////////////////////////////
168 inline void start () { running = true; start_time = globals->get_sim_time_sec(); }
169 inline void stop () { running = false; }
170 inline double elapsed () const { assert(running); return globals->get_sim_time_sec() - start_time; }
171 inline double start_or_elapsed ()
183 /////////////////////////////////////////////////////////////////////////////
184 // MK_VIII::PropertiesHandler ///////////////////////////////////////////////
185 /////////////////////////////////////////////////////////////////////////////
187 class PropertiesHandler
191 vector<SGPropertyNode_ptr> tied_properties;
196 SGPropertyNode_ptr ai_caged;
197 SGPropertyNode_ptr ai_roll;
198 SGPropertyNode_ptr ai_serviceable;
199 SGPropertyNode_ptr altimeter_altitude;
200 SGPropertyNode_ptr altimeter_serviceable;
201 SGPropertyNode_ptr altitude;
202 SGPropertyNode_ptr altitude_agl;
203 SGPropertyNode_ptr altitude_gear_agl;
204 SGPropertyNode_ptr orientation_roll;
205 SGPropertyNode_ptr asi_serviceable;
206 SGPropertyNode_ptr asi_speed;
207 SGPropertyNode_ptr autopilot_heading_lock;
208 SGPropertyNode_ptr flaps;
209 SGPropertyNode_ptr gear_down;
210 SGPropertyNode_ptr latitude;
211 SGPropertyNode_ptr longitude;
212 SGPropertyNode_ptr nav0_cdi_serviceable;
213 SGPropertyNode_ptr nav0_gs_distance;
214 SGPropertyNode_ptr nav0_gs_needle_deflection;
215 SGPropertyNode_ptr nav0_gs_serviceable;
216 SGPropertyNode_ptr nav0_has_gs;
217 SGPropertyNode_ptr nav0_heading_needle_deflection;
218 SGPropertyNode_ptr nav0_in_range;
219 SGPropertyNode_ptr nav0_nav_loc;
220 SGPropertyNode_ptr nav0_serviceable;
221 SGPropertyNode_ptr power;
222 SGPropertyNode_ptr replay_state;
223 SGPropertyNode_ptr vs;
224 } external_properties;
226 inline PropertiesHandler (MK_VIII *device)
230 inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
232 node->tie(raw_value);
233 tied_properties.push_back(node);
237 inline void tie (SGPropertyNode *node,
238 const char *relative_path,
239 const SGRawValue<T> &raw_value)
241 tie(node->getNode(relative_path, true), raw_value);
244 PropertiesHandler() {};
251 PropertiesHandler properties_handler;
254 /////////////////////////////////////////////////////////////////////////////
255 // MK_VIII::PowerHandler ////////////////////////////////////////////////////
256 /////////////////////////////////////////////////////////////////////////////
265 Timer power_loss_timer;
266 Timer abnormal_timer;
267 Timer low_surge_timer;
268 Timer high_surge_timer;
269 Timer very_high_surge_timer;
271 bool handle_abnormal_voltage (bool abnormal,
273 double max_duration);
279 inline PowerHandler (MK_VIII *device)
280 : mk(device), serviceable(false), powered(false) {}
282 void bind (SGPropertyNode *node);
286 /////////////////////////////////////////////////////////////////////////////
287 // MK_VIII::SystemHandler ///////////////////////////////////////////////////
288 /////////////////////////////////////////////////////////////////////////////
297 int last_replay_state;
298 Timer reposition_timer;
311 inline SystemHandler (MK_VIII *device)
312 : mk(device), state(STATE_OFF) {}
319 /////////////////////////////////////////////////////////////////////////////
320 // MK_VIII::ConfigurationModule /////////////////////////////////////////////
321 /////////////////////////////////////////////////////////////////////////////
323 class ConfigurationModule
326 // keep in sync with IOHandler::present_status()
329 CATEGORY_AIRCRAFT_MODE_TYPE_SELECT,
330 CATEGORY_AIR_DATA_INPUT_SELECT,
331 CATEGORY_POSITION_INPUT_SELECT,
332 CATEGORY_ALTITUDE_CALLOUTS,
333 CATEGORY_AUDIO_MENU_SELECT,
334 CATEGORY_TERRAIN_DISPLAY_SELECT,
335 CATEGORY_OPTIONS_SELECT_GROUP_1,
336 CATEGORY_RADIO_ALTITUDE_INPUT_SELECT,
337 CATEGORY_NAVIGATION_INPUT_SELECT,
338 CATEGORY_ATTITUDE_INPUT_SELECT,
339 CATEGORY_HEADING_INPUT_SELECT,
340 CATEGORY_WINDSHEAR_INPUT_SELECT,
341 CATEGORY_INPUT_OUTPUT_DISCRETE_TYPE_SELECT,
342 CATEGORY_AUDIO_OUTPUT_LEVEL,
343 CATEGORY_UNDEFINED_INPUT_SELECT_1,
344 CATEGORY_UNDEFINED_INPUT_SELECT_2,
345 CATEGORY_UNDEFINED_INPUT_SELECT_3,
352 STATE_INVALID_DATABASE,
353 STATE_INVALID_AIRCRAFT_TYPE
357 int effective_categories[N_CATEGORIES];
359 ConfigurationModule (MK_VIII *device);
362 void bind (SGPropertyNode *node);
367 int categories[N_CATEGORIES];
369 bool read_aircraft_mode_type_select (int value);
370 bool read_air_data_input_select (int value);
371 bool read_position_input_select (int value);
372 bool read_altitude_callouts (int value);
373 bool read_audio_menu_select (int value);
374 bool read_terrain_display_select (int value);
375 bool read_options_select_group_1 (int value);
376 bool read_radio_altitude_input_select (int value);
377 bool read_navigation_input_select (int value);
378 bool read_attitude_input_select (int value);
379 bool read_heading_input_select (int value);
380 bool read_windshear_input_select (int value);
381 bool read_input_output_discrete_type_select (int value);
382 bool read_audio_output_level (int value);
383 bool read_undefined_input_select (int value);
385 static bool m6_t2_is_bank_angle (Parameter<double> *agl,
388 static bool m6_t4_is_bank_angle (Parameter<double> *agl,
393 /////////////////////////////////////////////////////////////////////////////
394 // MK_VIII::FaultHandler ////////////////////////////////////////////////////
395 /////////////////////////////////////////////////////////////////////////////
407 static const unsigned int fault_inops[];
409 bool has_faults (unsigned int inop);
412 // keep in sync with IOHandler::present_status()
415 FAULT_ALL_MODES_INHIBIT,
418 FAULT_MOMENTARY_FLAP_OVERRIDE_INVALID,
419 FAULT_SELF_TEST_INVALID,
420 FAULT_GLIDESLOPE_CANCEL_INVALID,
421 FAULT_STEEP_APPROACH_INVALID,
423 FAULT_TA_TCF_INHIBIT,
424 FAULT_MODES14_INPUTS_INVALID,
425 FAULT_MODE5_INPUTS_INVALID,
426 FAULT_MODE6_INPUTS_INVALID,
427 FAULT_BANK_ANGLE_INPUTS_INVALID,
428 FAULT_TCF_INPUTS_INVALID,
432 bool faults[N_FAULTS];
434 inline FaultHandler (MK_VIII *device)
439 void set_fault (Fault fault);
440 void unset_fault (Fault fault);
442 bool has_faults () const;
445 /////////////////////////////////////////////////////////////////////////////
446 // MK_VIII::IOHandler ///////////////////////////////////////////////////////
447 /////////////////////////////////////////////////////////////////////////////
461 struct LampConfiguration
467 struct FaultsConfiguration
469 double max_flaps_down_airspeed;
470 double max_gear_down_airspeed;
475 const LampConfiguration *lamp;
476 const FaultsConfiguration *faults;
478 bool steep_approach_enabled;
479 bool gpws_inhibit_enabled;
480 bool momentary_flap_override_enabled;
481 bool alternate_steep_approach;
482 bool use_internal_gps;
483 bool localizer_enabled;
484 bool use_gear_altitude;
485 bool use_attitude_indicator;
488 struct _s_input_feeders
494 bool glideslope_inhibit;
495 bool decision_height;
496 bool autopilot_engaged;
501 bool uncorrected_barometric_altitude;
502 bool barometric_altitude_rate;
504 bool glideslope_deviation;
506 bool localizer_deviation;
507 bool computed_airspeed;
508 bool decision_height;
516 bool landing_gear; // appendix E 6.6.2, 3.15.1.4
517 bool landing_flaps; // appendix E 6.6.4, 3.15.1.2
518 bool momentary_flap_override; // appendix E 6.6.6, 3.15.1.6
519 bool self_test; // appendix E 6.6.7, 3.15.1.10
520 bool glideslope_inhibit; // appendix E 6.6.11, 3.15.1.1
521 bool glideslope_cancel; // appendix E 6.6.13, 3.15.1.5
522 bool decision_height; // appendix E 6.6.14, 3.10.2
523 bool mode6_low_volume; // appendix E 6.6.15, 3.15.1.7
524 bool audio_inhibit; // appendix E 6.6.16, 3.15.1.3
525 bool ta_tcf_inhibit; // appendix E 6.6.20, 3.15.1.9
526 bool autopilot_engaged; // appendix E 6.6.21, 3.15.1.8
527 bool steep_approach; // appendix E 6.6.25, 3.15.1.11
528 bool gpws_inhibit; // appendix E 6.6.27, 3.15.1.12
533 Parameter<double> uncorrected_barometric_altitude; // appendix E 6.2.1
534 Parameter<double> barometric_altitude_rate; // appendix E 6.2.2
535 Parameter<double> gps_altitude; // appendix E 6.2.4
536 Parameter<double> gps_latitude; // appendix E 6.2.7
537 Parameter<double> gps_longitude; // appendix E 6.2.8
538 Parameter<double> gps_vertical_figure_of_merit; // appendix E 6.2.13
539 Parameter<double> radio_altitude; // appendix E 6.2.29
540 Parameter<double> glideslope_deviation; // appendix E 6.2.30
541 Parameter<double> roll_angle; // appendix E 6.2.31
542 Parameter<double> localizer_deviation; // appendix E 6.2.33
543 Parameter<double> computed_airspeed; // appendix E 6.2.39
544 Parameter<double> decision_height; // appendix E 6.2.41
552 bool gpws_warning; // appendix E 7.4.1, 3.15.2.5
553 bool gpws_alert; // appendix E 7.4.1, 3.15.2.6
554 bool audio_on; // appendix E 7.4.2, 3.15.2.10
555 bool gpws_inop; // appendix E 7.4.3, 3.15.2.3
556 bool tad_inop; // appendix E 7.4.3, 3.15.2.4
557 bool flap_override; // appendix E 7.4.5, 3.15.2.8
558 bool glideslope_cancel; // appendix E 7.4.6, 3.15.2.7
559 bool steep_approach; // appendix E 7.4.12, 3.15.2.9
564 int egpws_alert_discrete_1; // appendix E 7.1.1.1
565 int egpwc_logic_discretes; // appendix E 7.1.1.2
566 int mode6_callouts_discrete_1; // appendix E 7.1.1.3
567 int mode6_callouts_discrete_2; // appendix E 7.1.1.4
568 int egpws_alert_discrete_2; // appendix E 7.1.1.5
569 int egpwc_alert_discrete_3; // appendix E 7.1.1.6
577 Parameter<double> barometric_altitude_rate;
578 Parameter<double> decision_height;
579 Parameter<double> geometric_altitude;
580 Parameter<double> glideslope_deviation_dots;
581 Parameter<double> gps_altitude;
582 Parameter<double> gps_latitude;
583 Parameter<double> gps_longitude;
584 Parameter<double> gps_vertical_figure_of_merit;
585 Parameter<double> localizer_deviation_dots;
586 Parameter<double> radio_altitude;
587 Parameter<double> roll_angle;
588 Parameter<double> terrain_clearance;
591 IOHandler (MK_VIII *device);
597 void enter_ground ();
598 void enter_takeoff ();
600 void update_inputs ();
601 void update_input_faults ();
602 void update_alternate_discrete_input (bool *ptr);
603 void update_internal_latches ();
605 void update_egpws_alert_discrete_1 ();
606 void update_egpwc_logic_discretes ();
607 void update_mode6_callouts_discrete_1 ();
608 void update_mode6_callouts_discrete_2 ();
609 void update_egpws_alert_discrete_2 ();
610 void update_egpwc_alert_discrete_3 ();
611 void update_outputs ();
613 void update_lamps ();
614 void set_lamp (Lamp lamp);
616 bool gpws_inhibit () const;
617 bool real_flaps_down () const;
618 bool flaps_down () const;
619 bool flap_override () const;
620 bool steep_approach () const;
621 bool momentary_steep_approach_enabled () const;
623 void bind (SGPropertyNode *node);
629 ///////////////////////////////////////////////////////////////////////////
630 // MK_VIII::IOHandler::TerrainClearanceFilter /////////////////////////////
631 ///////////////////////////////////////////////////////////////////////////
633 class TerrainClearanceFilter
635 typedef deque< Sample<double> > samples_type;
636 samples_type samples;
640 inline TerrainClearanceFilter ()
643 double update (double agl);
647 ///////////////////////////////////////////////////////////////////////////
648 // MK_VIII::IOHandler (continued) /////////////////////////////////////////
649 ///////////////////////////////////////////////////////////////////////////
651 TerrainClearanceFilter terrain_clearance_filter;
656 Timer audio_inhibit_fault_timer;
657 Timer landing_gear_fault_timer;
658 Timer flaps_down_fault_timer;
659 Timer momentary_flap_override_fault_timer;
660 Timer self_test_fault_timer;
661 Timer glideslope_cancel_fault_timer;
662 Timer steep_approach_fault_timer;
663 Timer gpws_inhibit_fault_timer;
664 Timer ta_tcf_inhibit_fault_timer;
666 bool last_landing_gear;
667 bool last_real_flaps_down;
669 typedef deque< Sample< Parameter<double> > > altitude_samples_type;
670 altitude_samples_type altitude_samples;
674 bool glideslope_cancel;
677 void update_terrain_clearance ();
678 void reset_terrain_clearance ();
680 void handle_input_fault (bool test, FaultHandler::Fault fault);
681 void handle_input_fault (bool test,
684 FaultHandler::Fault fault);
686 void tie_input (SGPropertyNode *node,
690 void tie_input (SGPropertyNode *node,
692 Parameter<double> *input,
694 void tie_output (SGPropertyNode *node,
697 void tie_output (SGPropertyNode *node,
703 bool get_discrete_input (bool *ptr) const;
704 void set_discrete_input (bool *ptr, bool value);
706 void present_status ();
707 void present_status_section (const char *name);
708 void present_status_item (const char *name, const char *value = NULL);
709 void present_status_subitem (const char *name);
711 bool get_present_status () const;
712 void set_present_status (bool value);
714 bool *get_lamp_output (Lamp lamp);
717 /////////////////////////////////////////////////////////////////////////////
718 // MK_VIII::VoicePlayer /////////////////////////////////////////////////////
719 /////////////////////////////////////////////////////////////////////////////
725 ///////////////////////////////////////////////////////////////////////////
726 // MK_VIII::VoicePlayer::Voice ////////////////////////////////////////////
727 ///////////////////////////////////////////////////////////////////////////
733 /////////////////////////////////////////////////////////////////////////
734 // MK_VIII::VoicePlayer::Voice::Element ////////////////////////////////////////
735 /////////////////////////////////////////////////////////////////////////
742 virtual inline void play (float volume) {}
743 virtual inline void stop () {}
744 virtual bool is_playing () = 0;
745 virtual inline void set_volume (float volume) {}
748 /////////////////////////////////////////////////////////////////////////
749 // MK_VIII::VoicePlayer::Voice::SampleElement ///////////////////////////
750 /////////////////////////////////////////////////////////////////////////
752 class SampleElement : public Element
754 SGSharedPtr<SGSoundSample> _sample;
758 inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
759 : _sample(sample), _volume(volume) { silence = false; }
761 virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
762 virtual inline void stop () { if (_sample) _sample->stop(); }
763 virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
764 virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
767 /////////////////////////////////////////////////////////////////////////
768 // MK_VIII::VoicePlayer::Voice::SilenceElement //////////////////////////
769 /////////////////////////////////////////////////////////////////////////
771 class SilenceElement : public Element
777 inline SilenceElement (double duration)
778 : _duration(duration) { silence = true; }
780 virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
781 virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
784 /////////////////////////////////////////////////////////////////////////
785 // MK_VIII::VoicePlayer::Voice (continued) //////////////////////////////
786 /////////////////////////////////////////////////////////////////////////
790 inline Voice (VoicePlayer *_player)
791 : element(NULL), player(_player), volume(1.0) {}
795 inline void append (Element *_element) { elements.push_back(_element); }
798 void stop (bool now);
799 void set_volume (float _volume);
800 void volume_changed ();
808 vector<Element *> elements;
809 vector<Element *>::iterator iter;
811 inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
814 ///////////////////////////////////////////////////////////////////////////
815 // MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
816 ///////////////////////////////////////////////////////////////////////////
830 Voice *application_data_base_failed;
832 Voice *bank_angle_bank_angle;
833 Voice *bank_angle_bank_angle_3;
834 Voice *bank_angle_inop;
835 Voice *bank_angle_pause_bank_angle;
836 Voice *bank_angle_pause_bank_angle_3;
837 Voice *callouts_inop;
838 Voice *configuration_type_invalid;
840 Voice *dont_sink_pause_dont_sink;
841 Voice *five_hundred_above;
843 Voice *glideslope_inop;
845 Voice *hard_glideslope;
847 Voice *minimums_minimums;
850 Voice *sink_rate_pause_sink_rate;
851 Voice *soft_glideslope;
853 Voice *terrain_pause_terrain;
854 Voice *too_low_flaps;
856 Voice *too_low_terrain;
857 Voice *altitude_callouts[n_altitude_callouts];
860 inline VoicePlayer (MK_VIII *device)
861 : voice(NULL), next_voice(NULL), mk(device), speaker(this) {}
872 void play (Voice *_voice, unsigned int flags = 0);
878 void stop (unsigned int flags = 0);
880 void set_volume (float _volume);
883 inline void bind (SGPropertyNode *node) { speaker.bind(node); }
887 ///////////////////////////////////////////////////////////////////////////
888 // MK_VIII::VoicePlayer::Speaker //////////////////////////////////////////
889 ///////////////////////////////////////////////////////////////////////////
898 inline void tie (SGPropertyNode *node, const char *name, T *ptr)
900 player->mk->properties_handler.tie
901 (node, (string("speaker/") + name).c_str(),
902 RawValueMethodsData<MK_VIII::VoicePlayer::Speaker,T,T*>
904 &MK_VIII::VoicePlayer::Speaker::get_property,
905 &MK_VIII::VoicePlayer::Speaker::set_property));
910 inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
913 inline T get_property (T *ptr) const { return *ptr; }
917 inline Speaker (VoicePlayer *_player)
924 void bind (SGPropertyNode *node);
925 void update_configuration ();
929 ///////////////////////////////////////////////////////////////////////////
930 // MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
931 ///////////////////////////////////////////////////////////////////////////
935 SGSharedPtr<SGSampleGroup> _sgr;
938 map< string, SGSharedPtr<SGSoundSample> > samples;
939 vector<Voice *> _voices;
944 SGSoundSample *get_sample (const char *name);
946 inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
947 inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
948 inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
950 inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
953 inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
954 template <class T1, class T2>
955 inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
956 template <class T1, class T2, class T3>
957 inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
958 template <class T1, class T2, class T3, class T4>
959 inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
963 /////////////////////////////////////////////////////////////////////////////
964 // MK_VIII::SelfTestHandler /////////////////////////////////////////////////
965 /////////////////////////////////////////////////////////////////////////////
967 class SelfTestHandler
980 ACTION_SLEEP = 1 << 0,
981 ACTION_VOICE = 1 << 1,
982 ACTION_DISCRETE_ON_OFF = 1 << 2,
989 double sleep_duration;
997 double button_press_timestamp;
998 IOHandler::Outputs saved_outputs;
1001 bool _was_here (int position);
1003 Action sleep (double duration);
1004 Action play (VoicePlayer::Voice *voice);
1005 Action discrete_on (bool *discrete, double duration);
1006 Action discrete_on_off (bool *discrete, double duration);
1007 Action discrete_on_off (bool *discrete, VoicePlayer::Voice *voice);
1026 inline SelfTestHandler (MK_VIII *device)
1027 : mk(device), button_pressed(false), state(STATE_NONE) {}
1029 inline void power_off () { stop(); }
1030 inline void set_inop () { stop(); }
1031 void handle_button_event (bool value);
1035 /////////////////////////////////////////////////////////////////////////////
1036 // MK_VIII::AlertHandler ////////////////////////////////////////////////////
1037 /////////////////////////////////////////////////////////////////////////////
1043 unsigned int old_alerts;
1044 unsigned int voice_alerts;
1045 unsigned int repeated_alerts;
1046 VoicePlayer::Voice *altitude_callout_voice;
1049 inline bool has_alerts (unsigned int test) const { return (alerts & test) != 0; }
1050 inline bool has_old_alerts (unsigned int test) const { return (old_alerts & test) != 0; }
1051 inline bool must_play_voice (unsigned int test) const { return ! has_old_alerts(test) || (repeated_alerts & test) != 0; }
1052 bool select_voice_alerts (unsigned int test);
1057 ALERT_MODE1_PULL_UP = 1 << 0,
1058 ALERT_MODE1_SINK_RATE = 1 << 1,
1060 ALERT_MODE2A_PREFACE = 1 << 2,
1061 ALERT_MODE2B_PREFACE = 1 << 3,
1062 ALERT_MODE2A = 1 << 4,
1063 ALERT_MODE2B = 1 << 5,
1064 ALERT_MODE2B_LANDING_MODE = 1 << 6,
1065 ALERT_MODE2A_ALTITUDE_GAIN = 1 << 7,
1066 ALERT_MODE2A_ALTITUDE_GAIN_TERRAIN_CLOSING = 1 << 8,
1068 ALERT_MODE3 = 1 << 9,
1070 ALERT_MODE4_TOO_LOW_FLAPS = 1 << 10,
1071 ALERT_MODE4_TOO_LOW_GEAR = 1 << 11,
1072 ALERT_MODE4AB_TOO_LOW_TERRAIN = 1 << 12,
1073 ALERT_MODE4C_TOO_LOW_TERRAIN = 1 << 13,
1075 ALERT_MODE5_SOFT = 1 << 14,
1076 ALERT_MODE5_HARD = 1 << 15,
1078 ALERT_MODE6_MINIMUMS = 1 << 16,
1079 ALERT_MODE6_ALTITUDE_CALLOUT = 1 << 17,
1080 ALERT_MODE6_LOW_BANK_ANGLE_1 = 1 << 18,
1081 ALERT_MODE6_HIGH_BANK_ANGLE_1 = 1 << 19,
1082 ALERT_MODE6_LOW_BANK_ANGLE_2 = 1 << 20,
1083 ALERT_MODE6_HIGH_BANK_ANGLE_2 = 1 << 21,
1084 ALERT_MODE6_LOW_BANK_ANGLE_3 = 1 << 22,
1085 ALERT_MODE6_HIGH_BANK_ANGLE_3 = 1 << 23,
1087 ALERT_TCF_TOO_LOW_TERRAIN = 1 << 24
1092 ALERT_FLAG_REPEAT = 1 << 0
1095 unsigned int alerts;
1097 inline AlertHandler (MK_VIII *device)
1104 void set_alerts (unsigned int _alerts,
1105 unsigned int flags = 0,
1106 VoicePlayer::Voice *_altitude_callout_voice = NULL);
1107 void unset_alerts (unsigned int _alerts);
1109 inline void repeat_alert (unsigned int alert) { set_alerts(alert, ALERT_FLAG_REPEAT); }
1110 inline void set_altitude_callout_alert (VoicePlayer::Voice *voice) { set_alerts(ALERT_MODE6_ALTITUDE_CALLOUT, 0, voice); }
1113 /////////////////////////////////////////////////////////////////////////////
1114 // MK_VIII::StateHandler ////////////////////////////////////////////////////
1115 /////////////////////////////////////////////////////////////////////////////
1121 Timer potentially_airborne_timer;
1123 void update_ground ();
1124 void enter_ground ();
1125 void leave_ground ();
1127 void update_takeoff ();
1128 void enter_takeoff ();
1129 void leave_takeoff ();
1135 inline StateHandler (MK_VIII *device)
1136 : mk(device), ground(true), takeoff(true) {}
1138 void post_reposition ();
1142 /////////////////////////////////////////////////////////////////////////////
1143 // MK_VIII::Mode1Handler ////////////////////////////////////////////////////
1144 /////////////////////////////////////////////////////////////////////////////
1150 Timer pull_up_timer;
1151 Timer sink_rate_timer;
1153 double sink_rate_tti; // time-to-impact in minutes
1155 double get_pull_up_bias ();
1158 double get_sink_rate_bias ();
1159 bool is_sink_rate ();
1160 double get_sink_rate_tti ();
1162 void update_pull_up ();
1163 void update_sink_rate ();
1168 bool flap_override_bias;
1170 double (*pull_up_min_agl1) (double vs);
1171 int pull_up_max_agl1;
1172 double (*pull_up_min_agl2) (double vs);
1173 int pull_up_max_agl2;
1174 } EnvelopesConfiguration;
1178 const EnvelopesConfiguration *envelopes;
1181 inline Mode1Handler (MK_VIII *device)
1187 /////////////////////////////////////////////////////////////////////////////
1188 // MK_VIII::Mode2Handler ////////////////////////////////////////////////////
1189 /////////////////////////////////////////////////////////////////////////////
1194 ///////////////////////////////////////////////////////////////////////////
1195 // MK_VIII::Mode2Handler::ClosureRateFilter ///////////////////////////////
1196 ///////////////////////////////////////////////////////////////////////////
1198 class ClosureRateFilter
1200 /////////////////////////////////////////////////////////////////////////
1201 // MK_VIII::Mode2Handler::ClosureRateFilter::PassFilter /////////////////
1202 /////////////////////////////////////////////////////////////////////////
1214 inline PassFilter (double _a0, double _a1, double _b1)
1215 : a0(_a0), a1(_a1), b1(_b1) {}
1217 inline double filter (double input)
1219 last_output = a0 * input + a1 * last_input + b1 * last_output;
1225 inline void reset ()
1232 /////////////////////////////////////////////////////////////////////////
1233 // MK_VIII::Mode2Handler::ClosureRateFilter (continued) /////////////////
1234 /////////////////////////////////////////////////////////////////////////
1239 Parameter<double> last_ra; // last radio altitude
1240 Parameter<double> last_ba; // last barometric altitude
1241 PassFilter ra_filter; // radio altitude rate filter
1242 PassFilter ba_filter; // barometric altitude rate filter
1244 double limit_radio_altitude_rate (double r);
1247 Parameter<double> output;
1249 inline ClosureRateFilter (MK_VIII *device)
1251 ra_filter(0.05, 0, 0.95), // low-pass filter
1252 ba_filter(0.93, -0.93, 0.86) {} // high-pass-filter
1258 ///////////////////////////////////////////////////////////////////////////
1259 // MK_VIII::Mode2Handler (continued) //////////////////////////////////////
1260 ///////////////////////////////////////////////////////////////////////////
1264 ClosureRateFilter closure_rate_filter;
1266 Timer takeoff_timer;
1267 Timer pull_up_timer;
1269 double a_start_time;
1270 Timer a_altitude_gain_timer;
1271 double a_altitude_gain_alt;
1273 void check_pull_up (unsigned int preface_alert, unsigned int alert);
1275 bool b_conditions ();
1290 const Configuration *conf;
1292 inline Mode2Handler (MK_VIII *device)
1293 : mk(device), closure_rate_filter(device) {}
1297 void leave_ground ();
1298 void enter_takeoff ();
1302 /////////////////////////////////////////////////////////////////////////////
1303 // MK_VIII::Mode3Handler ////////////////////////////////////////////////////
1304 /////////////////////////////////////////////////////////////////////////////
1311 bool has_descent_alt;
1315 double max_alt_loss (double _bias);
1316 double get_bias (double initial_bias, double alt_loss);
1317 bool is (double *alt_loss);
1323 int (*max_agl) (bool flap_override);
1324 double (*max_alt_loss) (bool flap_override, double agl);
1327 const Configuration *conf;
1329 inline Mode3Handler (MK_VIII *device)
1330 : mk(device), armed(false), has_descent_alt(false) {}
1332 void enter_takeoff ();
1336 /////////////////////////////////////////////////////////////////////////////
1337 // MK_VIII::Mode4Handler ////////////////////////////////////////////////////
1338 /////////////////////////////////////////////////////////////////////////////
1348 double (*min_agl2) (double airspeed);
1350 } EnvelopesConfiguration;
1354 const EnvelopesConfiguration *ac;
1355 const EnvelopesConfiguration *b;
1356 } ModesConfiguration;
1360 VoicePlayer::Voice *voice_too_low_gear;
1361 const ModesConfiguration *modes;
1364 inline Mode4Handler (MK_VIII *device)
1365 : mk(device),ab_bias(0.0),ab_expanded_bias(0.0),c_bias(0.0) {}
1367 double get_upper_agl (const EnvelopesConfiguration *c);
1374 double ab_expanded_bias;
1377 const EnvelopesConfiguration *get_ab_envelope ();
1378 double get_bias (double initial_bias, double min_agl);
1379 void handle_alert (unsigned int alert, double min_agl, double *bias);
1382 void update_ab_expanded ();
1386 /////////////////////////////////////////////////////////////////////////////
1387 // MK_VIII::Mode5Handler ////////////////////////////////////////////////////
1388 /////////////////////////////////////////////////////////////////////////////
1400 bool is_soft (double bias);
1402 double get_soft_bias (double initial_bias);
1404 void update_hard (bool is);
1405 void update_soft (bool is);
1408 inline Mode5Handler (MK_VIII *device)
1409 : mk(device), soft_bias(0.0) {}
1414 /////////////////////////////////////////////////////////////////////////////
1415 // MK_VIII::Mode6Handler ////////////////////////////////////////////////////
1416 /////////////////////////////////////////////////////////////////////////////
1421 // keep in sync with altitude_callout_definitions[]
1424 ALTITUDE_CALLOUT_1000,
1425 ALTITUDE_CALLOUT_500,
1426 ALTITUDE_CALLOUT_400,
1427 ALTITUDE_CALLOUT_300,
1428 ALTITUDE_CALLOUT_200,
1429 ALTITUDE_CALLOUT_100,
1430 ALTITUDE_CALLOUT_50,
1431 ALTITUDE_CALLOUT_40,
1432 ALTITUDE_CALLOUT_30,
1433 ALTITUDE_CALLOUT_20,
1437 typedef bool (*BankAnglePredicate) (Parameter<double> *agl,
1438 double abs_roll_deg,
1443 bool minimums_enabled;
1444 bool smart_500_enabled;
1445 VoicePlayer::Voice *above_field_voice;
1447 bool altitude_callouts_enabled[n_altitude_callouts];
1448 bool bank_angle_enabled;
1449 BankAnglePredicate is_bank_angle;
1452 static const int altitude_callout_definitions[];
1454 inline Mode6Handler (MK_VIII *device)
1459 void enter_takeoff ();
1460 void leave_takeoff ();
1461 void set_volume (float volume);
1462 bool altitude_callouts_enabled ();
1468 bool last_decision_height;
1469 Parameter<double> last_radio_altitude;
1470 Parameter<double> last_altitude_above_field;
1472 bool altitude_callouts_issued[n_altitude_callouts];
1473 bool minimums_issued;
1474 bool above_field_issued;
1477 Parameter<bool> has_runway;
1481 double elevation; // elevation in feet
1484 void reset_minimums ();
1485 void reset_altitude_callouts ();
1486 bool is_playing_altitude_callout ();
1487 bool is_near_minimums (double callout);
1488 bool is_outside_band (double elevation, double callout);
1489 bool inhibit_smart_500 ();
1491 void update_minimums ();
1492 void update_altitude_callouts ();
1494 bool test_runway (const FGRunway *_runway);
1495 bool test_airport (const FGAirport *airport);
1496 void update_runway ();
1498 void get_altitude_above_field (Parameter<double> *parameter);
1499 void update_above_field_callout ();
1501 bool is_bank_angle (double abs_roll_angle, double bias);
1502 bool is_high_bank_angle ();
1503 unsigned int get_bank_angle_alerts ();
1504 void update_bank_angle ();
1506 class AirportFilter : public FGAirport::AirportFilter
1509 AirportFilter(Mode6Handler *s)
1512 virtual bool passAirport(FGAirport *a) const;
1514 virtual FGPositioned::Type maxType() const {
1515 return FGPositioned::AIRPORT;
1523 /////////////////////////////////////////////////////////////////////////////
1524 // MK_VIII::TCFHandler //////////////////////////////////////////////////////
1525 /////////////////////////////////////////////////////////////////////////////
1531 double latitude; // latitude in degrees
1532 double longitude; // longitude in degrees
1537 Position position; // position of threshold
1538 double heading; // runway heading
1543 static const double k;
1550 Position center; // center point
1551 double elevation; // elevation in feet
1552 double half_length; // runway half length, in nautical miles
1553 RunwayEdge edges[2]; // runway threshold and end
1554 Position bias_area[4]; // vertices of the bias area
1559 double initial_value;
1561 double get_azimuth_difference (double from_lat,
1566 double get_azimuth_difference (const FGRunway *_runway);
1568 FGRunway* select_runway (const FGAirport *airport);
1569 void update_runway ();
1571 void get_bias_area_edges (Position *edge,
1573 double half_width_m,
1574 Position *bias_edge1,
1575 Position *bias_edge2);
1577 bool is_inside_edge_triangle (RunwayEdge *edge);
1578 bool is_inside_bias_area ();
1583 class AirportFilter : public FGAirport::AirportFilter
1586 AirportFilter(MK_VIII *device)
1589 virtual bool passAirport(FGAirport *a) const;
1599 inline TCFHandler (MK_VIII *device)
1605 /////////////////////////////////////////////////////////////////////////////
1606 // MK_VIII (continued) //////////////////////////////////////////////////////
1607 /////////////////////////////////////////////////////////////////////////////
1612 PowerHandler power_handler;
1613 SystemHandler system_handler;
1614 ConfigurationModule configuration_module;
1615 FaultHandler fault_handler;
1616 IOHandler io_handler;
1617 VoicePlayer voice_player;
1618 SelfTestHandler self_test_handler;
1619 AlertHandler alert_handler;
1620 StateHandler state_handler;
1621 Mode1Handler mode1_handler;
1622 Mode2Handler mode2_handler;
1623 Mode3Handler mode3_handler;
1624 Mode4Handler mode4_handler;
1625 Mode5Handler mode5_handler;
1626 Mode6Handler mode6_handler;
1627 TCFHandler tcf_handler;
1631 int runway_database;
1635 MK_VIII (SGPropertyNode *node);
1637 virtual void init ();
1638 virtual void bind ();
1639 virtual void unbind ();
1640 virtual void update (double dt);
1644 # pragma warning( pop )
1647 #endif // __INSTRUMENTS_MK_VIII_HXX