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>
39 #include "Airports/runways.hxx"
40 #include "Airports/simple.hxx"
41 #include "Main/globals.hxx"
43 ///////////////////////////////////////////////////////////////////////////////
44 // MK_VIII ////////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////////////////
47 class MK_VIII : public SGSubsystem
49 // keep in sync with Mode6Handler::altitude_callout_definitions[]
50 static const int n_altitude_callouts = 11;
52 /////////////////////////////////////////////////////////////////////////////
53 // MK_VIII::RawValueMethodsData /////////////////////////////////////////////
54 /////////////////////////////////////////////////////////////////////////////
56 template <class C, class VT, class DT>
57 class RawValueMethodsData : public SGRawValue<VT>
60 typedef VT (C::*getter_t) (DT) const;
61 typedef void (C::*setter_t) (DT, VT);
63 RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
64 : _obj(obj), _data(data), _getter(getter), _setter(setter) {}
66 virtual VT getValue () const
69 return (_obj.*_getter)(_data);
71 return SGRawValue<VT>::DefaultValue;
73 virtual bool setValue (VT value)
77 (_obj.*_setter)(_data, value);
83 virtual SGRawValue<VT> *clone () const
85 return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
95 /////////////////////////////////////////////////////////////////////////////
96 // MK_VIII::Parameter ///////////////////////////////////////////////////////
97 /////////////////////////////////////////////////////////////////////////////
108 : _value(0), ncd(true) {}
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; }
115 inline void set (const Parameter<T> *parameter)
120 set(parameter->get());
123 inline void set (const Parameter<double> *parameter, double factor)
128 set(parameter->get() * factor);
132 /////////////////////////////////////////////////////////////////////////////
133 // MK_VIII::Sample //////////////////////////////////////////////////////////
134 /////////////////////////////////////////////////////////////////////////////
143 inline Sample (T _value)
144 : timestamp(globals->get_sim_time_sec()), value(_value) {}
147 /////////////////////////////////////////////////////////////////////////////
148 // MK_VIII::Timer ///////////////////////////////////////////////////////////
149 /////////////////////////////////////////////////////////////////////////////
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 ()
176 /////////////////////////////////////////////////////////////////////////////
177 // MK_VIII::PropertiesHandler ///////////////////////////////////////////////
178 /////////////////////////////////////////////////////////////////////////////
180 class PropertiesHandler
184 vector<SGPropertyNode *> tied_properties;
189 SGPropertyNode *ai_caged;
190 SGPropertyNode *ai_roll;
191 SGPropertyNode *ai_serviceable;
192 SGPropertyNode *altimeter_altitude;
193 SGPropertyNode *altimeter_serviceable;
194 SGPropertyNode *altitude;
195 SGPropertyNode *altitude_agl;
196 SGPropertyNode *asi_serviceable;
197 SGPropertyNode *asi_speed;
198 SGPropertyNode *autopilot_heading_lock;
199 SGPropertyNode *flaps;
200 SGPropertyNode *gear_down;
201 SGPropertyNode *latitude;
202 SGPropertyNode *longitude;
203 SGPropertyNode *nav0_cdi_serviceable;
204 SGPropertyNode *nav0_gs_distance;
205 SGPropertyNode *nav0_gs_needle_deflection;
206 SGPropertyNode *nav0_gs_serviceable;
207 SGPropertyNode *nav0_has_gs;
208 SGPropertyNode *nav0_heading_needle_deflection;
209 SGPropertyNode *nav0_in_range;
210 SGPropertyNode *nav0_nav_loc;
211 SGPropertyNode *nav0_serviceable;
212 SGPropertyNode *power;
213 SGPropertyNode *replay_state;
215 } external_properties;
217 inline PropertiesHandler (MK_VIII *device)
221 inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
223 node->tie(raw_value);
224 tied_properties.push_back(node);
228 inline void tie (SGPropertyNode *node,
229 const char *relative_path,
230 const SGRawValue<T> &raw_value)
232 tie(node->getNode(relative_path, true), raw_value);
239 /////////////////////////////////////////////////////////////////////////////
240 // MK_VIII::PowerHandler ////////////////////////////////////////////////////
241 /////////////////////////////////////////////////////////////////////////////
250 Timer power_loss_timer;
251 Timer abnormal_timer;
252 Timer low_surge_timer;
253 Timer high_surge_timer;
254 Timer very_high_surge_timer;
256 bool handle_abnormal_voltage (bool abnormal,
258 double max_duration);
264 inline PowerHandler (MK_VIII *device)
265 : mk(device), serviceable(false), powered(false) {}
267 void bind (SGPropertyNode *node);
271 /////////////////////////////////////////////////////////////////////////////
272 // MK_VIII::SystemHandler ///////////////////////////////////////////////////
273 /////////////////////////////////////////////////////////////////////////////
282 int last_replay_state;
283 Timer reposition_timer;
296 inline SystemHandler (MK_VIII *device)
297 : mk(device), state(STATE_OFF) {}
304 /////////////////////////////////////////////////////////////////////////////
305 // MK_VIII::ConfigurationModule /////////////////////////////////////////////
306 /////////////////////////////////////////////////////////////////////////////
308 class ConfigurationModule
311 // keep in sync with IOHandler::present_status()
314 CATEGORY_AIRCRAFT_MODE_TYPE_SELECT,
315 CATEGORY_AIR_DATA_INPUT_SELECT,
316 CATEGORY_POSITION_INPUT_SELECT,
317 CATEGORY_ALTITUDE_CALLOUTS,
318 CATEGORY_AUDIO_MENU_SELECT,
319 CATEGORY_TERRAIN_DISPLAY_SELECT,
320 CATEGORY_OPTIONS_SELECT_GROUP_1,
321 CATEGORY_RADIO_ALTITUDE_INPUT_SELECT,
322 CATEGORY_NAVIGATION_INPUT_SELECT,
323 CATEGORY_ATTITUDE_INPUT_SELECT,
324 CATEGORY_HEADING_INPUT_SELECT,
325 CATEGORY_WINDSHEAR_INPUT_SELECT,
326 CATEGORY_INPUT_OUTPUT_DISCRETE_TYPE_SELECT,
327 CATEGORY_AUDIO_OUTPUT_LEVEL,
328 CATEGORY_UNDEFINED_INPUT_SELECT_1,
329 CATEGORY_UNDEFINED_INPUT_SELECT_2,
330 CATEGORY_UNDEFINED_INPUT_SELECT_3,
337 STATE_INVALID_DATABASE,
338 STATE_INVALID_AIRCRAFT_TYPE
342 int effective_categories[N_CATEGORIES];
344 ConfigurationModule (MK_VIII *device);
347 void bind (SGPropertyNode *node);
352 int categories[N_CATEGORIES];
354 bool read_aircraft_mode_type_select (int value);
355 bool read_air_data_input_select (int value);
356 bool read_position_input_select (int value);
357 bool read_altitude_callouts (int value);
358 bool read_audio_menu_select (int value);
359 bool read_terrain_display_select (int value);
360 bool read_options_select_group_1 (int value);
361 bool read_radio_altitude_input_select (int value);
362 bool read_navigation_input_select (int value);
363 bool read_attitude_input_select (int value);
364 bool read_heading_input_select (int value);
365 bool read_windshear_input_select (int value);
366 bool read_input_output_discrete_type_select (int value);
367 bool read_audio_output_level (int value);
368 bool read_undefined_input_select (int value);
370 static bool m6_t2_is_bank_angle (Parameter<double> *agl,
373 static bool m6_t4_is_bank_angle (Parameter<double> *agl,
378 /////////////////////////////////////////////////////////////////////////////
379 // MK_VIII::FaultHandler ////////////////////////////////////////////////////
380 /////////////////////////////////////////////////////////////////////////////
392 static const unsigned int fault_inops[];
394 bool has_faults (unsigned int inop);
397 // keep in sync with IOHandler::present_status()
400 FAULT_ALL_MODES_INHIBIT,
403 FAULT_MOMENTARY_FLAP_OVERRIDE_INVALID,
404 FAULT_SELF_TEST_INVALID,
405 FAULT_GLIDESLOPE_CANCEL_INVALID,
406 FAULT_STEEP_APPROACH_INVALID,
408 FAULT_TA_TCF_INHIBIT,
409 FAULT_MODES14_INPUTS_INVALID,
410 FAULT_MODE5_INPUTS_INVALID,
411 FAULT_MODE6_INPUTS_INVALID,
412 FAULT_BANK_ANGLE_INPUTS_INVALID,
413 FAULT_TCF_INPUTS_INVALID,
417 bool faults[N_FAULTS];
419 inline FaultHandler (MK_VIII *device)
424 void set_fault (Fault fault);
425 void unset_fault (Fault fault);
427 bool has_faults () const;
430 /////////////////////////////////////////////////////////////////////////////
431 // MK_VIII::IOHandler ///////////////////////////////////////////////////////
432 /////////////////////////////////////////////////////////////////////////////
445 struct LampConfiguration
451 struct FaultsConfiguration
453 double max_flaps_down_airspeed;
454 double max_gear_down_airspeed;
459 const LampConfiguration *lamp;
460 const FaultsConfiguration *faults;
462 bool steep_approach_enabled;
463 bool gpws_inhibit_enabled;
464 bool momentary_flap_override_enabled;
465 bool alternate_steep_approach;
466 bool use_internal_gps;
467 bool localizer_enabled;
470 struct _s_input_feeders
476 bool glideslope_inhibit;
477 bool decision_height;
478 bool autopilot_engaged;
483 bool uncorrected_barometric_altitude;
484 bool barometric_altitude_rate;
486 bool glideslope_deviation;
488 bool localizer_deviation;
489 bool computed_airspeed;
490 bool decision_height;
498 bool landing_gear; // appendix E 6.6.2, 3.15.1.4
499 bool landing_flaps; // appendix E 6.6.4, 3.15.1.2
500 bool momentary_flap_override; // appendix E 6.6.6, 3.15.1.6
501 bool self_test; // appendix E 6.6.7, 3.15.1.10
502 bool glideslope_inhibit; // appendix E 6.6.11, 3.15.1.1
503 bool glideslope_cancel; // appendix E 6.6.13, 3.15.1.5
504 bool decision_height; // appendix E 6.6.14, 3.10.2
505 bool mode6_low_volume; // appendix E 6.6.15, 3.15.1.7
506 bool audio_inhibit; // appendix E 6.6.16, 3.15.1.3
507 bool ta_tcf_inhibit; // appendix E 6.6.20, 3.15.1.9
508 bool autopilot_engaged; // appendix E 6.6.21, 3.15.1.8
509 bool steep_approach; // appendix E 6.6.25, 3.15.1.11
510 bool gpws_inhibit; // appendix E 6.6.27, 3.15.1.12
515 Parameter<double> uncorrected_barometric_altitude; // appendix E 6.2.1
516 Parameter<double> barometric_altitude_rate; // appendix E 6.2.2
517 Parameter<double> gps_altitude; // appendix E 6.2.4
518 Parameter<double> gps_latitude; // appendix E 6.2.7
519 Parameter<double> gps_longitude; // appendix E 6.2.8
520 Parameter<double> gps_vertical_figure_of_merit; // appendix E 6.2.13
521 Parameter<double> radio_altitude; // appendix E 6.2.29
522 Parameter<double> glideslope_deviation; // appendix E 6.2.30
523 Parameter<double> roll_angle; // appendix E 6.2.31
524 Parameter<double> localizer_deviation; // appendix E 6.2.33
525 Parameter<double> computed_airspeed; // appendix E 6.2.39
526 Parameter<double> decision_height; // appendix E 6.2.41
534 bool gpws_warning; // appendix E 7.4.1, 3.15.2.5
535 bool gpws_alert; // appendix E 7.4.1, 3.15.2.6
536 bool audio_on; // appendix E 7.4.2, 3.15.2.10
537 bool gpws_inop; // appendix E 7.4.3, 3.15.2.3
538 bool tad_inop; // appendix E 7.4.3, 3.15.2.4
539 bool flap_override; // appendix E 7.4.5, 3.15.2.8
540 bool glideslope_cancel; // appendix E 7.4.6, 3.15.2.7
541 bool steep_approach; // appendix E 7.4.12, 3.15.2.9
546 int egpws_alert_discrete_1; // appendix E 7.1.1.1
547 int egpwc_logic_discretes; // appendix E 7.1.1.2
548 int mode6_callouts_discrete_1; // appendix E 7.1.1.3
549 int mode6_callouts_discrete_2; // appendix E 7.1.1.4
550 int egpws_alert_discrete_2; // appendix E 7.1.1.5
551 int egpwc_alert_discrete_3; // appendix E 7.1.1.6
559 Parameter<double> barometric_altitude_rate;
560 Parameter<double> decision_height;
561 Parameter<double> geometric_altitude;
562 Parameter<double> glideslope_deviation_dots;
563 Parameter<double> gps_altitude;
564 Parameter<double> gps_latitude;
565 Parameter<double> gps_longitude;
566 Parameter<double> gps_vertical_figure_of_merit;
567 Parameter<double> localizer_deviation_dots;
568 Parameter<double> radio_altitude;
569 Parameter<double> roll_angle;
570 Parameter<double> terrain_clearance;
573 IOHandler (MK_VIII *device);
579 void enter_ground ();
580 void enter_takeoff ();
582 void update_inputs ();
583 void update_input_faults ();
584 void update_alternate_discrete_input (bool *ptr);
585 void update_internal_latches ();
587 void update_egpws_alert_discrete_1 ();
588 void update_egpwc_logic_discretes ();
589 void update_mode6_callouts_discrete_1 ();
590 void update_mode6_callouts_discrete_2 ();
591 void update_egpws_alert_discrete_2 ();
592 void update_egpwc_alert_discrete_3 ();
593 void update_outputs ();
595 void update_lamps ();
596 void set_lamp (Lamp lamp);
598 bool gpws_inhibit () const;
599 bool real_flaps_down () const;
600 bool flaps_down () const;
601 bool flap_override () const;
602 bool steep_approach () const;
603 bool momentary_steep_approach_enabled () const;
605 void bind (SGPropertyNode *node);
609 ///////////////////////////////////////////////////////////////////////////
610 // MK_VIII::IOHandler::TerrainClearanceFilter /////////////////////////////
611 ///////////////////////////////////////////////////////////////////////////
613 class TerrainClearanceFilter
615 deque< Sample<double> > samples;
619 inline TerrainClearanceFilter ()
622 double update (double agl);
626 ///////////////////////////////////////////////////////////////////////////
627 // MK_VIII::IOHandler (continued) /////////////////////////////////////////
628 ///////////////////////////////////////////////////////////////////////////
632 TerrainClearanceFilter terrain_clearance_filter;
637 Timer audio_inhibit_fault_timer;
638 Timer landing_gear_fault_timer;
639 Timer flaps_down_fault_timer;
640 Timer momentary_flap_override_fault_timer;
641 Timer self_test_fault_timer;
642 Timer glideslope_cancel_fault_timer;
643 Timer steep_approach_fault_timer;
644 Timer gpws_inhibit_fault_timer;
645 Timer ta_tcf_inhibit_fault_timer;
647 bool last_landing_gear;
648 bool last_real_flaps_down;
650 deque< Sample< Parameter<double> > > altitude_samples;
654 bool glideslope_cancel;
657 void update_terrain_clearance ();
658 void reset_terrain_clearance ();
660 void handle_input_fault (bool test, FaultHandler::Fault fault);
661 void handle_input_fault (bool test,
664 FaultHandler::Fault fault);
666 void tie_input (SGPropertyNode *node,
670 void tie_input (SGPropertyNode *node,
672 Parameter<double> *input,
674 void tie_output (SGPropertyNode *node,
677 void tie_output (SGPropertyNode *node,
681 bool get_discrete_input (bool *ptr) const;
682 void set_discrete_input (bool *ptr, bool value);
684 void present_status ();
685 void present_status_section (const char *name);
686 void present_status_item (const char *name, const char *value = NULL);
687 void present_status_subitem (const char *name);
689 bool get_present_status () const;
690 void set_present_status (bool value);
692 bool *get_lamp_output (Lamp lamp);
695 /////////////////////////////////////////////////////////////////////////////
696 // MK_VIII::VoicePlayer /////////////////////////////////////////////////////
697 /////////////////////////////////////////////////////////////////////////////
703 ///////////////////////////////////////////////////////////////////////////
704 // MK_VIII::VoicePlayer::Voice ////////////////////////////////////////////
705 ///////////////////////////////////////////////////////////////////////////
711 /////////////////////////////////////////////////////////////////////////
712 // MK_VIII::VoicePlayer::Voice::Element ////////////////////////////////////////
713 /////////////////////////////////////////////////////////////////////////
720 virtual inline void play (double volume) {}
721 virtual inline void stop () {}
722 virtual bool is_playing () = 0;
723 virtual inline void set_volume (double volume) {}
726 /////////////////////////////////////////////////////////////////////////
727 // MK_VIII::VoicePlayer::Voice::SampleElement ///////////////////////////
728 /////////////////////////////////////////////////////////////////////////
730 class SampleElement : public Element
732 SGSoundSample *_sample;
736 inline SampleElement (SGSoundSample *sample, double volume = 1.0)
737 : _sample(sample), _volume(volume) { silence = false; }
739 virtual inline void play (double volume) { set_volume(volume); _sample->play_once(); }
740 virtual inline void stop () { _sample->stop(); }
741 virtual inline bool is_playing () { return _sample->is_playing(); }
742 virtual inline void set_volume (double volume) { _sample->set_volume(volume * _volume); }
745 /////////////////////////////////////////////////////////////////////////
746 // MK_VIII::VoicePlayer::Voice::SilenceElement //////////////////////////
747 /////////////////////////////////////////////////////////////////////////
749 class SilenceElement : public Element
755 inline SilenceElement (double duration)
756 : _duration(duration) { silence = true; }
758 virtual inline void play (double volume) { start_time = globals->get_sim_time_sec(); }
759 virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
762 /////////////////////////////////////////////////////////////////////////
763 // MK_VIII::VoicePlayer::Voice (continued) //////////////////////////////
764 /////////////////////////////////////////////////////////////////////////
768 inline Voice (VoicePlayer *_player)
769 : player(_player), volume(1.0), element(NULL) {}
773 inline void append (Element *_element) { elements.push_back(_element); }
776 void stop (bool now);
777 void set_volume (double _volume);
778 void volume_changed ();
786 vector<Element *> elements;
787 vector<Element *>::iterator iter;
789 inline double get_volume () const { return player->volume * player->speaker.volume * volume; }
792 ///////////////////////////////////////////////////////////////////////////
793 // MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
794 ///////////////////////////////////////////////////////////////////////////
808 Voice *application_data_base_failed;
810 Voice *bank_angle_bank_angle;
811 Voice *bank_angle_bank_angle_3;
812 Voice *bank_angle_inop;
813 Voice *bank_angle_pause_bank_angle;
814 Voice *bank_angle_pause_bank_angle_3;
815 Voice *callouts_inop;
816 Voice *configuration_type_invalid;
818 Voice *dont_sink_pause_dont_sink;
819 Voice *five_hundred_above;
821 Voice *glideslope_inop;
823 Voice *hard_glideslope;
825 Voice *minimums_minimums;
828 Voice *sink_rate_pause_sink_rate;
829 Voice *soft_glideslope;
831 Voice *terrain_pause_terrain;
832 Voice *too_low_flaps;
834 Voice *too_low_terrain;
835 Voice *altitude_callouts[n_altitude_callouts];
838 inline VoicePlayer (MK_VIII *device)
839 : mk(device), speaker(this), voice(NULL), next_voice(NULL) {}
850 void play (Voice *_voice, unsigned int flags = 0);
856 void stop (unsigned int flags = 0);
858 void set_volume (double _volume);
861 inline void bind (SGPropertyNode *node) { speaker.bind(node); }
865 ///////////////////////////////////////////////////////////////////////////
866 // MK_VIII::VoicePlayer::Speaker //////////////////////////////////////////
867 ///////////////////////////////////////////////////////////////////////////
875 float orientation[3];
879 float reference_dist;
883 inline void tie (SGPropertyNode *node, const char *name, T *ptr)
885 player->mk->properties_handler.tie
886 (node, (string("speaker/") + name).c_str(),
887 RawValueMethodsData<MK_VIII::VoicePlayer::Speaker,T,T*>
889 &MK_VIII::VoicePlayer::Speaker::get_property,
890 &MK_VIII::VoicePlayer::Speaker::set_property));
894 inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
897 inline T get_property (T *ptr) const { return *ptr; }
902 inline Speaker (VoicePlayer *_player)
912 position[0] = 0; position[1] = 0; position[2] = 0;
913 orientation[0] = 0; orientation[1] = 0; orientation[2] = 0;
916 void bind (SGPropertyNode *node);
917 void update_configuration ();
920 ///////////////////////////////////////////////////////////////////////////
921 // MK_VIII::VoicePlayer (continued) ///////////////////////////////////////
922 ///////////////////////////////////////////////////////////////////////////
928 map<string, SGSoundSample *> samples;
929 vector<Voice *> _voices;
934 SGSoundSample *get_sample (const char *name);
936 inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
937 inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
938 inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
940 inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
943 inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
944 template <class T1, class T2>
945 inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
946 template <class T1, class T2, class T3>
947 inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
948 template <class T1, class T2, class T3, class T4>
949 inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
952 /////////////////////////////////////////////////////////////////////////////
953 // MK_VIII::SelfTestHandler /////////////////////////////////////////////////
954 /////////////////////////////////////////////////////////////////////////////
956 class SelfTestHandler
969 ACTION_SLEEP = 1 << 0,
970 ACTION_VOICE = 1 << 1,
971 ACTION_DISCRETE_ON_OFF = 1 << 2,
978 double sleep_duration;
986 double button_press_timestamp;
987 IOHandler::Outputs saved_outputs;
990 bool _was_here (int position);
992 Action sleep (double duration);
993 Action play (VoicePlayer::Voice *voice);
994 Action discrete_on (bool *discrete, double duration);
995 Action discrete_on_off (bool *discrete, double duration);
996 Action discrete_on_off (bool *discrete, VoicePlayer::Voice *voice);
1015 inline SelfTestHandler (MK_VIII *device)
1016 : mk(device), state(STATE_NONE), button_pressed(false) {}
1018 inline void power_off () { stop(); }
1019 inline void set_inop () { stop(); }
1020 void handle_button_event (bool value);
1024 /////////////////////////////////////////////////////////////////////////////
1025 // MK_VIII::AlertHandler ////////////////////////////////////////////////////
1026 /////////////////////////////////////////////////////////////////////////////
1032 unsigned int old_alerts;
1033 unsigned int voice_alerts;
1034 unsigned int repeated_alerts;
1035 VoicePlayer::Voice *altitude_callout_voice;
1038 inline bool has_alerts (unsigned int test) const { return (alerts & test) != 0; }
1039 inline bool has_old_alerts (unsigned int test) const { return (old_alerts & test) != 0; }
1040 inline bool must_play_voice (unsigned int test) const { return ! has_old_alerts(test) || (repeated_alerts & test) != 0; }
1041 bool select_voice_alerts (unsigned int test);
1046 ALERT_MODE1_PULL_UP = 1 << 0,
1047 ALERT_MODE1_SINK_RATE = 1 << 1,
1049 ALERT_MODE2A_PREFACE = 1 << 2,
1050 ALERT_MODE2B_PREFACE = 1 << 3,
1051 ALERT_MODE2A = 1 << 4,
1052 ALERT_MODE2B = 1 << 5,
1053 ALERT_MODE2B_LANDING_MODE = 1 << 6,
1054 ALERT_MODE2A_ALTITUDE_GAIN = 1 << 7,
1055 ALERT_MODE2A_ALTITUDE_GAIN_TERRAIN_CLOSING = 1 << 8,
1057 ALERT_MODE3 = 1 << 9,
1059 ALERT_MODE4_TOO_LOW_FLAPS = 1 << 10,
1060 ALERT_MODE4_TOO_LOW_GEAR = 1 << 11,
1061 ALERT_MODE4AB_TOO_LOW_TERRAIN = 1 << 12,
1062 ALERT_MODE4C_TOO_LOW_TERRAIN = 1 << 13,
1064 ALERT_MODE5_SOFT = 1 << 14,
1065 ALERT_MODE5_HARD = 1 << 15,
1067 ALERT_MODE6_MINIMUMS = 1 << 16,
1068 ALERT_MODE6_ALTITUDE_CALLOUT = 1 << 17,
1069 ALERT_MODE6_LOW_BANK_ANGLE_1 = 1 << 18,
1070 ALERT_MODE6_HIGH_BANK_ANGLE_1 = 1 << 19,
1071 ALERT_MODE6_LOW_BANK_ANGLE_2 = 1 << 20,
1072 ALERT_MODE6_HIGH_BANK_ANGLE_2 = 1 << 21,
1073 ALERT_MODE6_LOW_BANK_ANGLE_3 = 1 << 22,
1074 ALERT_MODE6_HIGH_BANK_ANGLE_3 = 1 << 23,
1076 ALERT_TCF_TOO_LOW_TERRAIN = 1 << 24
1081 ALERT_FLAG_REPEAT = 1 << 0
1084 unsigned int alerts;
1086 inline AlertHandler (MK_VIII *device)
1093 void set_alerts (unsigned int _alerts,
1094 unsigned int flags = 0,
1095 VoicePlayer::Voice *_altitude_callout_voice = NULL);
1096 void unset_alerts (unsigned int _alerts);
1098 inline void repeat_alert (unsigned int alert) { set_alerts(alert, ALERT_FLAG_REPEAT); }
1099 inline void set_altitude_callout_alert (VoicePlayer::Voice *voice) { set_alerts(ALERT_MODE6_ALTITUDE_CALLOUT, 0, voice); }
1102 /////////////////////////////////////////////////////////////////////////////
1103 // MK_VIII::StateHandler ////////////////////////////////////////////////////
1104 /////////////////////////////////////////////////////////////////////////////
1110 Timer potentially_airborne_timer;
1112 void update_ground ();
1113 void enter_ground ();
1114 void leave_ground ();
1116 void update_takeoff ();
1117 void enter_takeoff ();
1118 void leave_takeoff ();
1124 inline StateHandler (MK_VIII *device)
1125 : mk(device), ground(true), takeoff(true) {}
1127 void post_reposition ();
1131 /////////////////////////////////////////////////////////////////////////////
1132 // MK_VIII::Mode1Handler ////////////////////////////////////////////////////
1133 /////////////////////////////////////////////////////////////////////////////
1139 Timer pull_up_timer;
1140 Timer sink_rate_timer;
1142 double sink_rate_tti; // time-to-impact in minutes
1144 double get_pull_up_bias ();
1147 double get_sink_rate_bias ();
1148 bool is_sink_rate ();
1149 double get_sink_rate_tti ();
1151 void update_pull_up ();
1152 void update_sink_rate ();
1157 bool flap_override_bias;
1159 double (*pull_up_min_agl1) (double vs);
1160 int pull_up_max_agl1;
1161 double (*pull_up_min_agl2) (double vs);
1162 int pull_up_max_agl2;
1163 } EnvelopesConfiguration;
1167 const EnvelopesConfiguration *envelopes;
1170 inline Mode1Handler (MK_VIII *device)
1176 /////////////////////////////////////////////////////////////////////////////
1177 // MK_VIII::Mode2Handler ////////////////////////////////////////////////////
1178 /////////////////////////////////////////////////////////////////////////////
1183 ///////////////////////////////////////////////////////////////////////////
1184 // MK_VIII::Mode2Handler::ClosureRateFilter ///////////////////////////////
1185 ///////////////////////////////////////////////////////////////////////////
1187 class ClosureRateFilter
1189 /////////////////////////////////////////////////////////////////////////
1190 // MK_VIII::Mode2Handler::ClosureRateFilter::PassFilter /////////////////
1191 /////////////////////////////////////////////////////////////////////////
1203 inline PassFilter (double _a0, double _a1, double _b1)
1204 : a0(_a0), a1(_a1), b1(_b1) {}
1206 inline double filter (double input)
1208 last_output = a0 * input + a1 * last_input + b1 * last_output;
1214 inline void reset ()
1221 /////////////////////////////////////////////////////////////////////////
1222 // MK_VIII::Mode2Handler::ClosureRateFilter (continued) /////////////////
1223 /////////////////////////////////////////////////////////////////////////
1228 Parameter<double> last_ra; // last radio altitude
1229 Parameter<double> last_ba; // last barometric altitude
1230 PassFilter ra_filter; // radio altitude rate filter
1231 PassFilter ba_filter; // barometric altitude rate filter
1233 double limit_radio_altitude_rate (double r);
1236 Parameter<double> output;
1238 inline ClosureRateFilter (MK_VIII *device)
1240 ra_filter(0.05, 0, 0.95), // low-pass filter
1241 ba_filter(0.93, -0.93, 0.86) {} // high-pass-filter
1247 ///////////////////////////////////////////////////////////////////////////
1248 // MK_VIII::Mode2Handler (continued) //////////////////////////////////////
1249 ///////////////////////////////////////////////////////////////////////////
1253 ClosureRateFilter closure_rate_filter;
1255 Timer takeoff_timer;
1256 Timer pull_up_timer;
1258 double a_start_time;
1259 Timer a_altitude_gain_timer;
1260 double a_altitude_gain_alt;
1262 void check_pull_up (unsigned int preface_alert, unsigned int alert);
1264 bool b_conditions ();
1279 const Configuration *conf;
1281 inline Mode2Handler (MK_VIII *device)
1282 : mk(device), closure_rate_filter(device) {}
1286 void leave_ground ();
1287 void enter_takeoff ();
1291 /////////////////////////////////////////////////////////////////////////////
1292 // MK_VIII::Mode3Handler ////////////////////////////////////////////////////
1293 /////////////////////////////////////////////////////////////////////////////
1300 bool has_descent_alt;
1304 double max_alt_loss (double _bias);
1305 double get_bias (double initial_bias, double alt_loss);
1306 bool is (double *alt_loss);
1312 int (*max_agl) (bool flap_override);
1313 double (*max_alt_loss) (bool flap_override, double agl);
1316 const Configuration *conf;
1318 inline Mode3Handler (MK_VIII *device)
1319 : mk(device), armed(false), has_descent_alt(false) {}
1321 void enter_takeoff ();
1325 /////////////////////////////////////////////////////////////////////////////
1326 // MK_VIII::Mode4Handler ////////////////////////////////////////////////////
1327 /////////////////////////////////////////////////////////////////////////////
1337 double (*min_agl2) (double airspeed);
1339 } EnvelopesConfiguration;
1343 const EnvelopesConfiguration *ac;
1344 const EnvelopesConfiguration *b;
1345 } ModesConfiguration;
1349 VoicePlayer::Voice *voice_too_low_gear;
1350 const ModesConfiguration *modes;
1353 inline Mode4Handler (MK_VIII *device)
1356 double get_upper_agl (const EnvelopesConfiguration *c);
1363 double ab_expanded_bias;
1366 const EnvelopesConfiguration *get_ab_envelope ();
1367 double get_bias (double initial_bias, double min_agl);
1368 void handle_alert (unsigned int alert, double min_agl, double *bias);
1371 void update_ab_expanded ();
1375 /////////////////////////////////////////////////////////////////////////////
1376 // MK_VIII::Mode5Handler ////////////////////////////////////////////////////
1377 /////////////////////////////////////////////////////////////////////////////
1389 bool is_soft (double bias);
1391 double get_soft_bias (double initial_bias);
1393 void update_hard (bool is);
1394 void update_soft (bool is);
1397 inline Mode5Handler (MK_VIII *device)
1403 /////////////////////////////////////////////////////////////////////////////
1404 // MK_VIII::Mode6Handler ////////////////////////////////////////////////////
1405 /////////////////////////////////////////////////////////////////////////////
1410 // keep in sync with altitude_callout_definitions[]
1413 ALTITUDE_CALLOUT_1000,
1414 ALTITUDE_CALLOUT_500,
1415 ALTITUDE_CALLOUT_400,
1416 ALTITUDE_CALLOUT_300,
1417 ALTITUDE_CALLOUT_200,
1418 ALTITUDE_CALLOUT_100,
1419 ALTITUDE_CALLOUT_50,
1420 ALTITUDE_CALLOUT_40,
1421 ALTITUDE_CALLOUT_30,
1422 ALTITUDE_CALLOUT_20,
1426 typedef bool (*BankAnglePredicate) (Parameter<double> *agl,
1427 double abs_roll_deg,
1432 bool minimums_enabled;
1433 bool smart_500_enabled;
1434 VoicePlayer::Voice *above_field_voice;
1436 bool altitude_callouts_enabled[n_altitude_callouts];
1437 bool bank_angle_enabled;
1438 BankAnglePredicate is_bank_angle;
1441 static const int altitude_callout_definitions[];
1443 inline Mode6Handler (MK_VIII *device)
1448 void enter_takeoff ();
1449 void leave_takeoff ();
1450 void set_volume (double volume);
1451 bool altitude_callouts_enabled ();
1457 bool last_decision_height;
1458 Parameter<double> last_radio_altitude;
1459 Parameter<double> last_altitude_above_field;
1461 bool altitude_callouts_issued[n_altitude_callouts];
1462 bool minimums_issued;
1463 bool above_field_issued;
1466 Parameter<bool> has_runway;
1470 double elevation; // elevation in feet
1473 void reset_minimums ();
1474 void reset_altitude_callouts ();
1475 bool is_playing_altitude_callout ();
1476 bool is_near_minimums (double callout);
1477 bool is_outside_band (double elevation, double callout);
1478 bool inhibit_smart_500 ();
1480 void update_minimums ();
1481 void update_altitude_callouts ();
1483 bool test_runway (const FGRunway *_runway);
1484 bool test_airport (const FGAirport *airport);
1485 void update_runway ();
1487 void get_altitude_above_field (Parameter<double> *parameter);
1488 void update_above_field_callout ();
1490 bool is_bank_angle (double abs_roll_angle, double bias);
1491 bool is_high_bank_angle ();
1492 unsigned int get_bank_angle_alerts ();
1493 void update_bank_angle ();
1496 /////////////////////////////////////////////////////////////////////////////
1497 // MK_VIII::TCFHandler //////////////////////////////////////////////////////
1498 /////////////////////////////////////////////////////////////////////////////
1504 double latitude; // latitude in degrees
1505 double longitude; // longitude in degrees
1510 Position position; // position of threshold
1511 double heading; // runway heading
1516 static const double k;
1523 Position center; // center point
1524 double elevation; // elevation in feet
1525 double half_length; // runway half length, in nautical miles
1526 RunwayEdge edges[2]; // runway threshold and end
1527 Position bias_area[4]; // vertices of the bias area
1532 double initial_value;
1534 double get_azimuth_difference (double from_lat,
1539 double get_azimuth_difference (const FGRunway *_runway);
1541 void select_runway (const FGAirport *airport, FGRunway *_runway);
1542 bool test_airport (const FGAirport *airport);
1543 void update_runway ();
1545 void get_bias_area_edges (Position *edge,
1547 double half_width_m,
1548 Position *bias_edge1,
1549 Position *bias_edge2);
1551 bool is_inside_edge_triangle (RunwayEdge *edge);
1552 bool is_inside_bias_area ();
1563 inline TCFHandler (MK_VIII *device)
1569 /////////////////////////////////////////////////////////////////////////////
1570 // MK_VIII (continued) //////////////////////////////////////////////////////
1571 /////////////////////////////////////////////////////////////////////////////
1576 PropertiesHandler properties_handler;
1577 PowerHandler power_handler;
1578 SystemHandler system_handler;
1579 ConfigurationModule configuration_module;
1580 FaultHandler fault_handler;
1581 IOHandler io_handler;
1582 VoicePlayer voice_player;
1583 SelfTestHandler self_test_handler;
1584 AlertHandler alert_handler;
1585 StateHandler state_handler;
1586 Mode1Handler mode1_handler;
1587 Mode2Handler mode2_handler;
1588 Mode3Handler mode3_handler;
1589 Mode4Handler mode4_handler;
1590 Mode5Handler mode5_handler;
1591 Mode6Handler mode6_handler;
1592 TCFHandler tcf_handler;
1596 int runway_database;
1600 MK_VIII (SGPropertyNode *node);
1602 virtual void init ();
1603 virtual void bind ();
1604 virtual void unbind ();
1605 virtual void update (double dt);
1608 #endif // __INSTRUMENTS_MK_VIII_HXX