X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInstrumentation%2Fmk_viii.cxx;h=9b0ee2b480428d5d32f0c16010907d18e914071d;hb=d15d2ad2703e0572e3b9a24d238d6089be1ec6b9;hp=118d740b70e64584758f257e336d4d9fa9e6bfe4;hpb=e48967cb1de18922fb148f05fe56966af917688f;p=flightgear.git diff --git a/src/Instrumentation/mk_viii.cxx b/src/Instrumentation/mk_viii.cxx old mode 100755 new mode 100644 index 118d740b7..9b0ee2b48 --- a/src/Instrumentation/mk_viii.cxx +++ b/src/Instrumentation/mk_viii.cxx @@ -16,7 +16,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. // /////////////////////////////////////////////////////////////////////////////// // @@ -70,17 +70,22 @@ #include #include #include +#include #include -SG_USING_STD(string); +using std::string; -#include "Airports/runways.hxx" -#include "Airports/simple.hxx" -#ifndef _MSC_VER -# include "Include/version.h" +#include +#include + +#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H +# include +#else +# include #endif -#include "Main/fg_props.hxx" -#include "Main/globals.hxx" + +#include
+#include
#include "instrument_mgr.hxx" #include "mk_viii.hxx" @@ -168,35 +173,6 @@ get_reciprocal_heading (double h) return heading_add(h, 180); } -// Searches for the closest airport whose Manhattan distance to -// @lat,@lon is inferior to @min_manhattan_distance (expressed in -// degrees) and for which @test_airport returns true. Returns NULL if -// no airport was found. -template -static const FGAirport * -get_closest_airport (double lat, - double lon, - double min_manhattan_distance, - C &obj, - bool (C::*test_airport) (const FGAirport *)) -{ - const FGAirport *airport = NULL; - const airport_list *airport_list = globals->get_airports()->getAirportList(); - - for (size_t i = 0; i < airport_list->size(); i++) - { - const FGAirport *a = (*airport_list)[i]; - double dist = fabs(lat - a->getLatitude()) + fabs(lon - a->getLongitude()); - if (dist < min_manhattan_distance && (obj.*test_airport)(a)) - { - airport = a; - min_manhattan_distance = dist; - } - } - - return airport; -} - /////////////////////////////////////////////////////////////////////////////// // PropertiesHandler ////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -211,6 +187,9 @@ MK_VIII::PropertiesHandler::init () mk_node(altimeter_serviceable) = fgGetNode("/instrumentation/altimeter/serviceable", true); mk_node(altitude) = fgGetNode("/position/altitude-ft", true); mk_node(altitude_agl) = fgGetNode("/position/altitude-agl-ft", true); + mk_node(altitude_gear_agl) = fgGetNode("/position/gear-agl-ft", true); + mk_node(altitude_radar_agl) = fgGetNode("/instrumentation/radar-altimeter/radar-altitude-ft", true); + mk_node(orientation_roll) = fgGetNode("/orientation/roll-deg", true); mk_node(asi_serviceable) = fgGetNode("/instrumentation/airspeed-indicator/serviceable", true); mk_node(asi_speed) = fgGetNode("/instrumentation/airspeed-indicator/indicated-speed-kt", true); mk_node(autopilot_heading_lock) = fgGetNode("/autopilot/locks/heading", true); @@ -232,17 +211,6 @@ MK_VIII::PropertiesHandler::init () mk_node(vs) = fgGetNode("/velocities/vertical-speed-fps", true); } -void -MK_VIII::PropertiesHandler::unbind () -{ - vector::iterator iter; - - for (iter = tied_properties.begin(); iter != tied_properties.end(); iter++) - (*iter)->untie(); - - tied_properties.clear(); -} - /////////////////////////////////////////////////////////////////////////////// // PowerHandler /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -389,6 +357,7 @@ MK_VIII::SystemHandler::update () if (replay_state != last_replay_state) { mk->alert_handler.reposition(); + mk->io_handler.reposition(); last_replay_state = replay_state; state = STATE_REPOSITION; @@ -578,7 +547,7 @@ MK_VIII::ConfigurationModule::read_aircraft_mode_type_select (int value) { 255, &m1_t1, &m2_t1, &m3_t1, &m4_t1, m6_t2, &f_fast, 2000 } }; - for (int i = 0; i < n_elements(aircraft_types); i++) + for (size_t i = 0; i < n_elements(aircraft_types); i++) if (aircraft_types[i].type == value) { mk->mode1_handler.conf.envelopes = aircraft_types[i].m1; @@ -654,7 +623,7 @@ MK_VIII::ConfigurationModule::read_altitude_callouts (int value) { 101, { FIELD_500_ABOVE, 0 } } }; - int i; + unsigned i; mk->mode6_handler.conf.minimums_enabled = false; mk->mode6_handler.conf.smart_500_enabled = false; @@ -685,7 +654,7 @@ MK_VIII::ConfigurationModule::read_altitude_callouts (int value) break; default: - for (int k = 0; k < n_altitude_callouts; k++) + for (unsigned k = 0; k < n_altitude_callouts; k++) if (mk->mode6_handler.altitude_callout_definitions[k] == values[i].callouts[j]) mk->mode6_handler.conf.altitude_callouts_enabled[k] = true; break; @@ -741,7 +710,7 @@ MK_VIII::ConfigurationModule::read_options_select_group_1 (int value) bool MK_VIII::ConfigurationModule::read_radio_altitude_input_select (int value) { - // unimplemented + mk->io_handler.conf.altitude_source = value; return (value >= 0 && value <= 4) || (value >= 251 && value <= 255); } @@ -761,7 +730,10 @@ MK_VIII::ConfigurationModule::read_navigation_input_select (int value) bool MK_VIII::ConfigurationModule::read_attitude_input_select (int value) { - // unimplemented + if (value == 2) + mk->io_handler.conf.use_attitude_indicator=true; + else + mk->io_handler.conf.use_attitude_indicator=false; return (value >= 0 && value <= 6) || value == 253 || value == 255; } @@ -802,7 +774,7 @@ MK_VIII::ConfigurationModule::read_input_output_discrete_type_select (int value) { 255, { false, false }, true, false, true } }; - for (int i = 0; i < n_elements(io_types); i++) + for (size_t i = 0; i < n_elements(io_types); i++) if (io_types[i].type == value) { mk->io_handler.conf.lamp = &io_types[i].lamp_conf; @@ -830,7 +802,7 @@ MK_VIII::ConfigurationModule::read_audio_output_level (int value) { 4, -24 } }; - for (int i = 0; i < n_elements(values); i++) + for (size_t i = 0; i < n_elements(values); i++) if (values[i].id == value) { mk->voice_player.set_volume(mk->voice_player.conf.volume = modify_amplitude(1.0, values[i].relative_dB)); @@ -1008,7 +980,12 @@ MK_VIII::IOHandler::TerrainClearanceFilter::update (double agl) // [PILOT] page 20 specifies that the terrain clearance is equal to // 75% of the radio altitude, averaged over the previous 15 seconds. - deque< Sample >::iterator iter; + // no updates when simulation is paused (dt=0.0), and add 5 samples/second only + if (globals->get_sim_time_sec() - last_update < 0.2) + return value; + last_update = globals->get_sim_time_sec(); + + samples_type::iterator iter; // remove samples older than 15 seconds for (iter = samples.begin(); iter != samples.end() && globals->get_sim_time_sec() - (*iter).timestamp >= 15; iter = samples.begin()) @@ -1021,8 +998,10 @@ MK_VIII::IOHandler::TerrainClearanceFilter::update (double agl) double new_value = 0; if (samples.size() > 0) { + // time consuming loop => queue limited to 75 samples + // (= 15seconds * 5samples/second) for (iter = samples.begin(); iter != samples.end(); iter++) - new_value += (*iter).value; + new_value += (*iter).value; new_value /= samples.size(); } new_value *= 0.75; @@ -1038,6 +1017,7 @@ MK_VIII::IOHandler::TerrainClearanceFilter::reset () { samples.clear(); value = 0; + last_update = -1.0; } MK_VIII::IOHandler::IOHandler (MK_VIII *device) @@ -1078,6 +1058,7 @@ MK_VIII::IOHandler::boot () mk_doutput(glideslope_cancel) = power_saved.glideslope_cancel; altitude_samples.clear(); + reset_terrain_clearance(); } void @@ -1173,9 +1154,21 @@ MK_VIII::IOHandler::update_inputs () mk_ainput(barometric_altitude_rate).set(mk_node(vs)->getDoubleValue() * 60); if (mk_ainput_feed(radio_altitude)) { + double agl; + switch (conf.altitude_source) + { + case 3: + agl = mk_node(altitude_gear_agl)->getDoubleValue(); + break; + case 4: + agl = mk_node(altitude_radar_agl)->getDoubleValue(); + break; + default: // 0,1,2 (and any currently unsupported values) + agl = mk_node(altitude_agl)->getDoubleValue(); + break; + } // Some flight models may return negative values when on the // ground or after a crash; do not allow them. - double agl = mk_node(altitude_agl)->getDoubleValue(); mk_ainput(radio_altitude).set(SG_MAX2(0.0, agl)); } if (mk_ainput_feed(glideslope_deviation)) @@ -1193,11 +1186,20 @@ MK_VIII::IOHandler::update_inputs () } if (mk_ainput_feed(roll_angle)) { + if (conf.use_attitude_indicator) + { + // read data from attitude indicator instrument (requires vacuum system to work) if (mk_node(ai_serviceable)->getBoolValue() && ! mk_node(ai_caged)->getBoolValue()) mk_ainput(roll_angle).set(mk_node(ai_roll)->getDoubleValue()); else mk_ainput(roll_angle).unset(); } + else + { + // use simulator source + mk_ainput(roll_angle).set(mk_node(orientation_roll)->getDoubleValue()); + } + } if (mk_ainput_feed(localizer_deviation)) { if (mk_node(nav0_serviceable)->getBoolValue() @@ -1267,8 +1269,8 @@ MK_VIII::IOHandler::update_inputs () // Erase everything from the beginning of the list up to the sample // preceding the most recent sample whose age is >= 1 second. - deque< Sample< Parameter > >::iterator erase_last = altitude_samples.begin(); - deque< Sample< Parameter > >::iterator iter; + altitude_samples_type::iterator erase_last = altitude_samples.begin(); + altitude_samples_type::iterator iter; for (iter = altitude_samples.begin(); iter != altitude_samples.end(); iter++) if (globals->get_sim_time_sec() - (*iter).timestamp >= 1) @@ -1364,6 +1366,12 @@ MK_VIII::IOHandler::reset_terrain_clearance () update_terrain_clearance(); } +void +MK_VIII::IOHandler::reposition () +{ + reset_terrain_clearance(); +} + void MK_VIII::IOHandler::handle_input_fault (bool test, FaultHandler::Fault fault) { @@ -1579,7 +1587,7 @@ MK_VIII::IOHandler::update_egpws_alert_discrete_1 () { 19, mk_voice(minimums_minimums) } }; - for (int i = 0; i < n_elements(voices); i++) + for (size_t i = 0; i < n_elements(voices); i++) if (voices[i].voice == mk->voice_player.voice) { mk_aoutput(egpws_alert_discrete_1) = 1 << voices[i].bit; @@ -1613,7 +1621,7 @@ MK_VIII::IOHandler::update_egpwc_logic_discretes () { 25, mk_alert(MODE5_SOFT) | mk_alert(MODE5_HARD) } }; - for (int i = 0; i < n_elements(logic); i++) + for (size_t i = 0; i < n_elements(logic); i++) if (mk_test_alerts(logic[i].alerts)) mk_aoutput(egpwc_logic_discretes) |= 1 << logic[i].bit; } @@ -1639,7 +1647,7 @@ MK_VIII::IOHandler::update_mode6_callouts_discrete_1 () { 25, mk_altitude_voice(Mode6Handler::ALTITUDE_CALLOUT_300) } }; - for (int i = 0; i < n_elements(voices); i++) + for (size_t i = 0; i < n_elements(voices); i++) if (voices[i].voice == mk->voice_player.voice) { mk_aoutput(mode6_callouts_discrete_1) = 1 << voices[i].bit; @@ -1668,7 +1676,7 @@ MK_VIII::IOHandler::update_mode6_callouts_discrete_2 () { 23, mk_voice(five_hundred_above) } }; - for (int i = 0; i < n_elements(voices); i++) + for (size_t i = 0; i < n_elements(voices); i++) if (voices[i].voice == mk->voice_player.voice) { mk_aoutput(mode6_callouts_discrete_2) = 1 << voices[i].bit; @@ -1840,7 +1848,8 @@ MK_VIII::IOHandler::tie_input (SGPropertyNode *node, bool *input, bool *feed) { - mk->properties_handler.tie(node, (string("inputs/discretes/") + name).c_str(), RawValueMethodsData(*this, input, &MK_VIII::IOHandler::get_discrete_input, &MK_VIII::IOHandler::set_discrete_input)); + mk->properties_handler.tie(node, (string("inputs/discretes/") + name).c_str(), + FGVoicePlayer::RawValueMethodsData(*this, input, &MK_VIII::IOHandler::get_discrete_input, &MK_VIII::IOHandler::set_discrete_input)); if (feed) mk->properties_handler.tie(node, (string("input-feeders/discretes/") + name).c_str(), SGRawValuePointer(feed)); } @@ -2078,7 +2087,7 @@ MK_VIII::IOHandler::present_status () "TCF INPUTS INVALID" }; - for (int i = 0; i < n_elements(fault_names); i++) + for (size_t i = 0; i < n_elements(fault_names); i++) if (mk->fault_handler.faults[i]) present_status_subitem(fault_names[i]); } @@ -2104,7 +2113,7 @@ MK_VIII::IOHandler::present_status () "VOLUME SELECT" }; - for (int i = 0; i < n_elements(category_names); i++) + for (size_t i = 0; i < n_elements(category_names); i++) { std::ostringstream value; value << "= " << mk->configuration_module.effective_categories[i]; @@ -2126,285 +2135,50 @@ MK_VIII::IOHandler::set_present_status (bool value) /////////////////////////////////////////////////////////////////////////////// -// VoicePlayer //////////////////////////////////////////////////////////////// +// MK_VIII::VoicePlayer /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -void -MK_VIII::VoicePlayer::Speaker::bind (SGPropertyNode *node) -{ - // uses xmlsound property names - tie(node, "volume", &volume); - tie(node, "pitch", &pitch); - tie(node, "position/x", &position[0]); - tie(node, "position/y", &position[1]); - tie(node, "position/z", &position[2]); - tie(node, "orientation/x", &orientation[0]); - tie(node, "orientation/y", &orientation[1]); - tie(node, "orientation/z", &orientation[2]); - tie(node, "orientation/inner-cone", &inner_cone); - tie(node, "orientation/outer-cone", &outer_cone); - tie(node, "reference-dist", &reference_dist); - tie(node, "max-dist", &max_dist); -} - -void -MK_VIII::VoicePlayer::Speaker::update_configuration () -{ - map::iterator iter; - for (iter = player->samples.begin(); iter != player->samples.end(); iter++) - { - SGSoundSample *sample = (*iter).second; - - sample->set_pitch(pitch); - sample->set_offset_pos(position); - sample->set_orientation(orientation, - inner_cone, - outer_cone, - outer_gain); - sample->set_reference_dist(reference_dist); - sample->set_max_dist(max_dist); - } - - if (player->voice) - player->voice->volume_changed(); -} - -MK_VIII::VoicePlayer::Voice::~Voice () -{ - for (iter = elements.begin(); iter != elements.end(); iter++) - delete *iter; // we owned the element - elements.clear(); -} - -void -MK_VIII::VoicePlayer::Voice::play () -{ - iter = elements.begin(); - element = *iter; - - element->play(get_volume()); -} - -void -MK_VIII::VoicePlayer::Voice::stop (bool now) -{ - if (element) - { - if (now || element->silence) - { - element->stop(); - element = NULL; - } - else - iter = elements.end() - 1; // stop after the current element finishes - } -} - -void -MK_VIII::VoicePlayer::Voice::set_volume (double _volume) -{ - volume = _volume; - volume_changed(); -} - -void -MK_VIII::VoicePlayer::Voice::volume_changed () -{ - if (element) - element->set_volume(get_volume()); -} - -void -MK_VIII::VoicePlayer::Voice::update () -{ - if (element) - { - if (! element->is_playing()) - { - if (++iter == elements.end()) - element = NULL; - else - { - element = *iter; - element->play(get_volume()); - } - } - } -} - -MK_VIII::VoicePlayer::~VoicePlayer () -{ - vector::iterator iter1; - for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++) - delete *iter1; - _voices.clear(); - -/* sound mgr already destroyed - samples already deleted - map::iterator iter2; - for (iter2 = samples.begin(); iter2 != samples.end(); iter2++) - { - bool status = globals->get_soundmgr()->remove((*iter2).first); - assert(status); - } -*/ - samples.clear(); -} - void MK_VIII::VoicePlayer::init () { -#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay" - - make_voice(&voices.application_data_base_failed, "application-data-base-failed"); - make_voice(&voices.bank_angle, "bank-angle"); - make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle"); - make_voice(&voices.bank_angle_bank_angle_3, "bank-angle", "bank-angle", 3.0); - make_voice(&voices.bank_angle_inop, "bank-angle-inop"); - make_voice(&voices.bank_angle_pause_bank_angle, "bank-angle", STDPAUSE, "bank-angle"); - make_voice(&voices.bank_angle_pause_bank_angle_3, "bank-angle", STDPAUSE, "bank-angle", 3.0); - make_voice(&voices.callouts_inop, "callouts-inop"); - make_voice(&voices.configuration_type_invalid, "configuration-type-invalid"); - make_voice(&voices.dont_sink, "dont-sink"); - make_voice(&voices.dont_sink_pause_dont_sink, "dont-sink", STDPAUSE, "dont-sink"); - make_voice(&voices.five_hundred_above, "500-above"); - make_voice(&voices.glideslope, "glideslope"); - 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.minimums, "minimums"); - make_voice(&voices.minimums_minimums, "minimums", "minimums"); - make_voice(&voices.pull_up, "pull-up"); - make_voice(&voices.sink_rate, "sink-rate"); - make_voice(&voices.sink_rate_pause_sink_rate, "sink-rate", STDPAUSE, "sink-rate"); - make_voice(&voices.soft_glideslope, new Voice::SampleElement(get_sample("glideslope"), modify_amplitude(1.0, -6))); - make_voice(&voices.terrain, "terrain"); - make_voice(&voices.terrain_pause_terrain, "terrain", STDPAUSE, "terrain"); - make_voice(&voices.too_low_flaps, "too-low-flaps"); - make_voice(&voices.too_low_gear, "too-low-gear"); - make_voice(&voices.too_low_terrain, "too-low-terrain"); - - for (int i = 0; i < n_altitude_callouts; i++) - { - std::ostringstream name; - name << "altitude-" << mk->mode6_handler.altitude_callout_definitions[i]; - make_voice(&voices.altitude_callouts[i], name.str().c_str()); - } - - speaker.update_configuration(); -} - -SGSoundSample * -MK_VIII::VoicePlayer::get_sample (const char *name) -{ - std::ostringstream refname; - refname << mk->name << "[" << mk->num << "]" << "/" << name; - - SGSoundMgr *soundmgr = globals->get_soundmgr(); - if (soundmgr->is_working() == false) - { - return NULL; - } - - SGSoundSample *sample = soundmgr->find(refname.str()); - if (! sample) - { - SGPath sample_path(globals->get_fg_root()); - sample_path.append("Sounds/mk-viii"); - - string filename = string(name) + ".wav"; - try - { - sample = new SGSoundSample(sample_path.c_str(), filename.c_str()); - } - catch (const sg_exception &e) - { - SG_LOG(SG_INSTR, SG_ALERT, "Error loading MK VIII sound sample \"" + filename + "\": " + e.getFormattedMessage()); - exit(1); - } - - soundmgr->add(sample, refname.str()); - samples[refname.str()] = sample; - } - - return sample; -} - -void -MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags) -{ - if (test_bits(flags, PLAY_NOW) || ! voice || voice->element->silence) - { - if (voice) - voice->stop(true); - - voice = _voice; - looped = test_bits(flags, PLAY_LOOPED); - - next_voice = NULL; - next_looped = false; - - voice->play(); - } - else - { - next_voice = _voice; - next_looped = test_bits(flags, PLAY_LOOPED); - } -} - -void -MK_VIII::VoicePlayer::stop (unsigned int flags) -{ - if (voice) - { - voice->stop(test_bits(flags, STOP_NOW)); - if (voice->element) - looped = false; - else - voice = NULL; - next_voice = NULL; - } -} - -void -MK_VIII::VoicePlayer::set_volume (double _volume) -{ - volume = _volume; - if (voice) - voice->volume_changed(); -} - -void -MK_VIII::VoicePlayer::update () -{ - if (voice) - { - voice->update(); - - if (next_voice) - { - if (! voice->element || voice->element->silence) - { - voice = next_voice; - looped = next_looped; - - next_voice = NULL; - next_looped = false; - - voice->play(); - } - } - else - { - if (! voice->element) - { - if (looped) - voice->play(); - else - voice = NULL; - } - } - } + FGVoicePlayer::init(); + +#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay" + make_voice(&voices.application_data_base_failed, "application-data-base-failed"); + make_voice(&voices.bank_angle, "bank-angle"); + make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle"); + make_voice(&voices.bank_angle_bank_angle_3, "bank-angle", "bank-angle", 3.0); + make_voice(&voices.bank_angle_inop, "bank-angle-inop"); + make_voice(&voices.bank_angle_pause_bank_angle, "bank-angle", STDPAUSE, "bank-angle"); + make_voice(&voices.bank_angle_pause_bank_angle_3, "bank-angle", STDPAUSE, "bank-angle", 3.0); + make_voice(&voices.callouts_inop, "callouts-inop"); + make_voice(&voices.configuration_type_invalid, "configuration-type-invalid"); + make_voice(&voices.dont_sink, "dont-sink"); + make_voice(&voices.dont_sink_pause_dont_sink, "dont-sink", STDPAUSE, "dont-sink"); + make_voice(&voices.five_hundred_above, "500-above"); + make_voice(&voices.glideslope, "glideslope"); + 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.minimums, "minimums"); + make_voice(&voices.minimums_minimums, "minimums", "minimums"); + make_voice(&voices.pull_up, "pull-up"); + make_voice(&voices.sink_rate, "sink-rate"); + make_voice(&voices.sink_rate_pause_sink_rate, "sink-rate", STDPAUSE, "sink-rate"); + make_voice(&voices.soft_glideslope, new Voice::SampleElement(get_sample("glideslope"), modify_amplitude(1.0, -6))); + make_voice(&voices.terrain, "terrain"); + make_voice(&voices.terrain_pause_terrain, "terrain", STDPAUSE, "terrain"); + make_voice(&voices.too_low_flaps, "too-low-flaps"); + make_voice(&voices.too_low_gear, "too-low-gear"); + make_voice(&voices.too_low_terrain, "too-low-terrain"); + + for (unsigned i = 0; i < n_altitude_callouts; i++) + { + std::ostringstream name; + name << "altitude-" << MK_VIII::Mode6Handler::altitude_callout_definitions[i]; + make_voice(&voices.altitude_callouts[i], name.str().c_str()); + } + speaker.update_configuration(); } /////////////////////////////////////////////////////////////////////////////// @@ -2616,7 +2390,7 @@ MK_VIII::SelfTestHandler::run () if (mk->mode6_handler.conf.above_field_voice) return play(mk->mode6_handler.conf.above_field_voice); } - for (int i = 0; i < n_altitude_callouts; i++) + for (unsigned i = 0; i < n_altitude_callouts; i++) if (! was_here_offset(i)) { if (mk->mode6_handler.conf.altitude_callouts_enabled[i]) @@ -2681,6 +2455,8 @@ MK_VIII::SelfTestHandler::stop () button_pressed = false; state = STATE_NONE; + // reset self-test handler position + current=0; } } @@ -2905,6 +2681,7 @@ MK_VIII::AlertHandler::update () { assert(altitude_callout_voice != NULL); mk->voice_player.play(altitude_callout_voice); + altitude_callout_voice = NULL; } } else if (select_voice_alerts(ALERT_MODE4_TOO_LOW_GEAR)) @@ -2988,11 +2765,11 @@ MK_VIII::AlertHandler::update () mk->voice_player.play(mk_voice(bank_angle_pause_bank_angle)); } - // set new state - - old_alerts = alerts; + // remember all alerts voiced so far... + old_alerts |= voice_alerts; + // ... forget those no longer active + old_alerts &= alerts; repeated_alerts = 0; - altitude_callout_voice = NULL; } void @@ -3012,6 +2789,8 @@ MK_VIII::AlertHandler::unset_alerts (unsigned int _alerts) { alerts &= ~_alerts; repeated_alerts &= ~_alerts; + if (_alerts & ALERT_MODE6_ALTITUDE_CALLOUT) + altitude_callout_voice = NULL; } /////////////////////////////////////////////////////////////////////////////// @@ -3627,9 +3406,16 @@ MK_VIII::Mode3Handler::max_alt_loss (double _bias) double MK_VIII::Mode3Handler::get_bias (double initial_bias, double alt_loss) { - if (mk_data(radio_altitude).get() > 0) - while (alt_loss > max_alt_loss(initial_bias)) + // do not repeat altitude-loss alerts below 30ft agl + if (mk_data(radio_altitude).get() > 30) + { + if (initial_bias < 0.0) // sanity check + initial_bias = 0.0; + // mk-viii spec: repeat alerts whenever losing 20% of initial altitude + while ((alt_loss > max_alt_loss(initial_bias))&& + (initial_bias < 1.0)) initial_bias += 0.2; + } return initial_bias; } @@ -3761,8 +3547,15 @@ MK_VIII::Mode4Handler::get_ab_envelope () double MK_VIII::Mode4Handler::get_bias (double initial_bias, double min_agl) { - while (mk_data(radio_altitude).get() < min_agl - min_agl * initial_bias) - initial_bias += 0.2; + // do not repeat terrain/gear/flap alerts below 30ft agl + if (mk_data(radio_altitude).get() > 30.0) + { + if (initial_bias < 0.0) // sanity check + initial_bias = 0.0; + while ((mk_data(radio_altitude).get() < min_agl - min_agl * initial_bias)&& + (initial_bias < 1.0)) + initial_bias += 0.2; + } return initial_bias; } @@ -3821,6 +3614,7 @@ MK_VIII::Mode4Handler::update_ab () } mk_unset_alerts(mk_alert(MODE4_TOO_LOW_FLAPS) | mk_alert(MODE4_TOO_LOW_GEAR)); + ab_bias=0.0; } void @@ -3846,6 +3640,7 @@ MK_VIII::Mode4Handler::update_ab_expanded () } mk_unset_alerts(mk_alert(MODE4AB_TOO_LOW_TERRAIN)); + ab_expanded_bias=0.0; } void @@ -3862,7 +3657,10 @@ MK_VIII::Mode4Handler::update_c () && mk_data(radio_altitude).get() < mk_data(terrain_clearance).get()) handle_alert(mk_alert(MODE4C_TOO_LOW_TERRAIN), mk_data(terrain_clearance).get(), &c_bias); else + { mk_unset_alerts(mk_alert(MODE4C_TOO_LOW_TERRAIN)); + c_bias=0.0; + } } void @@ -3902,6 +3700,7 @@ MK_VIII::Mode5Handler::is_hard () bool MK_VIII::Mode5Handler::is_soft (double bias) { + // do not repeat glide-slope alerts below 30ft agl if (mk_data(radio_altitude).get() > 30) { double bias_dots = 1.3 * bias; @@ -3940,7 +3739,10 @@ MK_VIII::Mode5Handler::is_soft (double bias) double MK_VIII::Mode5Handler::get_soft_bias (double initial_bias) { - while (is_soft(initial_bias)) + if (initial_bias < 0.0) // sanity check + initial_bias = 0.0; + while ((is_soft(initial_bias))&& + (initial_bias < 1.0)) initial_bias += 0.2; return initial_bias; @@ -4040,14 +3842,14 @@ MK_VIII::Mode6Handler::reset_minimums () void MK_VIII::Mode6Handler::reset_altitude_callouts () { - for (int i = 0; i < n_altitude_callouts; i++) + for (unsigned i = 0; i < n_altitude_callouts; i++) altitude_callouts_issued[i] = false; } bool MK_VIII::Mode6Handler::is_playing_altitude_callout () { - for (int i = 0; i < n_altitude_callouts; i++) + for (unsigned i = 0; i < n_altitude_callouts; i++) if (mk->voice_player.voice == mk_altitude_voice(i) || mk->voice_player.next_voice == mk_altitude_voice(i)) return true; @@ -4121,7 +3923,7 @@ MK_VIII::Mode6Handler::boot () last_radio_altitude.set(&mk_data(radio_altitude)); // [SPEC] 6.4.2 - for (int i = 0; i < n_altitude_callouts; i++) + for (unsigned i = 0; i < n_altitude_callouts; i++) altitude_callouts_issued[i] = ! mk_data(radio_altitude).ncd && mk_data(radio_altitude).get() <= altitude_callout_definitions[i]; @@ -4159,11 +3961,11 @@ MK_VIII::Mode6Handler::leave_takeoff () } void -MK_VIII::Mode6Handler::set_volume (double volume) +MK_VIII::Mode6Handler::set_volume (float volume) { mk_voice(minimums_minimums)->set_volume(volume); mk_voice(five_hundred_above)->set_volume(volume); - for (int i = 0; i < n_altitude_callouts; i++) + for (unsigned i = 0; i < n_altitude_callouts; i++) mk_altitude_voice(i)->set_volume(volume); } @@ -4173,7 +3975,7 @@ MK_VIII::Mode6Handler::altitude_callouts_enabled () if (conf.minimums_enabled || conf.smart_500_enabled || conf.above_field_voice) return true; - for (int i = 0; i < n_altitude_callouts; i++) + for (unsigned i = 0; i < n_altitude_callouts; i++) if (conf.altitude_callouts_enabled[i]) return true; @@ -4226,7 +4028,7 @@ MK_VIII::Mode6Handler::update_altitude_callouts () if (! mk->io_handler.gpws_inhibit() && ! mk->state_handler.ground // [1] && ! mk_data(radio_altitude).ncd) - for (int i = 0; i < n_altitude_callouts && mk_data(radio_altitude).get() <= altitude_callout_definitions[i]; i++) + for (unsigned i = 0; i < n_altitude_callouts && mk_data(radio_altitude).get() <= altitude_callout_definitions[i]; i++) if ((conf.altitude_callouts_enabled[i] || (altitude_callout_definitions[i] == 500 && conf.smart_500_enabled)) @@ -4235,7 +4037,7 @@ MK_VIII::Mode6Handler::update_altitude_callouts () || last_radio_altitude.get() > altitude_callout_definitions[i])) { // lock out all callouts superior or equal to this one - for (int j = 0; j <= i; j++) + for (unsigned j = 0; j <= i; j++) altitude_callouts_issued[j] = true; altitude_callouts_issued[i] = true; @@ -4259,76 +4061,59 @@ MK_VIII::Mode6Handler::update_altitude_callouts () bool MK_VIII::Mode6Handler::test_runway (const FGRunway *_runway) { - if (_runway->_length < mk->conf.runway_database) + if (_runway->lengthFt() < mk->conf.runway_database) return false; - // get position of threshold - double latitude, longitude, az; - geo_direct_wgs_84(0, - _runway->_lat, - _runway->_lon, - get_reciprocal_heading(_runway->_heading), - _runway->_length / 2 * SG_FEET_TO_METER, - &latitude, - &longitude, - &az); - + SGGeod pos( + SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get())); + // get distance to threshold double distance, az1, az2; - geo_inverse_wgs_84(0, - mk_data(gps_latitude).get(), - mk_data(gps_longitude).get(), - latitude, - longitude, - &az1, &az2, &distance); - + SGGeodesy::inverse(pos, _runway->threshold(), az1, az2, distance); return distance * SG_METER_TO_NM <= 5; } bool MK_VIII::Mode6Handler::test_airport (const FGAirport *airport) { - FGRunway r; - if (globals->get_runways()->search(airport->getId(), &r)) - do - { - if (test_runway(&r)) - return true; - - // reciprocal runway - r._heading = get_reciprocal_heading(r._heading); - if (test_runway(&r)) - return true; - } - while (globals->get_runways()->next(&r) && r._id == airport->getId()); + for (unsigned int r=0; rnumRunways(); ++r) { + FGRunway* rwy(airport->getRunwayByIndex(r)); + + if (test_runway(rwy)) return true; + } return false; } +bool MK_VIII::Mode6Handler::AirportFilter::passAirport(FGAirport* a) const +{ + bool ok = self->test_airport(a); + return ok; +} + void MK_VIII::Mode6Handler::update_runway () { - if (! mk_data(gps_latitude).ncd && ! mk_data(gps_longitude).ncd) - { - // Search for the closest runway threshold in range 5 - // nm. Passing 0.5 degrees (approximatively 30 nm) to - // get_closest_airport() provides enough margin for large - // airports, which may have a runway located far away from the - // airport's reference point. - - const FGAirport *airport = get_closest_airport(mk_data(gps_latitude).get(), - mk_data(gps_longitude).get(), - 0.5, - *this, - &MK_VIII::Mode6Handler::test_airport); - - if (airport) - runway.elevation = airport->getElevation(); - - has_runway.set(airport != NULL); - } - else - has_runway.unset(); + + if (mk_data(gps_latitude).ncd || mk_data(gps_longitude).ncd) { + has_runway.unset(); + return; + } + + // Search for the closest runway threshold in range 5 + // nm. Passing 30nm to + // get_closest_airport() provides enough margin for large + // airports, which may have a runway located far away from the + // airport's reference point. + AirportFilter filter(this); + FGPositionedRef apt = FGPositioned::findClosest( + SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get()), + 30.0, &filter); + if (apt) { + runway.elevation = apt->elevation(); + } + + has_runway.set(apt != NULL); } void @@ -4507,9 +4292,9 @@ MK_VIII::TCFHandler::get_azimuth_difference (const FGRunway *_runway) { return get_azimuth_difference(mk_data(gps_latitude).get(), mk_data(gps_longitude).get(), - _runway->_lat, - _runway->_lon, - _runway->_heading); + _runway->latitude(), + _runway->longitude(), + _runway->headingDeg()); } // Selects the most likely intended destination runway of @airport, @@ -4521,84 +4306,61 @@ MK_VIII::TCFHandler::get_azimuth_difference (const FGRunway *_runway) // This selection algorithm is not specified in [SPEC], but // http://www.egpws.com/general_information/description/runway_select.htm // talks about automatic runway selection. -void -MK_VIII::TCFHandler::select_runway (const FGAirport *airport, - FGRunway *_runway) +FGRunway* +MK_VIII::TCFHandler::select_runway (const FGAirport *airport) { - FGRunway r; - bool status = globals->get_runways()->search(airport->getId(), &r); - assert(status); - + FGRunway* _runway = 0; double min_diff = 360; - do - { - double diff; - - diff = get_azimuth_difference(&r); - if (diff < min_diff) - { - min_diff = diff; - *_runway = r; - } - - // reciprocal runway - r._heading = get_reciprocal_heading(r._heading); - diff = get_azimuth_difference(&r); - if (diff < min_diff) - { - min_diff = diff; - *_runway = r; - } + + for (unsigned int r=0; rnumRunways(); ++r) { + FGRunway* rwy(airport->getRunwayByIndex(r)); + double diff = get_azimuth_difference(rwy); + if (diff < min_diff) + { + min_diff = diff; + _runway = rwy; } - while (globals->get_runways()->next(&r) && r._id == airport->getId()); + } // of airport runways iteration + return _runway; } -bool -MK_VIII::TCFHandler::test_airport (const FGAirport *airport) +bool MK_VIII::TCFHandler::AirportFilter::passAirport(FGAirport* aApt) const { - FGRunway r; - if (globals->get_runways()->search(airport->getId(), &r)) - do - { - if (r._length >= mk->conf.runway_database) - return true; - } - while (globals->get_runways()->next(&r) && r._id == airport->getId()); - - return false; + return aApt->hasHardRunwayOfLengthFt(mk->conf.runway_database); } - + void MK_VIII::TCFHandler::update_runway () { has_runway = false; - if (! mk_data(gps_latitude).ncd && ! mk_data(gps_longitude).ncd) - { - // Search for the intended destination runway of the closest - // airport in range 15 nm. Passing 0.5 degrees (approximatively - // 30 nm) to get_closest_airport() provides enough margin for - // large airports, which may have a runway located far away from - // the airport's reference point. - - const FGAirport *airport = get_closest_airport(mk_data(gps_latitude).get(), - mk_data(gps_longitude).get(), - 0.5, - *this, - &MK_VIII::TCFHandler::test_airport); + if (mk_data(gps_latitude).ncd || mk_data(gps_longitude).ncd) { + return; + } + + // Search for the intended destination runway of the closest + // airport in range 15 nm. Passing 30nm to get_closest_airport() + // provides enough margin for + // large airports, which may have a runway located far away from + // the airport's reference point. + AirportFilter filter(mk); + FGAirport* apt = FGAirport::findClosest( + SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get()), + 30.0, &filter); + + if (!apt) return; + + FGRunway* _runway = select_runway(apt); + + if (!_runway) return; - if (airport) - { has_runway = true; - FGRunway _runway; - select_runway(airport, &_runway); - - runway.center.latitude = _runway._lat; - runway.center.longitude = _runway._lon; + runway.center.latitude = _runway->latitude(); + runway.center.longitude = _runway->longitude(); - runway.elevation = airport->getElevation(); + runway.elevation = apt->elevation(); - double half_length_m = _runway._length / 2 * SG_FEET_TO_METER; + double half_length_m = _runway->lengthM() * 0.5; runway.half_length = half_length_m * SG_METER_TO_NM; // b3 ________________ b0 @@ -4608,8 +4370,8 @@ MK_VIII::TCFHandler::update_runway () // b2 b1 // get heading to runway threshold (h0) and end (h1) - runway.edges[0].heading = _runway._heading; - runway.edges[1].heading = get_reciprocal_heading(_runway._heading); + runway.edges[0].heading = _runway->headingDeg(); + runway.edges[1].heading = get_reciprocal_heading(_runway->headingDeg()); double az; @@ -4633,7 +4395,7 @@ MK_VIII::TCFHandler::update_runway () &runway.edges[1].position.longitude, &az); - double half_width_m = _runway._width / 2 * SG_FEET_TO_METER; + double half_width_m = _runway->widthM() * 0.5; // get position of threshold bias area edges (b0 and b1) get_bias_area_edges(&runway.edges[0].position, @@ -4648,8 +4410,6 @@ MK_VIII::TCFHandler::update_runway () half_width_m, &runway.bias_area[2], &runway.bias_area[3]); - } - } } void @@ -4660,7 +4420,7 @@ MK_VIII::TCFHandler::get_bias_area_edges (Position *edge, Position *bias_edge2) { double half_bias_width_m = k * SG_NM_TO_METER + half_width_m; - double tmp_latitude, tmp_longitude, az; + double tmp_latitude = 0.0, tmp_longitude = 0.0, az = 0.0; geo_direct_wgs_84(0, edge->latitude, @@ -4884,8 +4644,15 @@ MK_VIII::TCFHandler::update () if (mk_test_alert(TCF_TOO_LOW_TERRAIN)) { double new_bias = bias; - while (*reference < initial_value - initial_value * new_bias) - new_bias += 0.2; + // do not repeat terrain alerts below 30ft agl + if (mk_data(radio_altitude).get() > 30) + { + if (new_bias < 0.0) // sanity check + new_bias = 0.0; + while ((*reference < initial_value - initial_value * new_bias)&& + (new_bias < 1.0)) + new_bias += 0.2; + } if (new_bias > bias) { @@ -4913,10 +4680,9 @@ MK_VIII::TCFHandler::update () /////////////////////////////////////////////////////////////////////////////// MK_VIII::MK_VIII (SGPropertyNode *node) - : name("mk-viii"), + : properties_handler(this), + name("mk-viii"), num(0), - - properties_handler(this), power_handler(this), system_handler(this), configuration_module(this), @@ -4968,7 +4734,7 @@ MK_VIII::bind () configuration_module.bind(node); power_handler.bind(node); io_handler.bind(node); - voice_player.bind(node); + voice_player.bind(node, "Sounds/mk-viii/"); } void