#include "adf.hxx"
+#include <iostream>
+#include <string>
+#include <sstream>
+
// Use a bigger number to be more responsive, or a smaller number
// to be more sluggish.
}
+ADF::ADF (SGPropertyNode *node )
+ :
+ _time_before_search_sec(0),
+ _last_frequency_khz(-1),
+ _transmitter_valid(false),
+ _transmitter_elevation_ft(0),
+ _transmitter_range_nm(0),
+ _ident_count(0),
+ _last_ident_time(0),
+ _last_volume(-1),
+ name("adf"),
+ num(0)
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in adf config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
+
ADF::ADF ()
: _time_before_search_sec(0),
_last_frequency_khz(-1),
_transmitter_range_nm(0),
_ident_count(0),
_last_ident_time(0),
- _last_volume(-1)
+ _last_volume(-1),
+ name("adf"),
+ num(0)
{
}
void
ADF::init ()
{
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
_longitude_node = fgGetNode("/position/longitude-deg", true);
_latitude_node = fgGetNode("/position/latitude-deg", true);
_altitude_node = fgGetNode("/position/altitude-ft", true);
_heading_node = fgGetNode("/orientation/heading-deg", true);
- _serviceable_node = fgGetNode("/instrumentation/adf/serviceable", true);
- _error_node = fgGetNode("/instrumentation/adf/error-deg", true);
+ _serviceable_node = node->getChild("serviceable", 0, true);
+ _error_node = node->getChild("error-deg", 0, true);
_electrical_node = fgGetNode("/systems/electrical/outputs/adf", true);
- _frequency_node =
- fgGetNode("/instrumentation/adf/frequencies/selected-khz", true);
- _mode_node = fgGetNode("/instrumentation/adf/mode", true);
-
- _in_range_node = fgGetNode("/instrumentation/adf/in-range", true);
- _bearing_node =
- fgGetNode("/instrumentation/adf/indicated-bearing-deg", true);
- _ident_node = fgGetNode("/instrumentation/adf/ident", true);
- _volume_node = fgGetNode("/instrumentation/adf/volume-norm", true);
- _ident_audible_node = fgGetNode("/instrumentation/adf/ident-audible", true);
+ branch = branch + "/frequencies";
+ SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
+ _frequency_node = fnode->getChild("selected-khz", 0, true);
+ _mode_node = node->getChild("mode", 0, true);
+ _volume_node = node->getChild("volume-norm", 0, true);
+ _in_range_node = node->getChild("in-range", 0, true);
+ _bearing_node = node->getChild("indicated-bearing-deg", 0, true);
+ _ident_node = node->getChild("ident", 0, true);
+ _ident_audible_node = node->getChild("ident-audible", 0, true);
+
morse.init();
+
+ std::ostringstream temp;
+ temp << name << num;
+ adf_ident = temp.str();
+
+ _serviceable_node->setBoolValue(true);
}
void
_last_volume = volume;
SGSoundSample *sound;
- sound = globals->get_soundmgr()->find( "adf-ident" );
+ sound = globals->get_soundmgr()->find( adf_ident );
if ( sound != NULL )
sound->set_volume( volume );
else
}
if ( _ident_count < 4 ) {
- if ( !globals->get_soundmgr()->is_playing("adf-ident") ) {
- globals->get_soundmgr()->play_once( "adf-ident" );
+ if ( !globals->get_soundmgr()->is_playing(adf_ident) ) {
+ globals->get_soundmgr()->play_once( adf_ident );
++_ident_count;
}
}
_in_range_node->setBoolValue(false);
set_bearing(delta_time_sec, 90);
_ident_node->setStringValue("");
- globals->get_soundmgr()->stop( "adf-ident" );
+ globals->get_soundmgr()->stop( adf_ident );
}
}
_last_ident = ident;
_ident_node->setStringValue(ident.c_str());
- if ( globals->get_soundmgr()->exists( "adf-ident" ) ) {
- // stop is required! -- remove alone wouldn't stop immediately
- globals->get_soundmgr()->stop( "adf-ident" );
- globals->get_soundmgr()->remove( "adf-ident" );
+ if ( globals->get_soundmgr()->exists( adf_ident ) ) {
+ // stop is required! -- remove alone wouldn't stop immediately
+ globals->get_soundmgr()->stop( adf_ident );
+ globals->get_soundmgr()->remove( adf_ident );
}
SGSoundSample *sound;
sound = morse.make_ident( ident, LO_FREQUENCY );
sound->set_volume(_last_volume = 0);
- globals->get_soundmgr()->add( sound, "adf-ident" );
+ globals->get_soundmgr()->add( sound, adf_ident );
int offset = (int)(sg_random() * 30.0);
_ident_count = offset / 4;
public:
+ ADF ( SGPropertyNode *node );
ADF ();
virtual ~ADF ();
int _ident_count;
time_t _last_ident_time;
double _last_volume;
+
+ string name;
+ int num;
+ string adf_ident;
};
// A higher number means more responsive.
#define RESPONSIVENESS 50.0
+AirspeedIndicator::AirspeedIndicator ( SGPropertyNode *node )
+ :
+ name("airspeed-indicator"),
+ num(0),
+ pitot_port("/systems/pitot"),
+ static_port("/systems/static")
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else if ( cname == "pitot-port" ) {
+ pitot_port = cval;
+ } else if ( cname == "static-port" ) {
+ static_port = cval;
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in aispeed-indicator config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
-AirspeedIndicator::AirspeedIndicator ()
+
+AirspeedIndicator::AirspeedIndicator ( int i )
+ :
+ name("airspeed-indicator"),
+ num(0),
+ pitot_port("/systems/pitot"),
+ static_port("/systems/static")
{
+ num = i;
}
AirspeedIndicator::~AirspeedIndicator ()
void
AirspeedIndicator::init ()
{
- _serviceable_node =
- fgGetNode("/instrumentation/airspeed-indicator/serviceable",
- true);
- _total_pressure_node =
- fgGetNode("/systems/pitot/total-pressure-inhg", true);
- _static_pressure_node =
- fgGetNode("/systems/static/pressure-inhg", true);
+ string branch;
+ branch = "/instrumentation/" + name;
+ pitot_port += "/total-pressure-inhg";
+ static_port += "/pressure-inhg";
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
+ _total_pressure_node = fgGetNode(pitot_port.c_str(), true);
+ _static_pressure_node = fgGetNode(static_port.c_str(), true);
_density_node = fgGetNode("/environment/density-slugft3", true);
- _speed_node =
- fgGetNode("/instrumentation/airspeed-indicator/indicated-speed-kt",
- true);
+ _speed_node = node->getChild("indicated-speed-kt", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
#ifndef FPSTOKTS
*
* Input properties:
*
- * /instrumentation/airspeed-indicator/serviceable
- * /systems/pitot[0]/total-pressure-inhg
- * /systems/static[0]/pressure-inhg
+ * /instrumentation/"name"/serviceable
+ * "pitot_port"/total-pressure-inhg
+ * "static_port"/pressure-inhg
* /environment/density-slugft3
*
* Output properties:
*
- * /instrumentation/airspeed-indicator/indicated-speed-kt
+ * /instrumentation/"name"/indicated-speed-kt
*/
class AirspeedIndicator : public SGSubsystem
{
public:
- AirspeedIndicator ();
+ AirspeedIndicator ( SGPropertyNode *node );
+ AirspeedIndicator ( int i);
virtual ~AirspeedIndicator ();
virtual void init ();
private:
+ string name;
+ int num;
+ string pitot_port;
+ string static_port;
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _total_pressure_node;
SGPropertyNode_ptr _static_pressure_node;
};
+Altimeter::Altimeter ( SGPropertyNode *node )
+ : _altitude_table(new SGInterpTable),
+ name("altimeter"),
+ num(0),
+ static_port("/systems/static")
+{
+
+ for (int i = 0; altitude_data[i][0] != -1; i++)
+ _altitude_table->addEntry(altitude_data[i][0], altitude_data[i][1]);
+
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else if ( cname == "static-port" ) {
+ static_port = cval;
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in altimeter config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
Altimeter::Altimeter ()
: _altitude_table(new SGInterpTable)
{
void
Altimeter::init ()
{
- _serviceable_node =
- fgGetNode("/instrumentation/altimeter/serviceable", true);
- _setting_node =
- fgGetNode("/instrumentation/altimeter/setting-inhg", true);
- _pressure_node =
- fgGetNode("/systems/static/pressure-inhg", true);
- _altitude_node =
- fgGetNode("/instrumentation/altimeter/indicated-altitude-ft", true);
+ string branch;
+ branch = "/instrumentation/" + name;
+ static_port += "/pressure-inhg";
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+
+ _serviceable_node = node->getChild("serviceable", 0, true);
+ _setting_node = node->getChild("setting-inhg", 0, true);
+ _pressure_node = fgGetNode(static_port.c_str(), true);
+ _altitude_node = node->getChild("indicated-altitude-ft", 0, true);
+
+ _serviceable_node->setBoolValue(true);
+ _setting_node->setDoubleValue(29.92);
}
void
*
* Input properties:
*
- * /instrumentation/altimeter/serviceable
- * /instrumentation/altimeter/setting-inhg
- * /systems/static[0]/pressure-inhg
+ * /instrumentation/"name"/serviceable
+ * /instrumentation/"name"/setting-inhg
+ * "static_port"/pressure-inhg
*
* Output properties:
*
- * /instrumentation/altimeter/indicated-altitude-ft
+ * /instrumentation/"name"/indicated-altitude-ft
*/
class Altimeter : public SGSubsystem
{
public:
+ Altimeter (SGPropertyNode *node);
Altimeter ();
virtual ~Altimeter ();
private:
+ string name;
+ int num;
+ string static_port;
+
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _setting_node;
SGPropertyNode_ptr _pressure_node;
#include <Main/util.hxx>
+AttitudeIndicator::AttitudeIndicator ( SGPropertyNode *node )
+ :
+ name("attitude-indicator"),
+ num(0),
+ vacuum_system("/systems/vacuum")
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = (int) child->getDoubleValue();
+ } else if ( cname == "vacuum-system" ) {
+ vacuum_system = cval;
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in attitude-indicator config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
AttitudeIndicator::AttitudeIndicator ()
{
}
void
AttitudeIndicator::init ()
{
- // TODO: allow index of pump and AI
- // to be configured.
+ string branch;
+ branch = "/instrumentation/" + name;
+ vacuum_system += "/suction-inhg";
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+
_pitch_in_node = fgGetNode("/orientation/pitch-deg", true);
_roll_in_node = fgGetNode("/orientation/roll-deg", true);
- _suction_node = fgGetNode("/systems/vacuum[0]/suction-inhg", true);
- _tumble_flag_node =
- fgGetNode("/instrumentation/attitude-indicator/config/tumble-flag",
- true);
- _caged_node =
- fgGetNode("/instrumentation/attitude-indicator/caged-flag", true);
- _tumble_node =
- fgGetNode("/instrumentation/attitude-indicator/tumble-norm", true);
- _pitch_int_node =
- fgGetNode("/instrumentation/attitude-indicator/internal-pitch-deg",
- true);
- _roll_int_node =
- fgGetNode("/instrumentation/attitude-indicator/internal-roll-deg",
- true);
- _pitch_out_node =
- fgGetNode("/instrumentation/attitude-indicator/indicated-pitch-deg",
- true);
- _roll_out_node =
- fgGetNode("/instrumentation/attitude-indicator/indicated-roll-deg",
- true);
+ _suction_node = fgGetNode(vacuum_system.c_str(), true);
+ SGPropertyNode *cnode = node->getChild("config", 0, true);
+ _tumble_flag_node = cnode->getChild("tumble-flag", 0, true);
+ _caged_node = node->getChild("caged-flag", 0, true);
+ _tumble_node = node->getChild("tumble-norm", 0, true);
+ _pitch_int_node = node->getChild("internal-pitch-deg", 0, true);
+ _roll_int_node = node->getChild("internal-roll-deg", 0, true);
+ _pitch_out_node = node->getChild("indicated-pitch-deg", 0, true);
+ _roll_out_node = node->getChild("indicated-roll-deg", 0, true);
+
+ //_serviceable_node->setBoolValue(true);
}
void
AttitudeIndicator::bind ()
{
- fgTie("/instrumentation/attitude-indicator/serviceable",
+ string branch;
+ branch = "/instrumentation/" + name + "/serviceable";
+
+ fgTie(branch.c_str(),
&_gyro, &Gyro::is_serviceable, &Gyro::set_serviceable);
- fgTie("/instrumentation/attitude-indicator/spin",
+ branch = "/instrumentation/" + name + "/spin";
+ fgTie(branch.c_str(),
&_gyro, &Gyro::get_spin_norm, &Gyro::set_spin_norm);
}
void
AttitudeIndicator::unbind ()
{
- fgUntie("/instrumentation/attitude-indicator/serviceable");
- fgUntie("/instrumentation/attitude-indicator/spin");
+ string branch;
+ branch = "/instrumentation/" + name + "/serviceable";
+
+ fgUntie(branch.c_str());
+ branch = "/instrumentation/" + name + "/spin";
+ fgUntie(branch.c_str());
}
void
/**
* Model a vacuum-powered attitude indicator.
*
- * This first, simple draft is hard-wired to vacuum pump #1.
- *
* Input properties:
*
- * /instrumentation/attitude-indicator/config/tumble-flag
- * /instrumentation/attitude-indicator/serviceable
- * /instrumentation/attitude-indicator/caged-flag
- * /instrumentation/attitude-indicator/tumble-norm
+ * /instrumentation/"name"/config/tumble-flag
+ * /instrumentation/"name"/serviceable
+ * /instrumentation/"name"/caged-flag
+ * /instrumentation/"name"/tumble-norm
* /orientation/pitch-deg
* /orientation/roll-deg
- * /systems/vacuum[0]/suction-inhg
+ * "vacuum-system"/suction-inhg
*
* Output properties:
*
- * /instrumentation/attitude-indicator/indicated-pitch-deg
- * /instrumentation/attitude-indicator/indicated-roll-deg
- * /instrumentation/attitude-indicator/tumble-norm
+ * /instrumentation/"name"/indicated-pitch-deg
+ * /instrumentation/"name"/indicated-roll-deg
+ * /instrumentation/"name"/tumble-norm
*/
class AttitudeIndicator : public SGSubsystem
{
public:
+ AttitudeIndicator ( SGPropertyNode *node );
AttitudeIndicator ();
virtual ~AttitudeIndicator ();
private:
+ string name;
+ int num;
+ string vacuum_system;
+
Gyro _gyro;
SGPropertyNode_ptr _tumble_flag_node;
#include <Main/util.hxx>
+Clock::Clock ( SGPropertyNode *node )
+ : _is_serviceable(true),
+ _gmt_time_sec(0),
+ _offset_sec(0),
+ _indicated_sec(0),
+ _standstill_offset(0),
+ name("clock"),
+ num(0)
+{
+ _indicated_string[0] = '\0';
+
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in clock config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
Clock::Clock ()
: _is_serviceable(true),
_gmt_time_sec(0),
void
Clock::init ()
{
- _serviceable_node = fgGetNode("/instrumentation/clock/serviceable", true);
- _offset_node = fgGetNode("/instrumentation/clock/offset-sec", true);
- _sec_node = fgGetNode("/instrumentation/clock/indicated-sec", true);
- _string_node = fgGetNode("/instrumentation/clock/indicated-string", true);
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
+ _offset_node = node->getChild("offset-sec", 0, true);
+ _sec_node = node->getChild("indicated-sec", 0, true);
+ _string_node = node->getChild("indicated-string", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
public:
+ Clock ( SGPropertyNode *node );
Clock ();
virtual ~Clock ();
char _indicated_string[16];
long _standstill_offset;
+ string name;
+ int num;
+
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _offset_node;
SGPropertyNode_ptr _sec_node;
}
+DME::DME ( SGPropertyNode *node )
+ : _last_distance_nm(0),
+ _last_frequency_mhz(-1),
+ _time_before_search_sec(0),
+ _transmitter_valid(false),
+ _transmitter_elevation_ft(0),
+ _transmitter_range_nm(0),
+ _transmitter_bias(0.0),
+ name("dme"),
+ num(0)
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in dme config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
DME::DME ()
: _last_distance_nm(0),
_last_frequency_mhz(-1),
void
DME::init ()
{
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+
_longitude_node = fgGetNode("/position/longitude-deg", true);
_latitude_node = fgGetNode("/position/latitude-deg", true);
_altitude_node = fgGetNode("/position/altitude-ft", true);
- _serviceable_node = fgGetNode("/instrumentation/dme/serviceable", true);
+ _serviceable_node = node->getChild("serviceable", 0, true);
_electrical_node = fgGetNode("/systems/electrical/outputs/dme", true);
- _source_node = fgGetNode("/instrumentation/dme/frequencies/source", true);
- _frequency_node =
- fgGetNode("/instrumentation/dme/frequencies/selected-mhz", true);
-
- _in_range_node = fgGetNode("/instrumentation/dme/in-range", true);
- _distance_node =
- fgGetNode("/instrumentation/dme/indicated-distance-nm", true);
- _speed_node =
- fgGetNode("/instrumentation/dme/indicated-ground-speed-kt", true);
- _time_node =
- fgGetNode("/instrumentation/dme/indicated-time-min", true);
+ SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
+ _source_node = fnode->getChild("source", 0, true);
+ _frequency_node = fnode->getChild("selected-mhz", 0, true);
+ _in_range_node = node->getChild("in-range", 0, true);
+ _distance_node = node->getChild("indicated-distance-nm", 0, true);
+ _speed_node = node->getChild("indicated-ground-speed", 0, true);
+ _time_node = node->getChild("indicated-time-min", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
// Figure out the source
const char * source = _source_node->getStringValue();
if (source[0] == '\0') {
- source = "/instrumentation/dme/frequencies/selected-mhz";
+ string branch;
+ branch = "/instrumentation/" + name + "/frequencies/selected-mhz";
+ source = branch.c_str();
_source_node->setStringValue(source);
}
* /position/latitude-deg
* /position/altitude-ft
* /systems/electrical/outputs/dme
- * /instrumentation/dme/serviceable
- * /instrumentation/dme/frequencies/source
- * /instrumentation/dme/frequencies/selected-mhz
+ * /instrumentation/"name"/serviceable
+ * /instrumentation/"name"/frequencies/source
+ * /instrumentation/"name"/frequencies/selected-mhz
*
* Output properties:
*
- * /instrumentation/dme/in-range
- * /instrumentation/dme/indicated-distance-nm
- * /instrumentation/dme/indicated-ground-speed-kt
- * /instrumentation/dme/indicated-time-kt
+ * /instrumentation/"name"/in-range
+ * /instrumentation/"name"/indicated-distance-nm
+ * /instrumentation/"name"/indicated-ground-speed-kt
+ * /instrumentation/"name"/indicated-time-kt
*/
class DME : public SGSubsystem
{
public:
+ DME ( SGPropertyNode *node );
DME ();
virtual ~DME ();
double _transmitter_range_nm;
double _transmitter_bias;
+ string name;
+ int num;
+
};
SG_USING_STD(string);
+GPS::GPS ( SGPropertyNode *node)
+ : _last_valid(false),
+ _last_longitude_deg(0),
+ _last_latitude_deg(0),
+ _last_altitude_m(0),
+ _last_speed_kts(0)
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in gps config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
GPS::GPS ()
: _last_valid(false),
_last_longitude_deg(0),
void
GPS::init ()
{
+ route = new SGRoute;
+ route->clear();
+
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+
_longitude_node = fgGetNode("/position/longitude-deg", true);
_latitude_node = fgGetNode("/position/latitude-deg", true);
_altitude_node = fgGetNode("/position/altitude-ft", true);
_magvar_node = fgGetNode("/environment/magnetic-variation-deg", true);
- _serviceable_node = fgGetNode("/instrumentation/gps/serviceable", true);
+ _serviceable_node = node->getChild("serviceable", 0, true);
_electrical_node = fgGetNode("/systems/electrical/outputs/gps", true);
- _wp0_longitude_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/longitude-deg", true);
- _wp0_latitude_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/latitude-deg", true);
- _wp0_altitude_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/altitude-ft", true);
- _wp0_ID_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/ID", true);
- _wp0_name_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/name", true);
- _wp0_course_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/desired-course-deg", true);
- _wp0_waypoint_type_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/waypoint-type", true);
- _wp1_longitude_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/longitude-deg", true);
- _wp1_latitude_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/latitude-deg", true);
- _wp1_altitude_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/altitude-ft", true);
- _wp1_ID_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/ID", true);
- _wp1_name_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/name", true);
- _wp1_course_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/desired-course-deg", true);
- _wp1_waypoint_type_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/waypoint-type", true);
- _get_nearest_airport_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/get-nearest-airport", true);
- _tracking_bug_node =
- fgGetNode("/instrumentation/gps/tracking-bug", true);
-
- _raim_node = fgGetNode("/instrumentation/gps/raim", true);
+
+ SGPropertyNode *wp_node = node->getChild("wp", 0, true);
+ SGPropertyNode *wp0_node = wp_node->getChild("wp", 0, true);
+ SGPropertyNode *wp1_node = wp_node->getChild("wp", 1, true);
+ addWp = wp1_node->getChild("Add-to-route", 0, true);
+
+ _wp0_longitude_node = wp0_node->getChild("longitude-deg", 0, true);
+ _wp0_latitude_node = wp0_node->getChild("latitude-deg", 0, true);
+ _wp0_altitude_node = wp0_node->getChild("altitude-deg", 0, true);
+ _wp0_ID_node = wp0_node->getChild("ID", 0, true);
+ _wp0_name_node = wp0_node->getChild("name", 0, true);
+ _wp0_course_node = wp0_node->getChild("desired-course-deg", 0, true);
+ _wp0_waypoint_type_node = wp0_node->getChild("waypoint-type", 0, true);
+ _wp0_distance_node = wp0_node->getChild("distance-nm", 0, true);
+ _wp0_ttw_node = wp0_node->getChild("TTW", 0, true);
+ _wp0_bearing_node = wp0_node->getChild("bearing-true-deg", 0, true);
+ _wp0_mag_bearing_node = wp0_node->getChild("bearing-mag-deg", 0, true);
+ _wp0_course_deviation_node =
+ wp0_node->getChild("course-deviation-deg", 0, true);
+ _wp0_course_error_nm_node = wp0_node->getChild("course-error-nm", 0, true);
+ _wp0_to_flag_node = wp0_node->getChild("to-flag", 0, true);
+ _true_wp0_bearing_error_node =
+ wp0_node->getChild("true-bearing-error-deg", 0, true);
+ _magnetic_wp0_bearing_error_node =
+ wp0_node->getChild("magnetic-bearing-error-deg", 0, true);
+
+ _wp1_longitude_node = wp1_node->getChild("longitude-deg", 0, true);
+ _wp1_latitude_node = wp1_node->getChild("latitude-deg", 0, true);
+ _wp1_altitude_node = wp1_node->getChild("altitude-deg", 0, true);
+ _wp1_ID_node = wp1_node->getChild("ID", 0, true);
+ _wp1_name_node = wp1_node->getChild("name", 0, true);
+ _wp1_course_node = wp1_node->getChild("desired-course-deg", 0, true);
+ _wp1_waypoint_type_node = wp1_node->getChild("waypoint-type", 0, true);
+ _wp1_distance_node = wp1_node->getChild("distance-nm", 0, true);
+ _wp1_ttw_node = wp1_node->getChild("TTW", 0, true);
+ _wp1_bearing_node = wp1_node->getChild("bearing-true-deg", 0, true);
+ _wp1_mag_bearing_node = wp1_node->getChild("bearing-mag-deg", 0, true);
+ _wp1_course_deviation_node =
+ wp1_node->getChild("course-deviation-deg", 0, true);
+ _wp1_course_error_nm_node = wp1_node->getChild("course-error-nm", 0, true);
+ _wp1_to_flag_node = wp1_node->getChild("to-flag", 0, true);
+ _true_wp1_bearing_error_node =
+ wp1_node->getChild("true-bearing-error-deg", 0, true);
+ _magnetic_wp1_bearing_error_node =
+ wp1_node->getChild("magnetic-bearing-error-deg", 0, true);
+ _get_nearest_airport_node =
+ wp1_node->getChild("get-nearest-airport", 0, true);
+
+ _tracking_bug_node = node->getChild("tracking-bug", 0, true);
+ _raim_node = node->getChild("raim", 0, true);
+
_indicated_longitude_node =
- fgGetNode("/instrumentation/gps/indicated-longitude-deg", true);
+ node->getChild("indicated-longitude-deg", 0, true);
_indicated_latitude_node =
- fgGetNode("/instrumentation/gps/indicated-latitude-deg", true);
+ node->getChild("indicated-latitude-deg", 0, true);
_indicated_altitude_node =
- fgGetNode("/instrumentation/gps/indicated-altitude-ft", true);
+ node->getChild("indicated-altitude-ft", 0, true);
_indicated_vertical_speed_node =
- fgGetNode("/instrumentation/gps/indicated-vertical-speed", true);
+ node->getChild("indicated-vertical-speed", 0, true);
_true_track_node =
- fgGetNode("/instrumentation/gps/indicated-track-true-deg", true);
+ node->getChild("indicated-track-true-deg", 0, true);
_magnetic_track_node =
- fgGetNode("/instrumentation/gps/indicated-track-magnetic-deg", true);
+ node->getChild("indicated-track_magnetic-deg", 0, true);
_speed_node =
- fgGetNode("/instrumentation/gps/indicated-ground-speed-kt", true);
- _wp0_distance_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/distance-nm", true);
- _wp0_ttw_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/TTW",true);
- _wp0_bearing_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/bearing-true-deg", true);
- _wp0_mag_bearing_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/bearing-mag-deg", true);
- _wp0_course_deviation_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/course-deviation-deg", true);
- _wp0_course_error_nm_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/course-error-nm", true);
- _wp0_to_flag_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/to-flag", true);
- _wp1_distance_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/distance-nm", true);
- _wp1_ttw_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/TTW",true);
- _wp1_bearing_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/bearing-true-deg", true);
- _wp1_mag_bearing_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/bearing-mag-deg", true);
- _wp1_course_deviation_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/course-deviation-deg", true);
- _wp1_course_error_nm_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/course-error-nm", true);
- _wp1_to_flag_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/to-flag", true);
+ node->getChild("indicated-ground-speed-kt", 0, true);
_odometer_node =
- fgGetNode("/instrumentation/gps/odometer", true);
+ node->getChild("odometer", 0, true);
_trip_odometer_node =
- fgGetNode("/instrumentation/gps/trip-odometer", true);
+ node->getChild("trip-odometer", 0, true);
_true_bug_error_node =
- fgGetNode("/instrumentation/gps/true-bug-error-deg", true);
+ node->getChild("true-bug-error-deg", 0, true);
_magnetic_bug_error_node =
- fgGetNode("/instrumentation/gps/magnetic-bug-error-deg", true);
- _true_wp0_bearing_error_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/true-bearing-error-deg", true);
- _magnetic_wp0_bearing_error_node =
- fgGetNode("/instrumentation/gps/wp/wp[0]/magnetic-bearing-error-deg", true);
- _true_wp1_bearing_error_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/true-bearing-error-deg", true);
- _magnetic_wp1_bearing_error_node =
- fgGetNode("/instrumentation/gps/wp/wp[1]/magnetic-bearing-error-deg", true);
+ node->getChild("magnetic-bug-error-deg", 0, true);
+
_leg_distance_node =
- fgGetNode("/instrumentation/gps/wp/leg-distance-nm", true);
+ wp_node->getChild("leg-distance-nm", 0, true);
_leg_course_node =
- fgGetNode("/instrumentation/gps/wp/leg-true-course-deg", true);
+ wp_node->getChild("leg-true-course-deg", 0, true);
_leg_magnetic_course_node =
- fgGetNode("/instrumentation/gps/wp/leg-mag-course-deg", true);
+ wp_node->getChild("leg-mag-course-deg", 0, true);
_alt_dist_ratio_node =
- fgGetNode("/instrumentation/gps/wp/alt-dist-ratio", true);
+ wp_node->getChild("alt-dist-ratio", 0, true);
_leg_course_deviation_node =
- fgGetNode("/instrumentation/gps/wp/leg-course-deviation-deg", true);
+ wp_node->getChild("leg-course-deviation-deg", 0, true);
_leg_course_error_nm_node =
- fgGetNode("/instrumentation/gps/wp/leg-course-error-nm", true);
+ wp_node->getChild("leg-course-error-nm", 0, true);
_leg_to_flag_node =
- fgGetNode("/instrumentation/gps/wp/leg-to-flag", true);
+ wp_node->getChild("leg-to-flag", 0, true);
_alt_deviation_node =
- fgGetNode("/instrumentation/gps/wp/alt-deviation-ft", true);
+ wp_node->getChild("alt-deviation-ft", 0, true);
+
+ _route = node->getChild("route", 0, true);
+ popWp = _route->getChild("Pop-WP", 0, true);
+
+ addWp->setBoolValue(false);
+ popWp->setBoolValue(false);
+
+ _serviceable_node->setBoolValue(true);
}
void
_true_bug_error_node->setDoubleValue(true_bug_error);
_magnetic_bug_error_node->setDoubleValue(magnetic_bug_error);
+
+ // Add WP 1 to the route.
+ if ( addWp->getBoolValue() )
+ {
+ addWp->setBoolValue(false);
+
+ SGWayPoint tempWp( _wp1_longitude_node->getDoubleValue(),
+ _wp1_latitude_node->getDoubleValue(),
+ _wp1_altitude_node->getDoubleValue(),
+ SGWayPoint::WGS84,
+ _wp1_ID_node->getStringValue(),
+ _wp1_name_node->getStringValue() );
+
+ route->add_waypoint(tempWp);
+
+ SGPropertyNode *wp =
+ _route->getChild("Waypoint", route->size()-1, true);
+ SGPropertyNode *id = wp->getChild("ID", 0, true);
+ SGPropertyNode *name = wp->getChild("Name", 0, true);
+ SGPropertyNode *lat = wp->getChild("Latitude", 0, true);
+ SGPropertyNode *lon = wp->getChild("Longitude", 0, true);
+ SGPropertyNode *alt = wp->getChild("Altitude", 0, true);
+
+ id->setStringValue( tempWp.get_id().c_str() );
+ name->setStringValue( tempWp.get_name().c_str() );
+ lat->setDoubleValue( tempWp.get_target_lat() );
+ lon->setDoubleValue( tempWp.get_target_lon() );
+ alt->setDoubleValue( tempWp.get_target_alt() );
+ }
+
+ if ( popWp->getBoolValue() )
+ {
+ popWp->setBoolValue(false);
+
+ route->delete_first();
+ }
+
} else {
_true_track_node->setDoubleValue(0.0);
_magnetic_track_node->setDoubleValue(0.0);
#endif
#include <simgear/props/props.hxx>
+#include <simgear/route/route.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
public:
+ GPS (SGPropertyNode *node);
GPS ();
virtual ~GPS ();
SGPropertyNode_ptr _leg_to_flag_node;
SGPropertyNode_ptr _alt_deviation_node;
+ SGPropertyNode *_route;
+ SGPropertyNode *addWp;
+ SGPropertyNode *popWp;
+
+ SGRoute *route;
+
bool _last_valid;
double _last_longitude_deg;
double _last_latitude_deg;
double range_error;
double elapsed_time;
+ string name;
+ int num;
+
};
#include <Main/util.hxx>
+HeadingIndicator::HeadingIndicator ( SGPropertyNode *node )
+ :
+ name("heading-indicator"),
+ num(0),
+ vacuum_system("/systems/vacuum")
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else if ( cname == "vacuum-system" ) {
+ vacuum_system = cval;
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in heading-indicator config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
HeadingIndicator::HeadingIndicator ()
{
}
void
HeadingIndicator::init ()
{
- _offset_node =
- fgGetNode("/instrumentation/heading-indicator/offset-deg", true);
+ string branch;
+ branch = "/instrumentation/" + name;
+ vacuum_system += "/suction-inhg";
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _offset_node = node->getChild("offset-deg", 0, true);
_heading_in_node = fgGetNode("/orientation/heading-deg", true);
- _suction_node = fgGetNode("/systems/vacuum[0]/suction-inhg", true);
- _heading_out_node =
- fgGetNode("/instrumentation/heading-indicator/indicated-heading-deg",
- true);
+ _suction_node = fgGetNode(vacuum_system.c_str(), true);
+ _heading_out_node = node->getChild("indicated-heading-deg", 0, true);
_last_heading_deg = (_heading_in_node->getDoubleValue() +
_offset_node->getDoubleValue());
+
+ //_serviceable_node->setBoolValue(true);
}
void
HeadingIndicator::bind ()
{
- fgTie("/instrumentation/heading-indicator/serviceable",
+ string branch;
+ branch = "/instrumentation/" + name + "/serviceable";
+ fgTie(branch.c_str(),
&_gyro, &Gyro::is_serviceable, &Gyro::set_serviceable);
- fgTie("/instrumentation/heading-indicator/spin",
+ branch = "/instrumentation/" + name + "/spin";
+ fgTie(branch.c_str(),
&_gyro, &Gyro::get_spin_norm, &Gyro::set_spin_norm);
}
void
HeadingIndicator::unbind ()
{
- fgUntie("/instrumentation/heading-indicator/serviceable");
- fgUntie("/instrumentation/heading-indicator/spin");
+ string branch;
+ branch = "/instrumentation/" + name + "/serviceable";
+ fgUntie(branch.c_str());
+ branch = "/instrumentation/" + name + "/spin";
+ fgUntie(branch.c_str());
}
void
/**
* Model a vacuum-powered heading indicator.
*
- * This first, simple draft is hard-wired to vacuum pump #1.
- *
* Input properties:
*
- * /instrumentation/heading-indicator/serviceable
- * /instrumentation/heading-indicator/spin
- * /instrumentation/heading-indicator/offset-deg
+ * /instrumentation/"name"/serviceable
+ * /instrumentation/"name"/spin
+ * /instrumentation/"name"/offset-deg
* /orientation/heading-deg
- * /systems/vacuum[0]/suction-inhg
+ * "vacuum_system"/suction-inhg
*
* Output properties:
*
- * /instrumentation/heading-indicator/indicated-heading-deg
+ * /instrumentation/"name"/indicated-heading-deg
*/
class HeadingIndicator : public SGSubsystem
{
public:
+ HeadingIndicator ( SGPropertyNode *node );
HeadingIndicator ();
virtual ~HeadingIndicator ();
Gyro _gyro;
double _last_heading_deg;
+ string name;
+ int num;
+ string vacuum_system;
+
SGPropertyNode_ptr _offset_node;
SGPropertyNode_ptr _heading_in_node;
SGPropertyNode_ptr _suction_node;
//
// This file is in the Public Domain and comes with no warranty.
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#include <simgear/structure/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/sg_inlines.h>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Main/util.hxx>
#include "instrument_mgr.hxx"
#include "airspeed_indicator.hxx"
FGInstrumentMgr::FGInstrumentMgr ()
{
- set_subsystem("asi", new AirspeedIndicator);
+ //set_subsystem("asi", new AirspeedIndicator(0));
+ //set_subsystem("asi-backup", new AirspeedIndicator(1, 1, 1));
set_subsystem("annunciator", new Annunciator);
- set_subsystem("ai", new AttitudeIndicator);
- set_subsystem("alt", new Altimeter);
- set_subsystem("ti", new TurnIndicator);
- set_subsystem("ball", new SlipSkidBall);
- set_subsystem("hi", new HeadingIndicator);
- set_subsystem("vsi", new VerticalSpeedIndicator);
- set_subsystem("compass", new MagCompass);
- set_subsystem("dme", new DME, 1.0);
- set_subsystem("adf", new ADF, 0.15);
- set_subsystem("gps", new GPS, 0.45);
- set_subsystem("clock", new Clock, 0.25);
+ //set_subsystem("ai", new AttitudeIndicator);
+ //set_subsystem("alt", new Altimeter);
+ //set_subsystem("ti", new TurnIndicator);
+ //set_subsystem("ball", new SlipSkidBall);
+ //set_subsystem("hi", new HeadingIndicator);
+ //set_subsystem("vsi", new VerticalSpeedIndicator);
+ //set_subsystem("compass", new MagCompass);
+ //set_subsystem("dme", new DME, 1.0);
+ //set_subsystem("adf", new ADF, 0.15);
+ //set_subsystem("gps", new GPS, 0.45);
+ //set_subsystem("clock", new Clock, 0.25);
+ //set_subsystem("nhi", new NewHeadingIndicator);
+
+ config_props = new SGPropertyNode;
+
+ SGPropertyNode *path_n = fgGetNode("/sim/instrumentation/path");
+
+ if (path_n) {
+ SGPath config( globals->get_fg_root() );
+ config.append( path_n->getStringValue() );
+
+ SG_LOG( SG_ALL, SG_INFO, "Reading instruments from "
+ << config.str() );
+ try {
+ readProperties( config.str(), config_props );
+
+ if ( build() ) {
+ enabled = true;
+ } else {
+ SG_LOG( SG_ALL, SG_ALERT,
+ "Detected an internal inconsistancy in the instrumentation");
+ SG_LOG( SG_ALL, SG_ALERT,
+ " system specification file. See earlier errors for" );
+ SG_LOG( SG_ALL, SG_ALERT,
+ " details.");
+ exit(-1);
+ }
+ } catch (const sg_exception& exc) {
+ SG_LOG( SG_ALL, SG_ALERT, "Failed to load instrumentation system model: "
+ << config.str() );
+ }
+
+ } else {
+ SG_LOG( SG_ALL, SG_WARN,
+ "No instrumentation model specified for this model!");
+ }
+
+ delete config_props;
}
FGInstrumentMgr::~FGInstrumentMgr ()
{
}
+bool FGInstrumentMgr::build ()
+{
+ SGPropertyNode *node;
+ int i;
+
+ int count = config_props->nChildren();
+ for ( i = 0; i < count; ++i ) {
+ node = config_props->getChild(i);
+ string name = node->getName();
+ std::ostringstream temp;
+ temp << i;
+ if ( name == "adf" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new ADF( node ), 0.15 );
+ } else if ( name == "airspeed-indicator" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new AirspeedIndicator( node ) );
+ } else if ( name == "altimeter" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new Altimeter( node ) );
+ } else if ( name == "attitude-indicator" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new AttitudeIndicator( node ) );
+ } else if ( name == "clock" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new Clock( node ), 0.25 );
+ } else if ( name == "dme" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new DME( node ), 1.0 );
+ } else if ( name == "heading-indicator" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new HeadingIndicator( node ) );
+ } else if ( name == "magnetic-compass" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new MagCompass( node ) );
+ } else if ( name == "slip-skid-ball" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new SlipSkidBall( node ) );
+ } else if ( name == "turn-indicator" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new TurnIndicator( node ) );
+ } else if ( name == "vertical-speed-indicator" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new VerticalSpeedIndicator( node ) );
+ } else if ( name == "gps" ) {
+ set_subsystem( "instrument" + temp.str(),
+ new GPS( node ), 0.45 );
+ } else {
+ SG_LOG( SG_ALL, SG_ALERT, "Unknown top level section: "
+ << name );
+ return false;
+ }
+ }
+ return true;
+}
+
// end of instrument_manager.cxx
FGInstrumentMgr ();
virtual ~FGInstrumentMgr ();
+ bool build ();
+
+private:
+ SGPropertyNode *config_props;
+ bool enabled;
};
#include <Main/util.hxx>
+MagCompass::MagCompass ( SGPropertyNode *node )
+ : _error_deg(0.0),
+ _rate_degps(0.0),
+ name("magnetic-compass"),
+ num(0)
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in magnetic-compass config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
MagCompass::MagCompass ()
: _error_deg(0.0),
_rate_degps(0.0)
void
MagCompass::init ()
{
- _serviceable_node =
- fgGetNode("/instrumentation/magnetic-compass/serviceable", true);
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
_heading_node =
fgGetNode("/orientation/heading-deg", true);
_beta_node =
fgGetNode("/accelerations/ned/east-accel-fps_sec", true);
_down_accel_node =
fgGetNode("/accelerations/ned/down-accel-fps_sec", true);
- _out_node =
- fgGetNode("/instrumentation/magnetic-compass/indicated-heading-deg",
- true);
+ _out_node = node->getChild("indicated-heading-deg", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
*
* Input properties:
*
- * /instrumentation/magnetic-compass/serviceable
+ * /instrumentation/"name"/serviceable
* /orientation/heading-deg
* /orientation/beta-deg
* /environment/magnetic-variation-deg
*
* Output properties:
*
- * /instrumentation/magnetic-compass/indicated-heading-deg
+ * /instrumentation/"name"/indicated-heading-deg
*/
class MagCompass : public SGSubsystem
{
public:
+ MagCompass ( SGPropertyNode *node);
MagCompass ();
virtual ~MagCompass ();
double _error_deg;
double _rate_degps;
+ string name;
+ int num;
+
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _heading_node;
SGPropertyNode_ptr _beta_node;
#include <Main/util.hxx>
+SlipSkidBall::SlipSkidBall ( SGPropertyNode *node)
+ :
+ name("slip-skid-ball"),
+ num(0)
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in slip-skid-ball config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
SlipSkidBall::SlipSkidBall ()
{
}
void
SlipSkidBall::init ()
{
- _serviceable_node =
- fgGetNode("/instrumentation/slip-skid-ball/serviceable", true);
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
_y_accel_node = fgGetNode("/accelerations/pilot/y-accel-fps_sec", true);
_z_accel_node = fgGetNode("/accelerations/pilot/z-accel-fps_sec", true);
- _out_node =
- fgGetNode("/instrumentation/slip-skid-ball/indicated-slip-skid", true);
- _override_node =
- fgGetNode("/instrumentation/slip-skid-ball/override", true);
+ _out_node = node->getChild("indicated-slip-skid", 0, true);
+ _override_node = node->getChild("iverride", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
*
* Input properties:
*
- * /instrumentation/slip-skid-ball/serviceable
+ * /instrumentation/"name"/serviceable
* /accelerations/pilot/y-accel-fps_sec
* /accelerations/pilot/z-accel-fps_sec
*
* Output properties:
*
- * /instrumentation/slip-skid-ball/indicated-slip-skid
+ * /instrumentation/"name"/indicated-slip-skid
*/
class SlipSkidBall : public SGSubsystem
{
public:
+ SlipSkidBall ( SGPropertyNode *node );
SlipSkidBall ();
virtual ~SlipSkidBall ();
Gyro _gyro;
double _last_pos;
+ string name;
+ int num;
+
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _y_accel_node;
SGPropertyNode_ptr _z_accel_node;
#define RESPONSIVENESS 0.5
+TurnIndicator::TurnIndicator ( SGPropertyNode *node) :
+ _last_rate(0),
+ name("turn-indicator"),
+ num(0)
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in turn-indicator config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
TurnIndicator::TurnIndicator () :
_last_rate(0)
{
void
TurnIndicator::init ()
{
+ string branch;
+ branch = "/instrumentation/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
_roll_rate_node = fgGetNode("/orientation/roll-rate-degps", true);
_yaw_rate_node = fgGetNode("/orientation/yaw-rate-degps", true);
_electric_current_node =
fgGetNode("/systems/electrical/outputs/turn-coordinator", true);
- _rate_out_node =
- fgGetNode("/instrumentation/turn-indicator/indicated-turn-rate", true);
+ _rate_out_node = node->getChild("indicated-turn-rate", 0, true);
+
+ //_serviceable_node->setBoolValue(true);
+
}
void
TurnIndicator::bind ()
{
- fgTie("/instrumentation/turn-indicator/serviceable",
+ string branch;
+ branch = "/instrumentation/" + name + "/serviceable";
+ fgTie(branch.c_str(),
&_gyro, &Gyro::is_serviceable, &Gyro::set_serviceable);
- fgTie("/instrumentation/turn-indicator/spin",
+ branch = "/instrumentation/" + name + "/spin";
+ fgTie(branch.c_str(),
&_gyro, &Gyro::get_spin_norm, &Gyro::set_spin_norm);
}
void
TurnIndicator::unbind ()
{
- fgUntie("/instrumentation/turn-indicator/serviceable");
- fgUntie("/instrumentation/turn-indicator/spin");
+ string branch;
+ branch = "/instrumentation/" + name + "/serviceable";
+ fgUntie(branch.c_str());
+ branch = "/instrumentation/" + name + "/spin";
+ fgUntie(branch.c_str());
}
void
*
* Input properties:
*
- * /instrumentation/turn-indicator/serviceable
- * /instrumentation/turn-indicator/spin
+ * /instrumentation/"name"/serviceable
+ * /instrumentation/"name"/spin
* /orientation/roll-rate-degps
* /orientation/yaw-rate-degps
* /systems/electrical/outputs/turn-coordinator
*
* Output properties:
*
- * /instrumentation/turn-indicator/indicated-turn-rate
+ * /instrumentation/"name"/indicated-turn-rate
*/
class TurnIndicator : public SGSubsystem
{
public:
+ TurnIndicator ( SGPropertyNode *node );
TurnIndicator ();
virtual ~TurnIndicator ();
Gyro _gyro;
double _last_rate;
+ string name;
+ int num;
+
SGPropertyNode_ptr _roll_rate_node;
SGPropertyNode_ptr _yaw_rate_node;
SGPropertyNode_ptr _electric_current_node;
#include <Main/util.hxx>
+VerticalSpeedIndicator::VerticalSpeedIndicator ( SGPropertyNode *node )
+ : _internal_pressure_inhg(29.92),
+ name("vertical-speed-indicator"),
+ num(0),
+ static_port("/systems/static")
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else if ( cname == "static-port" ) {
+ static_port = cval;
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in vertical-speed-indicator config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
VerticalSpeedIndicator::VerticalSpeedIndicator ()
: _internal_pressure_inhg(29.92)
{
void
VerticalSpeedIndicator::init ()
{
- _serviceable_node =
- fgGetNode("/instrumentation/vertical-speed-indicator/serviceable",
- true);
- _pressure_node =
- fgGetNode("/systems/static/pressure-inhg", true);
- _speed_node =
- fgGetNode("/instrumentation/vertical-speed-indicator/indicated-speed-fpm",
- true);
+ string branch;
+ branch = "/instrumentation/" + name;
+ static_port += "/pressure-inhg";
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
+ _pressure_node = fgGetNode(static_port.c_str(), true);
+ _speed_node = node->getChild("indicated-speed-fpm", 0, true);
+ _serviceable_node->setBoolValue(true);
// Initialize at ambient pressure
_internal_pressure_inhg = _pressure_node->getDoubleValue();
}
*
* Input properties:
*
- * /instrumentation/vertical-speed-indicator/serviceable
- * /systems/static[0]/pressure-inhg
+ * /instrumentation/"name"/serviceable
+ * "static_port"/pressure-inhg
*
* Output properties:
*
- * /instrumentation/vertical-speed-indicator/indicated-speed-fpm
+ * /instrumentation/"name"/indicated-speed-fpm
*/
class VerticalSpeedIndicator : public SGSubsystem
{
public:
+ VerticalSpeedIndicator ( SGPropertyNode *node );
VerticalSpeedIndicator ();
virtual ~VerticalSpeedIndicator ();
double _internal_pressure_inhg;
+ string name;
+ int num;
+ string static_port;
+
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _pressure_node;
SGPropertyNode_ptr _speed_node;
#include <Main/util.hxx>
-PitotSystem::PitotSystem ()
+
+PitotSystem::PitotSystem ( SGPropertyNode *node )
+ :
+ name("pitot"),
+ num(0)
{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in systems config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
+PitotSystem::PitotSystem ( int i )
+{
+ num = i;
+ name = "pitot";
}
PitotSystem::~PitotSystem ()
void
PitotSystem::init ()
{
- _serviceable_node = fgGetNode("/systems/pitot[0]/serviceable", true);
+ string branch;
+ branch = "/systems/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
_pressure_node = fgGetNode("/environment/pressure-inhg", true);
_density_node = fgGetNode("/environment/density-slugft3", true);
_velocity_node = fgGetNode("/velocities/airspeed-kt", true);
- _total_pressure_node =
- fgGetNode("/systems/pitot[0]/total-pressure-inhg", true);
+ _total_pressure_node = node->getChild("total-pressure-inhg", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
# error This library requires C++
#endif
+#include <simgear/compiler.h>
+
+#include STL_STRING
+SG_USING_STD(string);
+
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
*
* Input properties:
*
- * /systems/pitot[0]/serviceable
+ * /systems/"name"/serviceable
* /environment/pressure-slugft3
* /environment/density-slugft3
* /velocities/airspeed-kt
*
* Output properties:
*
- * /systems/pitot[0]/total-pressure-inhg
+ * /systems/"name"/total-pressure-inhg
*/
class PitotSystem : public SGSubsystem
{
public:
- PitotSystem ();
+ PitotSystem ( SGPropertyNode *node );
+ PitotSystem ( int i );
virtual ~PitotSystem ();
virtual void init ();
private:
+ int num;
+ string name;
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _pressure_node;
SGPropertyNode_ptr _density_node;
#include <Main/util.hxx>
-StaticSystem::StaticSystem ()
+StaticSystem::StaticSystem ( SGPropertyNode *node )
+ :
+ name("static"),
+ num(0)
{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in systems config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
+StaticSystem::StaticSystem ( int i )
+{
+ name = "static";
+ num = i;
}
StaticSystem::~StaticSystem ()
void
StaticSystem::init ()
{
- _serviceable_node = fgGetNode("/systems/static[0]/serviceable", true);
+ string branch;
+ branch = "/systems/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ _serviceable_node = node->getChild("serviceable", 0, true);
_pressure_in_node = fgGetNode("/environment/pressure-inhg", true);
- _pressure_out_node = fgGetNode("/systems/static[0]/pressure-inhg", true);
+ _pressure_out_node = node->getChild("pressure-inhg", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
* Input properties:
*
* /environment/pressure-inhg
- * /systems/static[0]/serviceable
+ * /systems/"name"/serviceable
*
* Output properties:
*
- * /systems/static[0]/pressure-inhg
+ * /systems/"name"/pressure-inhg
*
- * TODO: support multiple static ports and specific locations
+ * TODO: support specific locations
* TODO: support alternate air with errors
*/
class StaticSystem : public SGSubsystem
public:
- StaticSystem ();
+ StaticSystem ( SGPropertyNode *node );
+ StaticSystem ( int i );
virtual ~StaticSystem ();
virtual void init ();
private:
+ string name;
+ int num;
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _pressure_in_node;
SGPropertyNode_ptr _pressure_out_node;
//
// This file is in the Public Domain and comes with no warranty.
+#include <simgear/structure/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/sg_inlines.h>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Main/util.hxx>
+
+#include <iostream>
+#include <string>
+#include <sstream>
#include "system_mgr.hxx"
#include "electrical.hxx"
FGSystemMgr::FGSystemMgr ()
{
set_subsystem( "electrical", new FGElectricalSystem );
- set_subsystem( "pitot", new PitotSystem );
- set_subsystem( "static", new StaticSystem );
- set_subsystem( "vacuum-l", new VacuumSystem(0) );
- set_subsystem( "vacuum-r", new VacuumSystem(1) );
set_subsystem( "submodel", new SubmodelSystem() );
+
+ config_props = new SGPropertyNode;
+
+ SGPropertyNode *path_n = fgGetNode("/sim/systems/path");
+
+ if (path_n) {
+ SGPath config( globals->get_fg_root() );
+ config.append( path_n->getStringValue() );
+
+ SG_LOG( SG_ALL, SG_INFO, "Reading systems from "
+ << config.str() );
+ try {
+ readProperties( config.str(), config_props );
+
+ if ( build() ) {
+ enabled = true;
+ } else {
+ SG_LOG( SG_ALL, SG_ALERT,
+ "Detected an internal inconsistancy in the systems");
+ SG_LOG( SG_ALL, SG_ALERT,
+ " system specification file. See earlier errors for" );
+ SG_LOG( SG_ALL, SG_ALERT,
+ " details.");
+ exit(-1);
+ }
+ } catch (const sg_exception& exc) {
+ SG_LOG( SG_ALL, SG_ALERT, "Failed to load systems system model: "
+ << config.str() );
+ }
+
+ } else {
+ SG_LOG( SG_ALL, SG_WARN,
+ "No systems model specified for this model!");
+ }
+
+ delete config_props;
}
FGSystemMgr::~FGSystemMgr ()
{
}
+bool FGSystemMgr::build ()
+{
+ SGPropertyNode *node;
+ int i;
+
+ int count = config_props->nChildren();
+ for ( i = 0; i < count; ++i ) {
+ node = config_props->getChild(i);
+ string name = node->getName();
+ std::ostringstream temp;
+ temp << i;
+ if ( name == "pitot" ) {
+ set_subsystem( "system" + temp.str(),
+ new PitotSystem( node ) );
+ } else if ( name == "static" ) {
+ set_subsystem( "system" + temp.str(),
+ new StaticSystem( node ) );
+ } else if ( name == "vacuum" ) {
+ set_subsystem( "system" + temp.str(),
+ new VacuumSystem( node ) );
+ } else {
+ SG_LOG( SG_ALL, SG_ALERT, "Unknown top level section: "
+ << name );
+ return false;
+ }
+ }
+ return true;
+}
+
// end of system_manager.cxx
#endif
#include <simgear/compiler.h>
+#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
/**
* Manage aircraft systems.
*
- * In the initial draft, the systems present are hard-coded, but they
- * will soon be configurable for individual aircraft.
+ * Multiple aircraft systems can be configured for each aircraft.
*/
class FGSystemMgr : public SGSubsystemGroup
{
FGSystemMgr ();
virtual ~FGSystemMgr ();
+ bool build ();
+
+private:
+ SGPropertyNode *config_props;
+ bool enabled;
+
};
#endif // __SYSTEM_MGR_HXX
#include <Main/fg_props.hxx>
+VacuumSystem::VacuumSystem ( SGPropertyNode *node )
+ :
+ name("vacuum"),
+ num(0),
+ rpm("/engines/engine[0]/rpm"),
+ scale(1.0)
+
+{
+ int i;
+ for ( i = 0; i < node->nChildren(); ++i ) {
+ SGPropertyNode *child = node->getChild(i);
+ string cname = child->getName();
+ string cval = child->getStringValue();
+ if ( cname == "name" ) {
+ name = cval;
+ } else if ( cname == "number" ) {
+ num = child->getIntValue();
+ } else if ( cname == "rpm" ) {
+ rpm = cval;
+ } else if ( cname == "scale" ) {
+ scale = child->getDoubleValue();
+ } else {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in vacuum config logic" );
+ if ( name.length() ) {
+ SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+ }
+ }
+ }
+}
+
VacuumSystem::VacuumSystem( int i )
{
+ name = "vacuum";
num = i;
+ rpm = "/engines/engine[0]/rpm";
+ scale = 1.0;
}
VacuumSystem::~VacuumSystem ()
void
VacuumSystem::init()
{
- // TODO: allow index of engine to be
- // configured.
- SGPropertyNode *node = fgGetNode("/systems/vacuum", num, true );
+ string branch;
+ branch = "/systems/" + name;
+
+ SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
_serviceable_node = node->getChild("serviceable", 0, true);
- _rpm_node = fgGetNode("/engines/engine[0]/rpm", true);
+ _rpm_node = fgGetNode(rpm.c_str(), true);
_pressure_node = fgGetNode("/environment/pressure-inhg", true);
_suction_node = node->getChild("suction-inhg", 0, true);
+
+ _serviceable_node->setBoolValue(true);
}
void
if (!_serviceable_node->getBoolValue()) {
suction = 0.0;
} else {
- double rpm = _rpm_node->getDoubleValue();
+ double rpm = _rpm_node->getDoubleValue() * scale;
double pressure = _pressure_node->getDoubleValue();
// This magic formula yields about 4 inhg at 700 rpm
suction = pressure * rpm / (rpm + 4875.0);
*
* Input properties:
*
- * /engines/engine[0]/rpm
+ * "rpm"
* /environment/pressure-inhg
- * /systems/vacuum[0]/serviceable
+ * /systems/"name"/serviceable
*
* Output properties:
*
- * /systems/vacuum[n]/suction-inhg
+ * /systems/"name"/suction-inhg
*/
class VacuumSystem : public SGSubsystem
{
public:
+ VacuumSystem( SGPropertyNode *node );
VacuumSystem( int i );
virtual ~VacuumSystem ();
private:
+ string name;
int num;
+ string rpm;
+ double scale;
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _rpm_node;
SGPropertyNode_ptr _pressure_node;