1
0
Fork 0

GPWS: add optional support for Airbus-style callouts

The "Airbus" callouts ("2500", "hundred above", "retard") are not issued
by the original mk-viii unit, but adding support helps with better
simulation for Airbus a/c. The new callouts are disabled by default, and
are enabled by a specific setting of the GPWS "category-4" configuration
value (see Wiki).
This commit is contained in:
ThorstenB 2018-01-28 16:02:26 +01:00
parent 37085f29ac
commit 087995448f
2 changed files with 119 additions and 32 deletions

View file

@ -170,6 +170,7 @@ MK_VIII::PropertiesHandler::init ()
mk_node(autopilot_heading_lock) = fgGetNode("/autopilot/locks/heading", true);
mk_node(flaps) = fgGetNode("/controls/flight/flaps", true);
mk_node(gear_down) = fgGetNode("/controls/gear/gear-down", true);
mk_node(throttle) = fgGetNode("/controls/engines/engine/throttle", true);
mk_node(latitude) = fgGetNode("/position/latitude-deg", true);
mk_node(longitude) = fgGetNode("/position/longitude-deg", true);
mk_node(nav0_cdi_serviceable) = fgGetNode("/instrumentation/nav/cdi/serviceable", true);
@ -567,16 +568,18 @@ MK_VIII::ConfigurationModule::read_altitude_callouts (int value)
{
enum
{
MINIMUMS = -1,
SMART_500 = -2,
FIELD_500 = -3,
FIELD_500_ABOVE = -4
MINIMUMS = -1,
SMART_500 = -2,
FIELD_500 = -3,
FIELD_500_ABOVE = -4,
MINIMUMS_ABOVE_100 = -5,
RETARD = -6
};
static const struct
{
int id;
int callouts[13];
int callouts[16];
} values[] = {
{ 0, { MINIMUMS, SMART_500, 200, 100, 50, 40, 30, 20, 10, 0 } },
{ 1, { MINIMUMS, SMART_500, 200, 0 } },
@ -595,22 +598,35 @@ MK_VIII::ConfigurationModule::read_altitude_callouts (int value)
{ 14, { MINIMUMS, 100, 0 } },
{ 15, { MINIMUMS, 200, 100, 0 } },
{ 100, { FIELD_500, 0 } },
{ 101, { FIELD_500_ABOVE, 0 } }
{ 101, { FIELD_500_ABOVE, 0 } },
{1000, { RETARD, MINIMUMS_ABOVE_100, MINIMUMS, 2500, 1000, 500, 400, 300, 200, 100, 50, 40, 30,20, 10, 0 } },
{1001, { RETARD, MINIMUMS, 2500, 1000, 500, 400, 300, 200, 100, 50, 40, 30,20, 10, 0 } },
{1002, { MINIMUMS, 2500, 1000, 500, 400, 300, 200, 100, 50, 40, 30,20, 10, 0 } },
{1010, { RETARD, MINIMUMS_ABOVE_100, MINIMUMS, 1000, 500, 400, 300, 200, 100, 50, 40, 30,20, 10, 0 } },
{1011, { RETARD, MINIMUMS, 1000, 500, 400, 300, 200, 100, 50, 40, 30,20, 10, 0 } },
};
unsigned i;
mk->mode6_handler.conf.retard_enabled = false;
mk->mode6_handler.conf.minimums_above_100_enabled = false;
mk->mode6_handler.conf.minimums_enabled = false;
mk->mode6_handler.conf.smart_500_enabled = false;
mk->mode6_handler.conf.above_field_voice = NULL;
mk->mode6_handler.conf.altitude_callouts_enabled = 0;
for (i = 0; i < n_elements(values); i++)
for (unsigned int i = 0; i < n_elements(values); i++)
if (values[i].id == value)
{
for (int j = 0; values[i].callouts[j] != 0; j++)
switch (values[i].callouts[j])
{
case RETARD:
mk->mode6_handler.conf.retard_enabled = true;
break;
case MINIMUMS_ABOVE_100:
mk->mode6_handler.conf.minimums_above_100_enabled = true;
break;
case MINIMUMS:
mk->mode6_handler.conf.minimums_enabled = true;
break;
@ -1319,6 +1335,10 @@ MK_VIII::IOHandler::update_inputs ()
if (mk_dinput_feed(decision_height))
{
mk_dinput(decision_height_100) = ! mk_data(radio_altitude).ncd
&& ! mk_data(decision_height).ncd
&& mk_data(radio_altitude).get() <= mk_data(decision_height).get()+100;
mk_dinput(decision_height) = ! mk_data(radio_altitude).ncd
&& ! mk_data(decision_height).ncd
&& mk_data(radio_altitude).get() <= mk_data(decision_height).get();
@ -1646,6 +1666,7 @@ MK_VIII::IOHandler::update_mode6_callouts_discrete_2 ()
{ 11, mk_altitude_voice(Mode6Handler::ALTITUDE_CALLOUT_400) },
{ 12, mk_altitude_voice(Mode6Handler::ALTITUDE_CALLOUT_500) },
{ 13, mk_altitude_voice(Mode6Handler::ALTITUDE_CALLOUT_1000) },
{ 14, mk_altitude_voice(Mode6Handler::ALTITUDE_CALLOUT_2500) },
{ 18, mk_voice(bank_angle_pause_bank_angle) },
{ 18, mk_voice(bank_angle_pause_bank_angle_3) },
{ 23, mk_voice(five_hundred_above) }
@ -2135,7 +2156,9 @@ MK_VIII::VoicePlayer::init ()
make_voice(&voices.glideslope_inop, "glideslope-inop");
make_voice(&voices.gpws_inop, "gpws-inop");
make_voice(&voices.hard_glideslope, "glideslope", "glideslope", 3.0);
make_voice(&voices.retard, "retard");
make_voice(&voices.minimums, "minimums");
make_voice(&voices.minimums_100, "100-above");
make_voice(&voices.minimums_minimums, "minimums", "minimums");
make_voice(&voices.pull_up, "pull-up");
make_voice(&voices.sink_rate, "sink-rate");
@ -2355,6 +2378,11 @@ MK_VIII::SelfTestHandler::run ()
if (! mk->mode6_handler.altitude_callouts_enabled())
goto callouts_disabled;
}
if (! was_here())
{
if (mk->mode6_handler.conf.minimums_above_100_enabled)
return play(mk_voice(minimums_100));
}
if (! was_here())
{
if (mk->mode6_handler.conf.minimums_enabled)
@ -2367,10 +2395,10 @@ MK_VIII::SelfTestHandler::run ()
}
for (unsigned i = 0; i < n_altitude_callouts; i++)
if (! was_here_offset(i))
{
{
if (mk->mode6_handler.conf.altitude_callouts_enabled & (1<<i))
return play(mk_altitude_voice(i));
}
}
if (! was_here())
{
@ -2641,6 +2669,16 @@ MK_VIII::AlertHandler::update ()
if (! has_old_alerts(ALERT_MODE6_MINIMUMS))
mk->voice_player.play(mk_voice(minimums_minimums));
}
else if (select_voice_alerts(ALERT_MODE6_MINIMUMS_100))
{
if (! has_old_alerts(ALERT_MODE6_MINIMUMS_100))
mk->voice_player.play(mk_voice(minimums_100));
}
else if (select_voice_alerts(ALERT_MODE6_RETARD))
{
if (must_play_voice(ALERT_MODE6_RETARD))
mk->voice_player.play(mk_voice(retard), VoicePlayer::PLAY_LOOPED);
}
else if (select_voice_alerts(ALERT_MODE4AB_TOO_LOW_TERRAIN | ALERT_MODE4C_TOO_LOW_TERRAIN))
{
if (must_play_voice(ALERT_MODE4AB_TOO_LOW_TERRAIN | ALERT_MODE4C_TOO_LOW_TERRAIN))
@ -3807,12 +3845,13 @@ MK_VIII::Mode5Handler::update ()
// keep sorted in descending order
const int MK_VIII::Mode6Handler::altitude_callout_definitions[] =
{ 1000, 500, 400, 300, 200, 100, 50, 40, 30, 20, 10 };
{ 2500, 1000, 500, 400, 300, 200, 100, 50, 40, 30, 20, 10 };
void
MK_VIII::Mode6Handler::reset_minimums ()
{
minimums_issued = false;
minimums_above_100_issued = false;
}
void
@ -3820,6 +3859,7 @@ MK_VIII::Mode6Handler::reset_altitude_callouts ()
{
for (unsigned i = 0; i < n_altitude_callouts; i++)
altitude_callouts_issued[i] = false;
throttle_retarded = false;
}
bool
@ -3967,28 +4007,47 @@ MK_VIII::Mode6Handler::update_minimums ()
&& conf.minimums_enabled
&& ! minimums_issued
&& mk_dinput(landing_gear)
&& mk_dinput(decision_height)
&& ! last_decision_height)
{
minimums_issued = true;
{
if (mk_dinput(decision_height))
{
minimums_issued = true;
// If an altitude callout is playing, stop it now so that the
// minimums callout can be played (note that proper connection
// and synchronization of the radio-altitude ARINC 529 input,
// decision-height discrete and decision-height ARINC 529 input
// will prevent an altitude callout from being played near the
// decision height).
// If an altitude callout is playing, stop it now so that the
// minimums callout can be played (note that proper connection
// and synchronization of the radio-altitude ARINC 529 input,
// decision-height discrete and decision-height ARINC 529 input
// will prevent an altitude callout from being played near the
// decision height).
if (is_playing_altitude_callout())
mk->voice_player.stop(VoicePlayer::STOP_NOW);
if (is_playing_altitude_callout())
mk->voice_player.stop(VoicePlayer::STOP_NOW);
mk_set_alerts(mk_alert(MODE6_MINIMUMS));
}
mk_unset_alerts(mk_alert(MODE6_MINIMUMS_100));
mk_set_alerts(mk_alert(MODE6_MINIMUMS));
}
else
if (conf.minimums_above_100_enabled && (!minimums_above_100_issued) &&
mk_dinput(decision_height_100))
{
minimums_above_100_issued = true;
if (is_playing_altitude_callout())
mk->voice_player.stop(VoicePlayer::STOP_NOW);
mk_unset_alerts(mk_alert(MODE6_MINIMUMS));
mk_set_alerts(mk_alert(MODE6_MINIMUMS_100));
}
}
else
{
mk_unset_alerts(mk_alert(MODE6_MINIMUMS));
mk_unset_alerts(mk_alert(MODE6_MINIMUMS_100));
}
end:
last_decision_height = mk_dinput(decision_height);
last_decision_height_100 = mk_dinput(decision_height_100);
}
void
@ -3997,8 +4056,23 @@ MK_VIII::Mode6Handler::update_altitude_callouts ()
if (! mk->io_handler.gpws_inhibit() && is_playing_altitude_callout())
goto end;
if (! mk->io_handler.gpws_inhibit()
&& ! mk->state_handler.ground // [1]
if (! mk->io_handler.gpws_inhibit())
{
if (mk->mode6_handler.conf.retard_enabled &&
(!throttle_retarded)&&
(mk_data(radio_altitude).get() < 25))
{
if (mk_node(throttle)->getDoubleValue() > 0.05)
{
mk_repeat_alert(mk_alert(MODE6_RETARD));
goto end;
}
// throttle was closed
throttle_retarded = true;
}
mk_unset_alerts(mk_alert(MODE6_RETARD));
if (! mk->state_handler.ground // [1]
&& ! mk_data(radio_altitude).ncd)
for (unsigned i = 0; i < n_altitude_callouts && mk_data(radio_altitude).get() <= altitude_callout_definitions[i]; i++)
if (((conf.altitude_callouts_enabled & (1<<i))
@ -4023,6 +4097,7 @@ MK_VIII::Mode6Handler::update_altitude_callouts ()
goto end;
}
}
}
mk_unset_alerts(mk_alert(MODE6_ALTITUDE_CALLOUT));

View file

@ -55,7 +55,7 @@ class SGSampleGroup;
class MK_VIII : public SGSubsystem
{
// keep in sync with Mode6Handler::altitude_callout_definitions[]
static const unsigned n_altitude_callouts = 11;
static const unsigned n_altitude_callouts = 12;
/////////////////////////////////////////////////////////////////////////////
// MK_VIII::Parameter ///////////////////////////////////////////////////////
@ -164,6 +164,7 @@ class MK_VIII : public SGSubsystem
SGPropertyNode_ptr autopilot_heading_lock;
SGPropertyNode_ptr flaps;
SGPropertyNode_ptr gear_down;
SGPropertyNode_ptr throttle;
SGPropertyNode_ptr latitude;
SGPropertyNode_ptr longitude;
SGPropertyNode_ptr nav0_cdi_serviceable;
@ -460,6 +461,7 @@ public:
bool self_test; // appendix E 6.6.7, 3.15.1.10
bool glideslope_inhibit; // appendix E 6.6.11, 3.15.1.1
bool glideslope_cancel; // appendix E 6.6.13, 3.15.1.5
bool decision_height_100;
bool decision_height; // appendix E 6.6.14, 3.10.2
bool mode6_low_volume; // appendix E 6.6.15, 3.15.1.7
bool audio_inhibit; // appendix E 6.6.16, 3.15.1.3
@ -686,7 +688,9 @@ public:
Voice *gpws_inop;
Voice *hard_glideslope;
Voice *minimums;
Voice *minimums_100;
Voice *minimums_minimums;
Voice *retard;
Voice *pull_up;
Voice *sink_rate;
Voice *sink_rate_pause_sink_rate;
@ -818,6 +822,7 @@ private:
ALERT_MODE5_HARD = 1 << 15,
ALERT_MODE6_MINIMUMS = 1 << 16,
ALERT_MODE6_ALTITUDE_CALLOUT = 1 << 17,
ALERT_MODE6_LOW_BANK_ANGLE_1 = 1 << 18,
ALERT_MODE6_HIGH_BANK_ANGLE_1 = 1 << 19,
@ -826,7 +831,10 @@ private:
ALERT_MODE6_LOW_BANK_ANGLE_3 = 1 << 22,
ALERT_MODE6_HIGH_BANK_ANGLE_3 = 1 << 23,
ALERT_TCF_TOO_LOW_TERRAIN = 1 << 24
ALERT_TCF_TOO_LOW_TERRAIN = 1 << 24,
ALERT_MODE6_MINIMUMS_100 = 1 << 28,
ALERT_MODE6_RETARD = 1 << 29,
};
enum
@ -1163,6 +1171,7 @@ private:
// keep in sync with altitude_callout_definitions[]
typedef enum
{
ALTITUDE_CALLOUT_2500,
ALTITUDE_CALLOUT_1000,
ALTITUDE_CALLOUT_500,
ALTITUDE_CALLOUT_400,
@ -1209,13 +1218,16 @@ private:
private:
MK_VIII *mk;
bool last_decision_height;
Parameter<double> last_radio_altitude;
Parameter<double> last_altitude_above_field;
bool last_decision_height;
bool last_decision_height_100;
Parameter<double> last_radio_altitude;
Parameter<double> last_altitude_above_field;
bool altitude_callouts_issued[n_altitude_callouts];
bool minimums_issued;
bool minimums_above_100_issued;
bool above_field_issued;
bool throttle_retarded;
Timer runway_timer;
Parameter<bool> has_runway;